蓝牙音频A2DP(三) -- UIPC

蓝牙音频A2DP(三) -- UIPC_第1张图片

 对于Audio Flinger而言,他能够获取到a2dp的hw module,然后怎才能将数据送至蓝牙协议栈。蓝牙方面已经起了一个线程,专用于发送和接收media的数据,线程名称:btif_media_task.蓝牙与Audio的通信则采用了socket的方式,管理socket的中间文件为:UIPC。
 因此UIPC主要的作用就是,接收Audio的控制命令转发给bt,接收Audio的音频数据发送给bt。因此UIPC建立了两条socket,分别为:
#define A2DP_CTRL_PATH "/data/misc/bluedroid/.a2dp_ctrl"
#define A2DP_DATA_PATH "/data/misc/bluedroid/.a2dp_data"
其中第一条control socket在btif media task启动的时候随之创建。
bool btif_a2dp_start_media_task(void)
{
    ...
    thread_post(worker_thread, btif_media_thread_init, NULL);

    APPL_TRACE_EVENT("## A2DP MEDIA THREAD STARTED ##");

    return true;
    ...
}

static void btif_media_thread_init(UNUSED_ATTR void *context) {
  memset(&btif_media_cb, 0, sizeof(btif_media_cb));
  UIPC_Init(NULL);

#if (BTA_AV_INCLUDED == TRUE)
  UIPC_Open(UIPC_CH_ID_AV_CTRL , btif_a2dp_ctrl_cb);
#endif

  raise_priority_a2dp(TASK_HIGH_MEDIA);
  media_task_running = MEDIA_TASK_STATE_ON;
}
第二条data socket在收到audio cmd start时候创建。任何命令的处理,btif task都需要恢复ack,表明命令是否执行完成。
        case A2DP_CTRL_CMD_START:
            /* Don't sent START request to stack while we are in call.
               Some headsets like the Sony MW600, don't allow AVDTP START
               in call and respond BAD_STATE. */
            if (!btif_hf_is_call_idle())
            {
                a2dp_cmd_acknowledge(A2DP_CTRL_ACK_INCALL_FAILURE);
                break;
            }

            if (btif_av_stream_ready() == TRUE)
            {
                /* setup audio data channel listener */
                UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);

                /* post start event and wait for audio path to open */
                btif_dispatch_sm_event(BTIF_AV_START_STREAM_REQ_EVT, NULL, 0);

#if (BTA_AV_SINK_INCLUDED == TRUE)
                if (btif_media_cb.peer_sep == AVDT_TSEP_SRC)
                    a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);//发送回执
#endif
            }
            else if (btif_av_stream_started_ready())
            {
                /* already started, setup audio data channel listener
                   and ack back immediately */
                UIPC_Open(UIPC_CH_ID_AV_AUDIO, btif_a2dp_data_cb);

                a2dp_cmd_acknowledge(A2DP_CTRL_ACK_SUCCESS);//发送回执
            }
            else
            {
                a2dp_cmd_acknowledge(A2DP_CTRL_ACK_FAILURE);
                break;
            }
            break;
static int a2dp_command(struct a2dp_stream_common *common, char cmd)
{
    char ack;

    DEBUG("A2DP COMMAND %s", dump_a2dp_ctrl_event(cmd));

    /* send command */
    if (send(common->ctrl_fd, &cmd, 1, MSG_NOSIGNAL) == -1)
    {
        ERROR("cmd failed (%s)", strerror(errno));
        skt_disconnect(common->ctrl_fd);
        common->ctrl_fd = AUDIO_SKT_DISCONNECTED;
        return -1;
    }

    /* wait for ack byte */
    if (a2dp_ctrl_receive(common, &ack, 1) < 0)     //等待cmd回执
        return -1;
    ...
UIPC接收command机制:
1. 启动时,创建一个thread,接收command。
void UIPC_Init(void *p_data)
{
    UNUSED(p_data);

    BTIF_TRACE_DEBUG("UIPC_Init");

    memset(&uipc_main, 0, sizeof(tUIPC_MAIN));

    uipc_main_init();

    uipc_start_main_server_thread();
}

int uipc_start_main_server_thread(void)
{
    uipc_main.running = 1;

    if (pthread_create(&uipc_main.tid, (const pthread_attr_t *) NULL, (void*)uipc_read_task, NULL) < 0)
    {
        BTIF_TRACE_ERROR("uipc_thread_create pthread_create failed:%d", errno);
        return -1;
    }

    return 0;
}
 2. 监听每一个socket,发现数据后,有限判断是不是音频,再判断是不是命令。

static void uipc_read_task(void *arg)
{
    while (uipc_main.running)
    {
    result = select(uipc_main.max_fd+1, &uipc_main.read_set, NULL, NULL, NULL);   //发现有数据
    /* make sure we service audio channel first */
    uipc_check_fd_locked(UIPC_CH_ID_AV_AUDIO);   //先确定是不是音频

    /* check for other connections */
    for (ch_id = 0; ch_id < UIPC_CH_NUM; ch_id++) {
        if (ch_id != UIPC_CH_ID_AV_AUDIO)
            uipc_check_fd_locked(ch_id);         //再确定是不是command
    }
}
static int uipc_check_fd_locked(tUIPC_CH_ID ch_id)
{
    if (uipc_main.ch[ch_id].cback)
        //通知btif,有command过来
        uipc_main.ch[ch_id].cback(ch_id, UIPC_RX_DATA_READY_EVT);
}
 3. 通知btif去读取command并处理
static void btif_a2dp_ctrl_cb(tUIPC_CH_ID ch_id, tUIPC_EVENT event)
{
    switch(event)
    {
        case UIPC_RX_DATA_READY_EVT:
            btif_recv_ctrl_data();      //去获取command
            break;
     }
}

static void btif_recv_ctrl_data(void)
{
    UINT8 cmd = 0;
    int n;
    n = UIPC_Read(UIPC_CH_ID_AV_CTRL, NULL, &cmd, 1);  //读取该socket上的命令
}
经过上面复杂的操作,btif总算得到了audio发来的command,主要的命令就是suspend和start。

你可能感兴趣的:(bluetooth,android)