2016-08-06 18 views
4

Я следую инструкциям here, я собрал этот тестовый проект для обработки прерываний воспроизведения звука. В частности, я использую будильник из приложения часов iphone по умолчанию в качестве прерывания. Похоже, что обработчик прерываний вызывается, но не проходит мимо линии let = interruptionType, так как «неправильный тип» появился дважды.Как возобновить звук после перерыва в Swift?

import UIKit 
import AVFoundation 

class ViewController: UIViewController { 

    var player = AVAudioPlayer() 

    let audioPath = NSBundle.mainBundle().pathForResource("rachmaninov-romance-sixhands-alianello", ofType: "mp3")! 

    func handleInterruption(notification: NSNotification) { 

     guard let interruptionType = notification.userInfo?[AVAudioSessionInterruptionTypeKey] as? AVAudioSessionInterruptionType else { print("wrong type"); return } 

     switch interruptionType { 

     case .Began: 
      print("began") 
      // player is paused and session is inactive. need to update UI) 
      player.pause() 
      print("audio paused") 

     default: 
      print("ended") 
      /**/ 
      if let option = notification.userInfo?[AVAudioSessionInterruptionOptionKey] as? AVAudioSessionInterruptionOptions where option == .ShouldResume { 
       // ok to resume playing, re activate session and resume playing 
       // need to update UI 
       player.play() 
       print("audio resumed") 
      } 
      /**/ 
     } 
    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     // Do any additional setup after loading the view, typically from a nib. 

     do { 
      try player = AVAudioPlayer(contentsOfURL: NSURL(fileURLWithPath: audioPath)) 
      player.numberOfLoops = -1 // play indefinitely 
      player.prepareToPlay() 
      //player.delegate = player 

     } catch { 
      // process error here 
     } 

     // enable play in background https://stackoverflow.com/a/30280699/1827488 but this audio still gets interrupted by alerts 
     do { 
      try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback) 
      print("AVAudioSession Category Playback OK") 
      do { 
       try AVAudioSession.sharedInstance().setActive(true) 
       print("AVAudioSession is Active") 
      } catch let error as NSError { 
       print(error.localizedDescription) 
      } 
     } catch let error as NSError { 
      print(error.localizedDescription) 
     } 

     // add observer to handle audio interruptions 
     // using 'object: nil' does not have a noticeable effect 
     let theSession = AVAudioSession.sharedInstance() 
     NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(ViewController.handleInterruption(_:)), name: AVAudioSessionInterruptionNotification, object: theSession) 

     // start playing audio 
     player.play() 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 
} 

Кроме того, следуя идее here, я изменил обработчик

func handleInterruption(notification: NSNotification) { 

     //guard let interruptionType = notification.userInfo?[AVAudioSessionInterruptionTypeKey] as? AVAudioSessionInterruptionType else { print("wrong type"); return } 

     if notification.name != AVAudioSessionInterruptionNotification 
      || notification.userInfo == nil{ 
      return 
     } 

     var info = notification.userInfo! 
     var intValue: UInt = 0 
     (info[AVAudioSessionInterruptionTypeKey] as! NSValue).getValue(&intValue) 
     if let interruptionType = AVAudioSessionInterruptionType(rawValue: intValue) { 

      switch interruptionType { 

      case .Began: 
       print("began") 
       // player is paused and session is inactive. need to update UI) 
       player.pause() 
       print("audio paused") 

      default: 
       print("ended") 
       /**/
       if let option = notification.userInfo?[AVAudioSessionInterruptionOptionKey] as? AVAudioSessionInterruptionOptions where option == .ShouldResume { 
        // ok to resume playing, re activate session and resume playing 
        // need to update UI 
        player.play() 
        print("audio resumed") 
       } 
       /**/ 
       player.play() 
       print("audio resumed") 
      } 
     } 
    } 

Результаты в том, что все «начал», «аудио паузу», «закончился» и «аудио возобновлено» шоу но воспроизведение звука на самом деле не возобновляется.

Примечание: Я переехал player.play() вне комментируемого из where option == .ShouldResume, если заявление, потому что if условие не выполняется, когда происходит прерывание .Ended.

+1

извинений я сделал искажение, которое было исправлено. Обработчик прерываний получает вызов. – rockhammer

+0

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

+0

Спасибо за изменения в ответе CW!Если вы хотите полностью отреагировать на этот ответ, я с удовольствием удаляю версию CW и повышаю ваш уровень - хорошие усилия. – halfer

ответ

8

(Отправлено от имени ОП).

Решение найдено! После обсуждения here, подставила в viewDidLoad()

do { 
    try AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, withOptions: AVAudioSessionCategoryOptions.MixWithOthers) 
} catch {   
} 

После нажатия кнопки «ОК» на прерывание тревоги, воспроизведение аудио продолжается. В отличие от ранее отмеченного, решение НЕ требует обработчика прерывания (с которого @Leo Dabus с тех пор удаляется).

Однако, если вы используете обработчик прерывания, .play() НЕ должны вызываться в handleInterruption() так как это не гарантирует воспроизведение возобновить & кажется, чтобы предотвратить audioPlayerEndInterruption() называться (см docs). Вместо этого .play() должен быть вызван в пределах audioPlayerEndInterruption() (любая из трех версий), чтобы гарантировать возобновление.

Кроме того, AVAudioSession должен указывать опцию .MixWithOthers, отмеченную @Simon Newstead, если вы хотите, чтобы ваше приложение возобновило воспроизведение после прерывания, когда ваше приложение находится в фоновом режиме. Похоже, что если пользователь хочет, чтобы приложение продолжало играть, когда оно попадает в фоновый режим, логично предположить, что пользователь также хочет, чтобы приложение возобновляло воспроизведение после прерывания, когда приложение находится в фоновом режиме. Действительно, это поведение, проявляемое приложением Apple Music.

2

Предложение @rockhammers работало для меня. Here

перед классом

let theSession = AVAudioSession.sharedInstance() 

в viewDidLoad

NotificationCenter.default.addObserver(self, selector: #selector(ViewController.handleInterruption(notification:)), name: NSNotification.Name.AVAudioSessionInterruption, object: theSession) 

И тогда функция

func handleInterruption(notification: NSNotification) { 
    print("handleInterruption") 
    guard let value = (notification.userInfo?[AVAudioSessionInterruptionTypeKey] as? NSNumber)?.uintValue, 
     let interruptionType = AVAudioSessionInterruptionType(rawValue: value) 
     else { 
      print("notification.userInfo?[AVAudioSessionInterruptionTypeKey]", notification.userInfo?[AVAudioSessionInterruptionTypeKey]) 
      return } 
    switch interruptionType { 
    case .began: 
     print("began") 
     vox.pause() 
     music.pause() 
     print("audioPlayer.playing", vox.isPlaying) 
     /**/ 
     do { 
      try theSession.setActive(false) 
      print("AVAudioSession is inactive") 
     } catch let error as NSError { 
      print(error.localizedDescription) 
     } 
     pause() 
    default : 
     print("ended") 
     if let optionValue = (notification.userInfo?[AVAudioSessionInterruptionOptionKey] as? NSNumber)?.uintValue, AVAudioSessionInterruptionOptions(rawValue: optionValue) == .shouldResume { 
      print("should resume") 
      // ok to resume playing, re activate session and resume playing 
      /**/ 
      do { 
       try theSession.setActive(true) 
       print("AVAudioSession is Active again") 
       vox.play() 
       music.play() 
      } catch let error as NSError { 
       print(error.localizedDescription) 
      } 
      play() 
     } 
    } 
}