音频焦点
两个或者两个以上的app可以同时向同一输出流播放音频。系统会将所有音频流混合在一起,但这样会给用户带来很大的困扰。为了避免所有音乐app同时播放,ios引入了“音频焦点”的概念。在ios中,音频焦点是操作系统为了管理音频硬件而引入的概念,是指app对音频硬件在时间维度上的使用控制(不是使用权限,使用权限需要app单独申请)。app可以独占使用,也可以共享使用音频焦点,即独占或者共享音频硬件。
独占音频焦点,指的是只能有一个app使用音频硬件,而共享音频焦点,指的是多个app可以同时使用音频硬件,共享音频焦点通常会导致多个app播放的音频被混音(即手机会同时发出多个音频的声音)。
当你的app需要输出音频时,你的app就需要得到音频焦点,获得音频焦点之后,就可以播放声音了。不过,在app获得音频焦点之后,也不一定能一直持有音频焦点,因为其它app也可能抢占音频焦点。如果你的app的音频焦点被其它app抢占了,那么你的app应该暂停播放视频或者音频。
我们先来看一个录屏(如下所示,注意录屏里面所播放的声音),当酷狗音乐在播放的时候,我们启动一个demo,然后点击如下图的黑色框的按钮(按钮文案是"AVAudioSessionCategorySoloAmbient(系统默认)“),会发现酷狗音乐不再播放了,此时我们再点击如下图的红色框中的按钮(按钮文案是"释放音频焦点,以便回复酷狗音乐的播放”),然后酷狗音乐就继续播放音乐了。
音频焦点demo
上面录屏的demo的实现代码如下面第1张图所示,黑色框的代码表示demo app要抢占ios系统的音频焦点。抢占音频焦点只需要分别调用AVAudioSession类的两个方法:
- setCategory:error:方法
- setActive:error:方法
setCategory:error:方法的作用如下面第2张图所示,该方法用于告诉系统说本app要怎么使用音频。该方法的第1个参数的取值一共有7个,其中一个是AVAudioSessionCategorySoloAmbient,该值表示打断其他不支持混音的APP的音频播放。
而setActive:error:方法表示申请获取或者释放ios系统的音频焦点,该方法的返回值表示是否已经成功获取或者释放音频焦点。该方法的第1个参数为YES表示app要申请ios系统的音频焦点,而为NO表示app要释放ios系统的音频焦点。如下图所示,红色框的代码表示释放系统的音频焦点,AVAudioSessionSetActiveOptionNotifyOthersOnDeactivation表示app释放音频焦点的时候,会给其它app发送“音频焦点已经释放了”的通知,而酷狗音乐app会接收该通知,并在收到该通知后恢复音乐的播放。
AVAudioSession
AVAudioSession是一个类,如下图所示,每个运行中的app都有一个AVAudioSession类的单例,系统通过协调每个运行中的app的AVAudioSession的单例来管理音频的行为。
在ios中,app的AVAudioSession实例对象的默认功能配置(app冷起的时候就默认会有的能力)有:
- 支持音频播放,但不支持录音;
- 把手机调到静音模式会把app“静音”。比如当app正在播放音乐或者视频时,把手机调到静音模式,此时手机就不会发出音乐或者视频的声音;
- 锁屏也会把手机调到静音模式会把app“静音”;
- 当app播放音频或者视频时,后台正在播放的音频会被“静音”,因为后台正在播放音频的那个app的音频焦点被“抢”了。
AVAudioSession实例对象提供的默认功能往往不足以满足视频类的app的需求,此时你可以通过配置AVAudioSession的category、mode和option来操作音频以便满足需求:
- 调用AVAudioSession的setActive:error:方法来申请获取或者释放ios系统的音频焦点;
- 通过调用AVAudioSession的setCategory:mode:options:error:方法来改变音频的行为,该方法需要和setActive:error:方法结合使用才能真正的改变音频的行为
- 监听音频相关的通知,比如监听音频播放过程中被打断、耳机插入或者拔出的通知
- 使用音频硬件的一些高级功能,比如设置采样率、I/O缓存时长
AVAudioSession支持的category配置一共有7种类型,如下两张图所示。
以上7种category已经能满足大部分的场景了,但如果还需要满足要求更加细致的场景,那就需要在category的基础上结合option和mode来使用。每种category都有自己的option和mode类型,所以option和mode是对category的补充(细化对category的配置)。比如,如果你的app使用了Playback类型的category,该类型有两种option可以配置(即是否支持混音,对应上图的第4行第3列的位置),其中一种option能让你的音频和后台播放的音频(比如后台上正在播放酷狗音乐)同时播放(具体的option是AVAudioSessionCategoryOptionMixWithOthers),而另一种option能让后台播放的音频停止“出声音”(默认就是这种,即默认不支持混音)。
注意:如果你想要实现音频的后台播功能(具体是手机进入锁屏状态或者把app退到后台),就不仅需要把AudioSession的category设置为AVAudioSessionCategoryMultiRoute或者AVAudioSessionCategoryPlayAndRecord或者AVAudioSessionCategoryPlayback,还需要在info.list文件里面添加“Required background modes”这个选项,具体如下图的红框所示。否则的话当手机进入锁屏状态或者把app退到后台时,音频就会被“暂停”,此时你就听不到音频的声音了。
音频相关的通知
音频常见的通知如下:
- AVAudioSessionInterruptionNotification:当你app的音频被打断时,系统就会发出该通知。比如,当你app在播放非静音状态的视频时,此时突然有电话打进来,视频的声音会消失,而电话的铃声会出现,并且系统会发送该通知。
- AVAudioSessionRouteChangeNotification:当手机的音频相关的输入输出设备发生变化时,系统就会发出该通知。比如耳机的插入和拔出。