2016-04-16 2 views
2

Есть некоторые, казалось бы, похожие вопросы уже на SO, но после нескольких часов поиска и экспериментов с моим кодом я не смог найти четкий ответ. Самое близкое, что я мог найти, это this answer, который ссылается на «известную ошибку» 4 года назад, но не уточняет, как ее решить.Резюме AVAudioPlayer после телефонного звонка не работает

У меня есть класс audioPlayer, который воспроизводит аудиофайл с AVAudioPlayer и слушает AVAudioSessionDelegate методы beginInterruption и endInterruption. Я знаю, что endInterruption не гарантируется, поэтому я сохраняю логическое значение в beginInterruption и обрабатываю перезапуск воспроизведения звука в applicationDidBecomeActive.

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

Вот где я получаю странное поведение: Если пользователь отвечает вызов, когда они вешают все кажется работать, как ожидалось, но звук не выходит либо через наушники или громкоговорители.

Я могу проверить, что звук технически играет, печатая его громкость и текущее время каждую секунду, но звук не выходит.

Если я жду 20-40 секунд, звук внезапно прорезается и становится слышимым, как если бы он молча играл в фоновом режиме.

После дополнительной отладки я заметил, что AVAudioSession.sharedInstance().secondaryAudioShouldBeSilencedHint остается true за эти 20-40 секунд молчания, прежде чем внезапно перейти на false и позволить звуку воспроизвести.

Я подписался на AVAudioSessionSilenceSecondaryAudioHintNotification, чтобы увидеть, если я мог бы обнаружить это изменение, но оно никогда не вызывается, даже когда .secondaryAudioShouldBeSilencedHint изменяется от true к false.

Я даже попробовал AVAudioSession.sharedInstance().setActive(true) в методе, который возобновляет воспроизведение звука, но поведение не изменилось.

Наконец, я попытался установить таймер для задержки возобновления в течение 10 секунд после applicationDidBecomeActive, но поведение не изменилось.

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

Спасибо, что посмотрели!


Код:

установки AVAudioSession в init():

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.handleAudioHintChange), name: AVAudioSessionSilenceSecondaryAudioHintNotification, object: nil) 
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(self.handleAudioInterruption), name: AVAudioSessionInterruptionNotification, object: nil) 

do { 
    try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, withOptions: AVAudioSessionCategoryOptions.MixWithOthers) 
    print("AVAudioSession Category Playback OK") 
    do { 
    try AVAudioSession.sharedInstance().setActive(true, withOptions: .NotifyOthersOnDeactivation) 
    print("AVAudioSession is Active") 
    } catch let error as NSError { 
    print(error.localizedDescription) 
    } 
} catch let error as NSError { 
    print(error.localizedDescription) 
} 

обработчики уведомлений:

/////////////////////////////////// 
// This never gets called :(////// 

func handleAudioHintChange(notification: NSNotification) { 
    print("audio hint changed") 
} 
/////////////////////////////////// 

func handleAudioInterruption(notification: NSNotification) { 
    if notification.name != AVAudioSessionInterruptionNotification || notification.userInfo == nil{ 
    return 
    } 

    if let typeKey = notification.userInfo [AVAudioSessionInterruptionTypeKey] as? UInt, 
    let type = AVAudioSessionInterruptionType(rawValue: typeKey) { 
    switch type { 
     case .Began: 
     print("Audio Interruption Began") 
     NSUserDefaults.standardUserDefaults().setBool(true, forKey:"wasInterrupted") 

     case .Ended: 
     print("Audio Interuption Ended") 
    } 
    } 
} 

App Делегат: функция

func applicationDidBecomeActive(application: UIApplication) { 
    if(NSUserDefaults.standardUserDefaults().boolForKey("wasInterrupted")) { 
    audioPlayer.resumeAudioFromInterruption() 
    } 
} 

Перезагрузка:

// This works great if the phone call is declined 
func resumeAudioFromInterruption() { 
    NSUserDefaults.standardUserDefaults().removeObjectForKey("wasInterrupted") 
    do { 
    try AVAudioSession.sharedInstance().setActive(true) 
    print("AVAudioSession is Active") 
    } catch let error as NSError { 
    print(error.localizedDescription) 
    } 
    thisFunctionPlaysMyAudio() 

}

ответ

2

Я попытался сделать то же самое, хотя я не использовал никаких вариантов в методе setActive.

Похоже, что ошибка в iOS 9.3.1 не возобновляет воспроизведение AVAudioPlayer после завершения телефонного разговора.

Вот фрагмент того, что решить это для меня: (Извините за Objective-C)

- (void)handleInterruption:(NSNotification *) notification{ 
    if (notification.name != AVAudioSessionInterruptionNotification || notification.userInfo == nil) { 
     return; 
    } 

    NSDictionary *info = notification.userInfo; 

    if ([notification.name isEqualToString:AVAudioSessionInterruptionNotification]) { 

     if ([[info valueForKey:AVAudioSessionInterruptionTypeKey] isEqualToNumber:[NSNumber numberWithInt:AVAudioSessionInterruptionTypeBegan]]) { 
      NSLog(@"InterruptionTypeBegan"); 
     } else { 
      NSLog(@"InterruptionTypeEnded"); 

      //*The* Workaround - Add a small delay to the avplayer's play call; Without the delay, the playback will *not* be resumed 
      // 
      //(I didn't play much with the times, but 0.01 works with my iPhone 6S 9.3.1) 
      dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 0.01 * NSEC_PER_SEC), dispatch_get_main_queue(), ^{ 
       NSLog(@"playing"); 
       [_player play]; 
      }); 
     } 
    } 
} 

я добавил небольшую задержку игры вызова игрока, и это сработало.

Вы можете найти полный демонстрационный проект, который я сделал здесь: https://github.com/liorazi/AVAudioSessionWorkaround

я представил радар для компании Apple, мы надеемся, он будет получать закрепленную на следующей версии.

+0

Эй, спасибо за ответ. Я рад, что это может быть ошибка, а не только я сумасшедший. К сожалению, я уверен, что я также попытался отложить неудачу. Я дважды проверю и повторю попытку на этой неделе и дам вам знать, как это происходит ... –

+0

любые обновления по этому вопросу? –

+1

Пока нет, извините. Я полностью намерен пересмотреть это, но в списке есть другие вещи, которые мы решили расставить приоритеты. Я прокомментирую здесь, как только у меня появится возможность взглянуть. –

0

Используйте это после того, как вы закончите с Audio. .

AVAudioSession.sharedInstance() SetActive (ложные, withOptions: .NotifyOthersOnDeactivation)

0

У меня был такой же выпуск. Попробуйте перезагрузить плеер после прерывания:

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() 
    } 
    } 
Смежные вопросы