A2DP Source如何从android系统拿到音频数据

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可以调节下声音试试。

如果此文章解答了您的相关疑惑,节约了您的宝贵时间,可以赏小编鸡腿哟!

 

  • 6
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值