Linux Audio Stack & ALSA
来源:互联网 发布:淘宝军刺暗语 编辑:程序博客网 时间:2024/06/05 06:04
Linux Audio Stack
oss
- OSS借用了UNIX里”一切都是文件”的概念,。
把声卡模拟成一个/dev/dsp设备, 多块声卡就是dsp0, dsp1… - 要播放声音?打开dsp设备.往里面write数据就可以了.
- 设置比特率?用ioctl设置即可.
- 最简单的接口, 也是最没用的接口.因为应用程序完全没法对声音的播放进行控制.
- OSS是个阻塞的接口, write后, 要声音播放完毕才返回.
显然很糟糕, 因为在write和下一次write的微小时间间隔内, 声音出现了不连续.解决办法就是使用异步的write. write完了, 用ioctl轮询, 看还剩下多少数据.注意, 是轮询.轮询到还剩下不到1ms就播放玩了, 马上再write一个buffer过去.这就是OSS接口下的播放.
ALSA
- 当然OSS这个声音接口实在是太简单了, 于是他们搞了一个ALSA接口.ALSA先进了一些, 有了PLL接口.除了可以向声卡发送数据,
还可以为数据附带时钟信息.注意, 可以为数据附带时钟信息.意味着你可以不用精确的等待到一个时间再送出数据,
而是指定一块数据在指定的时间播放.还可以设定播放到某个byte的时候, 产生时钟信号通知程序, 好让程序能继续准备下一块buffer继续播放.然后asla又提供了一个高级的接口, libasound.so, libasound.so可以读取
/etc/asound.conf
、/usr/share/alsa/alsa.conf
、~/.asound.conf
配置文件, 还可以加载各种插件, 插件又可以通过配置文件配置.相当的高级.可以说, alsa是为专业的音频应用准备的.不论是OSS还是ALSA, 在民用声卡上都有一个致命的缺点:他们不支持混音.OSS和ALSA都只是声卡的接口.如果声卡本身不支持硬件混音,
那么程序就只能独占声卡.表现为只能有一个程序出声.好在alsa有一个补救措施, 那就是libasound.so.alsa不推荐直接使用alsa的内核接口编程,而是使用libasound.so的接口.如果使用了libasound.so的接口, 用户可以配置一个叫”dmix”的插件.然后把dmix模拟出来的声卡作为默认声卡.大家都输出到dmix, dmix再收集多个程序的声音, 一起混音然后输出给硬件.
这个问题看似解决了.实际上没有解决.受限于alsa的接口, dmix的实现质量相当的糟糕.首先, dmix为了混音, 强制重采样.重采样导致了音质的劣化.
其次, dmix没有C/S结构.通过共享内存协作完成混音和共享声卡, 一个程序的dmix出问题, 会导致所有正在发声的程序崩溃.ALSA的另一个缺点, 在使用了多个声卡后(蓝牙和HDMI普及了啊), 也开始暴露.那就是不能动态切换输出声卡.
我希望我带上蓝牙耳机后, 声音能从扬声器直接转移到耳机里播放.但是ALSA的先天缺陷导致无法实现这个功能.
播放器必须重新打开蓝牙声卡.也就是说, 把切换输出的责任全部交给播放器实现.播放器可以实现,
问题是所有的播放器都必须实现.另一个问题是, 用户必须到各个播放器下依次调节.非常麻烦.
PulseAudio
为了解决ALSA固有缺陷的目的, PulseAudio又出现了.
PulseAudio解决办法也是提供一个混音服务.混音服务后台执行, 独占声卡的访问权限.其他程序要播放声音的,
都需要将声音数据交给pulseaudio.由pulseaudio执行混音.那么, 重采样问题怎么解决呢?
pulseaudio提供了一个动态采样率模式.简单说明一下工作原理- A程序播放44100hz的声音, 提交给pulseaudio
- pulseaudio查询到声卡支持44100hz采样率播放, 直接输出
- A程序接着播放48000hz声音, 提交给pulseaudio
- pulseaudio查询到声卡是否支持48000hz采样率播放, 不支持则重采样到44100后输出.
如果声卡支持, 则直接输出.那么, 现在支持, 好, 设定声卡为48000模式, 然后直接输出. - A程序播放48000声音的同时, B程序开始播放44100的声音.
- pulseaudio将B程序的声音重采样到48000, 然后混音输出.
- A程序退出, B程序继续播放44100的声音
- pulseaudio将B程序的声音重采样到48000, 然后混音输出.
- B程序暂停或停止播放, 然后重新或继续播放44100的声音
- pulseaudio将设定声卡为44100模式, 然后直接输出.
- A程序又播放48000声音
- pulseaudio将A程序的声音重采样到44100, 然后混音输出.
- 用户切换到蓝牙耳机.只支持32000hz采样率.
- pulseaudio将A程序的48000hz重采样到32000hz, B的44100重采样到32000hz, 混音后输出给蓝牙耳机.
同样是系统混音, pulseaudio支持动态采样率调节.依据当前声卡支持的采样率和当前程序提交的数据,
动态修改内部混音的采样率.尽量减小不必要的重采样过程顺便提一下:google的Android不使用pulseaudio, 自己搞了个AudioFlinger,
不支持动态采样率, 还是会强制重采样到44100hz.
ALSA Project
ALSA 高级Linux音频架构
ALSA体系结构
- alsa-lib
- Control Interface (/dev/snd/controlCX)控制接口:提供管理声卡注册和请求可用设备的通用功能
- PCM Interface (/dev/snd/pcmCXDX) PCM接口:管理数字音频回放(playback)和录音(capture)的接口。它是开发数字音频程序最常用到的接口。
- Raw MIDI Interface (/dev/snd/midiCXDX) Raw MIDI接口:支持MIDI(Musical Instrument Digital Interface),标准的电子乐器。这些API提供对声卡上MIDI总线的访问。这个原始接口基于MIDI事件工作,由程序员负责管理协议以及时间处理。
- Timer Interface (/dev/snd/timer) 定时器(Timer)接口:为同步音频事件提供对声卡上时间处理硬件的访问。
- Sequencer Interface (/dev/snd/seq)时序器(Sequencer)接口
- Mixer Interface (/dev/snd/mixerCXDX) 混音器(Mixer)接口
- alsa-utils 一些常用有用的工具
- amixer:可以配置底层提供的alsa接口。
amixer contents
可以查看所有的控制接口和当前值amixer controls
可以列出所有的接口amixer cget (接口名)
可以获取指定接口值amixer cset (接口名)
可以设置指定接口值
- aplay/arecord 用于放音和录音的应用
- alsactl: 用于保存alsa配置
- alsamixer: alsamixer程序是amixer的ncurses的版本。
- aconnect, aseqnet 是进行MIDI连接和查看连接端口列表。
- amixer:可以配置底层提供的alsa接口。
- alsa-plugins
- alsa-tools
- …
环境搭建
kernel基于mozart linux-3.0.8 [speaker-master, commit id:8334430651460305e884496d9356b8b6f132ebaa]
板子使用 SP_M150_V2.0
- Sound card support
- [*] Advanced Linux Sound Architecture —>
- [*] ALSA for SoC audio support —>
- [*] ASoC support for Ingenic —>
- jz board type select —>
- soc 4775 codec type select (Audio support for wattle with internal codec) = Audio support for wattle with internal codec
- [*] Support DMIC for record
- [*] JZ audio dma clear auto dirty memor
- [*] JZ audio dma cyclic dma with hrtimer callback mode
- [] Open Sound System (DEPRECATED) —>
- [*] Advanced Linux Sound Architecture —>
测试
- 先使用amixer contents查看接口, 并用amixer cset 设置对应的值
- 使用aplay播放wav音频, 只支持wav格式
- 使用arecord 录音
ALSA混音
Alsa本身也提供混音的plugin,dmix.
应用程序不需要修改,添加配置dmix的/etc/asound.conf配置文件即可
效果是可以有多个应用同时放音
结构如下:
App1 App2 -------------------------------------Alsa-lib (dmix) User Space-------------------------------------Alsa Kernel Space------------------------------------- sound driver ------------------------------------- Hardware
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
ALSA编程
内核Alsa代码进行改动时会影响到应用程序的代码编写
ALSA放音
详细实例见:mozart_sdk/sources/application/molib_src/trunk/file-manager/player/mp3_utils.c
snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); snd_pcm_hw_params_alloca(¶ms); //分配params结构体 snd_pcm_hw_params_any(handle, params);//初始化params snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); //初始化访问权限 snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); //设置16位采样精度 snd_pcm_hw_params_set_channels(handle, params, channels); //设置声道,1表示单声道,2表示立体声 snd_pcm_hw_params_set_rate_near(handle, params, &rate, &dir); //设置>频率 snd_pcm_hw_params(handle, params); while(flag){ ... snd_pcm_writei (handle, Output, n); } snd_pcm_drain(handle); snd_pcm_close(handle);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
ALSA录音
详细实例见:mozart_sdk/sources/application/molib_src/trunk/utils/librecord/alsa/record.c
ALSA配置参数
有关调节音量,设置静音,详细实例见:/mozart_sdk/sources/application/molib_src/trunk/utils/volume/volume_alsa.c
char *card = "default"; snd_ctl_t *handle = NULL; snd_ctl_elem_value_t *ctl_elem_value; snd_ctl_open(&handle, card, 0); snd_ctl_elem_value_malloc (&ctl_elem_value); snd_ctl_elem_value_set_numid (ctl_elem_value, 11); snd_ctl_elem_value_set_interface (ctl_elem_value, SND_CTL_ELEM_IFACE_MIXER); snd_ctl_elem_value_set_name (ctl_elem_value, "Digital Playback mute"); snd_ctl_elem_value_set_integer(ctl_elem_value, 0, val); snd_ctl_elem_write(handle, ctl_elem_value); snd_ctl_close(handle); snd_ctl_elem_value_free (ctl_elem_value);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
参考
- ALSA project homepage
- ALSA project - the C library reference
- linux 3.0下混音播放解决方案 blog
- 系统混音的动态采样率 blog
- Linux声音系统 blog
- stackedit
- Linux Audio Stack & ALSA
- Linux Audio Stack & ALSA
- Linux Audio Stack & ALSA
- [Audio] Linux ALSA Mixer
- android audio/linux alsa音频-框架
- Audio codec linux driver 之 ALSA 架构的 DAPM 学习
- linux audio(alsa) 驱动注册的简明流程.
- linux audio(alsa) 驱动注册的简明流程.
- Audio codec linux driver 之 ALSA 架构的 DAPM 学习
- android audio/linux alsa音频-应用与驱动的接口
- Linux Audio ALSA Technical specification(Linux 音频ALSA技术说明)
- Alsa-Audio 二
- ALSA Audio API手册
- ALSA audio 术语
- Bluetooth stack, ALSA and Skype in Linux system
- Alsa SoC Audio(part 1)
- Alsa SoC Audio(part 2)
- ALSA Audio API 使用指南(中英版)
- Tf.shape
- GitHub 优秀的 Android 开源项目-参考自网络
- php一些基础语法
- Android 上传资源文件中的图片
- codeforce#420 E. Okabe and El Psy Kongroo(图论+矩阵快速幂)
- Linux Audio Stack & ALSA
- linux系统编程之管道(一):匿名管道(pipe)
- Unhandled exception in ***.exe(OLE32.DLL):0xC0000005:Access Violation
- Git教程5——远程仓库
- 黄油刀butterknife在Library上的使用(元素值必须为常量表达式)
- DB2 的REORG_学习(4)_表和索引重组的分析
- 分支定界法——0-1背包问题
- openldap 镜像同步慢的问题解决
- 和Postgresql系统监控有关的几个标准统计视图