内容来自互联网,使用了google翻译。
简介
在iOS中,音频焦点是操作系统为了管理音频硬件而引入的概念,是指App对音频硬件在时间纬度上的使用控制(不是使用权限,使用权限需要App单独申请);App可以独占使用,也可以共享使用—-独占/共享音频焦点。
独占音频焦点,则只能有一个App使用音频硬件;共享音频焦点,则多个App可以同时使用音频硬件,通常共享音频焦点会导致多个App播放的音频被混音。
iOS中还有个音频会话的概念,在一个App中只有一个音频会话。这里需要注意下,iOS系统只有一个音频焦点,所以App要想使用音频硬件,需要使用音频会话来抢占音频焦点。
抢占音频焦点示例:
// 一个App内所有场景/任务都共享同一个音频会话
AVAudioSession *session = [AVAudioSession sharedInstance]; //获取共享单例
//设置音频硬件使用模式
NSError *error = nil;
if ([session setCategory:AVAudioSessionCategoryAmbient error:&error] == NO)
{
NSLog(@"%@",error); //发生错误
return;
}
//抢占音频焦点
error = nil;
if ([session setActive:YES error:&error] == NO)
{
NSLog(@"%@",error); //发生错误
return;
}
上述代码中,先设置AVAudioSessionCategoryAmbient
模式,表示应用会随着静音键和屏幕关闭而静音,并且不会中止其它应用播放声音(可以和其它自带应用如iPod,safari等同时播放声音),然后再使用setActive
抢占音频焦点。
释放音频焦点
我们的App抢占音频焦点后,可能会导致其他App失去音频焦点,所以当我们使用完音频硬件时,应将音频焦点释放出来。
// 一个App内所有场景/任务都共享同一个音频会话
AVAudioSession *session = [AVAudioSession sharedInstance]; //获取共享单例
//释放音频焦点
NSError *error = nil;
if ([session setActive:NO error:&error] == NO)
{
NSLog(@"%@",error); //发生错误
return;
}
释放音频焦点还可以这样:
//也可以这样释放音频焦点, 为了确保之前被打断的正在播放音频的App能收到resume消息。
if ([session setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error] == NO )
{
NSLog(@"%@",error); //发生错误
return;
}
使用哪种方式,取决于App的音频硬件使用模式。
音频硬件使用模式
设置接口有两个,都可以设置音频使用模式。相关参数为AVAudioSessionCategory和AVAudioSessionCategoryOptions。需要注意的是,AVAudioSessionCategoryOptions是位枚举
,可以组合使用。
- (BOOL)setCategory:(AVAudioSessionCategory)category error:(NSError **)outError;
- (BOOL)setCategory:(AVAudioSessionCategory)category withOptions:(AVAudioSessionCategoryOptions)options error:(NSError **)outError;
AVAudioSessionCategory
-
AVAudioSessionCategoryAmbient
使用这个category的应用会随着静音键和屏幕关闭而静音。并且不会中止其它应用播放声音,可以和其它自带应用如iPod,safari等同时播放声音。
该Category无法在后台播放声音。
-
AVAudioSessionCategorySoloAmbient
类似于AVAudioSessionCategoryAmbient ,不同之处在于它会中止其它应用播放声音。 这个category为默认category。
该Category无法在后台播放声音。
-
AVAudioSessionCategoryPlayback
使用这个category的应用不会随着静音键和屏幕关闭而静音。默认情况下,其他不支持混音(nonmixable)的应用将被中止播放声音;也可以设置
AVAudioSessionCategoryOptionMixWithOthers
,让自己的应用支持混音,这时不会中止其他不支持混音的应用播放声音;该Category可在后台播放声音。
-
AVAudioSessionCategoryRecord
用于需要录音的场景,设置该category后,除了来电铃声,闹钟或日历提醒之外的其它系统声音都不会被播放。
该Category只提供单纯录音功能,可以在后台录音。
-
AVAudioSessionCategoryPlayAndRecord
在播放和录音同时存在的场景,这个category是唯一选择,应用不会随着静音键和屏幕关闭而静音。默认情况下,其他不支持混音(nonmixable)的应用将被中止播放声音;也可以设置
AVAudioSessionCategoryOptionMixWithOthers
,让自己的应用支持混音,这时不会中止其他不支持混音的应用播放声音
该Category可以在后台录音、播放声音。 -
AVAudioSessionCategoryMultiRoute
非专业场景基本上不会使用。支持多个音频路由同时工作。例如,手机扬声器播放歌曲A,同时连接该手机的耳机中播放歌曲B。
AVAudioSessionCategoryOptions
-
AVAudioSessionCategoryOptionMixWithOthers
播放声音时,支持和其他App混音。
仅在AVAudioSessionCategoryPlayAndRecord、AVAudioSessionCategoryPlayback 或 AVAudioSessionCategoryMultiRoute 时,才可以设置这个选项。
如果音频使用模式设置为 AVAudioSessionCategoryAmbient,则会自动设置此选项。 同样,设置 AVAudioSessionCategoryOptionDuckOthers 或 AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers 选项也会启用此选项。
-
AVAudioSessionCategoryOptionDuckOthers
播放声音时,支持和其他App混音,但是会降低其他App播放的声音。可以用在偶尔播放音频的场景,如导航播报。
仅在AVAudioSessionCategoryPlayAndRecord、AVAudioSessionCategoryPlayback 或 AVAudioSessionCategoryMultiRoute 时,才可以设置此选项。
-
AVAudioSessionCategoryOptionAllowBluetooth
支持蓝牙设备作为输入(这应指录音)。
仅 AVAudioSessionCategoryPlayAndRecord 或 AVAudioSessionCategoryRecord 时,才能设置此选项。
-
AVAudioSessionCategoryOptionDefaultToSpeaker
在没有其他音频设备时,使用内置扬声器播。
其他音频设备如耳机,会影响该选项,当耳机插入时,音频路由会转向耳机麦克风/耳机;拔出耳机时,音频路由则恢复到内置麦克风/内置扬声器。
只有在使用 AVAudioSessionCategoryPlayAndRecord 时才能设置此选项
-
AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers
iOS9及以上可用,播放音频时暂停来自其他App音频播放(注意,暂停而不是中止),播放完成释放音频焦点后,系统会恢复其他App的音频播放。
可以用在偶尔播放音频的场景,如导航播报。
仅当 AVAudioSessionCategoryPlayAndRecord、AVAudioSessionCategoryPlayback 或 AVAudioSessionCategoryMultiRoute 时,才能设置此选项。
-
AVAudioSessionCategoryOptionAllowBluetoothA2DP
iOS10及以上可用,支持A2DP的蓝牙设备。
如果将应用程序配置为 AVAudioSessionCategoryAmbient、AVAudioSessionCategorySoloAmbient 或 AVAudioSessionCategoryPlayback 类别,系统会自动路由到 A2DP 端口。
从 iOS10开始,使用 AVAudioSessionCategoryPlayAndRecord 的应用程序允许将输出路由到配对的蓝牙 A2DP 设备。
要启用此行为,请在设置音频会话的类别时传递此类别选项。
使用 AVAudioSessionCategoryMultiRoute 或 AVAudioSessionCategoryRecord 时,会隐式清除此选项(将不可使用A2DP设备)
-
AVAudioSessionCategoryOptionAllowAirPlay
iOS10及以上可用,支持AirPlay设备。
如果设置了 AVAudioSessionCategoryPlayAndRecord,那么需要显式设置此选项才支持AirPlay。
对于其他大多数音频使用模式,系统会隐式设置此选项;例外是AVAudioSessionCategoryMultiRoute 和 AVAudioSessionCategoryRecord ,这两个会隐式清除此选项。
-
AVAudioSessionCategoryOptionOverrideMutedMicrophoneInterruption
iOS14.5及以上可用,出于隐私考虑,系统在静音时使内置麦克风会中断录制。
当使用AVAudioSessionCategoryPlayAndRecord且开启了该选项,那么在静音时,播放将照常继续,但是麦克风中断录制(硬件会生成样本缓冲区,但值为 0)。
音频焦点使用原则
App使用音频焦点的原则:
- 谁使用谁抢占,使用完毕后要释放;
- 最小限度的音频模式。不要申请不必要的硬件资源,例如在听音乐场景申请麦克风是不必要的。
// 一个App内所有场景/任务都共享同一个音频会话
AVAudioSession *session = [AVAudioSession sharedInstance]; //获取共享单例
//当前音频模式
AVAudioSessionCategory lastCategory = session.category;
AVAudioSessionCategoryOptions lastCategoryOptions = session.categoryOptions;
if(音频模式是否满足场景需要)
{
//需要修改音频模式
NSError *error = nil;
if ([session setCategory:按需要设置 withOptions:按需要设置 error:&error] == NO)
{
//发生错误,异常处理
NSLog(@"%@",error);
return;
}
//抢占音频焦点
error = nil;
if ([session setActive:YES error:&error] == NO)
{
//发生错误,异常处理
NSLog(@"%@",error);
return;
}
}
/// 使用音频资源
///使用完毕后
if(是否需要恢复音频模式)
{
//需要恢复
NSError *error = nil;
if ([session setCategory:lastCategory withOptions:lastCategoryOptions error:&error] == NO)
{
//发生错误,异常处理
NSLog(@"%@",error);
return;
}
}
/// 没有其他场景需要使用音频焦点了
//释放音频焦点
NSError *error = nil;
if ([session setActive:YES error:&error] == NO)
{
//发生错误,异常处理
NSLog(@"%@",error);
return;
}
//也可以这样释放音频焦点,这时系统会通知其他App中断结束,可以恢复音频焦点了
//if ([session setActive:NO withOptions:AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation error:&error] == NO )
//{
// NSLog(@"%@",error); //发生错误
// return;
//}
需要注意的是,对于SDK开发来说,因为自身不能完全掌控宿主App,所以使用音频资源时应每次都要抢占音频焦点;而对音频焦点的释放,应提供释放音频焦点的默认实现,同时建议增加接口让供宿主App实现释放动作,以增加宿主App对音频焦点的掌控能力。