# SOUNDEC SDK软件架构说明

《SOUNDEC SDK软件架构说明》的目标读者群体是使用SNC8x系列专业音频处理器的开发工程师。本说明以SNC8600为例,提供了关于SNC8x系列音频处理器的软件架构说明,以及客户定制化接口及模板文件,旨在帮助客户快速上手SOUNDEC SDK并能够搭建基于九音科技标准样例的定制化音频应用。关于SNC8x系列处理器的对比,请参考产品对比表 (opens new window)

# 整体架构

Soundec Studio提供PC侧的开发调试功能, SOUNDEC SDK则提供固件侧完整的软件运行环境。

SOUNDEC SDK又分为上层的应用层,中间的Framework层以及底层驱动层:

  1. 底层提供完整的HAL及驱动层,HAL层以库文件形式提供,Driver层提供设备的统一接口,挂载,启动,各种set及get接口

  2. 中间层以Audio Manager为核心, 通过Audio Device管理音频硬件设备的挂载和驱动, 并通过 Audio Session管理设备间PCM数据流的输入输出

  3. 应用层提供了面向用户场景的基于Audio Device/Session的模板配置文件,使开发者可以进行快速扩展,实现定制的音频配置。

对于大多数开发者而言,直接使用应用层提供的模板配置文件进行扩展,可以快速搭建自己的音频链路,实现特定的应用场景,是SDK推荐的使用方式。当然开发者也可以绕过应用层,自行使用Audio Manager的接口来创建对应的音频通道,这需要对SDK的底层代码有一定的熟悉,难以做到快速开发。

# 中间层- Audio Manager详解

Audio Manger是整个中间层framework层的核心,面向音频处理,采用Device/Session设计, 根据应用的音频通路需求,开发者只需要新建和配置音频会话描述文件,系统即可通过 Audio Manager 自动加载对应的音频Device,从而完成音频模块的便携式配置,实现多入多出音频流通路的自由组合。

# Device/Session架构

# Device

# Session

  • 单入单出
  • 单入多出
  • 多入多出 Session 通路

# 处理逻辑

Audio Manager会根据开发者提供的配置文件执行如下操作

# 注册硬件/加载音频设备

硬件设备的注册接口见文件audio_hw_desc.c,通过其中auDeviceIfs数组定义了包含Codec(ADC&DAC), I2S, USB(Mic&Speaker)等音频设备及其描述接口

audioDevIf_t auDeviceIfs[AUDIO_DEVICE_MAX] = {
#if (CODEC_ADC_ENABLE)
	{
		.id = AUDIO_DEVICE_ADC_IN,
		.load = FALSE,
		.name = "adc",
		.rxCfgs = &auDrvCfg_adc,
		.txCfgs = NULL,
		.state = &auDrvSt_adc_in,
		.ops = &auDrvOps_adc_in,
	},
#endif
#if (CODEC_DAC_ENABLE)
	{
		.id = AUDIO_DEVICE_CODEC_OUT,
		.name = "codec",
		.load = FALSE,
		.rxCfgs = NULL,
		.txCfgs = &auDrvCfg_dac,
		.state = &auDrvSt_dac,
		.ops = &auDrvOps_dac,
	},
#endif
//其他音频模块配置描述...... 
#if (USB_ENABLE == 1)
	{
		.id = AUDIO_DEVICE_USB,
		.name = "usb",
		.load = FALSE,
		.rxCfgs = &auDrvCfg_usb_speaker,
		.txCfgs = &auDrvCfg_usb_mic,
		.state = &auDrvSt_usb,
		.ops = &auDrvOps_usb,
	},
#endif
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# 注册 Session/打开对应通路

音频通路 Session 的注册接口见文件 audio_session_desc_xx.c,以双麦会议音箱应用为例,其音频通路配置文件为audio_session_desc_2mic_meetingbox.c。此应用支持两路音频通路:AUDIO_SESSION_0 和 AUDIO_SESSION_1。

  • AUDIO_SESSION_0 支持 2 路输入(capture),1路输出(playback),输入信号经过(session0Proc)处理后输出;

  • AUDIO_SESSION_1 支持 1 路输入(capture),1路输出(playback),输入信号不需要处理,直接输出:

auSessionDesc_t auSessionDesc[AUDIO_SESSION_MAX] = {
	{
		.id 				= AUDIO_SESSION_0,
		.sessionPolicy 		= &session0Policy,									
		.captureNum 		= 1,
		.capture 			= session0StreamIn,
		.procIf 			= NULL,
		.playbackNum 		= 1,
		.playback 			= session0StreamOut,
	},
	{
		.id 				= AUDIO_SESSION_1,
		.sessionPolicy 		= &session0Policy,									
		.captureNum 		= 1,
		.capture 			= session1StreamIn,
		.procIf 			= NULL,
		.playbackNum 		= 1,
		.playback 			= session1StreamOut,
	},
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

通过调用 audioManager_init()接口,系统会根据 Session中的通路描述,以及capture 和playback中的格式说明,自动挂载对应的音频设备,完成 Audio Manager的初始化。通过调用audioManager_open_session(sessionID)接口,实现相关通路的开启。调用audioManager_close_session(sessionID)接口则会关闭对应通路。

# 数据流的读写处理

int8_t auRxCompleteCB(void *arg, void *data, uint32_t *len, auSlotSize_t bitSlot)
{
	auStream_t *stream = (auStream_t *)arg;
	if(!stream->var.suspend)
	{
		fifo_add_data(stream->fifo, data, *len, bitSlot);
		auSession_t *pSession = (auSession_t *)stream->fifo->fuc->get_sdata(stream->fifo);
		if(fifo_is_enough(stream->fifo) || fifo_is_empty(stream->fifo))
		{
			if(pSession->proc)
			{
				if (stream->ops->tuneSampleRate && fifo_get_playing_state(pSession->playback[0]->fifo))
					stream->ops->tuneSampleRate(fifo_get_data_len(pSession->playback[0]->fifo), fifo_get_fifo_size(pSession->playback[0]->fifo));
			}
			else
			{
				if (stream->ops->tuneSampleRate && fifo_get_playing_state(stream->fifo))
					stream->ops->tuneSampleRate(fifo_get_data_len(stream->fifo), fifo_get_fifo_size(stream->fifo));
			}
		}
	}
	return AUDIO_MNGR_FAIL;
}

int8_t auTxCompleteCB(void *arg, void *data, uint32_t *len, auSlotSize_t bitSlot)
{
	auStream_t *stream = (auStream_t *)arg;
	if(!stream->var.suspend)
	{
		fifo_get_data(stream->fifo, data, len, bitSlot);

		if(fifo_is_enough(stream->fifo) || fifo_is_empty(stream->fifo))
		{
			if (stream->ops->tuneSampleRate)
				stream->ops->tuneSampleRate(fifo_get_data_len(stream->fifo), fifo_get_fifo_size(stream->fifo));
		}

	}
	return AUDIO_MNGR_FAIL;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40

经过audioManager_init()的调用,所有已挂载的音频设备的数据接收和发送,都将在统一的接口中进行处理:fifo_push/fifo_pop

# 数据缓存处理和优化

所有音频数据的缓存区的创建、数据缓存、格式转换、优化管理,通过fifo_manager 实现;

typedef struct {
	void (*init) 					(struct fifo_handle_st *p_fifo);	/*len in byte*/
	void (*reset)					(struct fifo_handle_st *p_fifo, auStrmFormat_t streamFormat);
	void (*skip)					(struct fifo_handle_st *p_fifo, uint32_t pos, uint32_t len);
	void (*insert)					(struct fifo_handle_st *p_fifo, uint32_t pos, uint32_t len);
	uint32_t (*push)				(struct fifo_handle_st *p_fifo, uint8_t *__restrict data, uint32_t sizeInByte, auSlotSize_t bitWidth);
	uint32_t (*pop) 				(struct fifo_handle_st *p_fifo, uint8_t *data, uint32_t *len, auSlotSize_t bitWidth);
	uint32_t (*push_skip)			(struct fifo_handle_st *p_fifo, uint32_t len);
	uint32_t (*pop_skip) 			(struct fifo_handle_st *p_fifo, uint32_t *len);
	uint32_t (*get_fifo_head)		(struct fifo_handle_st *p_fifo);//return readPtr
	uint32_t (*get_fifo_tail)		(struct fifo_handle_st *p_fifo);//return writePtr
	bool (*is_empty)				(struct fifo_handle_st *p_fifo);
	bool (*is_full) 				(struct fifo_handle_st *p_fifo);
	bool (*is_enough)				(struct fifo_handle_st *p_fifo);
	uint32_t (*get_free_len)		(struct fifo_handle_st *p_fifo);
	uint32_t (*get_data_len)		(struct fifo_handle_st *p_fifo);
	uint32_t (*get_fifo_size)		(struct fifo_handle_st *p_fifo);
	uint32_t (*get_fifo_thresholdLevel)		(struct fifo_handle_st *p_fifo);
	uint8_t (*get_fifo_share)		(struct fifo_handle_st *p_fifo);
	fifoOffset_t (*get_status)		(struct fifo_handle_st *p_fifo);
	uint32_t (*add_share_fifo)		(struct fifo_handle_st *p_srcFifo, struct fifo_handle_st *p_shareFifo);
	uint32_t (*get_sdata)				(struct fifo_handle_st *p_fifo);
	void (*set_playing_state) 		(struct fifo_handle_st *p_fifo, bool isPlaying);
	bool (*get_playing_state) 		(struct fifo_handle_st *p_fifo);
}fifo_ctrl_t;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 应用层 - 定制Audio应用

应用层提供了很多标准样例音频应用以及相应的模板文件(音频会话描述文件),开发者基本无需考虑上一节描述的中间层和底层驱动层的内部实现逻辑,也不需要考虑音频设备的初始化调用等流程,而只需要根据架构的要求,在模板配置文件中描述音频走向及处理格式:音频的数据来源、音频源数量、源数据的处理(注册算法处理函数)、选择输出设备,即可生成自己的定制音频应用。

# 新增项目配置

根据不同的硬件设计及资源,配置板级资源:boardConfig.h,在其中定义并使能项目配置

#define D_CONFIG_XXXX

#define BOARD_VER 0x0101
#define D_CONFIG_2MIC_MEETING_BOX					0
#define D_CONFIG_2MIC_USB_HEADPHONE					0
#define D_CONFIG_2MIC_BT_HEADPHONE					0
#define D_CONFIG_USB_LIVE_MICROPHONE				0

#if D_CONFIG_2MIC_MEETING_BOX
#define PROJECT_NAME								"2mic_meeting_box"
#include "user_config_2mic_meetingbox.h"
#elif D_CONFIG_2MIC_USB_HEADPHONE
#define PROJECT_NAME								"2mic_usb_headphone"
#include "user_config_2mic_usb_headphone.h"
#elif D_CONFIG_2MIC_BT_HEADPHONE
#define PROJECT_NAME								"2mic_bt_headphone"
#include "user_config_2mic_bt_headphone.h"
#else
#define D_CONFIG_DEFAULT							1
#define PROJECT_NAME								"Soundec_default"
#include "user_config_default.h"
#endif

#endif  /* __BOARDCONFIG_H__ */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 新增配置文件和音频描述文件

为了支持客制化应用的快速开发,参考 default_config目录,创建配置文件和音频描述文件:

配置文件:user_config_xxx.h

音频描述文件:audio_session_desc_xxx.c

# 修改配置文件

以默认配置文件 user_config_default.h为例,根据相应的模块说明配置相关功能。详细功能开关说明可以 参考对应的ApplicationNote文件。

/*****************************************************
 *  Version config
 ****************************************************/
#define CONFIG_PRODUCT_VERSION				0x2013			/*version number*/

/*****************************************************
 *  Chip config
 ****************************************************/
#define CONFIG_CHIP_TYPE					CHIP_SNC8600
#define CONFIG_VDD_IO_18					0				/*0:VDD_IO 3.3V 1:VDD_IO 1.8V*/
/*****************************************************
 *  Module:		PLL
 ****************************************************/
#define SYSTEM_CRYSTAL						SYSTEM_CRYSTAL_24MHZ
#define PLL_OUT_VALUE						PLLOUT_220MHZ

//#define JTAG_DEBUG_ENABLE

/*****************************************************
 *  Module:		UART
 ****************************************************/
#define UART_ENABLE							1
#if(UART_ENABLE == 1)
//user code
#define UART_BUARD_RATE						BAUDRATE_115200	/*baud rate*/
#define UART_TX_INT_ENABLE					0
#define UART_RX_INT_ENABLE                  1
#define UART_RECEIVE						0
#define UART_QUEUE_SIZE						300 			/*decide by delay in onFifoReady() and instruction length*/
#endif

/*****************************************************
 *  Module:		AUDIO_MANAGER
 ****************************************************/
#define AUDIO_MANAGER						1   			/*must be 1*/
#if AUDIO_MANAGER
//#define TEST_AU_MANAGER
#endif

/*****************************************************
 *	Module:		DMA
 ****************************************************/
#define DMA_ENABLE							0
#define DMAC_CHX_NULL						6
#if(DMA_ENABLE)
#if(AUDIO_MANAGER)
#define DMA_CHX_MEM_TO_MEM					0
#define DMA_CHX_MEM_TO_I2S1					DMAC_CHANNEL_1
#define DMA_CHX_ADC_TO_MEM					DMAC_CHANNEL_5
#else
#define DMA_TEST_MODE_ENABLE				0
#if(DMA_TEST_MODE_ENABLE)
#define DMA_TEST_I2S_USB_ENABLE				0
#define DMA_TEST_CODEC_ADC_ENABLE			1
#endif	//DMA_TEST_MODE_ENABLE
#endif	//AUDIO_MANAGER
#endif	//DMA_ENABLE

/*****************************************************
 *  Module:		Codec
 ****************************************************/
#define CODEC_ENABLE						1
#if (CODEC_ENABLE)
#define CODEC_ADC_ENABLE  					1
#define CODEC_ADC12_ENABLE					1
#define CODEC_ADC34_ENABLE					0
#define CODEC_ADC56_ENABLE					0
#define CODEC_ADC78_ENABLE					0
#define CODEC_ADC9A_ENABLE					0

#define CODEC_DAC_ENABLE					1

#define CODEC_MASTER						1		/*SLAVE MODE:ADC12 must be initialized, or DAC can not work normally.*/
#define CODEC_ADC_DATA_MODE					CODEC_ADC_DATA_MODE_24BIT
#define CODEC_SLAVE_FRAC_SRC				CODEC_SLAVE_FRAC_SRC_SNC
#define CODEC_SLAVE_FRAC_SHARE				CODEC_SLAVE_FRAC_SHARE_DEDICATED
#define CODEC_FIFO_AE_LEVEL					4		/*Almost empty level*/
#if(DMA_ENABLE && AUDIO_MANAGER)
#define CODEC_FIFO_AF_LEVEL					1		/*Almost full level*/
#else
#define CODEC_FIFO_AF_LEVEL					4		/*Almost full level*/
#endif
#define ADC12_IS_AMIC						1		/* 1:Analog Microphone; 0:Digital Microphone*/
#define ADC_MICBIAS							1
#define CODEC_MIC_AGC_ENABLE				0
#define CODEC_SPK_DRC_ENABLE				0
#define DAC_AIAS 							1		/*DAC sample rate tuning*/
#define ADCX_AIAS 							0		/*ADC sample rate tuning(include all)*/
#define ADC12_AIAS 							1		/*ADC12 sample rate tuning*/
#define ADC3456_AIAS 						0		/*ADC3456 sample rate tuning*/
#define ADC789a_AIAS 						0		/*ADC789a sample rate tuning*/

#define CONFIG_CODEC_FREQUENCY				SAMPLING_RATE_48000
#endif

/*****************************************************
 *  Module:		USB
 ****************************************************/
#define USB_ENABLE     						1
#if USB_ENABLE

#define USB_PID								0x0829
#define USB_PRODUCT_STRING        			"USB Headset"

#define TEST_USB_SWITCH						1

#define USB_SPEED_CFG          				USB_SPEED_HIGH 	/*UAC10:USB_SPEED_HIGH or USB_SPEED_FULL UAC20:USB_SPEED_HIGH*/

#define SUPPORT_USB_HID						1
#define SUPPORT_USB_SPK    					1
#define SUPPORT_USB_MIC        				1
#define SUPPORT_USB_24BIT_ONLY              0
#define SUPPORT_UAC20						1
#define SUPPORT_USB_LPM						0
#define SUPPORT_USB_USR_STR					0
#if ((SUPPORT_USB_SPK)&&(SUPPORT_USB_MIC))
#define SUPPORT_SPK_SIDETONE            	0
#else
#define SUPPORT_SPK_SIDETONE            	0
#endif

#define SUPPORT_USB_INSERT_DETECTION		0    	/*USB insert detect*/
#if(SUPPORT_USB_INSERT_DETECTION)
#define TEST_DETECT_PC						0		/*identify PC or mobile phone*/
#if(SUPPORT_UAC20)
#define SUPPORT_UAC_SELF_ADAPTION			1		/*USB adaption:switch to UAC10 if UAC20 is not supported*/
#endif
#endif


#if(SUPPORT_USB_MIC)
#define	USB_MIC_CHANNELS                    2
#define USB_MIC_CHANNEL_SEL					(AUDIO_CHANNEL_LEFT | AUDIO_CHANNEL_RIGHT)

//multiple channels example, tested in 16bit 48k
/* 4-ch example
#define	USB_MIC_CHANNELS                    4
#define USB_MIC_CHANNEL_SEL					(AUDIO_CHANNEL_LEFT | AUDIO_CHANNEL_RIGHT | AUDIO_CHANNEL_L_SURROUND | AUDIO_CHANNEL_R_SURROUND)
*/

#define CONGIFG_USB_DEV_VOLUME_FIT_USBH
#define SUPPORT_USB_FEEDBACK				0
#if(SUPPORT_USB_FEEDBACK)
#define FEEDBACK_SOF_RATE					0x03U	/*2^(x)*/
#endif

#endif

/*****************************************************
 *  Module:		Alto tool
 ****************************************************/
#if USB_ENABLE
#define SUPPORT_ALTOTOOL        			0
#if (SUPPORT_ALTOTOOL)
#define SUPPORT_DSP_EQ    					1
#if (SUPPORT_DSP_EQ)
#define SUPPORT_MIC_EQ                		1
#define SUPPORT_SPKER_EQ              		1
#if (SUPPORT_SPKER_EQ)
#define SUPPORT_SPKER_STEREO_EQ				1
#endif	//SUPPORT_SPKER_EQ
#endif	//SUPPORT_DSP_EQ
#define SUPPORT_ALTOTOOL_CODEDC     		1
#define SUPPORT_ALTOTOOL_I2S           	 	1
#define SUPPORT_ALTOTOOL_DEBUG          	1
#define SUPPORT_ALTOTOOL_COMM           	1

#endif	//SUPPORT_ALTOTOOL
#endif	//USB_ENABLE

/*****************************************************
 *  Module:		I2S
 ****************************************************/
#define I2S_ENABLE    						0
#if (I2S_ENABLE == 1)
#define I2S1_ENABLE							0
#define I2S2_ENABLE							0
#define I2S3_ENABLE							0
#define I2S_TX_FIFO_LEVEL					8  /*1-16*/
#define I2S_RX_FIFO_LEVEL					8  /*1-16*/
#define I2S_SAMPLE_RATE_DETECT 				0
#define I2S_FIFO_WORD_LENGTH				5  /*2:16bit 4:24bit 5:32bit  192k do not support 32bit*/
#if(DMA_ENABLE)
#define I2S_DMA_ENABLE
#endif
#if(USB_ENABLE && SUPPORT_USB_SPK)
//#define TEST_USB_I2S_SYNC
#endif
#if(CODEC_ENABLE && CODEC_DAC_ENABLE)
//#define TEST_I2S_DAC_SYNC
#endif
#endif

/*****************************************************
 *	Module:		Flash
 ****************************************************/
#define FLASH_ENABLE						1
#if(FLASH_ENABLE)
#define FLASH_DEBUG_ENABLE					1
#define FLASH_WRITE_PROTECT_ENABLE			0
#define FLASH_SFC_CACHE_ENABLE				0
#define FLASH_SAVE_BANK_ENABLE				1
#if(FLASH_SAVE_BANK_ENABLE)
#define FLASH_SAVE_BANK_DEBUG_ENABLE		1
#endif
#define FLASH_GET_UID_ENABLE				1
#if(FLASH_GET_UID_ENABLE)
#define FLASH_UID_AS_USB_SN_ENABLE			1
#endif
#endif

/*****************************************************
 *  Module:		AUX ADC
 ****************************************************/
#define AUX_ADC_ENABLE						1
#if(AUX_ADC_ENABLE)
#define AUX_ADC_INTR_ENABLE					0
#define AUX_ADC_USE_CH0						1	/*if 0, use ch1*/
#define APP_ADC_KEY_ENABLE					1
#endif	//AUX_ADC_ENABLE

/*****************************************************
 *  Module:		RTC
 ****************************************************/
#define RTC_ENABLE							0
#if RTC_ENABLE == 1
//use code
#define RTC_ALARM_INT_ENABLE				1
#define RTC_MIN_INT_ENABLE					1
#define RTC_SEC_INT_ENABLE					1
#define RTC_SAMP_INT_ENABLE					1
#define RTC_WD_INT_ENABLE					1
#endif

/*****************************************************
 *  Module:		PWM
 ****************************************************/
#define PWMX_ENABLE							0
#if PWMX_ENABLE == 1
//use code
#define PWM_NORMAL_ENABLE					1
#define PWM_GPIO_MODE_ENABLE				1
#define PWM_TIMER1_MODE_ENABLE				1	/*count a*/
#define PWM_TIMER2_MODE_ENABLE				1	/*cycle count*/

#define PWM_INT_ENABLE						1
#endif

/*****************************************************
 *  Module:		I2C
 ****************************************************/
#define I2C_ENABLE							0
#if I2C_ENABLE == 1

#define I2C_MASTER_ENABLE					0
#if(I2C_MASTER_ENABLE == 1)
#define I2C_MASTER_SEL						I2C1_BASE
#define I2C_MASTER_SEL_IRQ  				I2C1_IRQn
#define TEST_I2C_MASTER						1
#endif //I2C_MASTER_ENABLE

#define I2C_SLAVE_ENABLE					0
#if(I2C_SLAVE_ENABLE == 1)
#define SLAVE_ADDRESS  						0x21
#define I2C_SLAVE_SEL						I2C2_BASE
#define I2C_SLAVE_SEL_IRQ  					I2C2_IRQn
#define TEST_I2C_SLAVE						1
#endif	//I2C_SLAVE_ENABLE
#endif //I2C_ENABLE
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269

# 修改音频通路描述文件

根据音频通路模型,描述每一路音频配置。每个通路均支持多路音频输入和多路音频输出,用户根据应用需求分别在 capture 和 playback 中描述输入和输出流的信息。

# 描述音频信号通路

以双麦会议音箱应用为例,音频描述文件为audio_session_desc_2mic_meetingbox.c其配 置支持两路音频通路:AUDIO_SESSION_0 和 AUDIO_SESSION_1。

  • AUDIO_SESSION_0 支持 2 路输入(capture),1路输出(playback),输入信号经过(session0Proc) 处理后输出;

  • AUDIO_SESSION_1 支持 1 路输入(capture),1路输出(playback),输入信号不需要处理,直接输 出:

auSessionDesc_t auSessionDesc[AUDIO_SESSION_MAX] = {
	{
		.id = AUDIO_SESSION_0,
		.sessionPolicy = &session0Policy,			
		.captureNum = 2,
		.capture = session0StreamIn,
		.procIf = &session0Proc,	
		.playbackNum = 1,
		.playback = session0StreamOut,
	},	
	{
		.id = AUDIO_SESSION_1,
		.captureNum = 1,
		.capture = session1StreamIn,
		.procIf = NULL,
		.playbackNum = 1,
		.playback = session1StreamOut,
	},
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 配置音频信号

以双麦会议音箱应用为例,配置音频流的输入、处理和输出信息:

# 1)输入配置----Capture

AudioManager 使用 Capture 相关定义描述输入源信息,其中: mems12_in作为音箱参考信号的输入源,mems34_in 作为两路数字麦克风的输入源;

auCaptureIf_t *session0StreamIn[]=
{
	&mems12_in,
	&mems34_in,
};
1
2
3
4
5

通过 auCaptureIf_t 配置接口,分别描述输入设备的硬件信息和音频格式,以mems12_in为例:

auCaptureIf_t mems12_in 	= {
	.capture = {
		.devId = AUDIO_DEVICE_MEMS12_IN,										//device id
		.type = STREAM_MUSIC,													//reserved
	},
	.format = {
		.channlesPerFrame	= 2,												//channels
		.frameLength		= SESSION0_FRAME_SIZE * SESSION0_BUFFER_MULTIPLE,   //points
		.pcmFormat			= PCM_PLANAR_FORMAT,								//data format:LL...LL RR...RR
		.bitSlot 			= BIT_SLOT_32,										//bit width for data push & pop, support 16bit/32bit
		.sampleRateHz 		= SAMPLING_RATE_16000,								//ADC sample rate
		.sampleRateHzMax 	= SAMPLING_RATE_16000,								//reserved
	},
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14

1)Capture输入源配置

a) devId 选择硬件设备为 ADC12(AUDIO_DEVICE_ MEMS12_IN)

b) 音频流类型为 Voice

2) Format音频格式

a) channelsPerFrame = 2 双声道

b) frameLength = 20,注意此处 frameLength 以时间ms(毫秒)为单位,用于表示 Mems12 的数据 缓存区大小

c) pcmFormat = PCM_PACKED_FORMAT,描述音频流的数据格式,支持两种存放格式:

◆声道交错存储:PCM_PACKED_FORMAT,如 LRLR...LR

◆ 声道独立存储:PLANAR_FORMAT,如 LLL...RRR

d) bitSlot:默认数据位宽

e) sampleRateHz:默认采样率,单位为 Hz

f)sampleRateHzMax:最大采样率,单位为 Hz

[注意]:如果输入信号需要算法处理,音频格式根据算法需求配置

# 2)处理配置----Proc

AudioManager 使用 Proc 相关定义描述音频流的处理信息: mems12_in和mems34_in 信号送入 session0Proc 中描述的 onFifoReady 回调函数进行处理。通过 auProcIf_t 接口,描述当前 session 通路上的算法信息,其中: proEvent用于描述算法对输入端的信号需求;outputFormat 用于描述算法输出格式信息。

auProcIf_t session0Proc = {
	.procEvent = {
		.frameThreshold = SESSION0_FRAME_SIZE,									//trigger soft interrupt threshold
		.onFifoReady = meetingBox_onFifoReady,									//soft interrupt process function
		.channelCopy = FALSE,													//reserved
		.irqNum = SW_IRQn,														//interrupt type
	},
	.outputFormat = {
		.channlesPerFrame	= 1,												//output channels
		.frameLength		= SESSION0_FRAME_SIZE * SESSION0_BUFFER_MULTIPLE,	//points
		.pcmFormat			= PCM_PACKED_FORMAT,								//data format:LR LR LR
		.bitSlot 			= BIT_SLOT_32,										//bit width for data push & pop, support 16bit/32bit
		.sampleRateHz 		= SAMPLING_RATE_16000,								//reserved
		.sampleRateHzMax 	= SAMPLING_RATE_16000,								//reserved
	},
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 3)输出配置----Playback

AudioManager 使用 Playback 相关定义描述音频流的输出信息,以下描述表示Session0的信号通过USB录音通道输出。

auPlaybackIf_t *session0StreamOut[] = {
	&usb_record,
};
1
2
3

通过 auPlaybackIf_t配置接口,描述输出设备的硬件信息、音频格式,以usb_record为例,其中关于Playback的设备信息和音频格式描述参考Capture:

auPlaybackIf_t usb_record 	= {
	.playback = {
		.devId = AUDIO_DEVICE_USB,												//device id
		.type = STREAM_VOICE,													//reserved
	},
	.format = {
		.channlesPerFrame	= 2,												//channels
		.frameLength		= SESSION0_FRAME_SIZE * SESSION0_BUFFER_MULTIPLE,	//points
		.pcmFormat			= PCM_PACKED_FORMAT,								//data format:LR LR LR
		.bitSlot 			= BIT_SLOT_32,										//bit width for data push & pop, support 16bit/32bit
		.sampleRateHz 		= SAMPLING_RATE_16000,								//USB record sample rate
		.sampleRateHzMax 	= SAMPLING_RATE_16000,								//reserved
	},
	.channelCopy = TRUE,														//two channels output the same data
	.fifoId		= 0,															//0~N,N<playbackNum, share fifo use the same fifoId
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

其中配置channelCopy:用于支持声道复制功能,配置此项为True表示将单声道音频源用双声道输出。

# 4)配置通路的通用属性

每个通路通过 auPolicyPatam_t结构体来定义和存储通路上的音频设置和处理控制,操作对整个音频通路(Session)有效。部分成员未定义使用功能,用于以后扩展

auPolicyParam_t session0Policy ={
	.interruptUnmixedSession = FALSE,											
	.syncSamplerate = TRUE,														
	.procBypass = FALSE,														

	.bitSlot = BIT_SLOT_32,														
	.sampleRate = SAMPLING_RATE_48000,											
	.maxSampleRate = SAMPLING_RATE_48000,										
	.maxLatencyInFrames = 0,													
};
1
2
3
4
5
6
7
8
9
10

# 算法集成

SDK本身支持音频算法的无缝导入,开发者可以利用现有SDK提供的auProcIf_t接口开发和移植自己的算法。另外,为了更好的支持算法执行效率,减少算法团队在嵌入式平台上的指令优化开销,九音科技SDK提供了支持32位、24位、16位等运算的HiFi3 浮点运算库和头文件,用于算法加速,开发者可以很方便的在SDK的xplorer开发环境中进行算法的开发或移植。

NatureDSP Signal Library是一个通用DSP库,包含了FIR滤波器,IIR滤波器、基本数学函数、矩阵运算和 FFT等函数,如下表所示:

Vectorized Version Scalar Version Purpose
FIR filters and related functions
bkfir Block real FIR filter
cxfir Complex block FIR filter
firdec Decimating block real FIR filter
firinterp Interpolating block real FIR filter
fir_convol, cxfir_convol Circular/linear convolution
fir_xcorr Circular/linear correlation
fir_acorr Circular/linear autocorrelation
fir_blms Blockwise Adaptive LMS algorithm
IIR filters
bqriir, bqciir Biquad Real block IIR
latr Lattice block Real II
Mathematics
vec_recip scl_recip Reciprocal on a vector of Q31 numbers
vec_divide scl_divide Division
vec_logn scl_logn Different kinds of logarithm
vec_log2 scl_log2 Different kinds of logarithm
vec_logn scl_logn Different kinds of logarithm
vec_antilog2 scl_antilog2 Different kinds of antilogarithm
vec_antilog10 scl_antilog10 Different kinds of antilogarithm
vec_antilogn scl_antilogn Different kinds of antilogarithm
vec_sqrt scl_sqrt Square root
vec_rsqrt scl_rsqrt Reciprocal square root
vec_sine scl_sine Sine
vec_cosine scl_cosine Cosine
vec_tan scl_tan Tangent
vec_atan, vec_atan2 scl_atan, scl_atan2 Arctangent
vec_tanh32x32 scl_tanh32x32 Hyperbolic tangent
vec_sigmoid32x32 scl_sigmoid32x32 Sigmoid
vec_softmax32x32 Softmax
vec_int2float scl_int2float Integer to float conversion
vec_float2int scl_float2int Float to integer conversion
Complex Mathematics
vec_complex2mag scl_complex2mag Complex magnitude
vec_complex2invmag scl_complex2invmag Reciprocal of complex magnitude
Vector Operations
vec_dot Vector dot product
vec_add Vector sum
vec_power Power of a vector
vec_shift, vec_scale Vector scaling with saturation
vec_bexp scl_bexp Common exponent
vec_min, vec_max Find a maximum/minimum in a vector
**Matrix Operations **
mtx_mpy Matrix multiply
mtx_vecmpy Matrix by vector multiple
Matrix Decomposition and Inversion Functions
mtx_inv Matrix inversion
Fitting/Interpolation
vec_poly Polynomial approximation
FFT/DCT
fft_cplx FFT on complex data
fft_real FFT on real data
ifft_cplx Inverse FFT on complex data
ifft_real Inverse FFT forming real data 2.9.4
fft_cplx_ie FFT on complex data with optimized memory usage
fft_real_ie FFT on real data with optimized memory usage
ifft_cplx_ie Inverse FFT on complex data with optimized memory usage
ifft_real_ie Inverse FFT forming real data with optimized memory usage
dct,mdct Discrete cosine transform
dct2d, idct2d 2D Discrete cosine transforms