Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS 8 stops streaming audio in background after 10 minutes

I have an app that plays streaming audio from a SHOUTcast server. Everything works fine when the app is on the foreground and auto-lock is disabled. The app is however also able to play audio in the background, this feature has always been working fine on iOS 6 and iOS 7. But now my users are reporting that background audio stops after about 10 minutes after they upgraded to iOS 8.

I'm able to reproduce the problem myself by simply running the app on iOS 8. Since the app itself is pretty complicated, I've made a simple demo to show the problem. I'm using Xcode 6 and Base SDK is set to iOS 8. I've added audio to UIBackgroundModes in my Info.plist. Does anybody know what's wrong with the code below?

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSURL *streamingURL = [NSURL URLWithString:@"http://www.radiofmgold.be/stream.php?ext=pls"];

    AVPlayerItem *playerItem = [AVPlayerItem playerItemWithURL:streamingURL];
    [self setPlayerItem:playerItem];

    AVPlayer *player = [AVPlayer playerWithPlayerItem:playerItem];
    [player setAllowsExternalPlayback:NO];

    [self setPlayer:player];
    [player play];

    [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];
    [[AVAudioSession sharedInstance] setActive: YES error: nil];

    return YES;
}
like image 798
s1m0n Avatar asked Oct 04 '14 18:10

s1m0n


People also ask

Why does audio stop playing on iPhone?

Sound settings: Sometimes, your iPhone's volume levels get turned down accidentally due to bumps inside your bag or fidgeting. Other software settings like the 'Do not disturb mode', 'Silent mode', or even sound enhancements can also cause this issue.


1 Answers

I experienced the same problem under iOS 8.0.2. My remote audio source plays in mp3. It seems an internal error is causing the AVAudioSession to restart. You can handle that in different ways:

You can observe the state of the AVPlayerItem.

void* YourAudioControllerItemStatusContext = "YourAudioControllerItemStatusContext";
...
@implementation YourAudioController
...
- (void)playStream {
    ...
    AVPlayerItem *item = [[AVPlayerItem alloc] initWithURL:streamUrl];
    [item addObserver:self forKeyPath:@"status" options:0 context:MJAudioControllerItemStatusContext];
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    if (context == YourAudioControllerItemStatusContext) {
        AVPlayerItem *item = object;
        if (item.status == AVPlayerItemStatusFailed) {
            [self recoverFromError];
        }
    }

This way seems not to be reliable since there can be an immense time delay until the state of the AVPlayerItem changes - if it changes at all.

I debugged through observeValueForKeyPath and found out that the state of the AVPlayerItem changes to AVErrorMediaServicesWereReset and has an error code -11819 set.

Since I experienced the AVErrorMediaServicesWereReset error I researched what causes this error - it's the AVAudioSession going crazy. Referring to the Technical Q&A from Apple you should register for the AVAudioSessionMediaServicesWereResetNotifications. Put that somewhere in your code:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioSessionWasReset:) name:AVAudioSessionMediaServicesWereResetNotification object:nil];

Then add this method:

- (void)audioSessionWasReset:(NSNotification *)notification {
    [self recoverFromError];
}

In the recoverFromError method try one of the following:

  • show an Alert that describes that theres an problem under iOS 8 and the stream needs to be restarted
  • restart the stream by setting the AVAudioSession active again and instantiate a new AVPlayer instance with a new AVPlayerItem

At the moment that are the only ways I know how to handle it. The question is why the AudioSession is getting restarted.

UPDATE The release of iOS 8.1 seams to have solved the issue.

like image 128
Hendrik Avatar answered Sep 22 '22 01:09

Hendrik