BT_蓝牙音乐整体架构分析

基于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的方式回调状态信息,然后上层根据回调的状态信息来执行一系列的操作;

相关推荐
幻雨様5 小时前
UE5多人MOBA+GAS 45、制作冲刺技能
android·ue5
Jerry说前后端6 小时前
Android 数据可视化开发:从技术选型到性能优化
android·信息可视化·性能优化
高阳言编程7 小时前
6. 向量处理机
架构
Meteors.7 小时前
Android约束布局(ConstraintLayout)常用属性
android
alexhilton8 小时前
玩转Shader之学会如何变形画布
android·kotlin·android jetpack
.Shu.9 小时前
Redis Reactor 模型详解【基本架构、事件循环机制、结合源码详细追踪读写请求从客户端连接到命令执行的完整流程】
数据库·redis·架构
gnip11 小时前
Jenkins部署前端项目实战方案
前端·javascript·架构
尚书12 小时前
全局核心状态 + 局部功能内聚模块化混合架构
架构
whysqwhw12 小时前
安卓图片性能优化技巧
android
车厘小团子12 小时前
🎨 前端多主题最佳实践:用 Less Map + generate-css 打造自动化主题系统
前端·架构·less