2016-04-16 34 views
2

すでに一見似たような質問がありますが、コードを検索して実験した後、私は明確な答えを見つけることができませんでした。私が見つけることができる最も近いものは、4年前に「既知のバグ」を暗示していたthis answerでしたが、それに対処する方法を詳しく説明していません。電話がかかっていない状態でAVAudioPlayerを再開する

AVAudioPlayerでオーディオファイルを再生し、AVAudioSessionDelegateのメソッドbeginInterruptionendInterruptionをリッスンしているaudioPlayerクラスがあります。 endInterruptionは保証されていないので、beginInterruptionにブール値を格納し、applicationDidBecomeActiveにオーディオ再生を再開するように処理します。

電話機が通話を受信したときに、ユーザーがそれを拒否したり、ボイスメールに移動させたりすると、これはすべて正常に動作します。私のアプリがアクティブ状態に戻るとすぐに、オーディオ再生が再開されます。私は奇妙な振る舞いを得ているところ

がここにあります:彼らはハングアップしたらユーザーが答え呼び出した場合は、すべては期待どおりに動作するようだが、何の音はヘッドフォンやスピーカーのいずれかを介して出てきません。

オーディオは技術的にはを再生していることを確認できます。ボリュームとcurrentTimeを毎秒印刷しても音は出ません。

私が20-40秒間待つと、突然音声が途切れて、静かに背景で再生しているかのように聞こえます。

よりデバッグした後、私はAVAudioSession.sharedInstance().secondaryAudioShouldBeSilencedHintが突然falseに変更し、オーディオ再生をさせる前に、沈黙のこれらの20〜40秒間trueままであることに気づきました。

私はこの変更を検出できるかどうかを確認するためにAVAudioSessionSilenceSecondaryAudioHintNotificationに加入したが、それが呼び出されることは決してありません、場合でもtrueからfalse.secondaryAudioShouldBeSilencedHint変更。

設定AVAudioSession.sharedInstance().setActive(true)をオーディオの再生を再開する方法で試してみましたが、動作は変更されませんでした。

最後に、applicationDidBecomeActiveの後に10秒間レジュームを遅らせるようにタイマーを設定しようとしましたが、動作は変更されませんでした。

なぜ、電話が私のアプリに戻ってオーディオセッションのコントロールを放棄していないように見えるのですか?

ありがとうございました!


コード:init()

AVAudioSessionセットアップ:

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") 
    } 
    } 
} 

アプリの委任:

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

私はアップルにレーダーを提出し、うまくいけば、それは次のリリースで固定しますよ:

あなたは私がここで作られた完全なデモプロジェクトを見つけることができます。

+0

ねえ、答えに感謝を。私はバグかもしれないと私は狂っているだけでなく、うれしいです。残念ながら、私は運がないまま遅延をも試みたと確信しています。今週もう一度チェックして、もう一度試してみて、それがどうなっているかを教えてください... –

+0

これに関するアップデートはありますか? –

+1

まだ、申し訳ありません。私はこれをもう一度見直すつもりですが、私たちが優先順位を決めることを決めた他のものがリスト上に上がっています。私は見てチャンスを得るとすぐにここでコメントします。 –

0

あなたがオーディオに終わった後、これを使用してください。

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() 
    } 
    } 
関連する問題