播放音频不难,使用AVAudioPlayer可以处理,细细的品味了下它,被它给震惊了一下。本片文章不是AVAudioPlayer的AV秀,而是相关上面罗列的中断问题的处理和优化。

先来个笑话:老姐是个女强人,姐夫很怕我老姐。昨晚姐夫洗完澡后,抱了堆脏衣服丢洗衣机洗。然后走到客厅对坐在沙发上看电视的老姐说:老婆,你昨晚换的衣服在哪?要不让我一起洗了吧?
老姐白了他一眼说:整天就知道洗衣做饭的,你能不能男子气概点?
姐夫听后,有点恼羞成怒了。扯着嗓子冲老姐吼了句:特么把昨晚你换的衣服让我洗了,不然劳资抽你!

1、了解音频会话

其实完全不用说这段东西,为什么要敲出来,是因为麒麟臂。如果下面东西看不懂,可以扫一眼直接过。希望我可以将这些东西可以很好的呈现出来。

大家有没有想过,当我们程序运行的时候来电话是的铃声来自哪里,反正我刚开始是以为系统的。其实不然,有一个叫做音频会话的东西来管理,它作为我们程序和系统之间的中间人,所有程序都默认有它,分类名称为Solo Ambient,无论你是否使用。罗列下它的事件:

a、当用户切换手机上静音按钮的状态时,如果没有对播放器做此方面的处理,播放器的声音会随着静音按钮一起切换。

b、当程序播放器播放的时候,所有后台播放的音频都会暂停(参考接入电话,此时播放中断)。

c、当锁屏的时候,所有声音都会消失。

d、激活音频播放,不激活音频录制。

如果我们没有针对以上情况作出手动的处理,所有程序默认都是有以上的事件。对于专门的播放类的程序来说以上某些功能就得修改。音频会话也有自己的分类,在此处就不详细介绍。如果我们需要一些复杂的功能,我们可以修改音频会话的相关行为,实现自定义开发使用options和modes。

2、处理中断事件

a、针对设备静音键和锁屏按钮的处理方法。在导入AVFoundation框架后,导入代码以下代码。因为音频会话通常会在应用程序启动时进行一次配置,所以可以写在以下位置

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {

    //AVAudioSessionCategoryPlayback为音频会话分类中的一种,当激活后应用程序将允许音频输出同时也可以和背景音混合
    AVAudioSession *session = [AVAudioSession sharedInstance];                //去得音频会话单例
    NSError *error;
    if (![session setCategory:AVAudioSessionCategoryPlayback error:&error]) { //设置音频会话的分类
        
        NSLog(@"erroe - %@",[error localizedDescription]);
    }
    
    if (![session setActive:YES error:&error]) {                              //激活
        
        NSLog(@"erroe - %@",[error localizedDescription]);
    }
    
    return YES;
}

当设置完后,可以实现对应功能即锁屏和静音键已经不起作用,但我们仍需要在Info.plist文件中进行一些配置。此设置的作用为允许后台播放音频,步骤为打开Info.plist、增加一个新的Required background modes类型数组,在其中添加名为App plays audio or streams audio/video using airPlay的选项。

android 息屏语音通话_python

此时运行工程就好了。

b、针对中断事件的处理,如挂完电话后、闹钟后等一些系统中断后继续播放

在中断事件发生时和结束会有相关的通知,此通知使我们进行操作的依据。首先注册通知,位置根据实际情况在具体的类中实现。

- (instancetype)init
{
    self = [super init];
    if (self) {
        
        //注册通知
        NSNotificationCenter *notification = [NSNotificationCenter defaultCenter];
        [notification addObserver:self selector:@selector(notificationAction:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
    }
    return self;
}

//通知回调方法
- (void)notificationAction:(NSNotification *)notificfation {
    
    NSDictionary *dic = notificfation.userInfo;       //取出通知总的信息
    AVAudioSessionInterruptionType type = [dic [AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];                                                 //AVAudioSessionInterruptionType结构体中包含中断开                                                       始和中断结束两个变量
    
    if (type == AVAudioSessionInterruptionTypeBegan) {//接收到中断
        
        //让播放暂停的事件
    }else {//中断结束
        
        //恢复播放的事件
    }
}

//将通知注销
- (void)dealloc {
    
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}

3、耳机拔插引起的线路变化

当我们使用耳机的时候,出现的情况是插入耳机继续播放,拔掉耳机暂停。整个过程的控制和2中的差不多,思路也为接收通知并实现相关事件。下面代码是耳机断开事件后使播放暂停的相关代码和过程分析:

- (instancetype)init
{
    self = [super init];
    if (self) {
        
        //注册通知
        NSNotificationCenter *notification = [NSNotificationCenter defaultCenter];
        [notification addObserver:self selector:@selector(notificationAction:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];
    }
    return self;
}

//通知回调方法
- (void)notificationAction:(NSNotification *)notificfation {
    
    NSDictionary *dic = notificfation.userInfo;     //取出通知总的信息
    AVAudioSessionRouteChangeReason type = [dic [AVAudioSessionRouteChangeReasonKey] unsignedIntegerValue];                                             //线路发生改变的通知
    
    if (type == AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {//线路断开,取出相关的描述,并判断是否为耳机断开(线路的描述信息整合在两个数组中,一个输入一个输出。数组中的元素都是AVAudioSessionRouteDescription类型,用于描述不同的I/O接口属性,找出第一个接口并判断是否为耳机)
    
        AVAudioSessionRouteDescription *description = dic[AVAudioSessionRouteChangePreviousRouteKey];
        AVAudioSessionPortDescription *previousOutput = description.outputs[0];
        NSString *str = previousOutput.portType;
        
        if ([str isEqualToString:AVAudioSessionPortHeadphones]) {
            
            //暂停事件
        }

    }
}

//将通知注销
- (void)dealloc {
    
    [[NSNotificationCenter defaultCenter] removeObserver:self];
}