IOS 8 прекращает потоковое аудио в фоновом режиме через 10 минут

У меня есть приложение, которое воспроизводит потоковое аудио с сервера SHOUTcast. Все работает нормально, когда приложение находится на переднем плане, а автоматическая блокировка отключена. Однако приложение также может воспроизводить аудио в фоновом режиме, эта функция всегда отлично работает на iOS 6 и iOS 7. Но теперь мои пользователи сообщают, что фоновый звук останавливается примерно через 10 минут после их обновления до iOS 8.

Я могу воспроизвести проблему самостоятельно, просто запустив приложение на iOS 8. Поскольку приложение очень сложно, я сделал простую демонстрацию, чтобы показать проблему. Я использую Xcode 6, а Base SDK установлен в iOS 8. Я добавил аудио в UIBackgroundModes в свой Info.plist. Кто-нибудь знает, что не так с кодом ниже?

- (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;
}

Ответ 1

У меня возникла такая же проблема в iOS 8.0.2. Мой удаленный источник звука воспроизводится в mp3. Кажется, внутренняя ошибка вызывает перезапуск AVAudioSession. Вы можете обрабатывать это по-разному:

Вы можете наблюдать состояние 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];
        }
    }

Этот способ кажется не надежным, так как может быть огромная временная задержка до тех пор, пока состояние AVPlayerItem не изменится - если оно вообще изменится.

Я отлаживал функцию observValueForKeyPath и выяснил, что состояние AVPlayerItem изменяется на AVErrorMediaServicesWereReset и имеет код ошибки -11819.

Поскольку у меня возникла ошибка AVErrorMediaServicesWereReset, я исследовал причину этой ошибки - это сбой AVAudioSession. Обращаясь к Technical Q & A от Apple, вы должны зарегистрироваться для AVAudioSessionMediaServicesWereResetNotifications. Поместите это где-нибудь в свой код:

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

Затем добавьте этот метод:

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

В методе recoverFromError попробуйте выполнить одно из следующих действий:

  • показать предупреждение, которое описывает, что проблема в iOS 8 и поток необходимо перезапустить
  • перезапустите поток, снова включив AVAudioSession и создайте экземпляр нового экземпляра AVPlayer с помощью нового AVPlayerItem

На данный момент это единственные способы, которыми я знаю, как справиться с этим. Вопрос в том, почему AudioSession перезапускается.

UPDATE Выпуск швов iOS 8.1, чтобы решить проблему.

Ответ 2

Я также испытал ту же проблему и протестировал ее на iPhone 5s с iOS 8.0.2 и iPad Mini Retina, работающем под iOS 8.1 beta 2, что означает, что это не исправлено в предстоящая бета-версия. Оба перестали воспроизводить звук примерно через 30 минут.

Когда AVPlayer.status == AVPlayerItemStatusFailed, вы можете выйти из AVPlayer.status для получения более подробной информации об ошибке. Я получаю:

Error Domain=AVFoundationErrorDomain Code=-11819 "Cannot Complete Action" UserInfo=0x178a75bc0 {NSLocalizedDescription=Cannot Complete Action, NSLocalizedRecoverySuggestion=Try again later.}

Даже когда вы пытаетесь поймать это и остановить и запустить мой плеер, я получаю фатальную ошибку, чтобы сообщить мне, что AVPlayer был освобожден. На этом этапе стоит попробовать повторно инициализировать новый экземпляр AVPlayer, предложенный Хендриком. Это все еще не решает тот факт, что звук будет временно отключен при попытке повторной инициализации. Ваш AVPlayer может также получать уведомления, прежде чем вы сможете повторно инициализировать его, то есть вы получите фатальную ошибку; это далеко не постоянное решение.

Возможно, кому-то еще повезет с этим и может предоставить более конкретное решение. Между тем, я также сообщил об этой ошибке Apple.

Обновление 15 октября 2014 года: Apple закрыла мой отчет об ошибке с этим статусом: Дубликат 18152675 (закрыт).

Ответ 3

Похоже, он исправлен в iOS 8.1

Ответ 4

Эта проблема, похоже, исправлена ​​с обновлением iOS8.1. Я обновил его вчера и смог транслировать в течение 45 минут, тогда как до обновления он сработал бы в течение 10-15 минут.