2016-08-06 84 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") 
      } 
     } 
    } 

結果是,所有的「開始」,「音頻暫停」,「結束」和「音頻恢復」秀在控制檯中,但音頻播放實際上並沒有恢復。

注意:我在where option == .ShouldResume if語句之外移動player.play(),因爲if條件在.Ended中斷髮生時不成立。

+1

道歉,我做這已得到糾正口誤。中斷處理程序正在調用。 – rockhammer

+0

好吧,這將是我第一次把東西放在那裏,所以它可能會花費我幾分鐘的時間...請繼續關注 – rockhammer

+0

感謝您對CW回答的編輯!如果您想自己轉發整個答案,我很樂意刪除CW版本,並讚揚你的努力。 – halfer

回答

8

(發佈代表OP)

找到解決方案!經過討論here,插入這viewDidLoad()

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

單擊「確定」在報警中斷後,音頻播放繼續。與之前提到的不同,該解決方案不需要中斷處理程序(@Leo Dabus已經刪除)。

但是,如果您使用的是中斷處理程序,.play()決不可以內handleInterruption()調用,因爲這樣做不保證發揮恢復&似乎防止audioPlayerEndInterruption()被稱爲(見docs)。相反,.play()必須在audioPlayerEndInterruption()(其3個版本中的任何一個)內調用以保證恢復。

此外,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() 
     } 
    } 
}