基于Android P版本分析
蓝牙音乐
概要
我们以蓝牙音乐为例,手机侧推送蓝牙音乐到车机侧进行播放,分析一下在这个过程中调用逻辑;
在蓝牙音乐过程中,其实我们涉及到了2个概念:A2DP和AVRCP;
A2DP
A2DP全称:Advenced Audio Distribution Profile,即蓝牙音频传输模型协定;
A2DP规定了使用蓝牙异步传输信道方式,传输高质量音乐文件数据的协议堆栈软件和使用方法,基于该协议就能通过以蓝牙方式传输高品质的音乐。例如使用蓝牙耳机或蓝牙音响设备来收听音乐了;
A2DP协议在frameworks层体现为两个:A2dpService和A2dpSinkService;
- A2dpService:作为音源输入端,提供音频流数据;
- A2dpSinkService:作为音源输出端,播放音源端提供的音频流数据;
AVRCP
AVRCP全称:Audio/Video Remote Control Profile,即音频/视频远程控制配置文件。
AVRCP设计用于提供控制TV,Hi-Fi设备等的标准接口,此配置文件用于许可单个远程控制设备(或其他设备)控制所有用于可以接入的A/V设备。AVRCP定义了如何控制流媒体的特征。包括暂停、停止、启动重放、音量控制及其他类型的远程控制操作(其实和DLNA的指令控制类似);
AVRCP是一种在蓝牙协议栈A2DP/AVRCP上实现的控制技术;
类描述
- A2dpSinkService:音频数据流接收端Service,定义音频流的输出端;
- AvrcpControllerService:远程控制端设备,通过发送命令帧到目标发起传输,如车载系统,蓝牙耳机,蓝牙音响;
- A2dpMediaBrowserService:多媒体浏览器服务,用于实现AVRCP和A2DP的MediaBrowserService接口,提供sendPassThroughCmd方法向下发送控制指令,实际上是调用了AvrcpControllerService的sendPassThroughCommandNative方法来调用到JNI层;
- A2dpSinkStreamHandler:蓝牙A2DP接收器流处理程序,用于处理A2dpSinkStateMachine和AvrcpControllerService之间的调用流转;
- AvrcpPlayer:用于描述包含有关远程播放器的信息;
在整个蓝牙音乐的工作流程中,这几个类承载着整个调用流程的控制和处理;
对应的在JNI层,还存在一个C++文件:
- com_android_bluetooth_avrcp_controller.cpp
这个C++主要用于承接Java层和C++的交互,包括从上而下的主动调用以及自下而上的Bluedroid回调各种状态信息等;
架构

涉及到了A2dpSink、Avrcp、JNI3个模块的设计,包括对应的StateMachine;
类图

大致的流程为:
A2dpMediaBrowserService和A2dpSinkService向AvrcpControllerService发送指令,而AvrcpControllerService向JNI层发送指令,最后通过callback的方式接收到底层上报的状态变更的信息;
指令
AvrcpControllerService 指令
Play State Values
CMD | DESC | VALUE |
---|---|---|
JNI_PLAY_STATUS_STOPPED | 停止 | 0x00 |
JNI_PLAY_STATUS_PLAYING | 播放 | 0x01 |
JNI_PLAY_STATUS_PAUSED | 暂停 | 0x02 |
JNI_PLAY_STATUS_FWD_SEEK | 上一首 | 0x03 |
JNI_PLAY_STATUS_REV_SEEK | 下一首 | 0x04 |
JNI_PLAY_STATUS_ERROR | 错误 | -1 |
JNI通过callback的方式向上层上报了上述的PlayState,上层通过对应的执行来执行响应的操作;
代码中对应的为AvrcpControllerService中onPlayStatusChanged回调方法中的参数;
Playback State
STATE | DESC | VALUE |
---|---|---|
STATE_NONE | 无 | 0 |
STATE_STOPPED | 停止 | 1 |
STATE_PAUSED | 暂停 | 2 |
STATE_PLAYING | 播放 | 3 |
STATE_FAST_FORWARDING | 4 | |
STATE_REWINDING | 5 | |
STATE_BUFFERING | 6 | |
STATE_ERROR | 错误 | 7 |
STATE_CONNECTING | 8 | |
STATE_SKIPPING_TO_PREVIOUS | 9 | |
STATE_SKIPPING_TO_NEXT | 10 | |
STATE_SKIPPING_TO_QUEUE_ITEM | 11 |
对应代码中的AvrcpPlayer中getPlayBackState方法的返回值;
需要和Play State进行区分,不要混淆;
KeyCoded for Pass Through Commands
CMD | DESC | VALUE |
---|---|---|
PASS_THRU_CMD_ID_PLAY | 播放 | 0x44 |
PASS_THRU_CMD_ID_PAUSE | 暂停 | 0x46 |
PASS_THRU_CMD_ID_VOL_UP | 增加音量 | 0x41 |
PASS_THRU_CMD_ID_VOL_DOWN | 减低音量 | 0x42 |
PASS_THRU_CMD_ID_STOP | 停止 | 0x45 |
PASS_THRU_CMD_ID_FF | ? | 0x49 |
PASS_THRU_CMD_ID_REWIND | 倒带 | 0x48 |
PASS_THRU_CMD_ID_FORWARD | 上一首 | 0x4B |
PASS_THRU_CMD_ID_BACKWARD | 下一首 | 0x4C |
通过定义名称看,这组command主要是用于sendPassThroughCmd方法,对应其中的Cmd;
A2dpSinkStateMachine 指令
EVENT 指令
CMD | DESC | VALUE |
---|---|---|
EVENT_AVRCP_CT_PLAY | 控制端_播放 | 301 |
EVENT_AVRCP_CT_PAUSE | 控制端_暂停 | 302 |
EVENT_AVRCP_TG_PLAY | 目标端_播放 | 303 |
EVENT_AVRCP_TG_PAUSE | 目标端_暂停 | 304 |
EVENT_REQUEST_FOCUS | 申请音频焦点 | 305 |
这些指令主要是用于响应A2dpSinkStateMachine中的Event事件,而这些Event指令对应了A2dpSinkStreamHandler中对应的指令响应;
A2dpSinkStreamHandler 指令
CMD | DESC | VALUE |
---|---|---|
SRC_STR_START | 远程设备启动音频流 | 0 |
SRC_STR_STOP | 远端设备停止音频流 | 1 |
SNK_PLAY | 本地设备执行播放指令 | 2 |
SNK_PAUSE | 本地设备执行暂停指令 | 3 |
SRC_PLAY | 远端设备执行播放指令 | 4 |
SRC_PAUSE | 远端设备执行暂停指令 | 5 |
DISCONNECT | 远端设备断开连接 | 6 |
AUDIO_FOCUS_CHANGE | 频焦点回调与相关的变化 | 7 |
REQUEST_FOCUS | 当媒体服务处于活动状态时请求焦点 | 8 |
DELAYED_PAUSE | 如果一个调用刚刚开始,允许堆栈时间稳定 | 9 |
UPDATE_TG_HANDLE_STATE | 如果接收到待定状态的活动消息或去激活消息,则更新TG标志 | 10 |
A2dpSinkStreamHandler中的指令对应了AvrcpControllerService的操作,而最终其实还是指向了AvrcpControllerStateMachine,指向了JNI底层操作;
蓝牙音乐流程分析
A2dpSinkService启动

我们知道,在开启蓝牙的时候,我们就将所有的ProfileService就进行了startService操作;其中就包含了A2dpSinkService和AvrcpControllerService这两个Service;
A2dpSinkService 连接

AvrcpControllerService 连接

和之前的A2dpSinkService启动的方式一样,AvrcpControllerService启动之后,会等待JNI层上报connect的连接状态,然后Bluetooth apk会根据上报的连接状态信息进行一些配置,包括创建AvrcpPlayer、上报ConnectionStateChange等操作;

连接成功之后,在开启蓝牙音乐应用进程之后,就可以获取到手机端(服务端)的媒体信息,然后显示到车机端(客服端)界面中;
AvrcpController准备就绪

主要是分为了几个JNI回调阶段:
- btavrcp_play_status_changed_callback
- btavrcp_track_changed_callback
- btavrcp_set_addressed_player_callback
- btavrcp_uids_changed_callback
- btavrcp_get_folder_items_callback
- btavrcp_playerapplicationsetting_callback
- btavrcp_playerapplicationsetting_changed_callback
这个阶段是蓝牙播放之前的准备阶段,JNI层回调上述的一些信息,使用这些信息进行配置;
AvrcpController 播放

这个流程主要是在服务端(手机端)开启,车机端(客户端)蓝牙服务接收到指令之后,Bluedroid通过JNI向上发送callback回调,用于开启蓝牙音乐的播放;
当上层接收到了底层发送的available和playback status changed回调之后,会申请对应的audio focus,AudioTrack的创建和开启是在底层执行的,不在上层体现;
AvrcpController 暂停

这个流程是车机端主动调用Pause流程,从BluetoothPlayer应用进程中发送指令,通过sendCmd的方式发送到底层,底层通过callback的方式回调状态信息,然后上层根据回调的状态信息来执行一系列的操作;