Audio Session Interruption

近期處理了一個掛斷電話後,莫名手機開始播放音樂的Bug。 因此順便在這總結一下,對於IOS的AudioSession中斷的幾種處理狀況。ios

1、經過C語言的init方法配置interruptionl回調。建議用這種方法,但有些細節須要注意,後續會談到。測試

AudioSessionInitialize (
    NULL,                            // 1
    NULL,                            // 2
    interruptionListenerCallback,    // 3
    userData                         // 4
);

而後在回調,實現以下邏輯代碼:ui

void interruptionListenerCallback ( void *inUserData,  UInt32  interruptionState ) {
    AudioViewController *controller = (AudioViewController *)inUserData;  
  if (interruptionState == kAudioSessionBeginInterruption) {         
        if (controller.audioRecorder) {
            [controller recordOrStop: (id) controller];                 
        } else if (controller.audioPlayer) {
            [controller pausePlayback];                                
            controller.interruptedOnPlayback = YES;                     
        }
    } else if ((interruptionState == kAudioSessionEndInterruption) && controller.interruptedOnPlayback) {
        [controller resumePlayback];
        controller.interruptedOnPlayback = NO;
    }
}

2、使用AVAudioSessionDelegate。若是你使用的是AVAudioPlayer或AVAudioRecorder,還可使用對應的AVAudioPlayerDelegate和 AVAudioRecorderDelegate。但AVAudioSessionDelegate在6.0後被棄用,因此使用有侷限性。後者沒有被棄用。spa

- (void) beginInterruption {
    if (playing) {
        playing = NO;
        interruptedWhilePlaying = YES;
        [self updateUserInterface];
    }
}
NSError
*activationError = nil; - (void) endInterruption { if (interruptedWhilePlaying) { BOOL success = [[AVAudioSession sharedInstance] setActive: YES error: &activationError]; if (!success) { /* handle the error in activationError */ } [player play]; playing = YES; interruptedWhilePlaying = NO; [self updateUserInterface]; } }

 

3、如上所說,6.0棄用了AVAudioSessionDelegate。因此6.0以後使用AVAudioSessionInterruptionNotification來實現相似的功能。AVAudioSessionInterruptionNotification的userInfo中包括AVAudioSessionInterruptionTypeKey和AVAudioSessionInterruptionTypeEnded。code

4、使用RouteChange的回調。對於音樂播放,若是固然當前是耳機模式,拔掉耳機通常是但願音樂暫停的。相似這種拔插設備,播放語音等聲音設備切換,通常經過RouteChange的回調來控制。blog

註冊RouteChange的回調:遊戲

   AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange,audioRouteChangeListenerCallback,nil);

回調處理代碼:it

void audioRouteChangeListenerCallback(void *inUserData, AudioSessionPropertyID inPropertyID, UInt32 inPropertyValueSize, const void *inPropertyValue) {
    if (inPropertyID != kAudioSessionProperty_AudioRouteChange)
        return;
    
    CFDictionaryRef routeChangeDictionary = inPropertyValue;
    CFNumberRef routeChangeReasonRef = CFDictionaryGetValue (routeChangeDictionary, CFSTR(kAudioSession_AudioRouteChangeKey_Reason));
    
    CFStringRef oldRouteRef = CFDictionaryGetValue (routeChangeDictionary,
                                                    CFSTR (kAudioSession_AudioRouteChangeKey_OldRoute));
    NSString *oldRouteString = (NSString *)oldRouteRef;
    
    SInt32 routeChangeReason;
    CFNumberGetValue (routeChangeReasonRef, kCFNumberSInt32Type, &routeChangeReason);
    if (routeChangeReason == kAudioSessionRouteChangeReason_OldDeviceUnavailable) {
        if (oldRouteStringplaying ) { //需判斷不可用Route爲耳機時
            playing = NO;
            interruptedWhilePlaying = NO;  //清除中斷標識,如電話中拔掉耳機掛斷時,不須要繼續播放
        }
    }
}

對於AudioSession的Route,有以下幾種模式:io

/* Known values of route:
*"Headset"
* "Headphone"
* "Speaker"
* "SpeakerAndMicrophone"
* "HeadphonesAndMicrophone"
* "HeadsetInOut"
* "ReceiverAndMicrophone"
* "Lineout"
*/

//ios5之後可以使用的一些類型
const CFStringRef kAudioSessionOutputRoute_LineOut;
const CFStringRef kAudioSessionOutputRoute_Headphones;
const CFStringRef kAudioSessionOutputRoute_BluetoothHFP;
const CFStringRef kAudioSessionOutputRoute_BluetoothA2DP;
const CFStringRef kAudioSessionOutputRoute_BuiltInReceiver;
const CFStringRef kAudioSessionOutputRoute_BuiltInSpeaker;
const CFStringRef kAudioSessionOutputRoute_USBAudio;
const CFStringRef kAudioSessionOutputRoute_HDMI;
const CFStringRef kAudioSessionOutputRoute_AirPlay;

 

關於其餘的一些總結:class

一、對於SDK6.0,AudioSession中斷是一個Bug版本。不會響應AVAudioSessionDelegate,且不響應AVAudioSessionInterruptionNotification。C語言中斷,當使用AVPlayer後,不響應kAudioSessionBeginInterruption,但響應kAudioSessionEndInterruption。 這是蘋果的Bug。對上這種Case,有以下處理辦法:

  1)當收到kAudioSessionEndInterruption時,調用暫停播放更新UI。

  2)使用RouteChange來判斷電話的接通和掛斷情境。但若是是耳機模式,電話的接通和掛斷,經測試,使用的是同一種Route。因此,對於SDK6.0,播放過程當中未接耳機時,可經過RouteChange來恢復播放。而耳機模式播放時,來電恢復播放,目前看來無完善的處理方式。

二、當後臺播放歌曲時,打開遊戲之類APP,聲道會被其APP佔用。這種Case會有kAudioSessionBeginInterruption。但返回時不會有kAudioSessionEndInterruption。因此,這種Case在回到APP時,須要interruptedWhilePlaying這個變量重置。

相關文章
相關標籤/搜索