BT_蓝牙音乐整体架构分析

1,549 阅读6分钟

基于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回调各种状态信息等;

架构

Avrcp架构图.png

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

类图

蓝牙音乐类图.png

大致的流程为:

A2dpMediaBrowserService和A2dpSinkService向AvrcpControllerService发送指令,而AvrcpControllerService向JNI层发送指令,最后通过callback的方式接收到底层上报的状态变更的信息;

指令

AvrcpControllerService 指令

Play State Values
CMDDESCVALUE
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
STATEDESCVALUE
STATE_NONE0
STATE_STOPPED停止1
STATE_PAUSED暂停2
STATE_PLAYING播放3
STATE_FAST_FORWARDING4
STATE_REWINDING5
STATE_BUFFERING6
STATE_ERROR错误7
STATE_CONNECTING8
STATE_SKIPPING_TO_PREVIOUS9
STATE_SKIPPING_TO_NEXT10
STATE_SKIPPING_TO_QUEUE_ITEM11

对应代码中的AvrcpPlayer中getPlayBackState方法的返回值;

需要和Play State进行区分,不要混淆;

KeyCoded for Pass Through Commands
CMDDESCVALUE
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_FF0x49
PASS_THRU_CMD_ID_REWIND倒带0x48
PASS_THRU_CMD_ID_FORWARD上一首0x4B
PASS_THRU_CMD_ID_BACKWARD下一首0x4C

通过定义名称看,这组command主要是用于sendPassThroughCmd方法,对应其中的Cmd;

A2dpSinkStateMachine 指令

EVENT 指令
CMDDESCVALUE
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 指令

CMDDESCVALUE
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启动

AvrcpController时序图.png

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

A2dpSinkService 连接

A2dpSink_connect时序图.png

AvrcpControllerService 连接

AvrcpController连接时序图.png

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

AvrcpController_歌曲信息获取业务时序图.png

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

AvrcpController准备就绪

AvrcpController准备就绪&等待播放指令.png

主要是分为了几个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 播放

AvrcpController指令开始播放_时序图.png

这个流程主要是在服务端(手机端)开启,车机端(客户端)蓝牙服务接收到指令之后,Bluedroid通过JNI向上发送callback回调,用于开启蓝牙音乐的播放;

当上层接收到了底层发送的available和playback status changed回调之后,会申请对应的audio focus,AudioTrack的创建和开启是在底层执行的,不在上层体现;

AvrcpController 暂停

AvrcpController_pause_时序图.png

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