42
votes

I'm testing my app in XCode 6 and find an issue with AVAudioSession in iOS8.

When I call

[[AVAudioSession sharedInstance] setActive:NO error:nil];

I get the following error message:

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.

In AVAudioSession.h, it says

Note that this method will throw an exception in apps linked on or after iOS 8 if the session is set inactive while it has running or paused I/O (e.g. audio queues, players, recorders, converters, remote I/Os, etc.).

But I'm not sure how can I check if there's running I/O and how can I dispose all when I need to reset the audio session.

5
Can you explain the context, and give a use case why you want to check if there is running I/O?vladof81
@vladof If there's no such error, I don't need to check running I/O. So the situation is, I want to make sure there's no running I/O when I call setActive:NOxialin
@Anton not a fix, but I found out that the other library I'm using - pjsip - is controlling start/stop audio session at a lower level. So, the way I handle it is to avoid calling setActive if I know the audio session is already setup. It's just my case. You have to figure out if there's anything else that share the audio session with your app.xialin

5 Answers

9
votes

I solved this problem, inserting this code in the method of AVAudioPlayerDelegate.

-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag{
  [audioPlayer stop];
  [audioPlayer prepareToPlay];
}

where audioPlayer is a variable declared in the header of my class.

the instruction prepareToPlay should resolve your problem!

1
votes

Be warned. If you are playing a movie (even with no sound and the audio track removed) then it will still create an I/O thread which will always cause the above error to be thrown.

1
votes

I'm using AVAudioEngine and AVAudioPlayerNode to play sounds. I meet the same problem. My environment is iOS 10.

I use AVAudioSession.sharedInstance() to handle AVAudioSession. When I run my app in simulator everything is fine, but when I switch it to my device. It failed.

I suppose that I'm using the same session to handle recording and playing. So it may cause some strange issues. In my case, I record the sound and delay 1s to play it. So when I use stopRecordingAudio(), I add this piece of code :

if audioEngine.running {
    audioEngine = AVAudioEngine() // var audioEngine = AVAudioEngine()
    try! AVAudioSession.sharedInstance().setActive(false)
}

After redefining audioEngine, audioEngine had been forced to stop and session was released. Crash is never happened again.

Hope this message could help you.

1
votes

Swift 5, IOS 12

I use AVPlayer, it does not have a prepareToPlay method. Therefore, Alessio Campanelli's answer does not solve my problem. But I noticed the following

player.pause()

print("currentTime:",  player.currentTime().seconds) //currentTime: 4.258164744
print("status:", player.status.rawValue) //status: 1 (readyToPlay)
print("timeControlStatus:", player.timeControlStatus.rawValue) //timeControlStatus: 0 (paused)
print("rate:", player.rate) //rate: 0.0

sleep(1)

print("currentTime:",  player.currentTime().seconds) //currentTime: 4.261325767
print("status:", player.status.rawValue) //status: 1 (readyToPlay)
print("timeControlStatus:", player.timeControlStatus.rawValue) //timeControlStatus: 0 (paused)
print("rate:", player.rate) //rate: 0.0

After you call the pause method, the player plays the audio file for a while. Although other properties say that it is in a pause. So the only solution I found is

player.pause()
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
    do {
        try AVAudioSession.sharedInstance().setActive(false)
    } catch let error {
        print(error)
    }
}

In fact, even 0.1 seconds is sufficient. This is a bad way, but I could not find anything better. If anyone knows how to check when the player stops playing the audio file, let me know.

0
votes

I pasued My AVplayer before AVAudioSession setActive NO;

[self.audioPlayer pause]; [[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:nil];