iOS AVPlayer的一些定制

烂漫一生 提交于 2020-01-28 05:35:01

用户点击了播放视频,但是此时手机是静音状态,产品说静音状态下也需要把声音给播放出来,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关联起来.

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!