AirPods远程控制适配

AirPods

16年底苹果推出了AirPods耳机。公司产品要适配AirPods,支持AirPods的远程控制。我在拿到耳机后,折腾了一会,连不上手机,竟然不知道怎么使用。~~~
上网找到了官方的使用方法:https://support.apple.com/zh-cn/HT207010

AirPods的远程控制默认是控制Siri和电话。快速施力轻点两下这个AirPod外侧可激活Siri或使用电话。这个不是我们App想要的远程控制,我们希望能通过AirPods来控制App的行为,即希望App能监听到AirPods的操作。在官方的使用说明中有这样一段话“如果您喜欢,您可以更改设置,使轻点两下时执行的操作变成播放或暂停音乐。”Ok,只要能双击播放,双击暂停音乐,那么App就能监听到远程控制事件,同线控耳机的那些远程控制事件一样。

下面是适配AirPods远程控制的一些小结。

AirPods在不同系统上的表现

AirPods在iOS10.2以下表现和普通的蓝牙耳机类似,能手动通过蓝牙连接上手机。

AirPods在iOS10.2以上的能支持双击操作,双击播放音乐,双击停止音乐;分别对应远程线控中的UIEventSubtypeRemoteControlPlay、UIEventSubtypeRemoteControlStop等事件。

如何监听远程控制事件:http://www.cnblogs.com/kenshincui/p/3950646.html#remoteControl

如何判断现在接入了AirPods

通过检查AVAudioSession的currentRoute中的输出port的名字,可以判断当前音频输出是否是AirPods

- (BOOL)isAirPods {
    NSArray<AVAudioSessionPortDescription *> *outputPorts = [AVAudioSession sharedInstance].currentRoute.outputs;
    for (AVAudioSessionPortDescription *desc in outputPorts) {
        if ([desc.portName rangeOfString:@"AirPods"].length > 0) {
            return YES;
        }
    }
    return NO;
}

这个代码在iOS10以下的系统也能工作,在iOS10以下AirPods表现如同蓝牙耳机,并且,portName 还是AirPods。
如果需要用户在戴上耳机的时候检查是否是AirPods,可以监听系统发出的AVAudioSessionRouteChangeNotification通知,在route改变时,通过上面的代码检查下,就可以知道是否是用户带上了AirPods耳机。
有时,我们需要检查当前输出音频设备是否有蓝牙,也可以像上面的代码一样

- (BOOL)isBluetooth {
    NSArray<AVAudioSessionPortDescription *> *outputPorts = [AVAudioSession sharedInstance].currentRoute.outputs;
    for (AVAudioSessionPortDescription *desc in outputPorts) {
        if ([desc.portType isEqualToString:AVAudioSessionPortBluetoothA2DP]
            || [desc.portType isEqualToString:AVAudioSessionPortBluetoothLE]
            || [desc.portType isEqualToString:AVAudioSessionPortBluetoothHFP]) {
            return YES;
        }
    }
    return NO;
}

AirPods的远程控制

这里说的AirPods远程控制,不是通过AirPods唤起Siri或者接系统电话,而是通过AirPods播放、停止音乐。 在连上AirPods后,需要在手机上进行设置,将AirPods的双击操作改成播放/停止音乐。具体设置方法见:https://support.apple.com/zh-cn/ht207009
下文说的AirPods远程控制也是指设置后,远程控制音乐播放/停止。

如果对iOS音频编程不是熟悉,可以先看看下面的文章。

对常用的两种音频category测试了下AirPods的远程控制,大致表现如下。

AVAudioSessionCategoryPlayback

在AVAudioSessionCategoryPlayback这个category下,App只能播放音乐,大部分音乐播放软件使用这个模式就可以了,基本上不用在设置什么就能支持AirPods的远程控制音乐播放暂停。

AVAudioSessionCategoryPlayAndRecord

如果App需要录音也需要播放音乐,就只能使用这个模式了。我们的App是个对讲机,需要录音,也需要播放声音,只能设置这个category。但是在这个模式下,AirPods的远程控制没有反应。需要修改下category的options。

  • iOS 10 以下
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetooth error:&error]
  • iOS 10 以上
[[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionAllowBluetoothA2DP error:&error]   

AVAudioSessionCategoryOptionAllowBluetoothA2DP 这个option在iOS10系统后才有。

音频模式的设置

我们的App有这几种模式需要设置 category + mode + options

  • 外放模式 AVAudioSessionCategoryPlayAndRecord + AVAudioSessionModeDefault + AVAudioSessionCategoryOptionDefaultToSpeaker
    该模式下,声音是从外放喇叭出来。

  • 听筒模式
    AVAudioSessionCategoryPlayAndRecord + AVAudioSessionModeDefault + none
    该模式下,声音是从听筒出来。

  • 处于后台时voicechat模式 AVAudioSessionCategoryPlayAndRecord + AVAudioSessionModeVoiceChat
    切入后台后,我们App在来电时需要打断其它App音频模式,所以需要设置voicechat的模式

但Airpod 仅在
AVAudioSessionCategoryPlayAndRecord + AVAudioSessionModeDefault + AVAudioSessionCategoryOptionAllowBluetoothA2DP
模式下 能连接上,并能远程控制。

AVAudioSessionCategoryPlayAndRecord + AVAudioSessionModeDefault + AVAudioSessionCategoryOptionAllowBluetooth
模式下,能连接上,但是不能远程控制。

如果是设置的其它模式,比如设置了模式
AVAudioSessionCategoryPlayAndRecord + AVAudioSessionModeVoiceChat
AVAudioSessionCategoryPlayAndRecord + AVAudioSessionModeDefault + AVAudioSessionCategoryOptionDefaultToSpeaker
后就不能连上Airpods了,并且在控制中心面板中也没有AirPods选项。