蓝牙耳机按键在Android侧的处理流程

    目前大多数音频视频设备采用红外遥控器,由于距离、角度、障碍物等的影响,红外遥控器的应用受到了很大限制。蓝牙无线通信技术可以实现传统红外遥控全部应用功能,而且客服了红外遥控器的局限性。蓝牙音频视频遥控应用框架(Audio Video Remote Control Profile,AVRCP)就是实现无线遥控功能的规范。

     蓝牙耳机按键的处理在android层主要就是对BT的AVRCP profile的处理。下面我们来具体看下。

    上层对接收到的AVRCP命令的处理有两部分。

       1、对metadata, play status and event notification的处理。(avrcp.java)

       2、对播放、暂停、停止、上一首、下一首的按键处理(快进和快退不在这里处理,是第一种情况)。使用uinput模拟输入设备转化为input event。

现在我们就来分别分析一下上述的两种处理。

一、avrcp音频属性的处理

AVRCP主要负责以下的功能:

1、 接受来自蓝牙耳机的请求,并返回响应;

2、 当用户直接用手机操作音乐时,将状态更新到蓝牙耳机;

3、 将手机音量的改变通知蓝牙耳机,将蓝牙耳机音量的改变通知手机audio;

上面的功能主要是通过回调函数、Native函数和AvrcpMessageHandler类实现的。回调函数负责将来自蓝牙耳机的消息通知给手机,Native函数返回响应给蓝牙耳机。

主要包含以下回调方法:

方法

介绍

getRcFeatrues

Avrcp是否支持absolute volume

getPlayStatus

获取播放状态

getElementAttr

获取音乐属性信息

registerNotification

获取register notification响应

volumeChangeCallback

蓝牙耳机音量改变

handlePassthroughCmd

处理passthrough命令

主要包含以下native方法:

方法

介绍

classInitNative

初始化回调方法

initNative

获取avrcp接口实例,并调用init初始化

cleanupNative

销毁avrcp接口实例

getPlayStatusRspNative

播放状态的响应

getElementAttrRspNative

获取音乐属性信息的响应

registerNotificationRspPlayStatusNative

响应register notification

registerNotificationRspTrackChangeNative

响应register notification

registerNotificationRspPlayPosNative

响应register notification

setVolumeNative

设置蓝牙耳机的音量

二、蓝牙耳机按键在android侧的映射处理 

AVRCP的按键定义:

代码路径在frameworks/base/data/keyboards/AVRCP.kl

key 200   MEDIA_PLAY_PAUSE    WAKE

key 201   MEDIA_PLAY_PAUSE    WAKE

key 166   MEDIA_STOP          WAKE

key 163   MEDIA_NEXT          WAKE

key 165   MEDIA_PREVIOUS      WAKE

key 168   MEDIA_REWIND        WAKE

key 208   MEDIA_FAST_FORWARD  WAKE

前面的key 值是在蓝牙耳机中定义的key code ,后面的MEDIA_xx是在android中定义的key code。

在google remote中,android接收端接收socket发来的IR CODE,然后将IRCODE模拟出来发给系统处理,这就是google remote接收端的原理。这里使用的是使用uinput模拟输入设备。通过 send_key函数,使用uinput桥接,发送input event。uinput原理是利用内核现有的uinput驱动,通过内核驱动uinput来发送input event。

avrcp按键映射成inputevent 处理过程:

Thread: InputDeviceReader是整个Input过程的控制中心(在Android4.x中,这个thread在InputManager.cpp中)。这个thread通过EventHub::getEvent()来读Linux的 /dev/input目录下的Input Devices,从而得到硬件的key input。基于一个与每个Input Device关联的key layout map,key input会被map成Android能够识别的Key Code,比如一个AVRCP Input Device的key input值200就会被map成MEDIA_PLAY。

需要注意的是,在EventHub::getEvnet()读Input Devices之前,需要判断Devices是否已经被打开。如果没有就需要去调用EventHub::openPlatformInput()去扫描 /dev/input/下有哪些设备,然后打开这些设备并载入它们各自的keylayout map(/frameworks/base/data/keyboards/ 中的*.kl文件就是用于定义key layout map的,其中的AVRCP.kl就定义了Bluetooth AVRCP Input Device的key layout map。在Android Device的root fs中,这些.kl文件会被放在/system/usr/keylayout/目录)。这些被打开的设备的file descriptor和device_t指针会分别保存在mFDs和mDevices中。

InputDeviceReaderThread得到Key Code之后,会交给Java层的代码来处理。最终由PhoneWindowManager.java中的interceptKeyBeforeQueueing()创建一个消息 MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK,经过消息的转发和处理最后在dispatchMediaKeyEven函数里创建并发送ACTION_MEDIA_BUTTON intent广播出去。

发送ACTION_MEDIA_BUTTON的代码路径:

frameworks/base/media/java/android/media/MediaFocusControl.java

接收ACTION_MEDIA_BUTTON的代码路径在:

packages/apps/Music/src/com/android/music/MediaButtonIntentReceiver.java

在文件MediaButtonIntentReceiver里会把按键转化为MediaPlaybackService的command,然后启动MediaPlaybackService对这些command进行处理,包括音乐进行暂停、播放、停止等操作。

MediaPlaybackService的代码路径:

packages/apps/Music/src/com/android/music/MediaPlaybackService.java

在 onStartCommand里对音乐播放器进行暂停、播放、停止等操作。

三、蓝牙耳机按键的hci log分析

简单说一下发送命令的处理过程,主要分为两步,按键按下发送一个Pass though命令,按键弹起的时候,会再次发送一个Pass though命令,第一个命令的State_flag为Button Pushed,第二个命令的state_flag为Button Released。每个命令都需要对方的回应,如果接受,则会回应Accepted,否则返回Rejected。下面就以蓝牙耳机的播放键为例子来说明一下。

播放按键的BT log如下:

如上图,1463帧的Role为CT,代表为蓝牙耳机,向手机发送play命令,手机回应accepted,然后,CT发送按键弹起的命令,收到ACCEPTED,整个播放的log就结束了。上面的NOTIFY,是蓝牙耳机发送的同步命令,手机会发送CHANGED进行响应,如果在100ms内,不能进行响应,则会先发送INTERIM进行告知,再发送CHANGED。

 

  • 2
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
蓝牙核心规格 蓝牙设备的构成组件。 蓝牙核心规格定义各种技术构成组件,开发人员可以用它们来创建构成繁荣的蓝牙生态系统的互操作性设备。蓝牙规格由蓝牙技术联盟 (SIG) 负责监督,并由Bluetooth SIG 工作组 定期更新和补充,以满足不断发展的技术和市场要求。 蓝牙的两种类型 部署最为普遍的两种规格为蓝牙基础率/增强数据率 (BR/EDR)(采用版本为 2.0/2.1)和低耗能 (LE) 蓝牙(采用版本为 4.0/4.1/4.2)。每项部署都有不同的用例,同时采用不同的芯片以满足基本硬件要求。双模芯片也适用于包含两种用例的应用。 存在哪些差异? 蓝牙 BR/EDR—可建立相对较短距离的持续无线连接,因此非常适用于流式音频等应用 蓝牙 LE—可建立短时间的长距离无线电连接,非常适用于无需持续连接但依赖电池具有较长寿命的的物联网 (IoT) 应用 双模—双模芯片可支持需要连接 BR/EDR 设备(例如音频耳机)以及 LE 设备(例如穿戴设备或零售信标)的单一设备(例如智能手机或平板电脑) 核心系统结构 尽管每项部署都有具体要求(详见蓝牙规格),但蓝牙核心系统结构有许多统一要素。该系统包含射频收发器、基带和协议栈,支持设备连接和交换各类数据。 蓝牙设备交换根据蓝牙规格协议信号。核心系统协议包括射频 (RF) 协议、链路控制 (LC) 协议、链路管理器 (LM) 协议以及逻辑链路控制和适配协议 (L2CAP),蓝牙规格详细定义了这些协议。 最低的三个系统层—射频、链路控制和链路管理器协议—通常被归属于称为蓝牙控制器的子系统。这是一种采用可选标准接口—主机控制器接口 (HCI)—的通用部署,支持与蓝牙系统的其他设备(即蓝牙主机)进行双向通信。 主控制器可能是以下配置之一,具体取决于用例: BR/EDR 控制器,包括射频、基带、链路管理器和可选 HCI LE 控制器,包括 LE PHY、链路层和可选 HCI BR/EDR 组合控制器和 LE 控制器,组合控制器共享一个蓝牙设备地址 蓝牙规格通过定义等效层之间交换的协议信息来实现系统之间的互操作性。它还通过定义蓝牙控制器和蓝牙主机之间的公用接口来实现独立蓝牙子系统之间的互操作性。 蓝牙栈 物理 (PHY) 层 通过蓝牙通信信道控制 2.4Ghz 射频的传输/接收。BR/EDR 提供的信道较多但带宽较窄,而 LE 使用的信道较少但带宽较宽。 链路层 定义数据包结构/信道、发现/连接程序以及发送/接收数据。 直接测试模式 允许测试人员向 PHY 层发出指令以传输或接收给定数据包序列,通过 HCI 或 2 线 UART 接口提交命令。 主机控制器接口 (HCI) 蓝牙控制器子系统(底部三层)和蓝牙主机之间的可选标准接口。 逻辑链路控制和适配协议 (L2CAP) 层 基于数据包的协议,可将数据包传输至 HCI 或直接传输到无主机系统中的链路管理器。支持更高级别的协议多路复用、数据包分割和重组,以及将服务质量信息传输到更高层。 属性协议 (ATT) 在建立连接之后定义数据交换客户端/服务器协议。使用通用属性配置文件 (GATT) 将属性分类为有意义的服务。ATT 主要用于 LE 部署,偶尔也会用于 BR/EDR 部署。 安全管理器 定义管理蓝牙设备之间配对完整性、身份验证以及加密的协议和操作,提供安全功能工具箱,其他组件可利用该工具箱支持不同应用所需的各种安全级别。 通用属性配置文件 (GATT) 使用属性协议,GATT 对封装设备组件性能的服务进行分组,并描述基于 GATT 功能的用例、角色和一般性能。其服务框架定义服务规程和格式及其特性,其中包括发现、读取、写入、通知以及指示特性以及配置特性广播。GATT 仅用于蓝牙 LE 部署。 详细了解 GATT 信息。 通用访问配置文件(GAP) 可与蓝牙 LE 部署中的 GATT 配合使用,以定义与发现蓝牙设备和共享信息相关的规程和角色,以及连接蓝牙设备的链路管理内容
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值