BES音频框架分析—Audioflinger

音频策略的执行者,负责输入输出流设备的管理及音频流数据的处理传输。 Audioflinger.c完成af创建及音频流管理。

af_open()

函数的调用:app_init(void)—>af_open();

函数内流程:

(1)初始化struct af_stream_cfg_t *role相关参数

(2)创建af_thread,并使用信号量机制完成线程同步,同时af线程内af_thread_stream_handler()会对是否信号丢失、dma地址指针非法,语音数据处理回调超时等做判断。

af_thread_tid = osThreadCreate(osThread(af_thread), NULL);
af_default_priority = af_get_priority();
osSignalSet(af_thread_tid, 0x0);

(3)af_thread_tid信号量的产生过程参考af_stream_open()

app_audio_open()

函数的调用:app_init(void)—>app_audio_open();

函数内流程:

(1)初始化提示音模块,调用app_prompt_list_init()完成了内存空间申请,app_prompt_list申请,app_prompt_handler_tid创建;

 if (NULL == app_prompt_request_mempool)
    {
        app_prompt_request_mempool = osPoolCreate(osPool(app_prompt_request_mempool));
    }
    app_prompt_list = list_new(app_prompt_list_free, NULL, NULL);
    app_prompt_handler_tid = osThreadCreate(osThread(app_prompt_handler_thread), NULL);

(2)设置APP_MODUAL_AUDIO模块的回调app_audio_handle_process(),根据当前设置的APP_BT_SETTING_T完成音频流的开启app_bt_stream_open或关闭app_bt_stream_close处理,其内部维护了一个audio队列,依赖于宏定义 AUDIO_QUEUE_SUPPORT

app_set_threadhandle(APP_MODUAL_AUDIO, app_audio_handle_process);

enum APP_BT_SETTING_T {
    APP_BT_SETTING_OPEN = 0,
    APP_BT_SETTING_CLOSE,
    APP_BT_SETTING_SETUP,
    APP_BT_SETTING_RESTART,
    APP_BT_SETTING_CLOSEALL,
    APP_BT_SETTING_CLOSEMEDIA,
    APP_BT_SETTING_NUM,
};

app_audio_list_append(&aud_status)//打开一个流需将其加入队列
app_audio_list_rmv_callback(&a2ud_status, &next_status, APP_BT_SETTING_Q_POS_HEAD)//关闭一个流需将其从队列中删除

(3)bt流触发器初始化app_bt_stream_init(),创建定时器,在音乐或电话流开启时启动定时器回调app_bt_stream_trigger_timeout_cb()向模块APP_MODUAL_AUDIO发消息进入回调app_audio_handle_process完成相应操作

osTimerCreate(osTimer(APP_BT_STREAM_TRIGGER_TIMEOUT), osTimerOnce, NULL);
app_audio_sendrequest_param(APP_BT_STREAM_A2DP_SBC, (uint8_t)APP_BT_SETTING_RESTART, 0, 0)
app_audio_sendrequest(APP_BT_STREAM_HFP_PCM, (uint8_t)APP_BT_SETTING_RESTART, 0);

(3) APP_BT_SETTING_T的产生过程参考bt_media_start()

app_audio_manager_open()

函数的调用:app_init(void)—>app_audio_manager_open();

函数内流程:

(1)设置APP_MODUAL_AUDIO_MANAGE模块回调app_audio_manager_handle_process(),根据当前BT_MEDIA_MANAGER完成音乐、电话、提示音的开启bt_media_start或关闭bt_media_stop处理。

app_set_threadhandle(APP_MODUAL_AUDIO_MANAGE, app_audio_manager_handle_process);

enum APP_BT_MEDIA_MANAGER_ID_T {
    APP_BT_STREAM_MANAGER_START = 0,
    APP_BT_STREAM_MANAGER_STOP,
    APP_BT_STREAM_MANAGER_STOP_MEDIA,
    APP_BT_STREAM_MANAGER_UPDATE_MEDIA,
    APP_BT_STREAM_MANAGER_SWAP_SCO,
    APP_BT_STREAM_MANAGER_CTRL_VOLUME,
    APP_BT_STREAM_MANAGER_TUNE_SAMPLERATE_RATIO,
    APP_BT_STREAM_MANAGER_NUM,
};

(2) 通过调用audio_prompt_init_handler()—> memset((uint8_t *)&audio_prompt_env, 0, sizeof(audio_prompt_env));将提示音AUDIO_PROMPT_ENV_T初始化为0;

(3) APP_BT_SETTING_T的产生过程分音乐、电话、提示音三部分介绍

app_voice_report()

函数调用:在需要播放铃声的地方直接调用

[En]

Function call: call the API directly where the tone needs to be played

函数内流程:

(1) app_voice_report(APP_STATUS_INDICATION_T status, uint8_t device_id)是提示音总入口函数,APP_STATUS_INDICATION_T 枚举类型参数表示提示音序号,用来索引提示音ID ,device_id 表示设备号,一般是0.

typedef enum APP_STATUS_INDICATION_T {
    APP_STATUS_INDICATION_POWERON = 0,
    APP_STATUS_INDICATION_AWAKEN,
              ······
}

(2)根据相关宏定义选择不同的提示音播放方式

void media_PlayAudio_locally(AUD_ID_ENUM id, uint8_t device_id)//仅本地播放
void media_PlayAudio_standalone_locally(AUD_ID_ENUM id, uint8_t device_id)//打断播放
void media_PlayAudio(AUD_ID_ENUM id,uint8_t device_id)//混合播放

(3) 如果是从耳发送命令给对端主耳播放app_tws_let_peer_device_play_audio_prompt()—–>tws_ctrl_send_cmd(),如果是主耳发送提示音任务请求app_prompt_push_request()—->app_prompt_list_append(app_prompt_list, &req);—->osSignalSet(app_prompt_handler_tid, PROMPT_HANDLER_SIGNAL_NEW_PROMPT_REQ);

app_prompt_handler_thread()

函数的调用:app_prompt_list_init()—>app_prompt_handler_thread()

函数内流程:

(1)收到信号PROMPT_HANDLER_SIGNAL_NEW_PROMPT_REQ后,根据当前是否有正在播放的提示音以及app_prompt_list是否为空,通过调用app_prompt_refresh_list来实现相关功能。

(2)收到信号PPROMPT_HANDLER_SIGNAL_CLEAR_REQ后,先清除app_prompt_list,然后混合模式下发送PROMPT_HANDLER_SIGNAL_PLAYING_COMPLETED信号停止提示音,最后通过app_audio_sendrequest(APP_PLAY_BACK_AUDIO, (uint8_t)APP_BT_SETTING_CLOSE, devId)—->app_audio_handle_process()完成提示音流的关闭。

(3)收到信号PROMPT_HANDLER_SIGNAL_PLAYING_COMPLETED,先标识当前没有正在播放的提示音,然后停止提示音保护定时器app_prompt_protector_timer,最后,调用app_prompt_refresh_list来实现相关功能。

app_prompt_refresh_list()

函数的调用:app_prompt_handler_thread()—>app_prompt_refresh_list()

函数内流程:

(1)如果当前有正在播放的提示音则退出,没有则继续判断app_prompt_list是否为空,如果为空则退出。

(2)如果app_prompt_list不为空,先标识当前有正在播放的提示音,然后调用app_prompt_start_protector()创建并开启提示音保护定时器app_prompt_protector_timer,在该定时器回调函数app_prompt_protector_timer_handler内,如果提示音在运行会递归调用app_prompt_start_protector(),定时时间结束发送 PROMPT_HANDLER_SIGNAL_CLEAR_REQ信号。

(3)向APP_MODUAL_AUDIO_MANAGE模块发送提示音提示音start请求,根据app_prompt_list的提示音播放类型调用不同的提示音播放处理函数,最总通过调用trigger_media_play()—->app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_START,BT_STREAM_MEDIA,device_id,convertedId)—->app_audio_manager_handle_process()完成提示音的开启。

(4)每处理完一个提示音节点后要将app_prompt_list种对应的该节点删除

bt_media_start()

函数的调用:app_audio_manager_handle_process()—>bt_media_start()

函数的作用:根据stream_type、active_type、current_media分类统筹SBC、VOICE、MEDIA的开启与关闭。

函数内流程:

(1)如果stream_type是BT_STREAM_SBC,若BT_STREAM_MEDIA是active状态则退出,若BT_STREAM_VOICE是active状态则提高系统主频并退出,若当前不是音乐流,设置并开启

if (bt_media_is_media_active_by_type(BT_STREAM_MEDIA))
{
   goto exit;
}
if(bt_media_is_media_active_by_type(BT_STREAM_VOICE))
{
    /// sbc and voice is all on so set sys freq to 104m
    app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_104M);
    return;
}
if (!bt_media_cur_is_bt_stream_sbc())
{
     bt_media_set_current_media(BT_STREAM_SBC);
     app_audio_sendrequest(APP_BT_STREAM_A2DP_SBC,(uint8_t)(APP_BT_SETTING_SETUP),(uint32_t)(app_bt_get_device(device_id)->sample_rate & A2D_STREAM_SAMP_FREQ_MSK));
     app_audio_sendrequest(APP_BT_STREAM_A2DP_SBC, ( uint8_t )APP_BT_SETTING_OPEN, 0);
}

(2)如果stream_type是BT_STREAM_MEDIA,若BT_STREAM_VOICE是active状态,关闭通话流开启提示音流,若BT_STREAM_SBC是active状态, 关闭音乐流开启提示音流,其他情况直接开启提示音流。

if(bt_media_is_media_active_by_type(BT_STREAM_VOICE))
{
   if(bt_media_get_current_media() & BT_STREAM_VOICE)
   {
      bt_media_set_current_media(BT_STREAM_MEDIA);
      app_audio_sendrequest(APP_BT_STREAM_HFP_PCM, (uint8_t)APP_BT_SETTING_CLOSE, 0);
      app_audio_sendrequest(APP_PLAY_BACK_AUDIO, (uint8_t)APP_BT_SETTING_OPEN, media_id);
   }
   else if(bt_media_get_current_media() & BT_STREAM_MEDIA)
   {
       bt_media_set_current_media(BT_STREAM_MEDIA);
       app_audio_sendrequest(APP_PLAY_BACK_AUDIO, (uint8_t)APP_BT_SETTING_OPEN,media_id);
   }
}
else if(bt_media_is_media_active_by_type(BT_STREAM_SBC))
{
   if(bt_media_get_current_media() & BT_STREAM_SBC)
   {
      app_audio_sendrequest(APP_BT_STREAM_A2DP_SBC, (uint8_t)APP_BT_SETTING_CLOSE, 0);
      bt_media_clear_current_media(BT_STREAM_SBC);
      bt_media_set_current_media(BT_STREAM_MEDIA);
      app_audio_sendrequest(APP_PLAY_BACK_AUDIO, (uint8_t)APP_BT_SETTING_OPEN, media_id);
   }
   else if(bt_media_get_current_media() & BT_STREAM_MEDIA)
   {
     app_audio_sendrequest(APP_PLAY_BACK_AUDIO, (uint8_t)APP_BT_SETTING_OPEN, media_id);
   }
else
{
   bt_media_set_current_media(BT_STREAM_MEDIA);
   app_audio_sendrequest(APP_PLAY_BACK_AUDIO, (uint8_t)APP_BT_SETTING_OPEN, media_id);
}

(3)如果stream_type是BT_STREAM_VOICE,若BT_STREAM_MEDIA是active状态同时BT_STREAM_VOICE也是active状态停止提示音流开启通话流;若只有BT_STREAM_MEDIA是active状态继续播放提示音。若BT_STREAM_SBC是active状态, 关闭音乐流开启通话流。

if(bt_media_is_media_active_by_type(BT_STREAM_MEDIA))
  {
     //if call is active ,so disable media report
     if(bt_media_is_media_active_by_type(BT_STREAM_VOICE))
     {
       if(bt_media_get_current_media() & BT_STREAM_MEDIA)
        {
            if (app_play_audio_get_aud_id() == AUD_ID_BT_CALL_INCOMING_NUMBER)
            {
              app_prompt_stop_all();
              app_audio_sendrequest(APP_PLAY_BACK_AUDIO, (uint8_t)APP_BT_SETTING_CLOSE, 0);
              bt_media_clear_media_type(BT_STREAM_MEDIA, device_id);
              bt_media_set_current_media(BT_STREAM_VOICE);
              app_audio_sendrequest(APP_BT_STREAM_HFP_PCM, (uint8_t)APP_BT_SETTING_OPEN, 0);
          }
      }
  }
 else
    {
       //call is not active so media report continue
    }
return;
}

if (bt_media_is_media_active_by_type(BT_STREAM_SBC))
{
  ///if sbc is open  stop sbc
  if(bt_media_get_current_media() & BT_STREAM_SBC)
   {
     app_audio_sendrequest(APP_BT_STREAM_A2DP_SBC, (uint8_t)APP_BT_SETTING_CLOSE, 0);
     bt_media_clear_current_media(BT_STREAM_SBC);
   }
   ///start voice stream
   bt_media_set_current_media(BT_STREAM_VOICE);
   app_audio_sendrequest_param(APP_BT_STREAM_HFP_PCM, (uint8_t)APP_BT_SETTING_OPEN, 0,APP_SYSFREQ_104M);
   }
  else
  {
    bt_media_set_current_media(BT_STREAM_VOICE);
    app_audio_sendrequest(APP_BT_STREAM_HFP_PCM, (uint8_t)APP_BT_SETTING_OPEN, 0);
  }
}

函数的调用:app_audio_handle_process()—>app_bt_stream_open();

功能:完成不同类型流量的打通

[En]

Function: complete the opening of different types of flows

函数内流程:

(1)根据流的类型完成电话bt_sco_player(true, freq)接口的调用

(2)根据流的类型完成音乐bt_sbc_player(PLAYER_OPER_START, freq)接口的调用

(3)根据流的类型完成提示音app_play_audio_onoff(true, status)接口的调用

app_bt_stream_close

函数的调用:app_audio_handle_process()—>app_bt_stream_close();

功能:完成不同类型流的关闭

[En]

Function: complete the closure of different types of streams

函数内流程:

(1)根据流的类型完成电话bt_sco_player(false, APP_SYSFREQ_32K)接口的调用

(2)根据流的类型完成音乐bt_sbc_player(PLAYER_OPER_STOP, APP_SYSFREQ_32K)接口的调用

(3)根据流的类型完成提示音app_play_audio_onoff(false, NULL)接口的调用

app_play_audio_onoff()

函数的调用:app_bt_stream_open()/app_bt_stream_close()—->app_play_audio_onoff()

功能:控制提示音流开关,参数配置

[En]

Function: control prompt sound flow switch, parameter configuration

函数内流程:

(1)提示音播放初始化,关联具体的音频文件,获取提示音数据, 由media_Play_init_audio()—–>media_runtime_audio_prompt_update()实现。在该函数内,需要将视线准备好的提示音文件读取到对应ID下的static U8* g_app_audio_data = NULL。调用btif_sbc_decode_frames()对提示音文件进行解码。

const uint8_t EN_BT_AWAKEN[] = {
#include "res/en/SOUND_AWAKEN.txt"
};
const uint8_t CN_BT_AWAKEN[] = {
#include "res/cn/SOUND_AWAKEN.txt"
};
#if defined(VOICE_RECOGNITION_ALG)
case AUD_ID_BT_AWAKEN:
    g_app_audio_data = (g_language==MEDIA_DEFAULT_LANGUAGE)?(U8*)EN_BT_AWAKEN: (U8*)CN_BT_AWAKEN;
    g_app_audio_length = (g_language==MEDIA_DEFAULT_LANGUAGE)?sizeof(EN_BT_AWAKEN): sizeof(CN_BT_AWAKEN);
break;
#endif

(2) 配置提示音流相关参数,注册回调函数app_play_sbc_more_data(),配置完成后调用af_stream_open()使配置参数生效。

        memset(&stream_cfg, 0, sizeof(stream_cfg));
        stream_cfg.sample_rate  = AUD_SAMPRATE_16000;
        stream_cfg.bits         = AUD_BITS_16;
        stream_cfg.vol          = 16;
        stream_cfg.device       = AUD_STREAM_USE_I2S0_MASTER;
        stream_cfg.io_path      = AUD_IO_PATH_NULL;
        stream_cfg.channel_num  = AUD_CHANNEL_NUM_2;
        stream_cfg.handler      = app_play_sbc_more_data;
        stream_cfg.data_size    = APP_AUDIO_PLAYBACK_BUFF_SIZE;
        stream_cfg.data_ptr     = BT_AUDIO_CACHE_2_UNCACHE(bt_audio_buff);

(3)通过配置trigger_device及app_ibrt_voice_report_trigger_init()实现TWS 模式下主从提示音同步播放,触发初始化完成后调用af_stream_start()启动提示音流。

(4)完成关闭提示音流、触发反初始化、停止提示音播放。

af_stream_open

函数的调用:app_play_audio_onoff()—-> af_stream_open()

函数内流程:

(1)填充role指针相关参数,首先将输入参数*cfg拷贝到role->cfg,然后配置role->dma_cfg相关参数,接着调用af_stream_update_dma_buffer()根据输入参数stream类型、role及参数cfg更新对应的role->dma_cfg缓冲区,最后拷贝回调函数role->handler。role指向一个结构体类型的二维数组元素,该二维数组af_stream[id][stream]是一个静态全局变量。

struct af_stream_cfg_t {
    //used inside
    struct af_stream_ctl_t ctl;
    //dma buf parameters, RAM can be alloced in different way
    uint8_t *dma_buf_ptr;
    uint32_t dma_buf_size;
    //store stream cfg parameters
    struct AF_STREAM_CONFIG_T cfg;
    //dma cfg parameters
#ifdef DYNAMIC_AUDIO_BUFFER_COUNT
    uint8_t dma_desc_cnt;
#endif
    struct HAL_DMA_DESC_T dma_desc[MAX_AUDIO_BUFFER_COUNT];
    struct HAL_DMA_CH_CFG_T dma_cfg;
    //callback function
    AF_STREAM_HANDLER_T handler;
};

(2)根据输入参数stream类型(capture还是playback)以及 device = cfg->device的类型调用对应device的hal层初始化open接口;

(3)回调函数role->handler即stream_cfg.handler 触发执行,通过注册dma_cfg的回调函数af_dma_irq_handler,在触发DMA中断后调用该回调函数向af_thread_tid线程发送信号0x01 << (id * 2 + stream),在af_thread执行af_thread_stream_handler(id, stream)内的role->handler(buf, len);

(4)更新Audioflinger状态为AF_STATUS_STREAM_OPEN_CLOSE;

(5)特殊情况下,调用af_stream_setup()进行音频进一步配置,af_stream_setup()会根据输入参数stream类型和stream参数cfg,对af_stream_open()内open后的device配置hal层驱动详细参数,最终完成stream的建立。

af_stream_start

函数的调用:app_play_audio_onoff()—-> af_stream_start()

函数内流程:

(1)在af_stream_open()完成后调用,根据输入参数stream id、stream类型和stream参数cfg调用对应device的hal层start驱动接口,启动数据流的IO接口完成stream的打开;

(2)更新Audioflinger状态为AF_STATUS_STREAM_START_STOP。

af_stream_stop

函数的调用:app_play_audio_onoff()—-> af_stream_stop()

函数内流程:

(1)调用hal_audma_stop()停止dma采集,根据输入参数stream id和stream类型调用对应device的hal层stop驱动接口;

(2)清除Audioflinger状态AF_STATUS_STREAM_START_STOP。

af_stream_close

函数的调用:app_play_audio_onoff()—-> af_stream_close()

函数内流程:

(1)释放dma参数dma_cfg,并根据输入参数stream id和stream类型调用对应device的hal层close接口,释放参数及关闭IO接口;

(2)清除Audioflinger状态AF_STATUS_STREAM_OPEN_CLOSE。

提示音转换

相关宏说明

  • VOICE_PROMPT宏用于控制提示音功能开关,这里是打开状态,
  • MEDIA_PLAY_24BIT := 0表示提示音数据采用16位格式
  • MIX_AUDIO_PROMPT_WITH_A2DP_MEDIA_ENABLED := 0表示不将提示音与音乐混合播放
  • TWS_PROMPT_SYNC := 1表示开启主从提示音同步功能
  • AUDIO_PROMPT_USE_DAC2_ENABLED := 0表示不使用DAC2模式。

app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_START,BT_STREAM_VOICE,BT_DEVICE_ID_1,0)
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_STOP,BT_STREAM_VOICE,BT_DEVICE_ID_1,0);

app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_START, BT_STREAM_SBC, device_id, MAX_RECORD_NUM);
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_STOP, BT_STREAM_SBC, device_id, MAX_RECORD_NUM);

app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_START,BT_STREAM_MEDIA,device_id,convertedId);
app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_STOP_MEDIA, BT_STREAM_MEDIA, device_id, 0);

  • *Stream ID
enum AUD_STREAM_ID_T {
    AUD_STREAM_ID_0 = 0,//codec音频处理
    AUD_STREAM_ID_1,//btpcm音频处理
    AUD_STREAM_ID_2,//ANC音频处理(依赖于宏ANC_APP)
    AUD_STREAM_ID_3,//media音频(提示音等)处理(依赖于宏MEDIA_PLAYER_SUPPORT)
    AUD_STREAM_ID_NUM,
};
  • *Stream类型
enum AUD_STREAM_T {
    AUD_STREAM_PLAYBACK = 0,
    AUD_STREAM_CAPTURE,
    AUD_STREAM_NUM,
};
  • af *状态
enum AF_STATUS_T{
    AF_STATUS_NULL = 0x00,
    AF_STATUS_OPEN_CLOSE = 0x01,
    AF_STATUS_STREAM_OPEN_CLOSE = 0x02,
    AF_STATUS_STREAM_START_STOP = 0x04,
    AF_STATUS_STREAM_PAUSE_RESTART = 0x08,
    AF_STATUS_MASK = 0x0F,
};
  • af_stream *参数
struct af_stream_cfg_t {
    //used inside
    struct af_stream_ctl_t ctl;
    //dma buf parameters, RAM can be alloced in different way
    uint8_t *dma_buf_ptr;
    uint32_t dma_buf_size;
    //store stream cfg parameters
    struct AF_STREAM_CONFIG_T cfg;
    //dma cfg parameters
#ifdef DYNAMIC_AUDIO_BUFFER_COUNT
    uint8_t dma_desc_cnt;
#endif
    struct HAL_DMA_DESC_T dma_desc[MAX_AUDIO_BUFFER_COUNT];
    struct HAL_DMA_CH_CFG_T dma_cfg;
    //callback function
    AF_STREAM_HANDLER_T handler;
};
  • af_stream_config *参数
struct AF_STREAM_CONFIG_T {
    enum AUD_SAMPRATE_T sample_rate;//采样频率
    enum AUD_CHANNEL_MAP_T channel_map;
    enum AUD_CHANNEL_NUM_T channel_num;//通道数
    enum AUD_BITS_T bits;//位宽
    enum AUD_STREAM_USE_DEVICE_T device;//设备
    enum AUD_IO_PATH_T io_path;//IO路径
    enum AUD_DATA_ALIGN_T align;
    enum AUD_FS_FIRST_EDGE_T fs_edge;//边沿
    uint16_t fs_cycles;//音频总线时钟频率
    uint8_t slot_cycles;//时隙周期
    bool chan_sep_buf;
    bool sync_start;
    uint8_t vol;//音量
    AF_STREAM_HANDLER_T handler;//数据处理回调
    uint8_t *data_ptr;//数据指针
    uint32_t data_size;//数据长度
};

如何填充stream参数和音频接口需求和device选择相关,如果是TDM或I2S设备,不需要配置io_path,如果选择了内部codec,stream需要配置io_path,分为输入和输出两部分,输入代表不同应用场景的mic配置,具体配置在文件tgt_hardware.c内,配置mic的顺序和组合以及vmic,输出是speaker。如下代码是自定义的一个输入io_path,组合了fb和vpu。

#define CFG_HW_AUD_INPUT_PATH_MIC_CH1 (AUD_CHANNEL_MAP_CH1 | AUD_VMIC_MAP_VMIC5) //fb MIC
#define CFG_HW_AUD_INPUT_PATH_MIC_CH0 (AUD_CHANNEL_MAP_CH0 | AUD_VMIC_MAP_VMIC5) //main MIC
#define CFG_HW_AUD_INPUT_PATH_MIC_CH3 (AUD_CHANNEL_MAP_CH3) //ref
#define CFG_HW_AUD_INPUT_PATH_MIC_CH4 (AUD_CHANNEL_MAP_CH4 | AUD_VMIC_MAP_VMIC3) //VPU MIC
#if defined(VOICE_RECOGNITION_ALG)
#define CFG_HW_AUD_INPUT_PATH_FBVPU_DEV    (CFG_HW_AUD_INPUT_PATH_MIC_CH1 | CFG_HW_AUD_INPUT_PATH_MIC_CH4)//fb+vpu
#endif

const struct AUD_IO_PATH_CFG_T cfg_audio_input_path_cfg[CFG_HW_AUD_INPUT_PATH_NUM] = {
#if defined(SPEECH_TX_AEC_CODEC_REF)
    // NOTE: If enable Ch5 and CH6, need to add channel_num when setup audioflinger stream
    { AUD_INPUT_PATH_MAINMIC, CFG_HW_AUD_INPUT_PATH_MAINMIC_DEV | AUD_CHANNEL_MAP_ECMIC_CH0, },
#else
    { AUD_INPUT_PATH_MAINMIC, CFG_HW_AUD_INPUT_PATH_MAINMIC_DEV, },
#endif
#if defined(VOICE_RECOGNITION_ALG)
    { AUD_INPUT_PATH_FBVPU,  CFG_HW_AUD_INPUT_PATH_FBVPU_DEV, },

#endif
    { AUD_INPUT_PATH_LINEIN,  CFG_HW_AUD_INPUT_PATH_LINEIN_DEV, },
#ifdef VOICE_DETECTOR_SENS_EN
    { AUD_INPUT_PATH_VADMIC,  CFG_HW_AUD_INPUT_PATH_VADMIC_DEV, },
#else
    { AUD_INPUT_PATH_ASRMIC,  CFG_HW_AUD_INPUT_PATH_ASRMIC_DEV, },
#endif
    { AUD_INPUT_PATH_ANC_ASSIST,    CFG_HW_AUD_INPUT_PATH_ANC_ASSIST_DEV, },
#if defined(SPEECH_TX_AEC_CODEC_REF)
    { AUD_INPUT_PATH_HEARING,   CFG_HW_AUD_INPUT_PATH_HEARING_DEV | AUD_CHANNEL_MAP_ECMIC_CH0, },
#else
    { AUD_INPUT_PATH_HEARING,   CFG_HW_AUD_INPUT_PATH_HEARING_DEV, },
#endif
};

#define CFG_HW_AUD_INPUT_PATH_NUM           (5)

不同设备stream参数的配置如下

/*****************************TDM设备**************************************/
        /*hearable_mic_stream*/
        stream_cfg.sample_rate  = AUD_SAMPRATE_16000;
        stream_cfg.bits         = AUD_BITS_16;
        stream_cfg.vol          = 16;
        stream_cfg.device       = AUD_STREAM_USE_TDM1_MASTER;
        stream_cfg.sync_start   = false;
        stream_cfg.slot_cycles  = HAL_TDM_SLOT_CYCLES_16;
        stream_cfg.fs_cycles    = HAL_TDM_FS_CYCLES_1;
        stream_cfg.io_path      = AUD_IO_PATH_NULL;
        stream_cfg.channel_num  = AUD_CHANNEL_NUM_2;
        stream_cfg.handler      = hearable_mic_data_come;
        stream_cfg.data_size    = HBLE_AUDIO_BUFF_SIZE;
        stream_cfg.data_ptr     = BT_AUDIO_CACHE_2_UNCACHE(hearable_capture_buff);
        capture_buf             = stream_cfg.data_ptr;
        capture_size            = stream_cfg.data_size;
        af_stream_open(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE, &stream_cfg);

        /*hearable_spk_stream*/
        memset(&stream_cfg, 0, sizeof(stream_cfg));
        stream_cfg.sample_rate  = AUD_SAMPRATE_16000;
        stream_cfg.bits         = AUD_BITS_16;
        stream_cfg.vol          = 16;
        stream_cfg.device       = AUD_STREAM_USE_TDM1_MASTER;
        stream_cfg.sync_start   = false;
        stream_cfg.slot_cycles  = HAL_TDM_SLOT_CYCLES_16;
        stream_cfg.fs_cycles    = HAL_TDM_FS_CYCLES_1;
        stream_cfg.io_path      = AUD_IO_PATH_NULL;
        stream_cfg.channel_num  = AUD_CHANNEL_NUM_2;
        stream_cfg.handler      = hearable_spk_data_out;
        stream_cfg.data_size    = HBLE_PLAYBACK_BUFF_SIZE;
        stream_cfg.data_ptr     = BT_AUDIO_CACHE_2_UNCACHE(hearable_playback_buff);
        playback_buf            = stream_cfg.data_ptr;
        playback_size           = stream_cfg.data_size;
       af_stream_open(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, &stream_cfg);

       af_stream_start(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
       af_stream_start(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);

/***************************内部CODEC设备****************************************/
        /*hearable_mic_stream*/
        stream_cfg.sample_rate  = AUD_SAMPRATE_16000;
        stream_cfg.bits         = AUD_BITS_16;
        stream_cfg.vol          = 16;
        stream_cfg.device       = AUD_STREAM_USE_INT_CODEC;
        stream_cfg.io_path      = AUD_INPUT_PATH_MAINMIC;
        stream_cfg.channel_num  = AUD_CHANNEL_NUM_2;
        stream_cfg.handler      = hearable_mic_data_come;
        stream_cfg.data_size    = HBLE_AUDIO_BUFF_SIZE;
        stream_cfg.data_ptr     = BT_AUDIO_CACHE_2_UNCACHE(hearable_capture_buff);
        capture_buf             = stream_cfg.data_ptr;
        capture_size            = stream_cfg.data_size;
        af_stream_open(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE, &stream_cfg);

        /*hearable_spk_stream*/
        memset(&stream_cfg, 0, sizeof(stream_cfg));
        stream_cfg.sample_rate  = AUD_SAMPRATE_16000;
        stream_cfg.bits         = AUD_BITS_16;
        stream_cfg.vol          = 16;
        stream_cfg.device       = AUD_STREAM_USE_INT_CODEC;
        stream_cfg.io_path      = AUD_OUTPUT_PATH_SPEAKER;
        stream_cfg.channel_num  = AUD_CHANNEL_NUM_2;
        stream_cfg.handler      = hearable_spk_data_out;
        stream_cfg.data_size    = HBLE_AUDIO_BUFF_SIZE;
        stream_cfg.data_ptr     = BT_AUDIO_CACHE_2_UNCACHE(hearable_playback_buff);
        playback_buf            = stream_cfg.data_ptr;
        playback_size           = stream_cfg.data_size;
        af_stream_open(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, &stream_cfg);

        af_stream_start(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
        af_stream_start(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);

/***************************I2S设备****************************************/
        /*hearable_mic_stream*/
        stream_cfg.sample_rate  = AUD_SAMPRATE_16000;
        stream_cfg.bits         = AUD_BITS_16;
        stream_cfg.vol          = 16;
        stream_cfg.device       = AUD_STREAM_USE_I2S0_MASTER;
        stream_cfg.io_path      = AUD_IO_PATH_NULL;
        stream_cfg.channel_num  = AUD_CHANNEL_NUM_2;
        stream_cfg.handler      = hearable_mic_data_come;
        stream_cfg.data_size    = HBLE_AUDIO_BUFF_SIZE;
        stream_cfg.data_ptr     = BT_AUDIO_CACHE_2_UNCACHE(hearable_capture_buff);
        capture_buf             = stream_cfg.data_ptr;
        capture_size            = stream_cfg.data_size;
        af_stream_open(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE, &stream_cfg);

        /*hearable_spk_stream*/
        memset(&stream_cfg, 0, sizeof(stream_cfg));
        stream_cfg.sample_rate  = AUD_SAMPRATE_16000;
        stream_cfg.bits         = AUD_BITS_16;
        stream_cfg.vol          = 16;
        stream_cfg.device       = AUD_STREAM_USE_I2S0_MASTER;
        stream_cfg.io_path      = AUD_IO_PATH_NULL;
        stream_cfg.channel_num  = AUD_CHANNEL_NUM_2;
        stream_cfg.handler      = hearable_spk_data_out;
        stream_cfg.data_size    = HBLE_AUDIO_BUFF_SIZE;
        stream_cfg.data_ptr     = BT_AUDIO_CACHE_2_UNCACHE(hearable_playback_buff);
        playback_buf            = stream_cfg.data_ptr;
        playback_size           = stream_cfg.data_size;
        af_stream_open(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, &stream_cfg);

        af_stream_start(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
        af_stream_start(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);

  • bt_media_start(uint16_t stream_type, enum BT_DEVICE_ID_T device_id, uint16_t media_id)

函数的调用:app_audio_manager_open()—>bt_media_start()

函数内流程:

(1)如果stream_type是BT_STREAM_SBC,若BT_STREAM_MEDIA是active状态则退出,若BT_STREAM_VOICE是active状态则提高系统主频并退出,其他情况开启音乐流

(2)如果stream_type是BT_STREAM_MEDIA,若BT_STREAM_VOICE是active状态,关闭通话流开启提示音流,若BT_STREAM_SBC是active状态, 关闭音乐流开启提示音流

(3)如果stream_type是BT_STREAM_VOICE,若BT_STREAM_MEDIA是active状态同时BT_STREAM_VOICE也是active状态停止提示音流开启通话流;若只有BT_STREAM_MEDIA是active状态继续播放提示音。若BT_STREAM_SBC是active状态, 关闭音乐流开启通话流

(4)音乐流、通话流及提示音流的开启和关闭通过向模块APP_MODUAL_AUDIO发消息进入回调app_audio_handle_process完成相应操作

enum APP_BT_SETTING_T {
    APP_BT_SETTING_OPEN = 0,
    APP_BT_SETTING_CLOSE,
    APP_BT_SETTING_SETUP,
    APP_BT_SETTING_RESTART,
    APP_BT_SETTING_CLOSEALL,
    APP_BT_SETTING_CLOSEMEDIA,
    APP_BT_SETTING_NUM,
};

1.bt_media_start()
2.

app_audio_sendrequest(APP_BT_STREAM_A2DP_SBC, ( uint8_t )APP_BT_SETTING_OPEN, 0);/*开闭音乐流*/
app_audio_sendrequest(APP_BT_STREAM_HFP_PCM, (uint8_t)APP_BT_SETTING_OPEN, 0);/*开通话流*/
app_audio_sendrequest(APP_PLAY_BACK_AUDIO, (uint8_t)APP_BT_SETTING_OPEN, media_id);/*开提示音流*/

1.bt_media_stop()
2.

app_audio_sendrequest(APP_BT_STREAM_A2DP_SBC, (uint8_t)APP_BT_SETTING_CLOSE, 0);/*关闭音乐流*/
app_audio_sendrequest(APP_BT_STREAM_HFP_PCM, (uint8_t)APP_BT_SETTING_CLOSE, 0);/*关通话流*/
app_audio_sendrequest(APP_PLAY_BACK_AUDIO, (uint8_t)APP_BT_SETTING_CLOSE, 0);/*关提示音流*/
/*开关闭音乐流*/
app_audio_sendrequest(APP_BT_STREAM_A2DP_SBC, ( uint8_t )APP_BT_SETTING_OPEN, 0);
app_audio_sendrequest(APP_BT_STREAM_A2DP_SBC, (uint8_t)APP_BT_SETTING_CLOSE, 0);

/*开关通话流*/
app_audio_sendrequest(APP_BT_STREAM_HFP_PCM, (uint8_t)APP_BT_SETTING_OPEN, 0);
app_audio_sendrequest(APP_BT_STREAM_HFP_PCM, (uint8_t)APP_BT_SETTING_CLOSE, 0);

/*开关提示音流*/
app_audio_sendrequest(APP_PLAY_BACK_AUDIO, (uint8_t)APP_BT_SETTING_OPEN, media_id);
app_audio_sendrequest(APP_PLAY_BACK_AUDIO, (uint8_t)APP_BT_SETTING_CLOSE, 0);

Original: https://blog.csdn.net/qq_31604659/article/details/123370257
Author: 田_田_田
Title: BES音频框架分析—Audioflinger

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/497696/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球