【Bluedroid】蓝牙音频接收端活动设备切换机制深度解析(sink_set_active_device)
本文深入剖析Android蓝牙音频接收端(Sink)活动设备切换的全流程,涵盖设备状态管理、编解码器协商、多线程协作等核心机制。通过分析从应用层指令到底层音频会话建立的完整调用链,揭示蓝牙设备无缝切换的技术原理,重点关注异步操作、状态同步及编解码器配置的关键实现细节。
一、核心功能流程
设备切换入口:
sink_set_active_device
作为入口函数,验证模块状态后通过do_in_main_thread
调度核心逻辑到主线程执行。设备类型处理:
set_active_peer_int
根据设备类型 (源 / 接收器) 判断共存模式,调用对应模块的SetActivePeer
方法。活动设备设置:
btif_av_sink.SetActivePeer
处理三种场景:设备地址匹配、断开连接、新设备切换,验证设备状态后调用btif_a2dp_sink_restart_session
。会话管理:
btif_a2dp_sink_restart_session
协调会话终止、活动设备设置和新会话启动,调用底层bta_av_co_set_active_peer
更新系统状态。编解码器配置:
BtaAvCo::SetActivePeer
更新活动设备指针和编解码器配置,通过ReportSourceCodecState
上报编解码器状态到 JNI 层。
二、源码解析
sink_set_active_device
packages/modules/Bluetooth/system/btif/src/btif_av.cc
static bt_status_t sink_set_active_device(const RawAddress& peer_address) {log::verbose("Peer {}", ADDRESS_TO_LOGGABLE_CSTR(peer_address));if (!btif_av_sink.Enabled()) {log::warn("BTIF AV Source is not enabled");return BT_STATUS_NOT_READY;}// 异步操作准备std::promise<void> peer_ready_promise;std::future<void> peer_ready_future = peer_ready_promise.get_future();// 主线程执行异步操作bt_status_t status = do_in_main_thread(FROM_HERE, base::BindOnce(&set_active_peer_int,AVDT_TSEP_SRC, // peer_seppeer_address, std::move(peer_ready_promise)));if (status == BT_STATUS_SUCCESS) {peer_ready_future.wait();} else {log::warn("BTIF AV Sink fails to change peer");}return status;
}
将指定地址的蓝牙设备设置为当前活动设备。
set_active_peer_int
packages/modules/Bluetooth/system/btif/src/btif_av.cc
// Set the active peer
static void set_active_peer_int(uint8_t peer_sep,const RawAddress& peer_address,std::promise<void> peer_ready_promise) {log::warn("peer_sep={} ({}) peer_address={}",(peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink", peer_sep,ADDRESS_TO_LOGGABLE_CSTR(peer_address));BtifAvPeer* peer = nullptr;if (peer_sep == AVDT_TSEP_SNK) {if (!btif_av_src_sink_coexist_enabled() || (btif_av_src_sink_coexist_enabled() &&btif_av_both_enable() && (btif_av_sink.FindPeer(peer_address) == nullptr))) {btif_av_source.SetActivePeer(peer_address,std::move(peer_ready_promise));log::error("Error setting {} as active Sink peer",ADDRESS_TO_LOGGABLE_CSTR(peer_address));}return;}if (peer_sep == AVDT_TSEP_SRC) {if (!btif_av_src_sink_coexist_enabled() || (btif_av_src_sink_coexist_enabled() &&btif_av_both_enable() && (btif_av_source.FindPeer(peer_address) == nullptr))) {if (!btif_av_sink.SetActivePeer(peer_address,std::move(peer_ready_promise))) {log::error("Error setting {} as active Source peer",ADDRESS_TO_LOGGABLE_CSTR(peer_address));}}return;}// If reached here, we could not set the active peerlog::error("Cannot set active {} peer to {}: peer not {}",(peer_sep == AVDT_TSEP_SRC) ? "Source" : "Sink",ADDRESS_TO_LOGGABLE_CSTR(peer_address),(peer == nullptr) ? "found" : "connected");peer_ready_promise.set_value();
}
根据指定的设备类型(源或接收器)和地址,将对应的蓝牙设备设置为当前活动设备。
btif_av_sink.SetActivePeer
packages/modules/Bluetooth/system/btif/src/btif_av.cc
/*** Set the active peer.** @param peer_address the active peer address or RawAddress::kEmpty to* reset the active peer* @return true on success, otherwise false
*/
bool SetActivePeer(const RawAddress& peer_address,std::promise<void> peer_ready_promise) {log::info("peer: {}", ADDRESS_TO_LOGGABLE_STR(peer_address));// 1. 如果目标地址与当前活动设备相同,直接标记操作完成并返回成功if (active_peer_ == peer_address) {peer_ready_promise.set_value();return true; // Nothing has changed}// 2. 处理断开连接请求if (peer_address.IsEmpty()) {// 关闭音频接收器会话log::verbose("peer address is empty, shutdown the Audio sink");if (!btif_av_src_sink_coexist_enabled() ||(btif_av_src_sink_coexist_enabled() &&btif_av_source_active_peer().IsEmpty())) {if (!bta_av_co_set_active_peer(peer_address)) {log::warn("unable to set active peer to empty in BtaAvCo");}}btif_a2dp_sink_end_session(active_peer_); // 更新系统状态btif_a2dp_sink_shutdown(); // 终止当前 A2DP 会话并关闭音频接收器active_peer_ = peer_address;peer_ready_promise.set_value();return true;}// 3. 处理共存模式if (btif_av_src_sink_coexist_enabled()) {// 删除音频源的活动设备btif_av_source_delete_active_peer();}// 4. 验证目标设备状态BtifAvPeer* peer = FindPeer(peer_address);if (peer == nullptr || !peer->IsConnected()) {log::error("Error setting {} as active Sink peer",ADDRESS_TO_LOGGABLE_STR(peer_address));peer_ready_promise.set_value();return false;}// 5. 切换到新设备if (!btif_a2dp_sink_restart_session(active_peer_, peer_address,std::move(peer_ready_promise))) {// cannot set promise but need to be handled within restart_sessionreturn false;}log::info("Setting the active peer to peer address {}",ADDRESS_TO_LOGGABLE_STR(peer_address));active_peer_ = peer_address;return true;
}
设置当前活动的蓝牙音频设备。处理三种主要场景:保持现有连接不变、断开当前连接、以及切换到新的音频设备。
btif_a2dp_sink_restart_session
packages/modules/Bluetooth/system/btif/src/btif_av.cc
/*** Set the active peer.** @param peer_address the active peer address or RawAddress::kEmpty to* reset the active peer* @return true on success, otherwise false
*/
bool SetActivePeer(const RawAddress& peer_address,std::promise<void> peer_ready_promise) {log::info("peer: {}", ADDRESS_TO_LOGGABLE_STR(peer_address));// 1. 如果目标地址与当前活动设备相同,直接标记操作完成并返回成功if (active_peer_ == peer_address) {peer_ready_promise.set_value();return true; // Nothing has changed}// 2. 处理断开连接请求if (peer_address.IsEmpty()) {// 关闭音频接收器会话log::verbose("peer address is empty, shutdown the Audio sink");if (!btif_av_src_sink_coexist_enabled() ||(btif_av_src_sink_coexist_enabled() &&btif_av_source_active_peer().IsEmpty())) {if (!bta_av_co_set_active_peer(peer_address)) {log::warn("unable to set active peer to empty in BtaAvCo");}}btif_a2dp_sink_end_session(active_peer_); // 更新系统状态btif_a2dp_sink_shutdown(); // 终止当前 A2DP 会话并关闭音频接收器active_peer_ = peer_address;peer_ready_promise.set_value();return true;}// 3. 处理共存模式if (btif_av_src_sink_coexist_enabled()) {// 删除音频源的活动设备btif_av_source_delete_active_peer();}// 4. 验证目标设备状态BtifAvPeer* peer = FindPeer(peer_address);if (peer == nullptr || !peer->IsConnected()) {log::error("Error setting {} as active Sink peer",ADDRESS_TO_LOGGABLE_STR(peer_address));peer_ready_promise.set_value();return false;}// 5. 切换到新设备if (!btif_a2dp_sink_restart_session(active_peer_, peer_address,std::move(peer_ready_promise))) {// cannot set promise but need to be handled within restart_sessionreturn false;}log::info("Setting the active peer to peer address {}",ADDRESS_TO_LOGGABLE_STR(peer_address));active_peer_ = peer_address;return true;
}
重启音频会话,实现从一个蓝牙设备切换到另一个蓝牙设备,或启动与新设备的音频连接。负责协调会话终止、设备激活和新会话启动等多个步骤。
bta_av_co_set_active_peer
packages/modules/Bluetooth/system/btif/co/bta_av_co.cc
bool bta_av_co_set_active_peer(const RawAddress& peer_address) {return bta_av_co_cb.SetActivePeer(peer_address);
}bool BtaAvCo::SetActivePeer(const RawAddress& peer_address) {log::info("peer_address={}", ADDRESS_TO_LOGGABLE_STR(peer_address));// 使用互斥锁确保在多线程环境下对设备缓存和编解码器配置的访问安全std::lock_guard<std::recursive_mutex> lock(peer_cache_->codec_lock_);// 活动设备重置处理BtaAvCoState* reference_state = &bta_av_legacy_state_;if (peer_address.IsEmpty()) {// Reset the active peer;reference_state->setActivePeer(nullptr);reference_state->clearCodecConfig();return true;}// Find the peerBtaAvCoPeer* p_peer = peer_cache_->FindPeer(peer_address);if (p_peer == nullptr) {return false;}// 活动设备状态更新reference_state->setActivePeer(p_peer);reference_state->setCodecConfig(p_peer->codec_config);log::info("codec = {}",A2DP_CodecInfoString(reference_state->getCodecConfig()));// 编解码器配置报告// report the selected codec configuration of this new active peer.ReportSourceCodecState(p_peer);return true;
}
管理活动设备的状态和编解码器配置。通过设备缓存、状态管理和编解码器报告机制,确保蓝牙音频连接的稳定性和音频质量。
setActivePeer
packages/modules/Bluetooth/system/btif/co/bta_av_co.cc
void BtaAvCoState::setActivePeer(BtaAvCoPeer* peer) { active_peer_ = peer; }
通过维护 active_peer_
指针,为整个系统提供当前活动设备的引用。
setCodecConfig
packages/modules/Bluetooth/system/btif/co/bta_av_co.cc
/* Maximum size in bytes of the codec capabilities information element. */
#define AVDT_CODEC_SIZE 20// 存储编解码器配置
uint8_t codec_config_[AVDT_CODEC_SIZE];void BtaAvCoState::setCodecConfig(const uint8_t* codec_config) {memcpy(codec_config_, codec_config, AVDT_CODEC_SIZE);
}
更新当前活动设备的编解码器配置。通过内存复制的方式将外部传入的编解码器配置数据存储到内部状态中,为后续音频数据传输提供编码格式依据。
ReportSourceCodecState
packages/modules/Bluetooth/system/btif/co/bta_av_co.cc
bool BtaAvCo::ReportSourceCodecState(BtaAvCoPeer* p_peer) {// 1. 编解码器配置初始化btav_a2dp_codec_config_t codec_config = {.codec_type = BTAV_A2DP_CODEC_INDEX_SINK_MAX,.codec_priority = BTAV_A2DP_CODEC_PRIORITY_DISABLED,.sample_rate = BTAV_A2DP_CODEC_SAMPLE_RATE_NONE,.bits_per_sample = BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE,.channel_mode = BTAV_A2DP_CODEC_CHANNEL_MODE_NONE,.codec_specific_1 = 0,.codec_specific_2 = 0,.codec_specific_3 = 0,.codec_specific_4 = 0,};// 设备支持的所有编解码器能力std::vector<btav_a2dp_codec_config_t> codecs_local_capabilities;// 可选择使用的编解码器配置std::vector<btav_a2dp_codec_config_t> codecs_selectable_capabilities;// 2. 设备编解码器信息获取log::verbose("peer_address={}", ADDRESS_TO_LOGGABLE_STR(p_peer->addr));A2dpCodecs* codecs = p_peer->GetCodecs();if (codecs == nullptr) {log::error("Peer codecs is set to null");return false;}if (!codecs->getCodecConfigAndCapabilities(&codec_config,&codecs_local_capabilities,&codecs_selectable_capabilities)) {log::warn("Peer {} : error reporting audio source codec state: cannot get codec ""config and capabilities",ADDRESS_TO_LOGGABLE_STR(p_peer->addr));return false;}// 3. 编解码器状态上报log::info("peer {} codec_config={{}}", ADDRESS_TO_LOGGABLE_STR(p_peer->addr),codec_config.ToString());btif_av_report_source_codec_state(p_peer->addr, codec_config,codecs_local_capabilities,codecs_selectable_capabilities);return true;
}
蓝牙音频系统中用于报告源设备编解码器状态。负责收集目标设备支持的编解码器配置信息,并将其上报给系统其他模块,以便进行音频流协商和配置。
getCodecConfigAndCapabilities
packages/modules/Bluetooth/system/stack/a2dp/a2dp_codec_config.cc
bool A2dpCodecs::getCodecConfigAndCapabilities(btav_a2dp_codec_config_t* p_codec_config,std::vector<btav_a2dp_codec_config_t>* p_codecs_local_capabilities,std::vector<btav_a2dp_codec_config_t>* p_codecs_selectable_capabilities) {// 1. 线程安全控制std::lock_guard<std::recursive_mutex> lock(codec_mutex_);// 2. 获取当前编解码器配置if (current_codec_config_ != nullptr) {*p_codec_config = current_codec_config_->getCodecConfig();} else {btav_a2dp_codec_config_t codec_config;memset(&codec_config, 0, sizeof(codec_config));*p_codec_config = codec_config;}// 3. 获取本地编解码器能力std::vector<btav_a2dp_codec_config_t> codecs_capabilities;for (auto codec : orderedSourceCodecs()) {codecs_capabilities.push_back(codec->getCodecLocalCapability());}*p_codecs_local_capabilities = codecs_capabilities;// 4. 获取可选择编解码器能力codecs_capabilities.clear();for (auto codec : orderedSourceCodecs()) {btav_a2dp_codec_config_t codec_capability =codec->getCodecSelectableCapability();// 过滤无效配置:过滤掉采样率、位深、通道模式为 NONE 的无效配置// Don't add entries that cannot be usedif ((codec_capability.sample_rate == BTAV_A2DP_CODEC_SAMPLE_RATE_NONE) ||(codec_capability.bits_per_sample ==BTAV_A2DP_CODEC_BITS_PER_SAMPLE_NONE) ||(codec_capability.channel_mode == BTAV_A2DP_CODEC_CHANNEL_MODE_NONE)) {continue;}codecs_capabilities.push_back(codec_capability);}// 表示系统策略允许使用的编解码器配置*p_codecs_selectable_capabilities = codecs_capabilities;return true;
}
获取当前编解码器配置及设备支持的编解码器能力。在蓝牙音频设备切换或初始化时被调用,为系统提供编解码器协商所需的关键信息。
btif_av_report_source_codec_state
packages/modules/Bluetooth/system/btif/src/btif_av.cc
void btif_av_report_source_codec_state(const RawAddress& peer_address,const btav_a2dp_codec_config_t& codec_config,const std::vector<btav_a2dp_codec_config_t>& codecs_local_capabilities,const std::vector<btav_a2dp_codec_config_t>&codecs_selectable_capabilities) {log::verbose("peer_address={}", ADDRESS_TO_LOGGABLE_CSTR(peer_address));if (btif_av_source.Enabled()) {do_in_jni_thread(FROM_HERE,base::BindOnce(btif_av_source.Callbacks()->audio_config_cb,peer_address, codec_config, codecs_local_capabilities,codecs_selectable_capabilities));}
}
将底层获取的编解码器配置和能力信息传递给 JNI 层,实现蓝牙音频系统与上层应用的状态同步。支持音频设备能力展示、编码格式协商和用户界面更新等功能。
btif_a2dp_sink_startup
packages/modules/Bluetooth/system/btif/src/btif_a2dp_sink.cc
bool btif_a2dp_sink_startup() {log::info("");btif_a2dp_sink_cb.worker_thread.DoInThread(FROM_HERE, base::BindOnce(btif_a2dp_sink_startup_delayed));return true;
}static void btif_a2dp_sink_startup_delayed() {log::info("");LockGuard lock(g_mutex);// Nothing to do
}
btif_a2dp_sink_startup
负责调度启动任务到工作线程,btif_a2dp_sink_startup_delayed
提供了线程安全的执行环境。目前仅实现了线程安全控制,未包含具体初始化操作。
btif_a2dp_sink_start_session
packages/modules/Bluetooth/system/btif/src/btif_a2dp_sink.cc
// 启动与指定蓝牙设备的 A2DP 音频会话,并通过 Promise 通知会话准备完成
bool btif_a2dp_sink_start_session(const RawAddress& peer_address,std::promise<void> peer_ready_promise) {log::info("peer_address={}", ADDRESS_TO_LOGGABLE_STR(peer_address));if (btif_a2dp_sink_cb.worker_thread.DoInThread(FROM_HERE, base::BindOnce(btif_a2dp_sink_start_session_delayed,std::move(peer_ready_promise)))) {return true;} else {// cannot set promise but triggers crashlog::fatal("peer_address={} fails to context switch",ADDRESS_TO_LOGGABLE_STR(peer_address));return false;}
}// 在工作线程中实际执行会话启动逻辑,并通过 Promise 通知调用方会话已准备好
static void btif_a2dp_sink_start_session_delayed(std::promise<void> peer_ready_promise) {log::info("");LockGuard lock(g_mutex);peer_ready_promise.set_value();// Nothing to do
}
通过工作线程和 Promise-Future 机制实现非阻塞操作。当前实现仅完成了基本的异步调度和状态通知,未包含实际会话建立逻辑。
三、流程图
四、时序图
异步架构:通过
std::promise/std::future
实现主线程与工作线程的状态同步,确保音频会话安全切换状态管理:
active_peer_
指针全局标识活动设备,编解码配置通过内存拷贝(memcpy
)快速更新编解码协商:三层能力上报机制(当前配置/本地能力/可选能力)保障设备兼容性
模块化设计:
设备管理层(btif_av):处理连接状态
会话控制层(btif_a2dp_sink):管理音频生命周期
编解码层(bta_av_co):维护配置状态
LOG关键字:
sink_set_active_device|set_active_peer_int|SetActivePeer|btif_a2dp_sink_restart_session|ReportSourceCodecState|bluetooth:|btif_av_report_source_codec_state|btif_a2dp_sink_startup|btif_a2dp_sink_startup_delayed|btif_a2dp_sink_start_session|btif_a2dp_sink_start_session_delayed
logcat: