iOS AVPlayer的一些定製

用戶點擊了播放視頻,但是此時手機是靜音狀態,產品說靜音狀態下也需要把聲音給播放出來,so~ 原文: https://www.jianshu.com/p/998709165dfd

首先你要確保player的屬性muted爲NO,即非靜音,當然NO是系統默認的。然後設置一下category即可

//靜音狀態下播放
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:nil];

AVAudioSessionCategory是一個字符串枚舉,講一下幾個常用的category的含義:

// app的聲音可與其它app共存,但鎖屏和靜音模式會被靜音,除非當前app是唯一播放的app
AVAudioSessionCategoryAmbient
  
// 會停止其他程序的音頻播放。當設備被設置爲靜音模式,音頻會隨之靜音
AVAudioSessionCategorySoloAmbient 

// 僅用來錄音,無法播放音頻
AVAudioSessionCategoryRecord

// 會停止其它音頻播放,並且能在後臺播放,鎖屏和靜音模式都能播放聲音
AVAudioSessionCategoryPlayback 

// 能播也能錄,播放默認聲音是從聽筒出來
AVAudioSessionCategoryPlayAndRecord
  

上面提到的靜音模式,指的是點擊了iPhone手機上的靜音按鈕(靜音按鈕在AssistiveTouch,就是屏幕上的虛擬home鍵中比較容易找到),並不是指慢慢慢慢地降低聲音直到靜音,那不是靜音模式,只是聲音降到了0而已

 

AVAudioSessionCategoryPlayAndRecord 有個小坑, 默認是聽筒的聲音,需要在設置下輸出端口

- (BOOL)overrideOutputAudioPort:(AVAudioSessionPortOverride)portOverride error:(NSError * _Nullable *)outError;

其中portOverride參數有2個可選參數:

AVAudioSessionPortOverrideNone:我的理解是將音頻輸出設置聽筒,系統默認應該就是聽筒,因爲官方文檔給出的解釋是:

AVAudioSessionPortOverrideSpeaker:音頻輸出設置爲揚聲器。

3.App佔用聽筒或揚聲器

由於你的APP使用音頻通道時其他App可能正在使用它,所以需要調用這個方法。

- (BOOL)setActive:(BOOL)active error:(NSError * _Nullable *)outError;

使用方法:

//拿到AVAudioSession的單例對象
AVAudioSession *audioSession = [AVAudioSession sharedInstance]; 

//設置爲聽筒模式
//[audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideNone error:nil];
  
//設置爲公放模式
[audioSession overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];

 //讓我的App佔用聽筒或揚聲器
 [audioSession setActive:YES error:nil];

https://www.jianshu.com/p/47c7144db817 , 後臺播放音樂,耳機控制,鎖屏顯示音樂信息,https://www.jianshu.com/p/771b45e53619

平時經常用到頭條來看新聞和視頻,如果後臺還在播放着音樂,在播放視頻的時候,音樂會被中斷,視頻播放結束或者退出頁面,音樂就會再次響起,很好奇這是怎麼做到的,今天看到了.

其它App播放聲音打斷

如果用戶當時在後臺聽音樂,如QQ音樂,或者喜馬拉雅這些App,這個時候播放視頻後,其會被我們打斷,當我們不再播放視頻的時候,自然需要繼續這些後臺聲音的播放。

首先,我們需要先向設備註冊激活聲音打斷AudioSessionSetActive(YES);,當然我們也可以通過 [AVAudioSession sharedInstance].otherAudioPlaying;這個方法來判斷還有沒有其它業務的聲音在播放。 當我們播放完視頻後,需要恢復其它業務或App的聲音,這時我們可以調用如下方法:

    // AVplayer初始化的時候記錄下是否有別的播放器在播放
    if ([AVAudioSession sharedInstance].isOtherAudioPlaying) {

        NSLog(@"當前有其他播放器在播放!!");
        
    }
    

// 如果有別的播放器,在用戶暫停或者退出頁面,恢復其他播放器的播放
    NSError *error =nil;
    BOOL isSuccess = [[AVAudioSession sharedInstance] setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error];
    
    if (!isSuccess) {
        NSLog(@"__%@",error);
    }else{
        NSLog(@"成功播放了後臺音樂");
    }

當有打電話,鬧鈴等其他的事件導致了播放暫停

//中斷的通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
    //中斷事件
- (void)handleInterruption:(NSNotification *)notification{
    
    NSDictionary *info = notification.userInfo;
    //一箇中斷狀態類型
    AVAudioSessionInterruptionType type =[info[AVAudioSessionInterruptionTypeKey] integerValue];
    
    //判斷開始中斷還是中斷已經結束
    if (type == AVAudioSessionInterruptionTypeBegan) {
        //停止播放
        [self.player pause];
        
    }else {
        //如果中斷結束會附帶一個KEY值,表明是否應該恢復音頻
        AVAudioSessionInterruptionOptions options =[info[AVAudioSessionInterruptionOptionKey] integerValue];
        if (options == AVAudioSessionInterruptionOptionShouldResume) {
            //恢復播放
            [self.player play];
        }
        
    }
    
}

在用戶插入和拔出耳機時,導致視頻暫停,解決方法如下

//耳機插入和拔掉通知
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(audioRouteChangeListenerCallback:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]];

    //耳機插入、拔出事件
- (void)audioRouteChangeListenerCallback:(NSNotification*)notification {
    NSDictionary *interuptionDict = notification.userInfo;

    NSInteger routeChangeReason = [[interuptionDict valueForKey:AVAudioSessionRouteChangeReasonKey] integerValue];

    switch (routeChangeReason) {

        case AVAudioSessionRouteChangeReasonNewDeviceAvailable:

            break;

        case AVAudioSessionRouteChangeReasonOldDeviceUnavailable:
        {
            //判斷爲耳機接口
            AVAudioSessionRouteDescription *previousRoute =interuptionDict[AVAudioSessionRouteChangePreviousRouteKey];

            AVAudioSessionPortDescription *previousOutput =previousRoute.outputs[0];
            NSString *portType =previousOutput.portType;

            if ([portType isEqualToString:AVAudioSessionPortHeadphones]) {
                // 拔掉耳機繼續播放
                if (self.playing) {

                    [self.player play];
                }
            }

    }
            break;

        case AVAudioSessionRouteChangeReasonCategoryChange:
            // called at start - also when other audio wants to play

            break;
    }
}

正常情況下,音頻退到後臺繼續播放需要這麼做.申請後臺運行權限

-(void)applicationWillResignActive:(UIApplication *)application{
    //開啓後臺處理多媒體事件
    AVAudioSession *session=[AVAudioSession sharedInstance];
    [session setActive:YES error:nil];
    //後臺播放
    [session setCategory:AVAudioSessionCategoryPlayback error:nil];

}

但是我在前面做了靜音狀態下播放,[AVAudioSession sharedInstance]的Category已經是AVAudioSessionCategoryPlayback,所以在applicationWillResignActive就可以不用寫了.  

 

對了,還有一個小坑,就是AVPlayer光這麼設置是不行的, 這個是針對音頻的,視頻的話,需要在applicationDidEnterBackground把AVPlayer的AVPlayerLayer設置爲nil , 如果AVPlayerLayer還存在的話 , 是不能進行後臺播放的. 同理,applicationWillEnterForeground需要在把AVPlayerLayer與AVPlayer關聯起來.

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章