Android 13
简单来说就是两条本地socket通道,分别使用文件:
#define A2DP_CTRL_PATH "/data/misc/bluedroid/.a2dp_ctrl"
#define A2DP_DATA_PATH "/data/misc/bluedroid/.a2dp_data"
A2DP_CTRL_PATH是控制通道,A2DP_DATA_PATH是数据通道。
packages\modules\Bluetooth\system\audio_a2dp_hw\include\audio_a2dp_hw.h
1、首先需要关注一个文件 btif_a2dp_control.cc
// packages\modules\Bluetooth\system\btif\src\btif_a2dp_control.cc
void btif_a2dp_control_init(void) {
a2dp_uipc = UIPC_Init();
UIPC_Open(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, btif_a2dp_ctrl_cb, A2DP_CTRL_PATH);
}
里面的函数UIPC_Init
// packages\modules\Bluetooth\system\udrv\ulinux\uipc.cc
std::unique_ptr<tUIPC_STATE> UIPC_Init() {
std::unique_ptr<tUIPC_STATE> uipc = std::make_unique<tUIPC_STATE>();
LOG_DEBUG("UIPC_Init");
std::lock_guard<std::recursive_mutex> lock(uipc->mutex);
uipc_main_init(*uipc);
uipc_start_main_server_thread(*uipc);
return uipc;
}
初始化一些uipc的变量,然后启动主线程uipc_read_task
int uipc_start_main_server_thread(tUIPC_STATE& uipc) {
uipc.running = 1;
if (pthread_create(&uipc.tid, (const pthread_attr_t*)NULL, uipc_read_task,
&uipc) != 0) {
LOG_ERROR("uipc_thread_create pthread_create failed:%d", errno);
return -1;
}
return 0;
}
这里面的实现不太需要关注。
2、UIPC_Open(UIPC_CH_ID_AV_CTRL, btif_a2dp_ctrl_cb);启动控制通道。注册回调btif_a2dp_ctrl_cb
packages\modules\Bluetooth\system\btif\src\btif_a2dp_control.cc
static void btif_a2dp_ctrl_cb(UNUSED_ATTR tUIPC_CH_ID ch_id,
tUIPC_EVENT event) {
// Don't log UIPC_RX_DATA_READY_EVT by default, because it
// could be very chatty when audio is streaming.
if (event == UIPC_RX_DATA_READY_EVT) {
APPL_TRACE_DEBUG("%s: A2DP-CTRL-CHANNEL EVENT %s", __func__,
dump_uipc_event(event));
} else {
APPL_TRACE_WARNING("%s: A2DP-CTRL-CHANNEL EVENT %s", __func__,
dump_uipc_event(event));
}
switch (event) {
case UIPC_OPEN_EVT:
break;
case UIPC_CLOSE_EVT:
/* restart ctrl server unless we are shutting down */
if (btif_a2dp_source_media_task_is_running())
UIPC_Open(*a2dp_uipc, UIPC_CH_ID_AV_CTRL, btif_a2dp_ctrl_cb,
A2DP_CTRL_PATH);
break;
case UIPC_RX_DATA_READY_EVT:
btif_a2dp_recv_ctrl_data();
break;
default:
APPL_TRACE_ERROR("%s: ### A2DP-CTRL-CHANNEL EVENT %d NOT HANDLED ###",
__func__, event);
break;
}
}
3、btif_a2dp_recv_ctrl_data(); 这个函数就是处理收到的控制指令,例如get configure,set configure、stream start、stream suspend等。
4、当收到stream start的时候就会启动数据通道
static void btif_a2dp_recv_ctrl_data(void) {
tA2DP_CTRL_CMD cmd = A2DP_CTRL_CMD_NONE;
int n;
...
a2dp_cmd_pending = cmd;
switch (cmd) {
...
case A2DP_CTRL_CMD_START:
btif_a2dp_command_ack(btif_a2dp_control_on_start());
break;
...
}
static tA2DP_CTRL_ACK btif_a2dp_control_on_start() {
/*
* Don't send START request to stack while we are in a call.
* Some headsets such as "Sony MW600", don't allow AVDTP START
* while in a call, and respond with BAD_STATE.
*/
if (!bluetooth::headset::IsCallIdle()) {
APPL_TRACE_WARNING("%s: A2DP command start while call state is busy",
__func__);
return A2DP_CTRL_ACK_INCALL_FAILURE;
}
if (btif_a2dp_source_is_streaming()) {
APPL_TRACE_WARNING("%s: A2DP command start while source is streaming",
__func__);
return A2DP_CTRL_ACK_FAILURE;
}
if (btif_av_stream_ready()) {
/* Setup audio data channel listener */
UIPC_Open(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb,
A2DP_DATA_PATH);
/*
* Post start event and wait for audio path to open.
* If we are the source, the ACK will be sent after the start
* procedure is completed, othewise send it now.
*/
btif_av_stream_start();
if (btif_av_get_peer_sep() == AVDT_TSEP_SRC) return A2DP_CTRL_ACK_SUCCESS;
}
if (btif_av_stream_started_ready()) {
/*
* Already started, setup audio data channel listener and ACK
* back immediately.
*/
UIPC_Open(*a2dp_uipc, UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb,
A2DP_DATA_PATH);
return A2DP_CTRL_ACK_SUCCESS;
}
APPL_TRACE_WARNING("%s: A2DP command start while AV stream is not ready",
__func__);
return A2DP_CTRL_ACK_FAILURE;
}
5、启动数据通道后,会通过回调btif_a2dp_data_cb通知,进行一些必要的操作后(具体参考原生代码btif_a2dp_data_cb的实现),就可以使用UIPC_Read(UIPC_CH_ID_AV_AUDIO, &event, p_buf, len);读取到数据了。这里如果要使用自己的蓝牙可以建立线程读取数据,当stream stop或者stream suspend时cancel掉线程即可
6、注意:如果静音模式audio manager不会向控制发送stream start,所以如果其他指令都收到了没有收到stream start可以调节下声音试试。