2016-04-16 11 views
2

Es gibt einige scheinbar ähnliche Fragen bereits zu SO, aber nach stundenlangem Suchen und Experimentieren mit meinem Code konnte ich keine klare Antwort finden. Die nächste Sache, die ich finden konnte, war this answer, die vor 4 Jahren auf einen "bekannten Fehler" anspielt, aber nicht weiter darauf eingeht, wie man damit umgehen soll.AVAudioPlayer nach Anruf fortsetzen funktioniert nicht

Ich habe eine Audioplayer-Klasse, die eine Audiodatei mit AVAudioPlayer spielt und hört für die AVAudioSessionDelegate Methoden beginInterruption und endInterruption. Ich weiß, dass nicht garantiert ist, so dass ich einen boolean in beginInterruption speichern und handle Neustart der Audiowiedergabe in applicationDidBecomeActive.

Dies alles funktioniert perfekt wie erwartet, wenn das Telefon einen Anruf erhält und der Benutzer es ablehnt oder an Voicemail weiterleiten lässt. Sobald meine App in den aktiven Zustand zurückkehrt, wird die Audiowiedergabe fortgesetzt.

Hier ist, wo ich seltsame Verhalten bekommen: Wenn der Benutzer Antworten der Anruf, sobald sie alles aufhängen scheint wie erwartet zu funktionieren, aber kein Ton kommt entweder über Kopfhörer oder die Lautsprecher.

Ich kann überprüfen, dass das Audio technisch ist Wiedergabe durch Drucken seiner Lautstärke und currentTime jede Sekunde, aber der Ton kommt nicht heraus.

Wenn ich 20-40 Sekunden warte, wird der Ton plötzlich hörbar und hörbar, als hätte er still im Hintergrund gespielt.

Nach mehr Debugging, bemerkte ich, dass AVAudioSession.sharedInstance().secondaryAudioShouldBeSilencedHint bleibt true für diese 20-40 Sekunden Stille, bevor plötzlich auf false wechseln und das Audio spielen lassen.

ich zum AVAudioSessionSilenceSecondaryAudioHintNotification abonniert, um zu sehen, ob ich diese Änderung erkennen können, aber es wird nie, auch wenn .secondaryAudioShouldBeSilencedHint Änderungen von true zu false genannt.

Ich versuchte sogar explizit Einstellung AVAudioSession.sharedInstance().setActive(true) in der Methode, die die Wiedergabe des Audios wieder aufnimmt, aber das Verhalten hat sich nicht geändert.

Schließlich habe ich versucht, einen Timer zu setzen, um die Fortsetzung für 10 Sekunden nach applicationDidBecomeActive zu verzögern, aber das Verhalten hat sich nicht geändert.

Also, warum scheint es, dass der Anruf nicht die Steuerung der Audio-Sitzung auf meine App zurückgibt?

Danke für einen Blick!


Code:

AVAudioSession Setup in 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) 
} 

Mitteilung Handler:

/////////////////////////////////// 
// 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 Delegierter:

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

Restart-Funktion:

// 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() 

}

Antwort

2

Ich habe versucht, das gleiche zu tun, obwohl ich keine Optionen in der setActive Methode verwendet haben.

Es scheint einen Fehler in iOS 9.3.1 zu geben, der die Wiedergabe des AVAudioPlayers nach Ende des Telefonats nicht wieder aufnimmt. Hier

ist ein Ausschnitt von dem, was löste es für mich: (Sorry für die 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]; 
      }); 
     } 
    } 
} 

Ich habe eine kleine Verzögerung auf das Spiel Anruf des Spielers, und es funktionierte.

Sie können das vollständige Demo-Projekt finden ich hier gemacht: https://github.com/liorazi/AVAudioSessionWorkaround

ich ein Radar an Apple eingereicht, hoffentlich wird es auf der nächsten Version gefixt.

+0

Hey, danke für die Antwort. Ich bin froh, dass es möglich ist, einen Fehler zu machen und nicht nur, dass ich verrückt bin. Leider bin ich mir ziemlich sicher, dass ich auch ohne Glück eine Verspätung versucht habe. Ich werde diese Woche nochmal überprüfen und es erneut versuchen und euch wissen lassen, wie es läuft ... –

+0

irgendwelche Updates dazu? –

+1

Noch nicht, tut mir leid. Ich beabsichtige, dies noch einmal zu überdenken, aber es gibt andere Dinge, die oben auf der Liste stehen, die wir priorisiert haben. Ich werde hier kommentieren, sobald ich die Möglichkeit habe, einen Blick darauf zu werfen. –

0

verwenden, nachdem Sie mit Audio getan. .

AVAudioSession.sharedInstance() setActive (false, withOptions: .NotifyOthersOnDeactivation)

0

Ich hatte das gleiche Problem. Versuchen Sie Player nach der Unterbrechung neu zu laden:

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() 
    } 
    } 
Verwandte Themen