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

相关推荐
计蒙不吃鱼1 小时前
一篇文章实现Android图片拼接并保存至相册
android·java·前端
LucianaiB2 小时前
如何做好一份优秀的技术文档:专业指南与最佳实践
android·java·数据库
颜颜yan_2 小时前
【HarmonyOS5】UIAbility组件生命周期详解:从创建到销毁的全景解析
架构·harmonyos·鸿蒙·鸿蒙系统
打码人的日常分享5 小时前
智慧城市建设方案
大数据·架构·智慧城市·制造
鲁班大叔_0076 小时前
使用扣子与Dify的业务风险
架构·产品
hello早上好6 小时前
Spring不同类型的ApplicationContext的创建方式
java·后端·架构
duwei_wang7 小时前
[Android]-Admob配置过多导致的慢消息
android
Python智慧行囊7 小时前
Python 中 Django 中间件:原理、方法与实战应用
python·中间件·架构·django·开发
HyggeBest7 小时前
Mysql的数据存储结构
后端·架构
雨白8 小时前
发送自定义广播
android