ALSA并非是最近才出现的新事物,它实际上已经发展很多年了,不过直到在kernel 2.6,才成为OSS名正言顺的替代者。ALSA提供的不只是几个声卡的驱动程序,而是从驱动程序到上层应用程序的一整套解决方案。最近花了点时间去阅读ALSA相关资料和代码,本文记录了一些在研究过程中所记的笔记。
按照ALSA官方网站上的说法,它有如下特点:
1. 有效的支持所有类型的音频接口,从普通的声卡到专业的音频设备。
2. 完全模块化的声卡驱动程序。
3. SMP和线程安全的设计。
4. 一个用户空间的函数库,提供了高层次的编程接口,从而简化了应用程序的开发。
5. 支持较老的OSS API,兼容大多数OSS应用程序。
为什么说ALSA比OSS更有前途呢?从前有人说ALSA会有更好的性能和更少延迟。但设计良好的OSS驱动程序在性能上并不比ALSA驱动程序差,所以现在大家都不在性能上做比较了,而是说ALSA有下面这些优点:
1. 分离了内核代码和用户空间的代码。只有必要的代码才放到内核中,其它代码在alsalib中实现。
2. alsa-kernel/alsa-driver的架构设计得更好,不同驱动程序之间可以共享更多代码。驱动程序的行为也更加统一,对应用程序来说也是有好处的。
3. alsa-lib提供了更易使用的API,让应用程序的开发更为简单
不过OSS似乎也不太服气,不甘心就这样让ALSA抢了风头。Opensound网站上有一篇《关于音频的神话与坊间传说》,写得非常有煽动性和说服力,可以认为是对ALSA支持者的反驳。我个人也认为ALSA上述的优点完全可以通过改进OSS来达到,而不必推倒重来,或者真正的焦点在于OSS没有开放源代码,使得linux爱好者决定自己搞一套。不管怎么样,OSS也不会这么快成为历史,因为它支持所有的unix系统,而且ALSA则侧重于linux系统。
ALSA由下面几部分组成:
1. Driver 内核驱动程序,包括硬件相关的和一些公共代码。有近30万行代码,太庞大的了,只选择性的看了core里一些代码。比如粗略的浏览了一遍《Writing an ALSA Driver》,写得不错。
2. Library 用户空间的函数库,这是给应用程序使用的。要包含头文件asoundlib.h,链接共享库libasound.so。
3. Lib-plugins 提供了两个插件,一个用jack模拟alsa接口,一个用oss来模拟alsa接口。高!alsa可以作为jack的后端,jack也可以作为alsa的后端,alsa可以模拟oss,oss也可以模拟alsa。
4. Utilities一些基于alsa的命令行小程序,可以作为示例代码参考。
5. Tools 一些小工具, 比如vxloader可以用来加载Firmware。
6. Firmware 一些设备的Firmware,这些Firmware由内核在适当的时候通过hotplug加载。Firmware其实就是一些程序,每个设备实际上就是一个独立的嵌入式系统,声卡也一样,有自己的程序。但为了节约成本和方便升级,这些设备可能只有RAM而没有ROM,在起动设备时,由系统(如linux)把设备的Firmware加载到设备的RAM里,设备才能运行。
7. OSS Compat 与OSS兼容的代码。
目前ALSA内核提供给用户空间的接口有:
1. Information Interface (/proc/asound)
2. Control Interface (/dev/snd/controlCX)
3. Mixer Interface (/dev/snd/mixerCXDX)
4. PCM Interface (/dev/snd/pcmCXDX)
5. Raw MIDI Interface (/dev/snd/midiCXDX)
6. Sequencer Interface (/dev/snd/seq)
7. Timer Interface (/dev/snd/timer)
和OSS类似,也是以文件的方式提供的,但这些接口是给alsalib使用的,而不是给应用程序使用的。应用程序应该使用alsalib,或者更高级的接口,比如jack提供的接口。
ALSA编程
开发基于ALSA的应用程序时,不要直接使用alsa-driver提供的接口,而应该使用alsalib的函数。alsalib提供了丰富的功能,估计有好几百个函数,幸好常用的并不多。ALSA的howto提供一个简单的播放和录音的示例,值得参考。
TODO:
继续阅读alsa-driver和alsalib的代码。
研究JACK的架构。
~~end~~
Read More...
Summary only...
转载时请注明出处和作者联系方式
作者联系方式:李先静
昨天从整体上介绍了一下音频处理流程,让大家对音频处理有个大致的概念,以便进行深入的研究。
整个音频处理可以分为三个部分:
用户空间
Mplayerservice 它是一个独立的服务进程,其主要作用有;
1. 首先是充当一个抽象层,隔离下层的软件和硬件平台,让应用程序不受下层变化的影响,比如以前我们用mplayer,现在改为用gstreamer,上层应用程序不需要做任何修改。
2. 其次是负责播放任务的调度,上层有很多个应用程序要播放声音,像SMS,MMS,EMAIL,电话,媒体播放器和GUI等等,它们之间如何协调,这是很重要的。
3. 最后它在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.
~~end~~
Read More...
Summary only...