背景
今天正边写代码边听歌的时候,我的播放器忽然停了。当我重新点选一首歌的时候,播放器又自动停了。于是我打断点,看看是谁偷偷(guang ming zheng da )停掉了我的播放器。接着我就看到了某一个通知的处理函数里,当等于AVAudioSessionRouteChangeReasonCategoryChange枚举值的时候,暂停播放器。为了认识下这是什么,于是我踏入(扑通一声掉进)了音视频的知识。
基本音频交互概念
对于任何一个APP来说,用户都可能在APP运行时插拔耳机,按照iOS的HIG(人机界面指南)描述可以分为两种情况:录制中和播放录音
- 在录制过程中,用户插拔耳机时,你的应用程序应该停止录制。
- 播放的情况细分为两个小类,对应的结果不同:如果用户在播放过程中拔下耳机,应用程序应该暂停音频。如果用户在播放过程中插入耳机,你的应用程序应该允许播放继续。
要根据这些建议让应用程序响应此类事件,需要编写音频会话代码以处理音频硬件路由更改。某些类型的应用程序,比如游戏,并不总是需要对路线变化做出响应。然而,其他类型的应用程序,如媒体播放器,必须响应所有路由更改。
系统其实已经为我们提供了合适的时机,我们可以注册观察AVAudioSessionRouteChangeNotification类型的通知,这样我们的应用程序就可以收到此类更改的通知。然后,我们可以在侦听回调函数中编写执行需要的操作(例如,停掉我的播放器)。
实现原理
系统最初会在应用程序启动后确定音频路由。它会在应用程序运行时继续监视活动路由。当用户(包括但不限于)插入一对耳机、连接蓝牙LE耳机或拔下USB音频接口时,系统会发送一条AVAudioSessionRouteChangeNotification类型的通知来告诉我们音频路由更改。这样我们就可以了解这些更改发生的时间,从而可以更新用户界面或更改内部状态。
这个发出的通知包含一个userInfo字典,提供路线更改的详细信息。我们可以通过从userInfo字典中检索AVAudioSessionRouteChangeReason值来确定此更改的原因。连接新设备时,原因是AVAudioSessionRouteChangeReasonNewDeviceAvailable,删除一个设备时,原因是AvaudioSessionRouteChangeReasonOldDeviceAvailable。
音频改变的种类
既然我们知道了音频改变会有对应的原因,那么这个原因里都包括哪些呢?除了我们上文提到的新设备可用和旧设备不可用之外还有:
- unknown
指示更改原因的值未知。 - categoryChange
指示会话对象的类别已更改。 - override
指示应用程序覆盖了输出路由。 - wakeFromSleep
指示设备从睡眠中醒来时路由已更改。 - noSuitableRouteForCategory
表示由于指定类别现在没有合适的路由可用,路由已更改。 - routeConfigurationChange
指示一组I/O端口的配置已更改。
获取现在的路由信息
当新设备可用时,除了在通知中的userInfo字典查询路信息,我们还可以通过查询音频会话的currentRoute属性,以确定音频输出当前路由的位置。这将返回一个AvaudioSessionRoutedDescription对象,列出音频会话的所有输入和输出 。移除设备后,可以从userInfo字典中检索上一个路由的AvaudioSessionRoutedDescription对象。在这两种情况下,都可以查询路由描述的outputs属性,该属性返回一个AVAudioSessionPortDescription对象数组,提供音频输出路由的详细信息。
总计
音频设备的改变可以通过AVAudioSessionRouteChangeNotification通知来获知具体的改变。知识总是来的漫不经心,从一个小小的问题上就引出了这么多知识,学习吧,少年。