当前位置:网站首页>[learning notes] xr872 audio driver framework analysis
[learning notes] xr872 audio driver framework analysis
2022-06-13 01:59:00 【lovemengx】
Xradio Sdk Of Audio Drive framework and Linux Of ASOC The drive frame is very similar , It just simplifies a lot .
Diagram of the relationship between driver and chip
Below SOC It means XR872 chip , Here we use AC107 As an example to explain ,XR872 In fact, there is only one way I2S, Two routes are drawn here to facilitate the follow-up explanation .

As can be seen from the above figure :
On software , A complete sound card , Mainly by platform_driver and codec_driver form , Their composition and related configuration information are provided by snd_card_board_config determine , The system builds a new sound card according to this configuration .
On hardware ,XR872 adopt I2C and I2S And AC107 Connected to a ,I2C The interface is mainly in the codec driver Middle configuration codec , Such as sampling rate 、 Sampling bit depth 、 Data transmission format, etc . and I2S Mainly in the platform driver For audio data transmission .
Key data structure analysis
On software , There are mainly four core data structures , The relationship between them is as follows :

struct platform_driver:
It is a platform related digital audio interface driver , The main interaction objects are XR872 Inside I2S Interface , Such as configuration I2S Master-slave relationship , Data transfer format , clock frequency , start-up 、 stop it I2S The data transfer . One platform_driver On behalf of SOC On the one I2S controller .

struct codec_driver:
It is related to the concrete Codec Chip related drivers , The main interaction objects are AC107 , Play the role of configuration AC107 The function of the relevant register , The specific configuration will be the same as platfrom_driver Association synchronization , Such as configuration I2S Master-slave relationship , Data transfer format , clock frequency , start-up 、 Stop data collection . One codec_driver It means one Codec chip .

struct snd_card_board_config:
Describe the basic parameters of a sound card , Specify which codec_driver and Which one? platform_driver form . amount to Linux ASOC Medium Machine Driving role .

struct snd_card: The specific sound card reflects , One snd_card Corresponds to a sound card , Dynamically created during system operation .

Sound card registration process
One 、Codec Drive workflow ( With AC107 For example :src\driver\chip\codec\ac107.c)
1. Construct a struct codec_driver structure , And implement the relevant callback interface in the structure .
/*** codec dai ops ****/
static const struct codec_dai_ops ac107_codec_dai_ops = {
.set_sysclk = ac107_dai_set_sysclk,
.set_fmt = ac107_dai_set_fmt,
.set_volume = ac107_dai_set_volume,
.set_route = ac107_dai_set_route,
.hw_params = ac107_dai_hw_params,
.hw_free = ac107_dai_hw_free,
};
/*** codec ops ****/
static const struct codec_ops ac107_codec_ops = {
.open = ac107_codec_open,
.close = ac107_codec_close,
.reg_read = ac107_codec_reg_read,
.reg_write = ac107_codec_reg_write,
.ioctl = ac107_codec_ioctl,
};
/*** codec driver ****/
static struct codec_driver ac107_codec_drv = {
.name = AC107_CODEC_NAME,
.codec_attr = XRADIO_CODEC_AC107,
.init = ac107_codec_init,
.deinit = ac107_codec_deinit,
.dai_ops = &ac107_codec_dai_ops,
.codec_ops = &ac107_codec_ops,
};2. Provide a register and unload interface , The final implementation will ac107_codec_drv Add to hal_snd_codec_list Linked list .
HAL_Status ac107_codec_register(void)
{
// ......
// initialization I2C controller
if(HAL_I2C_Init(i, &i2c_param) != HAL_OK){
AC107_ERR("I2C-[%d] init Fail...\n",i);
}
// ......
// adopt I2C Read chip ID, Used to confirm whether the chip exists
AC107_I2C_READ(i2c_id, ac107_i2c_addr[i], CHIP_AUDIO_RST, I2C_MEMADDR_SIZE_8BIT, &chip_id, 1);
if(chip_id == 0x4B){
AC107_DBG("AC107-[0x%02x] on I2C-[%d] auto detect success\n",ac107_i2c_addr[i],i2c_id);
ac107_i2c_cfg_temp[detect_nums].i2c_id = i2c_id;
ac107_i2c_cfg_temp[detect_nums].i2c_addr = ac107_i2c_addr[i];
detect_nums++;
}
// ......
// take ac107_codec_drv Add to hal_snd_codec_list In the list
list_add(&ac107_codec_drv.node, &hal_snd_codec_list);
return HAL_OK;
}
HAL_Status ac107_codec_unregister(void)
{
// ......
// Traverse hal_snd_codec_list Link the list and put ac107_codec_drv remove
list_for_each_entry(codec_drv_ptr, &hal_snd_codec_list, node){
if(codec_drv_ptr == &ac107_codec_drv){
list_del(&ac107_codec_drv.node);
break;
}
}
// ......
return HAL_OK;
}
// src\driver\chip\hal_snd_card.c
HAL_Status HAL_SndCard_CodecRegisterAc107(void)
{
return ac107_codec_register();
}
HAL_Status HAL_SndCard_CodecUnregisterAc107(void)
{
return ac107_codec_unregister();
}Two 、platform Drive workflow ( With I2S For example :src\driver\chip\hal_i2s.c)
1. structure struct platform_driver data structure , And implement the relevant callback interface in the structure .
/*** platform dai ops ***/
static const struct platform_dai_ops xradio_i2s_dai_ops = {
.set_fmt = xradio_i2s_dai_set_fmt,
.set_clkdiv = xradio_i2s_set_clkdiv,
.hw_params = xradio_i2s_dai_hw_params,
.hw_free = xradio_i2s_dai_hw_free,
};
/*** platform ops ***/
static const struct platform_ops xradio_i2s_ops = {
.open = xradio_i2s_open,
.close = xradio_i2s_close,
.pcm_read = xradio_i2s_pcm_read,
.pcm_write = xradio_i2s_pcm_write,
.ioctl = xradio_i2s_ioctl,
};
/*** platform driver ***/
static struct platform_driver xradio_i2s_drv = {
.name = XRADIO_PLATFORM_I2S_NAME,
.platform_attr = XRADIO_PLATFORM_I2S,
.init = xradio_i2s_init,
.deinit = xradio_i2s_deinit,
.dai_ops = &xradio_i2s_dai_ops,
.platform_ops = &xradio_i2s_ops,
};2. Provide a register and unload interface , The final implementation will xradio_i2s_drv Add to hal_snd_platform_list Linked list .
HAL_Status xradio_i2s_register(void)
{
// ......
// take xradio_i2s_drv Add to hal_snd_platform_list In the list
list_add(&xradio_i2s_drv.node, &hal_snd_platform_list);
return HAL_OK;
}
HAL_Status xradio_i2s_unregister(void)
{
// ......
// Traverse hal_snd_platform_list Link the list and put xradio_i2s_drv remove
list_for_each_entry(i2s_drv_ptr, &hal_snd_platform_list, node){
if(i2s_drv_ptr == &xradio_i2s_drv){
list_del(&xradio_i2s_drv.node);
break;
}
}
// ......
return HAL_OK;
}
// src\driver\chip\hal_snd_card.c
HAL_Status HAL_SndCard_PlatformRegisterI2S(void)
{
return xradio_i2s_register();
}
HAL_Status HAL_SndCard_PlatformUnregisterI2S(void)
{
return xradio_i2s_unregister();
}3、 ... and 、 In the board level configuration file , Provide snd_card_board_config relation Codec and Platform And provide access interface ( Take the proposal configuration as an example :project\common\board\xr872_evb_ai\board_config.c)
board_ioctl() ---> board_get_pinmux_info() ---> snd_cards_board_cfg[] ---> ac107_codec_snd_card
#if PRJCONF_AC107_SOUNDCARD_EN
__xip_rodata const static struct snd_card_board_config ac107_codec_snd_card = {
.card_num = SND_CARD_1,
.card_name = HAL_SND_CARD_NAME(AC107_CODEC_NAME, SND_CARD_SUFFIX),
.codec_link = XRADIO_CODEC_AC107,
.platform_link = XRADIO_PLATFORM_I2S,
.pa_switch_ctl = NULL,
.codec_sysclk_src = SYSCLK_SRC_MCLK,
.codec_pllclk_src = 0,
.codec_pll_freq_in = 0,
.i2s_fmt = DAIFMT_CBS_CFS | DAIFMT_I2S | DAIFMT_NB_NF,
};
#endif
const static struct snd_card_board_config *snd_cards_board_cfg[] = {
// ......
#if PRJCONF_AC107_SOUNDCARD_EN
&ac107_codec_snd_card,
#endif
// ......
};
static HAL_Status board_get_pinmux_info(uint32_t major, uint32_t minor, uint32_t param, struct board_pinmux_info info[])
{
// ......
switch (major) {
// ......
// Realization HAL_DEV_MAJOR_AUDIO_CODEC command , according to card_num To return the corresponding snd_card_board_config
case HAL_DEV_MAJOR_AUDIO_CODEC:
for(i=0; i<HAL_ARRAY_SIZE(snd_cards_board_cfg); i++){
if(snd_cards_board_cfg[i]->card_num == minor){
if(snd_cards_board_cfg[i]->pa_switch_ctl){
info[0].pinmux = snd_cards_board_cfg[i]->pa_switch_ctl->pin_param;
info[0].count = snd_cards_board_cfg[i]->pa_switch_ctl->pin_param_cnt;
}
}
}
break;
// ......
}
return ret;
}
HAL_Status board_ioctl(HAL_BoardIoctlReq req, uint32_t param0, uint32_t param1)
{
// ......
switch (req) {
case HAL_BIR_PINMUX_INIT:
case HAL_BIR_PINMUX_DEINIT:
memset(info, 0, sizeof(info));
major = HAL_DEV_MAJOR((HAL_Dev_t)param0);
minor = HAL_DEV_MINOR((HAL_Dev_t)param0);
ret = board_get_pinmux_info(major, minor, param1, info);
// ......
}
// ......
return ret;
}Four 、 Trigger the sound card registration process
1. stay main.c Entry function call platform_init()
__sram_text
void platform_init(void)
{
platform_init_level0();
platform_init_level1();
platform_init_level2(); // Perform secondary initialization
platform_show_info();
}
/* init extern platform hardware and services */
__weak void platform_init_level2(void)
{
// ...
#if PRJCONF_AUDIO_SNDCARD_EN
board_soundcard_init(); // Initialize the sound card
audio_manager_init();
snd_pcm_init();
#if PRJCONF_AUDIO_CTRL_EN
audio_ctrl_init();
#endif
#endif
// ...
}
#if PRJCONF_AUDIO_SNDCARD_EN
__weak HAL_Status board_soundcard_init(void)
{
/* Codec register */
#if PRJCONF_INTERNAL_SOUNDCARD_EN
HAL_SndCard_CodecRegisterInternal();
#endif
#if PRJCONF_AC107_SOUNDCARD_EN
HAL_SndCard_CodecRegisterAc107(); // register AC107 namely ac107_codec_register()
#endif
#if PRJCONF_AC101_SOUNDCARD_EN
HAL_SndCard_CodecRegisterAc101();
#endif
//Add other codec register here
/* Platform register */
#if PRJCONF_PLATFORM_I2S_EN
HAL_SndCard_PlatformRegisterI2S(); // register I2S namely xradio_i2s_register();
#endif
//Add other platform register here
/* Snd Card register*/
HAL_SndCard_Register();
return HAL_OK;
}
__weak HAL_Status board_soundcard_deinit(void)
{
/* Snd Card unregister*/
HAL_SndCard_Unregister();
/* Platform unregister */
#if PRJCONF_PLATFORM_I2S_EN
HAL_SndCard_PlatformUnregisterI2S();
#endif
//Add other platform unregister here
/* Codec unregister */
#if PRJCONF_INTERNAL_SOUNDCARD_EN
HAL_SndCard_CodecUnregisterInternal();
#endif
#if PRJCONF_AC107_SOUNDCARD_EN
HAL_SndCard_CodecUnregisterAc107();
#endif
#if PRJCONF_AC101_SOUNDCARD_EN
HAL_SndCard_CodecUnregisterAc101();
#endif
//Add other codec unregister here
return HAL_OK;
}
#endif2. Sound card registration process
uint8_t HAL_SndCard_Register(void)
{
// ......
// Find all by traversing all sound card numbers snd_card_board_config
for(i=0; i<=SND_CARD_MAX; i++,snd_card_board_cfg = NULL)
{
// obtain struct snd_card_board_config Configuration information
hal_status = HAL_BoardIoctl(HAL_BIR_GET_CFG, HAL_MKDEV(HAL_DEV_MAJOR_AUDIO_CODEC, i), (uint32_t)&snd_card_board_cfg);
if(hal_status != HAL_OK || snd_card_board_cfg == NULL){
continue;
}
// Check whether the sound card number is legal
if(snd_card_board_cfg->card_num > SND_CARD_MAX){
HAL_SND_CARD_ERROR("Invalid snd card number-[%d], while the max card number is %d!\n",snd_card_board_cfg->card_num,SND_CARD_MAX);
continue;
}
// Traverse the sound card linked list , If the sound card hardware exists, it will not continue
if(!list_empty(&hal_snd_card_list)){
found = 0;
list_for_each_entry(sound_card, &hal_snd_card_list, node){
if(sound_card->card_num == snd_card_board_cfg->card_num){
found = 1;
break;
}
}
if(found){
HAL_SND_CARD_ERROR("The snd card number-[%d] has registered\n",snd_card_board_cfg->card_num);
continue;
}
}
// Traverse hal_snd_codec_list Linked list search snd_card_board_config designated codec_driver
if(snd_card_board_cfg->codec_link == XRADIO_CODEC_NULL){
codec_drv_ptr = NULL;
} else {
found = 0;
if(!list_empty(&hal_snd_codec_list)){
list_for_each_entry(codec_drv_ptr, &hal_snd_codec_list, node){
if(snd_card_board_cfg->codec_link == codec_drv_ptr->codec_attr){
found = 1;
break; //snd card match board config codec SUCCESS, break to continue register sound card
}
}
}
if(!found){
HAL_SND_CARD_ERROR("snd card-[%d] match board config codec Fail!\n",snd_card_board_cfg->card_num);
continue;
}
}
// Traverse hal_snd_platform_list Linked list search snd_card_board_config designated platform_driver
if(snd_card_board_cfg->platform_link == XRADIO_PLATFORM_NULL){
platform_drv_ptr = NULL;
} else {
found = 0;
if(!list_empty(&hal_snd_platform_list)){
list_for_each_entry(platform_drv_ptr, &hal_snd_platform_list, node){
if(snd_card_board_cfg->platform_link == platform_drv_ptr->platform_attr){
found = 1;
break; //snd card match board config platform SUCCESS, break to continue register sound card
}
}
}
if(!found){
HAL_SND_CARD_ERROR("snd card-[%d] match board config platform Fail!\n",snd_card_board_cfg->card_num);
continue;
}
}
// If none is found, continue to the next snd_card_board_config
if(codec_drv_ptr == NULL && platform_drv_ptr == NULL){
HAL_SND_CARD_ERROR("snd card-[%d] must link one codec or platform at least!\n",snd_card_board_cfg->card_num);
continue;
}
// If you find them all , Start creating a new sound card by applying for memory
sound_card = (struct snd_card *)HAL_Malloc(sizeof(struct snd_card));
if(!sound_card){
HAL_SND_CARD_ERROR("Malloc snd card-[%d] struct snd_card buffer Fail!\n",snd_card_board_cfg->card_num);
break;//continue;
}
HAL_Memset(sound_card, 0, sizeof(struct snd_card));
// relation codec driver and platform driver
sound_card->codec_drv = codec_drv_ptr;
sound_card->platform_drv = platform_drv_ptr;
/* Card lock init */
if(sound_card->card_lock.handle == NULL){
hal_status = HAL_MutexInit(&sound_card->card_lock);
if(hal_status != HAL_OK){
HAL_SND_CARD_ERROR("snd card[%d] mutex init Fail\n", (uint8_t)sound_card->card_num);
HAL_Free(sound_card);
continue;
}
}
// Copy snd_card_board_config Configuration information
sound_card->card_num = snd_card_board_cfg->card_num;
sound_card->card_name = snd_card_board_cfg->card_name;
sound_card->codec_sysclk_src = snd_card_board_cfg->codec_sysclk_src;
sound_card->codec_pllclk_src = snd_card_board_cfg->codec_pllclk_src;
sound_card->codec_pll_freq_in = snd_card_board_cfg->codec_pll_freq_in;
sound_card->i2s_fmt = snd_card_board_cfg->i2s_fmt;
sound_card->pa_switch_ctl = snd_card_board_cfg->pa_switch_ctl;
// If the power amplifier control pin is specified, set the status of the power amplifier control pin according to the configuration information
HAL_BoardIoctl(HAL_BIR_PINMUX_INIT, HAL_MKDEV(HAL_DEV_MAJOR_AUDIO_CODEC, (uint8_t)sound_card->card_num), 0);
if(sound_card->pa_switch_ctl){
//PA switch init
HAL_GPIO_WritePin(sound_card->pa_switch_ctl->pin_param->port,\
sound_card->pa_switch_ctl->pin_param->pin, !sound_card->pa_switch_ctl->on_state);
}
// call codec Of init Callback , That is to call ac107_codec_drv.init = ac107_codec_init()
if(sound_card->codec_drv && sound_card->codec_drv->init){
hal_status = sound_card->codec_drv->init();
if(hal_status != HAL_OK){
HAL_SND_CARD_ERROR("snd card[%d] codec init Fail\n", (uint8_t)sound_card->card_num);
HAL_Free(sound_card);
continue;
}
}
// call codec Of init Callback , That is to call xradio_i2s_drv.init = xradio_i2s_init()
if(sound_card->platform_drv && sound_card->platform_drv->init){
hal_status = sound_card->platform_drv->init();
if(hal_status != HAL_OK){
HAL_SND_CARD_ERROR("snd card[%d] platform-I2S init Fail\n", (uint8_t)sound_card->card_num);
HAL_Free(sound_card);
continue;
}
}
// ......
// If codec and platform Of init() They all succeeded , Then the sound card is officially added to the sound card linked list
list_add(&sound_card->node, &hal_snd_card_list);
card_nums++;
HAL_SND_CARD_DEBUG("/*** Register snd card[%d]->%s Success ***\\^_^\n\n",sound_card->card_num,sound_card->card_name);
}
return card_nums;
}
5、 ... and 、 It was recorded that audio_pcm_list In the list , by snd_pcm Class interface preparation
int snd_pcm_init(void)
{
char *pcm_priv_temp;
uint8_t *card_num, card_nums, i;
struct pcm_priv* audio_pcm_priv;
AUDIO_PCM_DEBUG("--->%s\n",__FUNCTION__);
/* Get snd card nums */
card_nums = HAL_SndCard_GetCardNums();
if(!card_nums){
AUDIO_PCM_ERROR("card nums is 0!\n");
return -1;
}
/* Malloc buffer and init */
pcm_priv_temp = (char *)pcm_zalloc(sizeof(struct pcm_priv) * card_nums);
card_num = (uint8_t *)pcm_zalloc(sizeof(uint8_t) * card_nums);
if(!pcm_priv_temp || !card_num){
AUDIO_PCM_ERROR("Malloc audio pcm buffer Fail!\n");
pcm_free(pcm_priv_temp);
pcm_free(card_num);
return -1;
}
HAL_SndCard_GetAllCardNum(card_num);
/* Init struct pcm_priv and list add */
for(i=0; i<card_nums; i++){
//Init struct pcm_priv
audio_pcm_priv = (struct pcm_priv *)(pcm_priv_temp + sizeof(struct pcm_priv)*i);
audio_pcm_priv->card_num = (Snd_Card_Num)card_num[i];
pcm_lock_init(&audio_pcm_priv->play_lock);
pcm_lock_init(&audio_pcm_priv->cap_lock);
pcm_lock_init(&audio_pcm_priv->write_lock);
//list add
list_add(&audio_pcm_priv->node, &audio_pcm_list);
}
/* Free get card num buffer */
pcm_free(card_num);
return 0;
}6、 ... and 、 Summarize workflow
according to AC107 Of snd_card_board_config To configure (ac107_codec_snd_card ) The data structure of the sound card is as follows :

Summarize the whole sound card workflow :

The whole sound card registration is to prepare for the four key linked lists : hal_snd_codec_list、hal_snd_platform_list、hal_snd_card_list、audio_pcm_list
hal_snd_codec_list: Save all successful registrations codec_driver, by HAL_SndCard_Register() To prepare for .
hal_snd_platform_list: Save all successful registrations platform_driver , by HAL_SndCard_Register() To prepare for .
hal_snd_card_list: Save through snd_card_board_config Configuration information , Successfully paired codec_driver、platform_driver And the sound card formed by the combination .
audio_pcm_list: Keep the sound card numbers of all sound cards , by snd_pcm_* Prepare for a series of interface functions ( It mainly establishes and maintains the buffer of the application layer )
Application layer usage
One 、 Application example
All of the above , It's all through API The interface method prepares the business logic of the upper application , The following is the simplest recording program .
#include <stdio.h>
#include <string.h>
#include "audio/pcm/audio_pcm.h"
#include "common/framework/platform_init.h"
int main(void)
{
int ret;
void *data;
unsigned int len;
struct pcm_config config;
// Platform initialization
platform_init();
// Configure audio parameters
config.channels = 1;
config.format = PCM_FORMAT_S16_LE;
config.period_count = 2;
config.period_size = 1024;
config.rate = 16000;
// adopt SND_CARD_1 Sound card signal open the specified sound card
ret = snd_pcm_open(SND_CARD_1, PCM_IN, &config);
if (ret) {
printf("snd_pcm_open fail.\n");
return ;
}
// Request buffer
len = config.channels * config.period_count * config.period_size;
data = malloc(len);
if (data == NULL) {
snd_pcm_close(AUDIO_SND_CARD_DEFAULT, PCM_IN);
return;
}
while (1)
{
// Read data from the sound card
ret = snd_pcm_read(AUDIO_SND_CARD_DEFAULT, data, len);
if (ret != len) {
printf("snd_pcm_read fail.\n");
break;
}
// Processing audio data
}
printf("record pcm over.\n");
free(data);
// Turn off the sound card
snd_pcm_close(AUDIO_SND_CARD_DEFAULT, PCM_IN);
return;
}Two 、 Open the workflow of sound card
int snd_pcm_open(Snd_Card_Num card_num, Audio_Stream_Dir stream_dir, struct pcm_config *pcm_cfg)
{
uint32_t buf_size;
struct pcm_priv *audio_pcm_priv;
AUDIO_PCM_DEBUG("--->%s\n",__FUNCTION__);
/* Get audio_pcm_priv */
audio_pcm_priv = card_num_to_pcm_priv(card_num);
if(audio_pcm_priv == NULL){
AUDIO_PCM_ERROR("Invalid sound card num [%d]!\n",(uint8_t)card_num);
return -1;
}
/* Init audio_pcm_priv */
if (stream_dir == PCM_OUT) {
//play lock
if (pcm_lock(&audio_pcm_priv->play_lock) != OS_OK) {
AUDIO_PCM_ERROR("Obtain play lock err...\n");
return -1;
}
// Request play buffer
buf_size = pcm_frames_to_bytes(pcm_cfg, pcm_config_to_frames(pcm_cfg));
audio_pcm_priv->play_priv.cache = pcm_zalloc(buf_size/2);
if (audio_pcm_priv->play_priv.cache == NULL) {
pcm_unlock(&audio_pcm_priv->play_lock);
AUDIO_PCM_ERROR("obtain play cache failed...\n");
return -1;
}
audio_pcm_priv->play_priv.length = 0;
audio_pcm_priv->play_priv.half_buf_size = buf_size/2;
} else {
//cap lock
if (pcm_lock(&audio_pcm_priv->cap_lock) != OS_OK) {
AUDIO_PCM_ERROR("obtain cap lock err...\n");
return -1;
}
// Request recording buffer
buf_size = pcm_frames_to_bytes(pcm_cfg, pcm_config_to_frames(pcm_cfg));
audio_pcm_priv->cap_priv.cache = pcm_zalloc(buf_size/2);
if (audio_pcm_priv->cap_priv.cache == NULL) {
pcm_unlock(&audio_pcm_priv->cap_lock);
AUDIO_PCM_ERROR("obtain cap cache failed...\n");
return -1;
}
audio_pcm_priv->cap_priv.length = 0;
audio_pcm_priv->cap_priv.half_buf_size = buf_size/2;
}
// Open the sound card
if (HAL_SndCard_Open(card_num, stream_dir, pcm_cfg) != HAL_OK) {
AUDIO_PCM_ERROR("Sound card-[%d] open Fai!\n",card_num);
if (stream_dir == PCM_OUT) {
pcm_free(audio_pcm_priv->play_priv.cache);
memset(&(audio_pcm_priv->play_priv), 0, sizeof(struct play_priv));
pcm_unlock(&audio_pcm_priv->play_lock);
} else {
pcm_free(audio_pcm_priv->cap_priv.cache);
memset(&(audio_pcm_priv->cap_priv), 0, sizeof(struct cap_priv));
pcm_unlock(&audio_pcm_priv->cap_lock);
}
return -1;
}
return 0;
}
HAL_Status HAL_SndCard_Open(Snd_Card_Num card_num, Audio_Stream_Dir stream_dir, struct pcm_config *pcm_cfg)
{
HAL_SND_CARD_DEBUG("--->%s\n",__FUNCTION__);
uint32_t dma_buf_size;
HAL_Status hal_status;
// From the sound card number hal_snd_card_list Find the corresponding sound card in the linked list
struct snd_card *sound_card = card_num_to_snd_card(card_num);
// ......
HAL_MutexLock(&sound_card->card_lock, OS_WAIT_FOREVER);
// According to the preset parameters, the sound card associated with codec To configure ( The parameters are from the board level file snd_card_board_config、 And applications pcm_cfg )
if(sound_card->codec_drv && sound_card->codec_drv->dai_ops){
// Set the system clock
if(sound_card->codec_drv->dai_ops->set_sysclk){
hal_status = sound_card->codec_drv->dai_ops->set_sysclk(sound_card->codec_sysclk_src,\
sound_card->codec_pllclk_src, sound_card->codec_pll_freq_in, pcm_cfg->rate);
if(hal_status != HAL_OK){
HAL_SND_CARD_ERROR("snd card[%d] codec set sysclk Fail!\n",(uint8_t)card_num);
goto codec_hw_free;
}
}
// Set up I2S Related parameters
if(sound_card->codec_drv->dai_ops->set_fmt){
hal_status = sound_card->codec_drv->dai_ops->set_fmt(sound_card->i2s_fmt);
if(hal_status != HAL_OK){
HAL_SND_CARD_ERROR("snd card[%d] codec set fmt Fail!\n",(uint8_t)card_num);
goto codec_hw_free;
}
}
// Configure hardware parameters
if(sound_card->codec_drv->dai_ops->hw_params){
hal_status = sound_card->codec_drv->dai_ops->hw_params(stream_dir, pcm_cfg);
if(hal_status != HAL_OK){
HAL_SND_CARD_ERROR("snd card[%d] codec config hw params Fail!\n",(uint8_t)card_num);
goto codec_hw_free;
}
}
}
// If it's done codec_ops->open The callback calls , Give Way codec To prepare
if(sound_card->codec_drv && sound_card->codec_drv->codec_ops){
//codec ioctl
//related Codec Ioctl place here
//codec open
if(sound_card->codec_drv->codec_ops->open){
hal_status = sound_card->codec_drv->codec_ops->open(stream_dir);
if(hal_status != HAL_OK){
HAL_SND_CARD_ERROR("snd card[%d] codec open Fail!\n",(uint8_t)card_num);
goto codec_hw_free;
}
}
}
// According to the preset parameters, the sound card associated with I2S To configure ( The parameters are from the board level file snd_card_board_config、 And applications pcm_cfg )
if(sound_card->platform_drv && sound_card->platform_drv->dai_ops){
// Set up I2S Related parameters
if(sound_card->platform_drv->dai_ops->set_fmt){
hal_status = sound_card->platform_drv->dai_ops->set_fmt(sound_card->i2s_fmt);
if(hal_status != HAL_OK){
HAL_SND_CARD_ERROR("snd card[%d] platform set fmt Fail!\n",(uint8_t)card_num);
goto platform_hw_free;
}
}
// Set up I2S The clock frequency division
if(sound_card->platform_drv->dai_ops->set_clkdiv){
hal_status = sound_card->platform_drv->dai_ops->set_clkdiv(pcm_cfg->rate);
if(hal_status != HAL_OK){
HAL_SND_CARD_ERROR("snd card[%d] platform set clkdiv Fail!\n",(uint8_t)card_num);
goto platform_hw_free;
}
}
// Set hardware parameters
if(sound_card->platform_drv->dai_ops->hw_params){
hal_status = sound_card->platform_drv->dai_ops->hw_params(stream_dir, pcm_cfg);
if(hal_status != HAL_OK){
HAL_SND_CARD_ERROR("snd card[%d] platform config hw params Fail!\n",(uint8_t)card_num);
goto platform_hw_free;
}
}
}
// If it's done platform_ops->open The callback calls , Give Way I2S To prepare
if(sound_card->platform_drv && sound_card->platform_drv->platform_ops && sound_card->platform_drv->platform_ops->open){
hal_status = sound_card->platform_drv->platform_ops->open(stream_dir);
if(hal_status != HAL_OK){
HAL_SND_CARD_ERROR("snd card[%d] platform-I2S open Fail!\n",(uint8_t)card_num);
goto platform_hw_free;
}
}
HAL_MutexUnlock(&sound_card->card_lock);
// If it is audio output , Then control the output pin of the power amplifier , Let the amplifier work
if(stream_dir == PCM_OUT){
if(sound_card->pa_switch_ctl){
if(sound_card->pa_switch_ctl->on_delay_before) HAL_MSleep(sound_card->pa_switch_ctl->on_delay_before);
HAL_GPIO_WritePin(sound_card->pa_switch_ctl->pin_param->port, sound_card->pa_switch_ctl->pin_param->pin, sound_card->pa_switch_ctl->on_state);
if(sound_card->pa_switch_ctl->on_delay_after) HAL_MSleep(sound_card->pa_switch_ctl->on_delay_after);
}
}
return HAL_OK;
platform_hw_free:
if(sound_card->platform_drv && sound_card->platform_drv->dai_ops && sound_card->platform_drv->dai_ops->hw_free){
hal_status = sound_card->platform_drv->dai_ops->hw_free(stream_dir);
if(hal_status != HAL_OK){
HAL_SND_CARD_ERROR("snd card[%d] platform hw free Fail!\n",(uint8_t)card_num);
}
}
//codec_close:
if(sound_card->codec_drv && sound_card->codec_drv->codec_ops && sound_card->codec_drv->codec_ops->close){
hal_status = sound_card->codec_drv->codec_ops->close(stream_dir);
if(hal_status != HAL_OK){
HAL_SND_CARD_ERROR("snd card[%d] codec close Fail!\n",(uint8_t)card_num);
}
}
codec_hw_free:
if(sound_card->codec_drv && sound_card->codec_drv->dai_ops && sound_card->codec_drv->dai_ops->hw_free){
hal_status = sound_card->codec_drv->dai_ops->hw_free(stream_dir);
if(hal_status != HAL_OK){
HAL_SND_CARD_ERROR("snd card[%d] codec hw free Fail!\n",(uint8_t)card_num);
}
}
HAL_MutexUnlock(&sound_card->card_lock);
return HAL_ERROR;
}3、 ... and 、 Read audio data flow
int snd_pcm_read(Snd_Card_Num card_num, void *data, uint32_t count)
{
// ...... Omit the buffer processing flow of the application layer
// Read data from sound card
if(read_remain >= half_buf_size){
hw_read = (read_remain / half_buf_size) * half_buf_size;
ret = HAL_SndCard_PcmRead(card_num, data_ptr, hw_read);
if(ret != hw_read){
AUDIO_PCM_ERROR("PCM read error!\n");
return ret ? count - read_remain + ret : count - read_remain;
}
data_ptr += hw_read;
read_remain -= hw_read;
if(!read_remain){
return count;
}
}
// ...... Omit the buffer processing flow of the application layer
return count;
}int HAL_SndCard_PcmRead(Snd_Card_Num card_num, uint8_t *buf, uint32_t size)
{
struct snd_card *sound_card = card_num_to_snd_card(card_num);
// ......
// If platform_driver The driver has implementation platform_ops->pcm_read() Give priority to pcm_read() Interface to read data
if(sound_card->platform_drv && sound_card->platform_drv->platform_ops && sound_card->platform_drv->platform_ops->pcm_read){
return sound_card->platform_drv->platform_ops->pcm_read(buf, size);
} else if (sound_card->codec_drv && sound_card->codec_drv->codec_ops && sound_card->codec_drv->codec_ops->ioctl){
// Otherwise, from codec_driver Driven codec_ops->ioctl Interface to read data
uint32_t cmd_param[2] = {(uint32_t)buf, size};
return sound_card->codec_drv->codec_ops->ioctl(CODEC_IOCTL_PCM_READ, cmd_param, 2);
}
return 0;
}Four 、 Close the sound card process
HAL_Status HAL_SndCard_Close(Snd_Card_Num card_num, Audio_Stream_Dir stream_dir)
{
HAL_SND_CARD_DEBUG("--->%s\n",__FUNCTION__);
HAL_Status hal_status;
struct snd_card *sound_card = card_num_to_snd_card(card_num);
if(!sound_card){
HAL_SND_CARD_ERROR("Invalid sound card num [%d]!\n",(uint8_t)card_num);
return HAL_INVALID;
}
// Turn off the power amplifier first
if(stream_dir == PCM_OUT){
if(sound_card->pa_switch_ctl){
HAL_GPIO_WritePin(sound_card->pa_switch_ctl->pin_param->port, sound_card->pa_switch_ctl->pin_param->pin, !sound_card->pa_switch_ctl->on_state);
}
}
HAL_MutexLock(&sound_card->card_lock, OS_WAIT_FOREVER);
// close I2S
if(sound_card->platform_drv && sound_card->platform_drv->platform_ops && sound_card->platform_drv->platform_ops->close){
hal_status = sound_card->platform_drv->platform_ops->close(stream_dir);
if(hal_status != HAL_OK){
HAL_SND_CARD_ERROR("snd card[%d] platform close Fail!\n",(uint8_t)card_num);
}
}
// close Codec
if(sound_card->codec_drv && sound_card->codec_drv->codec_ops && sound_card->codec_drv->codec_ops->close){
hal_status = sound_card->codec_drv->codec_ops->close(stream_dir);
if(hal_status != HAL_OK){
HAL_SND_CARD_ERROR("snd card[%d] codec close Fail!\n",(uint8_t)card_num);
}
}
// Release Codec hardware configuration
if(sound_card->codec_drv && sound_card->codec_drv->dai_ops && sound_card->codec_drv->dai_ops->hw_free){
hal_status = sound_card->codec_drv->dai_ops->hw_free(stream_dir);
if(hal_status != HAL_OK){
HAL_SND_CARD_ERROR("snd card[%d] codec hw free Fail!\n",(uint8_t)card_num);
}
}
// Release I2S hardware configuration
if(sound_card->platform_drv && sound_card->platform_drv->dai_ops && sound_card->platform_drv->dai_ops->hw_free){
hal_status = sound_card->platform_drv->dai_ops->hw_free(stream_dir);
if(hal_status != HAL_OK){
HAL_SND_CARD_ERROR("snd card[%d] platform hw free Fail!\n",(uint8_t)card_num);
}
}
HAL_MutexUnlock(&sound_card->card_lock);
return HAL_OK;
}
边栏推荐
- Delphi Google API text to speech MP3 file
- Luzhengyao, who has entered the prefabricated vegetable track, still needs to stop being impatient
- LabVIEW large project development tools to improve quality
- STM32 steering gear controller
- The first cell of devaxpress CXGRID after inserting a row is in focus editing status
- CXGRID keeps the original display position after refreshing the data
- Matplotlib drawing Chinese garbled code
- Vivo released originos ocean, and the domestic customized system is getting better and better
- Get started quickly cmake
- 5、 Improvement of inventory query function
猜你喜欢

开发者来稿|AMD赛灵思中文论坛分享 - 提问的智慧

Introduction to Google unit testing tools GTEST and gmoke

Use of Arduino series pressure sensors and detected data displayed by OLED (detailed tutorial)

Opencv camera calibration (1): internal and external parameters, distortion coefficient calibration and 3D point to 2D image projection

华为设备配置IP和虚拟专用网混合FRR

Using OpenCV in go

Devaxpress Chinese description --tdximageslider (picture rotation control)

Application circuit and understanding of BAT54C as power supply protection

How to learn C language and share super detailed experience (learning note 1 -- basic data types of C language)

记录:如何解决MultipartFile类的transferTo()上传图片报“系统找不到指定的路径“问题【亲测有效】
随机推荐
Decompression and compression of chrome resource file Pak
移动IPv6光猫登录的一般ip地址账号与密码,移动光猫变桥接模式
Use mediapipe+opencv to make a simple virtual keyboard
五、库存查询功能的完善
6、 Implementation of warehouse out management function
LeetCode每日一题——890. 查找和替换模式
C language conditional compilation routine
General IP address, account and password of mobile IPv6 optical cat login, and mobile optical cat is in bridging mode
Establishment of microservice development environment
STM32 timer interrupt learning notes
Alertwindowmanager pop up prompt window help (Part 1)
Why is "iFLYTEK Super Brain 2030 plan" more worthy of expectation than "pure" virtual human
swiper 横向轮播 grid
Devaxpress Chinese description --tcxpropertiesstore (property store recovery control)
Devexpress implementation flow chart
Sensorless / inductive manufacturing of brushless motor drive board based on stm32
Pyflink implements custom sourcefunction
万字讲清 synchronized 和 ReentrantLock 实现并发中的锁
蓝牙模块:使用问题集锦
[pytorch FAQ] numpy:dll load failed while importing_ multiarray_ Umath: the specified module could not be found.