how to find out if audio session is active in iOS - ios

I'm using AudioSessionSetActive(true) and AudioSessionSetActive(false) for setting the AudioSession to true or false in my iOS app.
At any point, I want to find out whether the session is active or not. Is there a way to do that?

Just ran into the same thing! There is no AudioSessionProperty key for querying whether or not the session is active. I believe this is another one of those set it and forget it deals where Apple believes apps should behave a certain way. Eg. most apps shouldn't need to know the state they should just set it as they need audio and kill it unconditionally as they are done playing audio. Of course this only works for the 90%. Apologies as this is not the best answer, I'm only reporting my suspicions. Maybe others have a better idea?

You can check if any audio is playing as it was launched by another app by inspecting the otherAudioPlaying property when you launch the app.
For internal tracking perhaps you could use a boolean when you do the AudioSessionSetActive(BOOL setActive) call. Though use of BOOL does not sound as a wonderful approach. Given my current knowledge I couldnt find any other way of determining if the AudioSession is active or not.

You can use this api to find out if audio session is active in iOS.
BOOL isPlaying = [[AVAudioSession sharedInstance] isOtherAudioPlaying];

Related

AVAudioSession mode switch volume difference

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.

PhoneGap/Cordova iOS playing sound disables microphone

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];

Unity sound not working after AVAudioSession is disabled

I'm currently working on a Unity3D iOS plugin. I'm trying to change the category of the app's AVAudioSession in order to implement audio ducking (i.e. Music app volume goes down while my sound effects are playing), which requires the AVAudioSession to be set as inactive and then as active again.
Well, after I set the session as inactive by using [[AVAudioSession sharedInstance] setActive:NO error:nil], Unity sounds simply won't work anymore, even after the session is set as active again. Native sounds still work, as I tested an AVAudioPlayer and it works perfectly.
Any idea on what's wrong?
User daniel_liu from Unity Answers helped me with this: Instead of setting the AVAudioSession as active/inactive by using the code I posted in the question, one should use UnitySetAudioSessionActive(true) and UnitySetAudioSessionActive(false).

How know if iOS device is sleeping in a background process

I have a application running in background and I need to know if device is sleeping in order to start a sincronisation process, but I didn't find information about this.
Does anyone know if it is posible and how do it?
Thanks.
You cannot know if the device is asleep because you have no control over the OS.
You can, otherwise, use the App Delegate method:
- (void)applicationWillResignActive:(UIApplication *)application
{
//your code goes here
}
if you want to wait till your app goes to background
I believe you can't do this using public API. The only thing which you can check whether your application is active or in background (using AppDelegate callbacks). And as Luke pointed out in comments, checking whether device "falls asleep" isn't iOS best design practice.
There are some private API's to do what you want, you can look at following questions:
Is there a way to check if the iOS device is locked/unlocked?
Detect screen on/off from iOS service
However, you should be aware that your app won't be accepted in AppStore in such case.

AVAudioSessionDelegate called at endInterruption, but beginInterruption not called

I'm setting up an AVAudioSession when the app launches and setting the delegate to the appDelegate. Everything seems to be working (playback, etc) except that beginInterruption on the delegate is not being called when the phone receives a call. When the call ends endInterruption is being called though.
The only thought I have is that the audio player code I'm using used to be based on AVAudioPlayer, but is now using AVPlayer. The callbacks for the AVAudioPlayer delegate for handling interrupts are still in there, but it seems odd that they would conflict in any way.
Looking at the header, in iOS6, it looks like AVAudioSessionDelegate is now deprecated.
Use AVAudioSessionInterruptionNotification instead in iOS6.
Update: That didn't work. I think there's a bug in the framework.
Yes, in my experience, beginInterruption, nor the newly documented AVAudioSessionInterruptionNotification work properly. What I had to do was track the status of the player using a local flag, then handle the endInterruption:withFlags: method in order to track recovery from interruptions.
With iOS 6, the resuming from an interruption will at least keep your AudioPlayer in the right place, so there was no need for me to store the last known play time of my AVAudioPlayer, I simply had to hit play.
Here's the solution that I came up with. It seems like iOS 6 kills your audio with a Media Reset if an AVPlayer stays resident too long. What ends up happening, is the AVPlayer plays, but no sound comes out. The rate on the AVPlayer is 1, but there's absolutely no sound. To add pain to the situation, there's no error on either the AVAudioSession setActive, nor the AVPlayer itself that indicates that there's a problem.
Add to the fact that you can't depend on appWillResignActive, because your app may already be in the background if you're depending on remote control gestures at all.
The final solution I implemented was to add a periodic observer on the AVPlayer, and record the last known time. When I receive the event that I've been given back control, I create a new AVPlayer, load it with the AVPlayerItem, and seekToTime to the proper time.
It's quite an annoying workaround, but at least it works, and avoids the periodic crashes that were happening.
I can confirm that using the C api, the interruption method is also not called when the interruption begins; only when it ends
(AudioSessionInitialize (nil, nil, interruptionListenerCallback, (__bridge void *)(self));
I've also filed a bug report with apple for the issue.
Edit: This is fixed in iOS 6.1 (but not iOS 6.0.1)
Just call:
[[AVAudioSession sharedInstance] setDelegate: self];
I just checked on my iPhone 5 (running iOS 6.0) by setting a breakpoint in the AudioSessionInterruptionListener callback function that was declared in AudioSessionInitialize(), and this interrupt callback does, in fact, get called when the app has an active audio session and audio unit and is interrupted with an incoming phone call (Xcode shows the app stopped at the breakpoint at the beginning of the interruption, which I then continue from).
I have the app then stop its audio unit and de-activate its audio session. Then, on the end interruption callback, the app re-activates the audio session and restarts the audio unit without problems (the app is recording audio properly afterwards).
I built a brand new audio streaming (AVPlayer) application atop iOS 6.0.x and found the same problem.
Delegates are now deprecated and we have to use notifications, that's great, however here's my findings:
During an incoming phone call I get only AVAudioSessionInterruptionTypeEnded in my handler, along with AVAudioSessionInterruptionOptionShouldResume. Audio session gets suspended automatically (audio fades) and I just need to resume playback of AVPlayer.
However when attempting to launch a game, such as CSR Racing, I oddly get the dreaded AVAudioSessionInterruptionTypeBegan but no sign when my application can resume playback, not even killing the game.
Now, this may depend on other factors, such as my audio category (in my case AVAudioSessionCategoryPlayback) and the mixing settings of both applications (kAudioSessionProperty_OverrideCategoryMixWithOthers), I'm not sure, but definitely I see something out of place.
Hopefully others reported that on 6.1beta this is fixed and I yet have to upgrade, so we'll see.

Resources