AVAudioSession error: Deactivating an audio session that has running I/O - ios

2017-02-24 14:56:44.280 PropertyManager[10172:5336578] 14:56:44.280 ERROR: [0x1a0a24000] AVAudioSession.mm:692: -[AVAudioSession setActive:withOptions:error:]: Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session.
2017-02-24 14:56:44.281 PropertyManager[10172:5336578] error === Error Domain=NSOSStatusErrorDomain Code=560030580 "(null)"
PropertyManager was compiled with optimization - stepping may behave oddly; variables may not be available.

Your error log is very succinctly self-expressive:
Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session
It tells you the problem and also the solution.
Right now you're doing something like this:
[[AVAudioSession sharedInstance] setActive:NO
withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation
error:nil];
You should however, first stop the audio player instance and then set the activation status to Yes or No.
[yourAudioPlayer stop];
[[AVAudioSession sharedInstance] setActive:NO
withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation
error:nil];
Refer to Apple Documentation to see values of enum AudioSessionSetActiveOption.
Also see: Apple Documentation on setActive:withOptions method
As for your second error
PropertyManager was compiled with optimization - stepping may behave oddly; variables may not be available.
see this excellent answer.

#NSNoob is 100% correct. The player (or something else) is still active.
More from dani-mp. He said:
I'd say that pausing the player is not a synchronous operation, so we
shouldn't be deactivating the session before knowing that the player
has been paused (see the response in this thread).
A solution for this problem could be that we listen to changes to
timeControlStatus and deactivate the audio session once the player has
really been paused.
The answer in the thread says
This error indicates that something in your app is still using audio
I/O at the time when the AVAudioSession setActive:NO is being called.
It’s impossible to say which object without more information, but
sometimes it’s the result of calling an asynchronous stop method on a
player of some sort and not waiting for the notification that the
player has stopped before deactivating the audio session.

Make audio player to stop before making recording session false.. if u suppose to make audio player to be nil.. remove that line.. it works for me..

Related

Error: Deactivating an audio session that has running I/O

My app uses device's microphone and manages AVAudioSession.
I want to check if there is other app playing audio, if so, I want my app to stop using microphone & stop my audio session, this is what I tried (the following code is periodically triggered to check is there other app playing audio):
BOOL isPlayingWithOthers = [[AVAudioSession sharedInstance] isOtherAudioPlaying];
if (isPlayingWithOthers) {
[[AVAudioSession sharedInstance] setActive:NO error:error];
}
I run my app, then, I open "My music" app, and playing a music, the above code is executed but I get the following error:
Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session.
Why I get this error? How to solve it in my case? (My app is running on iOS7 and above)

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

Stop audio recording and continue audio playback

My application plays music and records from mic at the same time. Recording can be started after playback is started or before playback is started
And now I want to stop recording but keep playback running at the same time.
How can I do this?
I can stop recording and playback by using
[[AVAudioSession sharedInstance] setActive:NO error:nil];
But the issue is: I want to stop recording only.
I tried to change category to AVAudioSessionCategoryPlayback using the following code
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error]
but that doesn't stop recording.
I solved the issue by explicitly stopping all recording activity without touching AVAudioSession at all.
The following warning
AVAudioSession.mm:623: -[AVAudioSession setActive:withOptions:error:]:
Deactivating an audio session that has running I/O. All I/O should be
stopped or paused prior to deactivating the audio session.
helped me to identify the issue.
Initially I forgot to call the AudioOutputUnitStop method of AudioUnit framework. Because of this recording process was still running and audio session were indicating that.

How to get SpeechKit and AVCaptureDevice to work with each other

I am using SpeechKit from Nuance to transcribe text from video as I record it. However, when SpeechKit is active, AVAudioSession generates the following error:
AVAudioSession.mm:646: -[AVAudioSession setActive:withOptions:error:]: Deactivating an audio session that has running I/O. All I/O should be stopped or paused prior to deactivating the audio session.
Disabling SpeechKit lets me record and preview the video. Enabling it generates the transcribed text, but doesn't record the video.
I have put a sample project online at:
https://github.com/jeffreality/iOSVideoTranscriber
My goal is to save the video with audio, as well as have a transcription.
You can move the following line to viewDidLoad:
#if ENABLE_TRANSCRIPTION
[SpeechKit setupWithID:#"Your ID"
host:#"dfo.nmdp.nuancemobility.net"
port:443
useSSL:NO
delegate:nil];
#endif
This ensures that speechKit has already been set up when you create your own capture session in viewDidAppear.
SpeechKit delegate method recognizerDidFinishRecording is called when the recognizer stops recording audio. It is automatically called when a silence is detected, or manually called when you do [voiceSearch stopRecording]. When this happens, your own recording has not finished, it needs time to save the audio file to disk, and the error message says all i/o should stop prior to deactivating an audio session. You can see a log by the sdk release audio session 1, which I think is deactivating a session and release it. So I think you should add this in the above method.
[[self.session.outputs[1] connectionWithMediaType:AVMediaTypeAudio] setEnabled:NO];
The output is AVCaptureMovieFileOutput you set up earlier, and connection is an audio connection, doing this seems to make the error disappear.

Resources