Фоновое аудио не возобновляется после звонка - PullRequest
22 голосов
/ 28 февраля 2012

Мой фоновый звук работает нормально почти все время. Экран заблокирован или выключен звук. Но когда у пользователя есть приложение в фоновом режиме, и он получает вызов, даже если пользователь не отвечает на вызов, фоновое аудио не возобновляется после окончания прерывания.

Приложение Музыка правильно возобновляет фоновый звук, если он был прерван.

Мне не хватает какого-либо свойства или мне нужен обратный вызов или установить фоновую задачу, чтобы продолжить выполнение фонового аудио после прерывания? Или это то, что мы не можем сделать?

Ответы [ 6 ]

22 голосов
/ 28 сентября 2013

Мы возобновляем звук после исходящего и входящего вызовов, пока приложение находится в фоновом режиме.

Мы воспроизводим аудио с AVAudioPlayer и слушаем AVAudioSessionInterruptionNotification .Apple автоматически приостанавливает AVAudioPlayer для вас в случае прерывания, и когда вы говорите, чтобы он возобновлялся после получения прерывания, Apple снова активирует ваш сеанс.См. Таблицу 3-2 из Обработка звуковых прерываний с рекомендациями, если вы используете другие типы звуковых технологий.

Подписаться на уведомление:

    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onAudioSessionEvent:) name:AVAudioSessionInterruptionNotification object:nil];

Обработка уведомления:

- (void) onAudioSessionEvent: (NSNotification *) notification
{
    //Check the type of notification, especially if you are sending multiple AVAudioSession events here
    if ([notification.name isEqualToString:AVAudioSessionInterruptionNotification]) {
        NSLog(@"Interruption notification received!");

        //Check to see if it was a Begin interruption
        if ([[notification.userInfo valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeBegan]]) {
            NSLog(@"Interruption began!");

        } else {
            NSLog(@"Interruption ended!");
            //Resume your audio
        }
    }
}
5 голосов
/ 28 февраля 2012

По своему опыту я обнаружил, что мне пришлось «подождать секунду или две», прежде чем пытаться снова открыть аудиоустройство.Я думаю, что после того, как ОС переключается обратно к вашему приложению после вызова, приложение телефона все еще закрывается.

как-то так, когда вы возвращаетесь на передний план после того, как узнаете, что ваш аудио сеанс был остановлен:

            dispatch_time_t restartTime = dispatch_time(DISPATCH_TIME_NOW, 
                                                      1.5LL * NSEC_PER_SEC);

            dispatch_after(restartTime, dispatch_get_global_queue(0, 0), ^{ 
                [audioSystem restart]; 
            });
2 голосов
/ 10 июля 2015

Я использую Xamarin, так что это C #, но следующий код работает для меня. Сначала я установил, что мой AppDelegate реализует методы делегата AVAudioSession, включая IAVAudioSessionDelegate

            public partial class AppDelegate: UIApplicationDelegate, IAVAudioSessionDelegate

Я добавил переменную в класс AppDelegate для аудиосеанса

            public static AVAudioSession AudioSession;

В переопределении метода FinishedLaunching:

            AudioSession = AVAudioSession.SharedInstance();
            AudioSession.Delegate = this;
            error = AudioSession.SetCategory( AVAudioSessionCategory.Playback, AVAudioSessionCategoryOptions.DuckOthers );
            AudioSession.SetMode( new NSString( "AVAudioSessionModeMoviePlayback" ), out error );

Два соответствующих метода делегата в AppDelegate.cs:

            [Export( "beginInterruption" )]
            public void BeginInterruption()
            {
                 PlayerViewController.BeginSessionInterruption();
            }

            [Export( "endInterruptionWithFlags:" )]
            public void EndInterruption( AVAudioSessionInterruptionFlags flags )
            {  // ignore the flags so we're not dependent on the interrupting event saying that we can resume
                 PlayerViewController.ResumeAfterSessionInterruption();
            }

My AppDelegate также имеет переопределение OnActivation для включения видеодорожек, если оно является видеоустройством, и переопределение DidEnterBackground, чтобы отключить видеодорожки мультимедиа, но при этом воспроизводить звук.

В методе PlayerViewController.BeginSessionInterruption () я не могу посмотреть Player.Rate, чтобы увидеть, запущен ли проигрыватель в данный момент, потому что прерывание будильника или телефонного звонка уже приостановило игрока. Из раздела «Реагирование на прерывания» в Руководстве по программированию аудиосеансов Apple, с моим акцентом:

  1. Ваше приложение активно, воспроизводит звук.
  2. Приходит телефонный звонок. Система активирует аудио сеанс телефонного приложения.
  3. Система деактивирует ваш аудио сеанс. На этом этапе * воспроизведение в вашем приложении остановлено *.
  4. Система вызывает функцию обратного вызова прослушивателя прерываний, указывающую, что ваш сеанс был деактивирован. ...

Кнопка Play моего PlayerViewController имеет свойство Paused для переключения между Play и Pause и рисования соответствующего изображения кнопки. Поэтому вместо проверки Player.Rate я смотрю, имеет ли свойство кнопки Paused значение false:

            public void BeginSessionInterruption()
            {
                 PlayerWasRunningOnInterruption = !btnPlay.Paused;
                 TogglePlayPause( true );  // put the Play button into the Paused state to agree with the player being stopped
            }

            public void ResumeAfterSessionInterruption()
            {
                NSError error;
                AppDelegate.AudioSession.SetActive( true, AVAudioSessionSetActiveOptions.NotifyOthersOnDeactivation, out error );  // always reactivate the audio session

                if ( PlayerWasRunningOnInterruption )
                {
// rewind a little bit
// call btnPlayClick to resume the playback as if the user pressed the Play button
                }
            }
0 голосов
/ 14 июня 2018

Посмотрите на:

https://developer.apple.com/documentation/avfoundation/avaudiosession#//apple_ref/doc/uid/TP40008240-CH1-DontLinkElementID_3

https://developer.apple.com/documentation/avfoundation/avaudiosession/responding_to_audio_session_interruptions

Код:

private func setupAudioSession() {
    do {

        try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, with: .mixWithOthers)
        try AVAudioSession.sharedInstance().setActive(true)

        setupAudioNotifications()

    } catch {
        print(error)
    }
}

private func setupAudioNotifications() {
    NotificationCenter.default.addObserver(self, selector: #selector(handleInterruption), name: .AVAudioSessionInterruption, object: nil)
}

@objc func handleInterruption(notification: Notification) {

    guard let userInfo = notification.userInfo,
        let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
        let type = AVAudioSessionInterruptionType(rawValue: typeValue) else {
            return
    }

    if type == .began {
        // Interruption began, take appropriate actions
        Player.shared.stop()

    } else if type == .ended {
        if let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt {
            let options = AVAudioSessionInterruptionOptions(rawValue: optionsValue)
            if options.contains(.shouldResume) {
                // Interruption Ended - playback should resume
                Player.shared.start()
            } else {
                // Interruption Ended - playback should NOT resume
            }
        }
    }
}
0 голосов
/ 19 апреля 2017

У меня работает только два варианта:

  1. перезагрузить AVPlayer или AVAudioPlayer после окончания прерывания

    func interruptionNotification(_ notification: Notification) {
    guard let type = notification.userInfo?[AVAudioSessionInterruptionTypeKey] as? UInt,
      let interruption = AVAudioSessionInterruptionType(rawValue: type) else {
        return
    }
    if interruption == .ended && playerWasPlayingBeforeInterruption {
      player.replaceCurrentItem(with: AVPlayerItem(url: radioStation.url))
      play()
    }
    

    }

  2. использование

AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, with: .mixWithOthers)

0 голосов
/ 27 мая 2015

если вы обнаруживаете только состояние вызова, вы можете использовать CTCallCenter , но если вы хотите обнаружить прерывание (включая прерывание вызова), вы можете использовать AVAudioSessionInterruptionNotification , и если выЧтобы поддерживать фон, вы должны добавить код, подобный следующему:

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

, прежде чем возобновить воспроизведение музыки в background.hope, это может помочь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...