I've developed an iPhone application that allows other apps to play audio in the background. To achieve this, I initialize my audio session like this:
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
At some point in my application I provide an audio player to play some files stored in CoreData with AVAudioPlayer. When the user hits the play button, the background audio should be paused. When the player has finished or is paused, the background audio should resume playback.
While resuming after the player has finished playback with
-(void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
[[AVAudioSession sharedInstance] setActive:NO withFlags:AVAudioSessionSetActiveFlags_NotifyOthersOnDeactivation error:nil];
}
works like a charm, I get stuck with resume after pause. It should work the same way within the button's IBAction
-(IBAction)pausePlayer
{
if (self.player.isPlaying) {
[self.player pause];
[[AVAudioSession sharedInstance] setActive:NO withFlags:AVAudioSessionSetActiveFlags_NotifyOthersOnDeactivation error:nil];
}
}
but I always get the same error:
Unable to deactivate audio session. Error: Error Domain=NSOSStatusErrorDomain Code=560030580 "The operation couldn’t be completed. (OSStatus error 560030580.)"
Any suggestions why it is impossible to inactivate the AudioSession in this case?
I tried for 3 hours finally got it here is what I have done
#import "ViewController.h"
#import <AVFoundation/AVFoundation.h>
@interface ViewController ()
@property(strong, nonatomic)AVAudioPlayer *player;
@property(strong)AVAudioSession *session;
@end
@implementation ViewController
- (IBAction)playsound:(id)sender
{
NSURL *url=[[NSURL alloc]initWithString:[[NSBundle mainBundle] pathForResource:@"sound" ofType:@"mp3"]];
NSError *err;
self.player=[[AVAudioPlayer alloc]initWithContentsOfURL:url error:&err];
[self.player setDelegate:self];
[self.player setVolume:2.5];
self.session=[AVAudioSession sharedInstance];
[self.player prepareToPlay];
[self.player play];
}
- (void)audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag
{
NSError *err;
[self.session setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&err];
}
@end
It seems that the deactivation is too early. According to the AVAudioSession class reference "Deactivating your session will fail if any associated audio objects (such as queues, converters, players or recorders) are currently running."
There seem to be a few solutions:
run the deactivation in a loop till it succeeds.
This is advocated in http://iknowsomething.com/ios-sdk-spritekit-sound/
postpone the deactivation, e.g till it is really necessary.
when using e.g. the Audio Queue service, you may consider to stop immediately. (not tested)
In a recording app with the possibility to listen the recordings, I only deactivate just before changing the category using the sequence: activate NO, setCategory and activate YES.
See e.g. "While your app is running, Apple recommends that you deactivate your audio session before changing any of the set values" in Apple's Audio Session Programming Guide