Reputation: 20564
When applicationDidEnterBackground:
triggers, I pause the audio which is playing using AVAudioPlayer
:
[self.avPlayer pause];
Now, when applicationWillEnterForeground:
triggers, the audio starts to play automatically! Since I didn't start the audio, the user interface is not updated and it shows that the audio is still in the paused state.
What's going on? This is happening in iOS 6.x, on iPad 2. This issue is not reproducing on the older iPad running iOS 5.x.
This is how I setup the AVAudioSession
:
// Setup the audio session
BOOL succeeded = NO;
NSError *sessionError = nil;
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setDelegate:self];
if ([session respondsToSelector:@selector(setPreferredSampleRate:error:)]) {
succeeded = [session setPreferredSampleRate:128000.0f error:&sessionError];
} else {
succeeded = [session setPreferredHardwareSampleRate:128000.0f error:&sessionError];
}
succeeded = [session setCategory:AVAudioSessionCategorySoloAmbient error:&sessionError];
succeeded = [session setActive:YES error:&sessionError];
Upvotes: 9
Views: 2324
Reputation: 12582
Regarding this absurd problem. It really seems to be a plain bug in iOS.
The only real solution we could find
In all three delegate calls ..
func applicationWillResignActive(_ application: UIApplication) {
yourPlayer.handleAppResign()
}
func applicationDidEnterBackground(_ application: UIApplication) {
yourPlayer.handleAppResign()
}
func applicationWillTerminate(_ application: UIApplication) {
yourPlayer.handleAppResign()
}
Then where you handle that specific case, you would have:
func ...handleThat() {
yourAVPlayer?.rate = 0
}
In fact just add this:
func ...handleThat() {
yourAVPlayer?.rate = 0
yourAVPlayer = nil
}
Normally you would not do that because you're usually simply pausing.
But, in fact, this seems to be the only solution to the crazy "Apple auto-un-pause" behavior.
There seems to be no other way.
Upvotes: 3
Reputation: 866
I was also facing the same problem. So I registered my class for UIApplicationWillResignActive and I paused audio when I received notification.
Upvotes: 0
Reputation: 19126
I found some weird UX and when going back and forth from the background and based on a bunch of posts, I'd plan for a little jiggling of the handle. I did something fairly simple - check if other music is playing when the app enters the foreground:
func applicationWillEnterForeground(application: UIApplication) {
if AVAudioSession.sharedInstance().otherAudioPlaying{
NSNotificationCenter.defaultCenter().postNotificationName(Notifications.ForegroundEnteredWithOtherAudioPlaying, object: nil)
}
}
If so, you can pause the player when that notification is received. You mentioned that did not work but without seeing the rest of your code, it's tough to know why.
One other thing I had to do is to remove the observer to the status
flag from the player item because I listen to that for the ReadyToPlay
value where I tell AvPlayer
to actually play. That gets fired when the app enters the foreground and there is an active audio session. So by removing that observer on pause and setting it every time on play, (which isn't crazy because I'd argue it's an OK constraint to say I only care to observe after I hit play), I'm able to control of lot of the weirdness.
I also wrote up a bunch of test cases which I'll share here to make sure your experience is in pretty good shape. It's not comprehensive but it's also fairly thorough.
// 1. Play, leave app, don't open anything else, come back
// 2. Play, leave app, open an app that plays music, come back
// 3. Play, leave app, open an app that plays music, play music, come back
// 4. Play, let audio go for 5 seconds, pause, open an app that plays music, come back
// 5. Play, let audio go for 5 seconds, pause, open an app that plays music, play music, come back
// 6. Press play, leave app before playback starts, open an app that plays music, come back
// 7. Crazy s$*t like play, leave app, open an app that plays music, play music, come back, tap a different song
Upvotes: 1
Reputation: 173
HRM's solution didn't work for me. The only way I got it to avoid resuming play automatically is to use stop: [self.avPlayer stop]
Upvotes: 0
Reputation: 2127
In one of my recent app, I found a similar issue where audio playback pauses automatically and resumes after you are interrupted by a call and GUI is not refreshing in my app. I have fixed the issue by using the following method:
Register this in the class where you handle player code
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
And use AVAudioSession
's audioPlayerEndInterruption
delegate method to get control after the application was resumed. In this function you can resume the playback and update UI accordingly.
- (void)audioPlayerEndInterruption:(AVAudioPlayer *)player withOptions:(NSUInteger)flags
Hope this helps.
Upvotes: 1