录音与放音驱动(CODEC MANAGER)¶
1. 特点¶
- 芯片内部自带CODEC;
- 为内部CODEC专门设计的ALC处理逻辑;
- IIS专用IISDMA;
- 驱动程序简单易用,使用灵活。
CI13XX系列芯片作为一款智能语音芯片,其语音通路(CODEC、IIS、IISDMA)占有非常重要的部分。CI13XX系列芯片还拥有片内的CODEC(单通道ADC和单通道DAC),使用CI13XX系列芯片进行录音和放音,可以不再外接CODEC芯片,大大增加了系统的稳定性,且降低了成本。专用的IISDMA使得配置IIS接收或者发送数据更加灵活、方便,且不用考虑其他外设使用DMA对其造成影响。且CI13XX系列芯片为片内CODEC的ADC和DAC设计了单独的IIS,二者独立工作,互不影响,使用灵活。另外,CI13XX系列芯片还有一路IIS为外接CODEC预留,保证用户依然可以根据自己的需要选择其他的CODEC芯片,采集多路语音,已满足更复杂的算法需求。录音和放音组件将CODEC、IIS和IISDMA串联起来,形成了CI13XX系列芯片的语音通路。
2. 概述¶
图1-1 放音设备驱动API
图1-1 录音设备驱动API
CI13XX系列芯片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);
}
}
}