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

相关推荐

  1. A2DP Source如何android系统音频数据

    2024-01-07 06:08:03       33 阅读
  2. Android开发如何入门进阶架构

    2024-01-07 06:08:03       17 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-07 06:08:03       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-07 06:08:03       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-07 06:08:03       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-07 06:08:03       20 阅读

热门阅读

  1. Docker Zookeeper 安装 简单教程

    2024-01-07 06:08:03       38 阅读
  2. 知名云计算项目实施体系资料合集

    2024-01-07 06:08:03       37 阅读
  3. Web前端篇——ElementUI的Backtop 不显示问题

    2024-01-07 06:08:03       38 阅读
  4. linux mv command and authority managemet

    2024-01-07 06:08:03       36 阅读
  5. 文心一言实战大全

    2024-01-07 06:08:03       36 阅读
  6. pyparamvalidate 重构背景和需求分析

    2024-01-07 06:08:03       36 阅读
  7. go 语言中的别名类型

    2024-01-07 06:08:03       38 阅读
  8. LightGlue-OpenCV 实现实时相机图片特征点匹配

    2024-01-07 06:08:03       39 阅读
  9. 数据库7种范式

    2024-01-07 06:08:03       22 阅读