0%

AVAudioPlayer中断处理

1.配置音频会话

1.1处理”铃声/静音”开关切换

测试上一节使用AVAudioPlayer播放音频的程序,当开始播放音频时切换设备侧面的”铃声/静音”开关,会发现音频输出也会在这两种状态下切换.为了让我们的程序在这两种状态下都能正常输出音乐,需要在程序启动时对音频会话进行明确的配置.在)application: didFinishLaunchingWithOptions:中加入如下代码即可:

 AVAudioSession *session = [AVAudioSession sharedInstance];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
[session setActive:YES error:nil];

1.2后台播放

当设备锁定或者应用进入后台时,如果也希望能正常播放音乐,还需要在工程中设置 Background Modes,有两种方法进行设置.

第一种,在Xcode中找到项目的info.plist,新添加一行名为Required background modes的数组,并在其中添加一项App plays audio or streams audio/video using AirPlay.

第二种,打开TARGETS下的Capabilities的分类,找到Background Modes,并在其子目录中勾选Audio,AirPlay and Picture in Picture.

2.中断处理

中断在移动设备中经常出现,比如电话呼入,闹钟响起等情况.对iOS来说,当中断发生时,播放中的音频会慢慢消失和暂停.这一效果是系统自动实现的,不过当中断消失时,音频并不会自动恢复.所以我们需要编写代码解决这个问题.

2.1中断通知

中断发生时,应用程序的AVAudioSession会发送通知AVAudioSessionInterruptionNotification,注册通知代码如下:

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleInterruption:) name:AVAudioSessionInterruptionNotification object:[AVAudioSession sharedInstance]];

在接收到通知的userInfo中,会包含一个AVAudioSessionInterruptionTypeKey,用来标识中断开始和中断结束.
当中断类型为AVAudioSessionInterruptionTypeKeyEnded时,userInfo中还会包含一个AVAudioSessionInterruptionOptions来表明音频会话是否已经重新激活以及是否可以再次播放.示例代码如下:

- (void)handleInterruption:(NSNotification *)notification
{
NSDictionary *info = notification.userInfo;
AVAudioSessionInterruptionType type = [info[AVAudioSessionInterruptionTypeKey] unsignedIntegerValue];
if (type == AVAudioSessionInterruptionTypeBegan) {
    //Handle InterruptionBegan
}else{
    AVAudioSessionInterruptionOptions options = [info[AVAudioSessionInterruptionOptionKey] unsignedIntegerValue];
    if (options == AVAudioSessionInterruptionOptionShouldResume) {
        //Handle Resume

    }
}
}

2.2 线路改变

在iOS设备上添加或移除音频输入,输出线路时,会发生线路改变,比如用户插入耳机或断开USB麦克风.当这些事件发生时,音频会根据情况改变输入或输入线路,同时AVAudioSession会发送一个相关变化的通知AVAudioSessionRouteChangeNotification.注册通知的相关代码如下:

        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleRouteChange:) name:AVAudioSessionRouteChangeNotification object:[AVAudioSession sharedInstance]];

根据苹果公司的文档,当用户插入耳机时,隐含的意思是用户不希望外界听到具体的音频了内容,这就意味着当用户断开耳机时,播放的内容可能需要保密,所以我们需要在断开耳机时停止音频播放.

AVAudioSessionRouteChangeNotification通知的userinfo中会带有通知发送的原因信息及前一个线路的描述.线路变更的原因保存在userinfo的AVAudioSessionRouteChangeReasonKey值中,通过返回值可以推断出不同的事件,对于旧音频设备中断对应的reason为AVAudioSessionRouteChangeReasonOldDeviceUnavailable.但光凭这个reason并不能断定是耳机断开,所以还需要使用通过AVAudioSessionRouteChangePreviousRouteKey获得上一线路的描述信息,注意线路的描述信息整合在一个输入NSArray和一个输出NSArray中,数组中的元素都是AVAudioSessionPortDescription对象.我们需要从线路描述中找到第一个输出接口并判断其是否为耳机接口,如果为耳机,则停止播放.
具体代码如下:

- (void)handleRouteChange:(NSNotification *)notification
{
NSDictionary *info = notification.userInfo;
AVAudioSessionRouteChangeReason reason = [info[AVAudioSessionRouteChangeReasonKey] unsignedIntegerValue];
if (reason == AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {  //旧音频设备断开
    //获取上一线路描述信息
    AVAudioSessionRouteDescription *previousRoute = info[AVAudioSessionRouteChangePreviousRouteKey];
    //获取上一线路的输出设备类型
    AVAudioSessionPortDescription *previousOutput = previousRoute.outputs[0];
    NSString *portType = previousOutput.portType;
    if ([portType isEqualToString:AVAudioSessionPortHeadphones]) {
    }
}
}