跳转至

录音与放音驱动(CODEC MANAGER)


1. 特点

  • 芯片内部自带CODEC;
  • 为内部CODEC专门设计的ALC处理逻辑;
  • IIS专用IISDMA;
  • 驱动程序简单易用,使用灵活。

CI231系列芯片作为一款智能语音芯片,其语音通路(CODEC、IIS、IISDMA)占有非常重要的部分。CI231系列芯片还拥有片内的CODEC(单通道ADC和单通道DAC),使用CI231系列芯片进行录音和放音,可以不再外接CODEC芯片,大大增加了系统的稳定性,且降低了成本。专用的IISDMA使得配置IIS接收或者发送数据更加灵活、方便,且不用考虑其他外设使用DMA对其造成影响。且CI231系列芯片为片内CODEC的ADC和DAC设计了单独的IIS,二者独立工作,互不影响,使用灵活。另外,CI231系列芯片还有一路IIS为外接CODEC预留,保证用户依然可以根据自己的需要选择其他的CODEC芯片,采集多路语音,已满足更复杂的算法需求。录音和放音组件将CODEC、IIS和IISDMA串联起来,形成了CI231系列芯片的语音通路。


2. 概述

放音设备驱动API

图1-1 放音设备驱动API

录音设备驱动API

图1-1 录音设备驱动API

CI231系列芯片SDK提供了一套录音设备和放音设备的驱动程序。通过调用这套驱动程序提供的API,用户就可以完成常规配置的录音和放音操作,而不需要考虑繁琐的IIS、IISDMA、CODEC的配置。这套驱动基于FreeRTOS编写,因此只能在FreeRTOS的基础上运行。


3. 录音放音设备API

函数名 描述
cm_reg_codec 注册codec
cm_config_pcm_buffer 配置录音/放音 PCM buffer
cm_config_codec 配置录音/放音 音频格式
cm_start_codec 开始录音/放音
cm_stop_codec 停止录音/放音
cm_read_codec 获取录音数据
cm_write_codec 写入放音数据
cm_get_pcm_buffer 获取放音 PCM buffer
cm_release_pcm_buffer 释放放音 PCM buffer
cm_set_codec_dac_gain 设置放音音量
cm_set_codec_alc 设置codec alc
cm_set_codec_dac_enable 设置codec dac 使能
cm_set_codec_mute 录音设备静音

4. 录音示例

驱动文件地址:”SDK\components\codec_manager\codec_manager.c”

初始化代码、获取数据的示例:

#include "audio_in_manage_inner.h"
#include "codec_manager.h"
#include "audio_play_api.h"
#include "audio_play_decoder.h"

#define RECORD_CODEC_INDEX 0

const cm_codec_hw_info_t inner_codec_info = 
{
    .IICx = IIC_NULL,
    .input_iis.IISx = IIS1,
    .input_iis.iis_mode_sel = IIS_MASTER,
    .input_iis.oversample = IIS_MCLK_FS_256,
    .input_iis.clk_source = AUDIO_PLAY_CLK_SOURCE_IPCORE,
    .input_iis.mclk_out_en = IIS_MCLK_OUT,
    .input_iis.iis_data_format = IIS_DF_IIS,
    .input_iis.sck_lrck_radio = IIS_SCK_LRCK_64,
    .input_iis.rx_cha = IIS_RX_CHANNAL_RX0,
    .input_iis.scklrck_out_en = IIS_SCKLRCK_OUT,
    codec_if = 
    {
        .codec_init = icodec_init,
        .codec_config = icodec_config,
        .codec_start = icodec_stop,
        .codec_ioctl = icodec_ioctl,
    }
}

const cm sound_info_t record_sound_info = 
{
    .sapmple_rate = 16000,
    .channel_flag = 3,
    .sample_depth = IIS_DW_16BIT,
}

void record_task(void* p)
{
    //注册内部codec
    cm_reg_codec(RECORD_CODEC_INDEX, (cm_codec_hw_info_t*)&inner_codec_info);

    //配置录音PCM buffer
    cm_record_buffer_info_t record_buffer_info;
    record_buffer_info.block_num = 2;
    record_buffer_info.block_size = 320*4; //576;
    record_buffer_info.buffer_size = record_buffer_info.block_size * record_buffer_info.block_num;
    record_buffer_info.pcm_buffer = pvPortMalloc(record_buffer_info.buffer_size);
    cm_config_pcm_buffer(RECORD_CODEC_INDEX, CODEC_INPUT, &record_buffer_info);

    //配置录音音频格式
    cm_config_codec(RECORD_CODEC_INDEX, CODEC_INPUT, &record_sound_info);

    //开始录音
    cm_start_codec(RECORD_CODEC_INDEX, CODEC_INPUT);

    while(1)
    {
        //录音
        uint32_t data_addr, data_size;
        cm_read_codec(RECORD_CODEC_INDEX, &data_addr, &data_size);

        if(data_addr)
        {

        }
        else
        {
            //mprintf("iisdma int too slow\n");
            continue;
        }
    }
}

5. 放音示例

驱动文件地址:”SDK\components\codec_manager\codec_manager.c”

初始化代码、写入数据播放示例:

#include "audio_in_manage_inner.h"
#include "codec_manager.h"
#include "audio_play_api.h"
#include "audio_play_decoder.h"

#define PLAYER_CODEC_INDEX 0
#define ALG_FRAME_SIZE (320) /*16ms perframe*/

uint16_t send_buf_addr[2048] = {0};

const cm_codec_hw_info_t inner_codec_info = 
{
    .IICx = IIC_NULL,
    .output_iis.IISx = IIS1,
    .output_iis.iis_mode_sel = IIS_MASTER,
    .output_iis.oversample = IIS_MCLK_FS_256,
    .output_iis.clk_source = AUDIO_PLAY_CLK_SOURCE_INTER_RC,
    .output_iis.mclk_out_en = IIS_MCLK_MODENULL,
    .output_iis.iis_data_format = IIS_DF_IIS,
    .output_iis.sck_lrck_radio = IIS_TX_CHANNAL_TX0,
    .output_iis.sck_lrck_radio = IIS_SCK_LRCK_64,
    .output_iis.scklrck_out_en = IIS_SCKLRCK_MODENULL,
    codec_if = 
    {
        .codec_init = icodec_init,
        .codec_config = icodec_config,
        .codec_start = icodec_stop,
        .codec_stop = icodec_stop,
        .codec_ioctl = icodec_ioctl,
    }
}

const cm sound_info_t play_sound_info = 
{
    .sapmple_rate = 16000,
    .channel_flag = 3,
    .sample_depth = IIS_DW_16BIT,
}

void play_task(void* p)
{
    //注册内部codec
    cm_reg_codec(PLAYER_CODEC_INDEX, (cm_codec_hw_info_t*)&inner_codec_info);

    //配置放音PCM buffer
    cm_play_buffer_info_t play_buffer_info;
    play_buffer_info.block_num = 2;
    play_buffer_info.buffer_num = 4;
    play_buffer_info.block_size = 320*4;
    play_buffer_info.buffer_size = play_buffer_info.block_size * play_buffer_info.block_num;
    play_buffer_info.pcm_buffer = pvPortMalloc(play_buffer_info.buffer_size*play_buffer_info.buffer_num);
    cm_config_pcm_buffer(PLAYER_CODEC_INDEX, CODEC_OUTPUT, &play_buffer_info);

    //配置放音音频格式
    cm_config_codec(PLAYER_CODEC_INDEX, CODEC_OUTPUT, &play_sound_info);

    //开始放音
    cm_start_codec(PLAYER_CODEC_INDEX, CODEC_OUTPUT);

    while(1)
    {
        //放音
        uint32_t ret_p = 0;
        cm_get_pcm_buffer(PLAYER_CODEC_INDEX,&ret_p,portMAX_DELAY);    //TODO HSL
        volatile int16_t * out_p = (void*)ret_p;

        if(out_p)
        {
            memcpy(out_p, send_buf_addr, ALG_FRAME_SIZE*2*2);    //播放数据来源于send_buf_addr
            cm_write_codec(PLAYER_CODEC_INDEX, out_p,portMAX_DELAY);
        }
    }
}