android soundrecorder之三 录音流程及数据流向

转载请标注原文地址:http://blog.csdn.net/uranus_wm/article/details/12851111

 

前两篇文章分别介绍了linux alsa结构和android soundrecorder的应用层实现

除了板级的初始过程,其他都是关于类层次关系的一些静态说明

这章主要介绍下录音的动态过程,以及数据是如何一步步获取和保存的

还是先上图:


这个图大致介绍了soundrecord的流程,alsa到kernel部分还有个control模块这里没有画出来

下面一张图里面会提到,实际上control模块还是影响我们代码量主要的模块,主要就是mixer和muxer的配置

HAL层以上前面已经说过了,这里我们关注HAL以下部分:

  1. 应用层点击录音按钮
  2. tinyalsa打开设备文件节点/dev/snd/pcmC0D0c,给出相应的采样通道,采样率,一帧数据大小,总buffer大小等
  3. tinyalsa打开设备文件节点/dev/snd/controlC0,设置codec内部相关寄存器,选择输入输出device,配置内部route,即所谓dapm
  4. tinyalsa通过pcmC0D0c触发录音开始,dai_link上时钟开启,dapm建立后,从main_mic接收的pcm信号就会通过codec内部route发送到AIFADCDAT线上cpu exynos4412这边AIFDACDAT接收pcm信号数据后,通过移位器将数据保存到I2S的RX_FIFO
  5. RX_FIFO收到数据,触发DMA控制器开始拷贝数据,DMA(pl330)将RX_FIFO中的数据拷贝到DMA专有的内存缓冲,本例中snd_dma_buffer起始物理地址addr=0x6036_0000
  6. tinyalsa通过ioctl向设备节点/dev/snd/pcmC0D0c发起读数据请求,snd_pcm会将dma缓冲buffer中的数据拷贝到tinyalsa传入的用户buffer中

下面这张顺序图详细记录了soundrecorder开启录音之后alsa的交互流程:

 

这里我要提到的是在snd_pcm_open之后,有很大一段代码是做constraint检查

最开始我在调试的时候这个constraint检查一直不过,也就是上面的1.1节点,然后后面的过程没法进行下去

snd_pcm_open()时增加了一大推rule;这些rule的作用其实就是检查tinyalsa指定的config对于当前dai_link是否支持

int snd_pcm_hw_constraints_init(struct snd_pcm_substream *substream)
{
	struct snd_pcm_runtime *runtime = substream->runtime;
	struct snd_pcm_hw_constraints *constrs = &runtime->hw_constraints;
	int k, err;

	for (k = SNDRV_PCM_HW_PARAM_FIRST_MASK; k <= SNDRV_PCM_HW_PARAM_LAST_MASK; k++) {
		snd_mask_any(constrs_mask(constrs, k));
	}

	for (k = SNDRV_PCM_HW_PARAM_FIRST_INTERVAL; k <= SNDRV_PCM_HW_PARAM_LAST_INTERVAL; k++) {
		snd_interval_any(constrs_interval(constrs, k));
	}

	snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_CHANNELS));
	snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_BUFFER_SIZE));
	snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_BUFFER_BYTES));
	snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_SAMPLE_BITS));
	snd_interval_setinteger(constrs_interval(constrs, SNDRV_PCM_HW_PARAM_FRAME_BITS));

	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT,
				   snd_pcm_hw_rule_format, NULL,
				   SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 
				  snd_pcm_hw_rule_sample_bits, NULL,
				  SNDRV_PCM_HW_PARAM_FORMAT, 
				  SNDRV_PCM_HW_PARAM_SAMPLE_BITS, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_SAMPLE_BITS, 
				  snd_pcm_hw_rule_div, NULL,
				  SNDRV_PCM_HW_PARAM_FRAME_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1);
	if (err < 0)
		return err;
	err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FRAME_BITS, 
				  snd_pcm_hw_rule_mul, NULL,
				  SNDRV_PCM_HW_PARAM_SAMPLE_BITS, SNDRV_PCM_HW_PARAM_CHANNELS, -1);
.......
}

其过程是这样的:

首先snd_pcm_hardware会声明自己支持的通道数,格式等,buffer_bytes_max是buffer总大小,其他值我也没有详细研究

基本按照linux原生拷贝,没有修改

static const struct snd_pcm_hardware dma_hardware = {
	.info			= SNDRV_PCM_INFO_INTERLEAVED |
				    SNDRV_PCM_INFO_BLOCK_TRANSFER |
				    SNDRV_PCM_INFO_MMAP |
				    SNDRV_PCM_INFO_MMAP_VALID |
				    SNDRV_PCM_INFO_PAUSE |
				    SNDRV_PCM_INFO_RESUME,
	.formats		= SNDRV_PCM_FMTBIT_S16_LE |
				    SNDRV_PCM_FMTBIT_U16_LE |
				    SNDRV_PCM_FMTBIT_U8 |
				    SNDRV_PCM_FMTBIT_S8,
	.channels_min		= 1,
	.channels_max		= 2,
	.buffer_bytes_max	= 128*1024,
	.period_bytes_min	= PAGE_SIZE,
	.period_bytes_max	= PAGE_SIZE*2,
	.periods_min		= 2,
	.periods_max		= 128,
	.fifo_size		= 32,
};

codec_dai这边声明如下:

static struct snd_soc_dai_driver wm8994_dai[] = {
	{
		.name = "wm8994-aif1",
		.id = 1,
		.playback = {
			.stream_name = "AIF1 Playback",
			.channels_min = 1,
			.channels_max = 2,
			.rates = WM8994_RATES,
			.formats = WM8994_FORMATS,
		},
		.capture = {
			.stream_name = "AIF1 Capture",
			.channels_min = 1,
			.channels_max = 2,
			.rates = WM8994_RATES,
			.formats = WM8994_FORMATS,
		 },
		.ops = &wm8994_aif1_dai_ops,
	},
	};

cpu_dai这边声明如下:


                
  • 2
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值