I am programming an app to allow for locally stored mp3 file playback as well as streaming from a server.
I use
AVAudioPlayer *player;
AVPlayer *player2;
depending on the type of playback. How do I query what the device volume level is initially so that I can set my volume.slider to its initial value?
First, import:
#import <AVFoundation/AVAudioSession.h>
Then get The system wide output volume set by the user using:
float volume = [[AVAudioSession sharedInstance] outputVolume];
Related
I am working on an iOS app with WebRTC. During the chat, volume is fine. But if I play an embedded youtube video through WKYTPlayerView, volume of the video is very low. If I disconnect the chat, video volume becomes normal again.
I have tried several things and I have been looking at this issue for few days. Here is how I am setting the category for audio session;
NSError *error = nil;
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord
withOptions: AVAudioSessionCategoryOptionMixWithOthers | AVAudioSessionCategoryOptionDefaultToSpeaker
error: &error];
if (error != nil) {
NSLog(#"Problem setting AVAudioSession to mix with others");
}
Any help is very much appreciated.
AFAIK, there are raised WebRTC issues. Here's 2 of them:
Low sound volume during calls
AGC sets volume to zero
You may want to check the given fix which is putting up a CL to fix the problem in all platforms. See if it also works for you.
Otherwise, you can try using mediastream-gain which is useful for controlling rhe volume of your microphone input before it's sent accross a peer connection in a WebRTC call.
Lastly, you may want to also check this thread for additional insights on application sharing to play YouTube videos.
I'm trying to combine media playback with VoIP feature (via Twilio) for iOS 9 and 8.While an audio stream plays in the background, I connect or disconnect a Voice Conference session which results in a volume jump from value X to value Y. This jump can be heard, as well as observed by a [AVAudioSession sharedInstance].outputVolume value change.I would like to prevent this jump and keep the volume at a constant level, unless the user manually decides to change it.Further investigation showed that while AVAudioSession's category is set to AVAudioSessionCategoryPlayAndRecord, switching between modes[[AVAudioSession sharedInstance] setMode:AVAudioSessionModeDefault error:&error]and[[AVAudioSession sharedInstance] setMode:AVAudioSessionModeVoiceChat error:&error]causes the app to operate in two completely separate volume scales, respectively.i.e there a volume for Mode "Default" and a completely unrelated volume for Mode "Voice Chat".AVAudioSession's documentation seems to omit any mention of volume in relation to mode/category switches and I can't find anything relevant on the interwebs...
Appreciate any help.
When setting your play and record category, pass AVAudioSessionCategoryOptionDefaultToSpeaker as an option:
[[AVAudioSession sharedInstance] AVAudioSessionCategoryPlayAndRecord withOptions: AVAudioSessionCategoryOptionDefaultToSpeaker error:&error];
This overrides the default play-and-record behaviour of switching from the speaker to the much quieter receiver. The reason for this being that play-and-record was designed for telephony, where you'd be holding the phone to year ear & presumably wouldn't want to have your hearing damaged by loud sounds.
Megan from Twilio here.
I'm not most familiar with the iOS SDK but you should be able to control connection audio from TCDevice parameters incomingSoundEnabled, outgoingSoundEnabled, and disconnectSoundEnabled as documented here.
Otherwise, I would suggest looking at the sharedInstance properties of AVAudioSession that the Twilio SDK calls upon as demonstrated in this post:
setCategory:error:
setActive:error:
overrideOutputAudioPort:error:
Please let me know if this helps.
I am currently working on a PhoneGap application that, upon pressing a button, is supposed to play an 8 seconds long sound clip, while at the same time streaming sound from the microphone over RTMP to a Wowza server through a Cordova plugin using the iOS library VideoCore.
My problem is that (on iOS exclusively) when the sound clip stops playing, the microphone - for some reason - also stops recording sound. However, the stream is still active, resulting in a sound clip on the server side consisting of 8 seconds of microphone input, then complete silence.
Commenting out the line that plays the sound results in the microphone recoding sound without a problem, however we need to be able to play the sound.
Defining the media variable:
_alarmSound = new Media("Audio/alarm.mp3")
Playing the sound and starting the stream:
if(_streamAudio){
startAudioStream(_alarmId);
}
if(localStorage.getItem("alarmSound") == "true"){
_alarmSound.play();
}
It seems to me like there is some kind of internal resource usage conflict occuring when PhoneGap stops playing the sound clip, however I have no idea what I can do to fix it.
I've encountered the same problem on iOS, and I solved it by doing two things:
AVAudioSession Category
In iOS, apps should specify their requirements on the sound resource using the singleton AVAudioSession. When using Cordova there is a plugin that enables you to do this: https://github.com/eworx/av-audio-session-adapter
So for example, when you want to just play sounds you set the category to PLAYBACK:
audioSession.setCategoryWithOptions(
AVAudioSessionAdapter.Categories.PLAYBACK,
AVAudioSessionAdapter.CategoryOptions.MIX_WITH_OTHERS,
successCallback,
errorCallback
);
And when you want to record sound using the microphone and still be able to playback sounds you set the category as PLAY_AND_RECORD:
audioSession.setCategoryWithOptions(
AVAudioSessionAdapter.Categories.PLAY_AND_RECORD,
AVAudioSessionAdapter.CategoryOptions.MIX_WITH_OTHERS,
successCallback,
errorCallback
);
cordova-plugin-media kills the AVAudioSession
The Media plugin that you're using for playback handles both recording and playback in a way that makes it impossible to combine with other sound plugins and the Web Audio API. It deactivates the AVAudioSession each time it has finished playback or recording. Since there is only one such session for your app, this effectively deactivates all sound in your app.
There is a bug registered for this: https://issues.apache.org/jira/browse/CB-11026
Since the bug is still not fixed, and you still want to use the Media plugin, the only way to fix this is to download the plugin code and comment out/remove the lines where the AVAudioSession is deactivated:
[self.avSession setActive:NO error:nil];
I found it took some effort to get the existing answers on this topic working with my code so I'm hoping this helps someone who needs a more explicit solution.
As of version 5.0.2 of the Cordova Media plugin this issue still persists. If you want to use this plugin, the most straightforward solution that I have found is to fork the plugin repository and make the following changes to src/ios/CDVSound.m. After quite some hours looking into this, I was unable to find a working solution without modifying the plugin source, nor was I able to find suitable alternative plugins.
Force session category
The author of the plugin mentioned in Edin's answer explains the issue with the AVAudioSession categories on a similar question. Since changes to CDVSound.m are necessary regardless, I found the following change easier than getting the eworx/av-audio-session-adapter plugin working.
Locate the following lines of code:
NSString* sessionCategory = bPlayAudioWhenScreenIsLocked ? AVAudioSessionCategoryPlayback : AVAudioSessionCategorySoloAmbient;
[self.avSession setCategory:sessionCategory error:&err];
Replace them with:
[self.avSession setCategory:AVAudioSessionCategoryPlayAndRecord error:&err];
Prevent session deactivation
Further more, the changes suggested in Edin's answer are necessary to prevent deactivation of additional audio sessions, however, not all instances need to be removed.
Remove the following line and surrounding conditional statements from the functions audioRecorderDidFinishRecording(), audioPlayerDidFinishPlaying and itemDidFinishPlaying():
[self.avSession setActive:NO error:nil];
The other instances of the code are used for error handling and resource release and, in my experience, do not need to be and should not be removed.
Update: Playback Volume
After apply these changes we experienced issues with low audio volume during playback (while recording was active). Adding the following lines after the respective setCategory lines from above allowed for playback at full volume. These changes are explained in the answer from which this fix was sourced.
[self.avSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];
and
[weakSelf.avSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];
I am currently making an app that is capable of streaming a music file. The problem is, our client wants it that while we are streaming an audio file, the streamed bytes will also be saved in the local storage. Which means that the streamed audio file will also be saved on the device's storage. For example I have this m4a file streamed, when the user stops streaming the audio file, the streamed music file will be saved in the device's local storage for future use.
Is this possible? If it is, what library should I use?
Thanks.
Yes it is possible use AVFoundation framework for this and play your audio.
First drag AVFoundation framework from built phase section then import like this #import <AVFoundation/AVFoundation.h>
Then declare AVAudioPlayer in .h file of your view controller instance like this
AVAudioPlayer *myAudioPlayer;
In view controller.m put this code
NSURL *fileURL = // your url.
myAudioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:fileURL error:nil];
myAudioPlayer.numberOfLoops = -1; //infinite loop
[myAudioPlayer play];
Via this way you are able to play audio in your iOS device.hope it will help your for playing audio
I've asked this question before but I feel I should start a new thread since my other thread is dated and probably poorly worded. I'm wondering what the best approach would be for adding volume control to an iOS app the is mostly silent. A good example would be a navigation app that only plays audio when you approach or miss a turn. In such an app, hearing a turn prompt which is not loud enough, the user would want the volume for the prompts to be audible and would naturally used the side volume controls to adjust prompts to their liking.
There are several problems here. One is that audio is not currently playing so the user has no reference as to how much it has been increased. This is more or less expected however there are technical issues that I am more interested in. To link the side volume control to your app you have to start and manage an audio session. I have not found an authoritative reference for such a situation as most documentation assumes you are currently playing or in the process of starting audio. Managing an audio session for a mostly silent app seems to be an edge case, though I find it rather common in that two of the major apps I've worked on require such functionality.
Of the various problems associated with audio session management, you have to address killing and restoring the audio session as you move in and out of the background. You have to consider other apps playing audio as you begin and stop the session. Depending on your type of app, you may have other more advanced needs such as custom override routing to the speakers, custom mute controls, etc. If you have any experience with such an app could you elaborate on how you addressed such challenges and expound on other issues?
One very common merhod is to set the audio session category appropriate for the type of app at launch, no matter whether sound is immanent or won't be played till tomorrow (as long as the purpose and settings of the app is to play such).
Added:
One way to allow to user to adjust the volume when the app is silent is to provide some means for the user to have your app to immediately start (and/or maybe stop) playing some sound with an amplitude typical for your app: some calibration tone/talk, your copyright notice, trademark jingle, or a safety message, for instance.
The main issue I see when developing apps that are mostly silent regard moving in/out of the foreground and playing nicely with other audio. To give a better idea of what I usually do I'll give some snippets from a recent project. (These are intentionally incomplete and only meant to illustrate a point.) For the sake of argument let's assume we have an AudioManager class that is responsible for maintaining the audio sessions. This class is what we use to instantiate our custom audio player. In such a class we put:
#interface MyAudioManager ()
#property (nonatomic, retain) BOOL alwaysMaintainAudioSession;
#property (nonatomic, retain) MyCustomAudioPlayer *player;
#end
#implementation MyAudioManager
#synthesize alwaysMaintainAudioSession;
#synthesize player;
-(void) applicationWillEnterForeground
{
isInBackground = NO;
if (NO==[self anyAudioIsPlaying] && self.alwaysMaintainAudioSession) {
[self activateAudioSession];
}
}
-(void) activateAudioSession
{
AudioSessionSetActive(TRUE);
AudioSessionAddPropertyListener ( kAudioSessionProperty_AudioRouteChange, AudioPropertyListener, self);
}
-(BOOL) anyAudioIsPlaying
{
return [self otherAudioIsPlaying] || [player isPlaying];
}
-(BOOL) otherAudioIsPlaying
{
UInt32 yesNo;
UInt32 propertySize = sizeof(yesNo);
OSStatus status = AudioSessionGetProperty(kAudioSessionProperty_OtherAudioIsPlaying, &propertySize, &yesNo);
if (kAudioSessionUnsupportedPropertyError == status) {
return MPMusicPlaybackStatePlaying == [theiPodMusicPlayer playbackState];
} else {
return MPMusicPlaybackStatePlaying == [theiPodMusicPlayer playbackState] || yesNo;
}
}
The manager allows you to set a property that always keeps the volume control linked to the app sounds which means we always make sure either a session is active or some other app is playing audio. In any other case the volume control reverts to controlling the ringer. So when entering the foreground we have to check for any other audio playing and conditionally activate the audio session. We also need to close the session when moving to the background to restore the ringer volume control.
-(void) applicationDidEnterBackground
{
if (NO==[self anyAudioIsPlaying]) {
AudioSessionSetActive(NO);
}
}
In my solution I include a bunch of other code to handle things like responding intelligently when bluetooth audio devices are connected, factory methods for creating the custom player, custom audio compression and more. The main idea, however, is handling other apps playing audio while attempting to keep the volume control linked to app volume while in the foreground.