Audio Session Interruption


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

一、通過C語言的init方法配置interruptionl回調。建議用這種方法,但有些細節需要注意,后續會談到。

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

然后在回調,實現如下邏輯代碼:

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;
    }
}

二、使用AVAudioSessionDelegate。如果你使用的是AVAudioPlayer或AVAudioRecorder,還可以使用對應的AVAudioPlayerDelegate和 AVAudioRecorderDelegate。但AVAudioSessionDelegate在6.0后被棄用,所以使用有局限性。后者沒有被棄用。

- (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]; } }

 

三、如上所說,6.0棄用了AVAudioSessionDelegate。所以6.0之后使用AVAudioSessionInterruptionNotification來實現類似的功能。AVAudioSessionInterruptionNotification的userInfo中包括AVAudioSessionInterruptionTypeKey和AVAudioSessionInterruptionTypeEnded。

四、使用RouteChange的回調。對於音樂播放,如果當然當前是耳機模式,拔掉耳機一般是希望音樂暫停的。類似這種拔插設備,播放語音等聲音設備切換,一般通過RouteChange的回調來控制。

注冊RouteChange的回調:

   AudioSessionAddPropertyListener(kAudioSessionProperty_AudioRouteChange,audioRouteChangeListenerCallback,nil);

回調處理代碼:

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,有如下幾種模式:

/* 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;

 

關於其他的一些總結:

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

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

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

2、當后台播放歌曲時,打開游戲之類APP,聲道會被其APP占用。這種Case會有kAudioSessionBeginInterruption。但返回時不會有kAudioSessionEndInterruption。所以,這種Case在回到APP時,需要interruptedWhilePlaying這個變量重置。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM