整个音频处理可以分为三个部分:
用户空间
Mplayerservice 它是一个独立的服务进程,其主要作用有;
首先是充当一个抽象层,隔离下层的软件和硬件平台,让应用程序不受下层变化的影响,比如以前我们用mplayer,现在改为用gstreamer,上层应用程序不需要做任何修改。
其次是负责播放任务的调度,上层有很多个应用程序要播放声音,像SMS,MMS,EMAIL,电话,媒体播放器和GUI等等,它们之间如何协调,这是很重要的。
最后它在MVC模型中充当模型的作用,播放状态可以由此转发给关心这些事件的应用程序。
Gstreamer 它是Mplayerservice的实现,其主要负责音视频的编解码,对此不太熟悉,而且已经有很多资料介绍,这里就不多说了。
ALSA lib 现在播放声音用的ALSA,而不是OSS了,ALSA内核提供的接口比较底层,ALSA lib把它们包装成易用的接口函数。
内核空间
ALSA接口:通过/dev/snd下的设备文件与用户空间进行交互,对于声音数据,它提供了两种交互方式,一种是基于文件IO的读写方式,播放时向里面写数据,录音时从里面读数据。另外一种是基于内存映射的方式,通过mmap把DMA内存映射到用户空间,直接从里面读写数据。
ALSA core:这块是比较复杂的,它主要的功能是抽取各种不同驱动的公共代码;为上层提供统一的接口;为下层提供一个框架。不过我们主要关心的是PCM数据的播放和读写,以及对硬件的控制。
ALSA driver:这一部分就是实际的驱动程序,包括与上面对应的PCM和Control两部分。
硬件
音频芯片我们用的是WM9713,它的主要功能其实就是A/D转换和D/A转换,播放时把数字信号转换成模拟信号,录音时把模拟信号转换成数字信号。因为触摸屏也用到了A/D转换,为了重用这个功能,所以WM9713集成了音频处理和触摸屏处理两部分功能。
WM9713支持AC97标准,通过64个寄存器对它进行控制,这个在WM9713的datasheet里有详细的描述。
WM9713与PXA300之间通过同步串号SSP通信。PXA300在硬件上对AC97有支持,它提供了FIFO,所以音频数据可以通过DMA方式读写。
驱动程序导读
sound/arm/codec/ac97acodec.c包装了对AC97寄存器的读写操作,zy_ac97_acodec_write向指定的偏移量写入数据,zy_ac97_acodec_read从指定的偏移量读取数据。&(p_ac97_reg->codec_regs_primary_aud[0])是寄存器的基址。
sound/arm/codec/acodec.c 提供codec的初始化和~初始化以及电源管理的suspend和resume函数。AC97的PIN配置可以参考arch/arm/mach-pxa/zylonite.c:zylonite_ac97_pins。
sound/arm/codec/lt*是marvell另外一个硬件平台Littleton的驱动。
sound/arm/codec/wm9713.c,这里面主要是对AC97控制功能的包装,提供比如像设置音量之类的函数,zy_acodec_set_pen_down_interrupt/zy_wm9713_enable_touch/zy_wm9713_disable_touch/zy_wm9713_disable_touch几个函数用于触摸屏控制和采样。
sound/arm/codec/wm9713_bb.c好像是用于BaseBand的,里面的内容与wm9713类似,具体差别还不是很清楚,希望哪位高手能告知。有时间再研究一下。
sound/arm/mhn_audio_card.c 声卡驱动入口,提供audio_codec_zy_driver结构,通过driver_register注册到内核里去,在audio_codec_zy_probe函数中创建声卡对象,并注册到ALSA框架中。
sound/arm/mhn_audio_control.c 对codec/wm9713.c中的函数进一步包装,通过audio_codec_control_new为声卡创建一个控制对象。
sound/arm/mhn_audio_pcm.c 对PCM对象进行包装,audio_codec_pcm_new中可以创建HIFI PCM和Voice PCM,两个的差别,我不太清楚,希望哪位高手能告知。SSP的初始化和~初始化也是在这里做的。
sound/arm/mhn_audio_voice_pcm.c 实现了voice PCM对象,其核心就是结构voice_pcm_ops,该结构中最重要的成员是voice_pcm_trigger,voice_pcm_trigger负责DMA传输的起动和停止。
sound/core/pcm_native.c 对下层的PCM驱动提供包装,为上层提供统一的接口,snd_pcm_f_ops_playback文件操作结构提供播放功能的函数,snd_pcm_f_ops_capture文件操作结构提供录音功能的函数。
sound/core/control.c对下层的Control驱动提供包装,为上层提供统一的接口,snd_ctl_f_ops文件操作结构提供控制功能函数,其中主要是snd_ctl_ioctl函数。
播放的过程大致如下:
Snd_pcm_f_ops_playback.write即snd_pcm_write调用snd_pcm_lib_write
snd_pcm_lib_write调用Snd_pcm_lib_write1
Snd_pcm_lib_write1通过snd_pcm_lib_write_transfer把数据写入DMA buffer中,然后调用snd_pcm_start开始DMA传输数据到WM9713里去。
录音的过程大致如下:
Snd_pcm_f_ops_capture.read即snd_pcm_read调用snd_pcm_lib_read
snd_pcm_lib_read调用snd_pcm_lib_read1
snd_pcm_lib_read1调用snd_pcm_start从WM9713传输数据到DMA内存中,然后调用snd_pcm_lib_read_transfer拷贝数据到用户的buffer.