PCM data flow - part 1: Overview

http://blog.csdn.net/azloong/article/details/14105023


Kernel     - 3.4.5

SoC        - Samsung exynos

CODEC      - WM8994

Machine    - goni_wm8994

Userspace  - tinyalsa


ALSA/ASoC驱动有如下三部分构成:

·          Platform:通常指某款SoC平台,如exynos、omap、qcom等等。Platform又可细分两部分:

           1.  cpu dai:在嵌入式系统里面通常指CPU的I2S、PCM总线控制器,负责将音频数据从I2S tx FIFO搬运到CODEC(回放的情形,录制则方向相反)。cpu_dai通过snd_soc_register_dai()来注册。注:DAI是Digital Audio Interface的缩写,分为cpu_dai和codec_dai,这两者通过I2S/PCM总线连接;AIF是AudioInterface的缩写,一般分为I2S和PCM接口。

           2.  pcm dma:负责将dmabuffer中的音频数据搬运到I2S tx FIFO,这部分的逻辑比较复杂,以下几篇会对它详细阐述。音频dma驱动通过snd_soc_register_platform()来注册。值得留意的是:某些情形下是不需要dma操作的,比如Modem和CODEC直连,因为Modem本身已经把数据送到PCM FIFO了,这时只需启动codec_dai接收数据即可;该情形下,Machine驱动dai_link中需要指定.platform_name = "snd-soc-dummy", 这是虚拟出来的platform驱动,实现见sound/soc/soc-utils.c。

·          Codec:对于Playback来说,userspace送过来的PCM数据是经过抽样量化出来的数字信号,在codec经过DAC转换成模拟信号送到外放耳机输出,这样我们就可以听到声音了。Codec字面意思是编解码器,但芯片里面的功能部件很多,常见的有AIF、DAC、ADC、Mixer、PGA、Line-in、Line-out,有些高端的codec芯片还有EQ、DSP、SRC、DRC、AGC、Echo canceller、Noise suppression等部件。

·          Machine:指某一款机器,它把cpu_dai、codec_dai、modem_dai各个音频接口通过定义dai_link链结起来,然后注册snd_soc_card。和上面两个不一样,Platform和CODEC驱动一般是可以重用的,而Machine有它特定的硬件特性,几乎是不可重用的。所谓的硬件特性指:DAIs之间的链结;通过某个GPIO打开Amplifier;通过某个GPIO检测耳机插拔;使用某个时钟如MCLK/External OSC作为I2S、CODEC模块的基准时钟源等等。


从上面的描述来看,对于回放的情形,PCM数据流向大致是:

  1. copy_from_user      DMA              I2S    AIF->DAC->PGA/Mixer  
  2.      ^               ^                ^           ^  
  3.      |               |                |           |  
  4. ce------>dma buffer----->I2S tx FIFO----->CODEC------>SPK/HP/Earp  


这系列初步定为如下几个部分:

·          分析ALSA/ASoC的注册过程,soc-core如何找出并绑定dai_link上配置的cpu_dai、codec_dai、platform并逐一完成各自的初始化(probe)。

·          当pcm_open时,如何建立hw constraints;如何检查硬件参数(hw params)是否在hw constraints约束范围之内;如何回调platform/codec/machine的hw_params()完成各音频接口的时钟/格式配置。

·          当pcm_write时,1)如何把音频数据从用户态缓冲区拷贝到dma_alloc_writecombine()分配出来的dma buffer中;2)如何启动DMA把数据从dmabuffer搬运到I2S tx FIFO;3)如何启动I2S总线控制器把数据从I2S tx FIFO搬运到codec。但在这之前,会先分析dma ops函数集的作用及dma buffer分配过程,dma搬运的源地址和目的地址如何设定,这部分平台相关。

·          xrun出现的根源是什么?有些资料这样提及:“xrun指的是,声卡period一到,引发一个中断,告诉alsa驱动,要填入数据,或读走数据,但是问题在于alsa的读取和写入操作必须用户调用writei和readi才会发生的,它不会去缓存数据;如果上层没有用户调用writei和readi,那么就会产生overrun(录制时,数据都满了,还没被读走)和underrun(需要数据来播放,却不写入数据),统称为xrun”。这里源码上分析它是如何产生的,这样我们知道需要正确配置好哪个参数才能更好避免xrun或取得更好的表现性能。

·          最后探讨Android音频系统的deep buffer和low latency。


dai_link:machine驱动中定义的音频数据链路,它指定用到的cpu_dai、codec_dai、platform分别是什么。比如对于goni_wm8994平台的media链路:codec="wm8994-codec"、codec_dai="wm8994-aif1"、cpu_dai="samsung-i2s",pcm_dma="samsung-audio",这四者就构成了一条音频数据链路。一个系统可能有多个音频数据链路,比如media和voice,因此可以定义多个dai_link。如WM8994的典型设计,有三个dai_link,分别是AP-AIF1的"HIFI",BP-AIF2的"Voice",BT-AIF3(AIF3并不是真正的DAI,它需要桥接到AIF1或AIF2上才能工作)。


代码如下:

  1. static struct snd_soc_dai_link goni_dai[] = {  
  2. {  
  3.     .name = "WM8994",  
  4.     .stream_name = "WM8994 HiFi",  
  5.     .cpu_dai_name = "samsung-i2s.0",  
  6.     .codec_dai_name = "wm8994-aif1",  
  7.     .platform_name = "samsung-audio",  
  8.     .codec_name = "wm8994-codec.0-001a",  
  9.     .init = goni_wm8994_init,  
  10.     .ops = &goni_hifi_ops,  
  11. }, {  
  12.     .name = "WM8994 Voice",  
  13.     .stream_name = "Voice",  
  14.     .cpu_dai_name = "goni-voice-dai",  
  15.     .codec_dai_name = "wm8994-aif2",  
  16.     .codec_name = "wm8994-codec.0-001a",  
  17.     .ops = &goni_voice_ops,  
  18. },  
  19. };  

hw constraints:指平台本身的硬件特性限制,如所能支持的通道数/采样率/数据格式、DMA支持的周期大小(period size)范围、周期次数(period count)范围等,通过snd_pcm_hardware结构直观描述,如下:

  1. static const struct snd_pcm_hardware dma_hardware = {  
  2.     .info           = SNDRV_PCM_INFO_INTERLEAVED |  
  3.                     SNDRV_PCM_INFO_BLOCK_TRANSFER |  
  4.                     SNDRV_PCM_INFO_MMAP |  
  5.                     SNDRV_PCM_INFO_MMAP_VALID |  
  6.                     SNDRV_PCM_INFO_PAUSE |  
  7.                     SNDRV_PCM_INFO_RESUME,  
  8.     .formats        = SNDRV_PCM_FMTBIT_S16_LE |  
  9.                     SNDRV_PCM_FMTBIT_U16_LE |  
  10.                     SNDRV_PCM_FMTBIT_U8 |  
  11.                     SNDRV_PCM_FMTBIT_S8,  
  12.     .channels_min       = 2,  
  13.     .channels_max       = 2,  
  14.     .buffer_bytes_max   = 128*1024,  
  15.     .period_bytes_min   = PAGE_SIZE,  
  16.     .period_bytes_max   = PAGE_SIZE*2,  
  17.     .periods_min        = 2,  
  18.     .periods_max        = 128,  
  19.     .fifo_size      = 32,  
  20. };  

hw params:用户层设置的硬件参数,如channels、sample rate、pcm format、period size、period count;这些参数受hw constraints约束。

sw params:用户层设置的软件参数,如start threshold、stop threshold、silence threshold。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值