关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » HTML5 »Linux ALSA 音频处理深入解析

    Linux ALSA 音频处理深入解析

    2014-10-11 00:00:00 出处:Kivision
    分享

    简介

    任何人假如经常的使用linux机器处理音乐,那么他迟早会和ALSA打交道。ALSA是Advanced Linux Sound Architecture的简称,和过时的Open Sound System(OSS)比起来更强大功能更多。事实上,你可能已经不知不觉的使用了ALSA,比如ALSA的OSS模拟功能。当在web上搜索关于ALSA的答案时,我发现都是提问和自相矛盾的声明,鲜有确切的答案。我想有两个原因:首先,有些声音问题不像看起来那么简单,此外ALSA文档简直是一团糟。本文会尝试解决这些声音问题,并矫正一团糟的ALSA文档。

    在我们正式开始之前,你最好先浏览一下其他资源。他们有的包含一些例子程序,可以用这些程序执行调用ALSA来播放或者录音;此外他们可能也包含了你要找的答案。

    我首先特别推荐一篇信息全面的页面http://www.sabi.co.uk/Notes/linuxSoundALSA.html, 和本文侧重于深层次研究相比,它的覆盖面更广。

    其他的资源包括:

    a LINUX Journal article about basic ALSA programming 包含一些示例代码

    tutorials on the ALSA project web site 包含一些示例代码

    one of the developers’ home page 比较旧

    有些文档内嵌在ALSA library的源代码中,可以使用源码文档生成工具doxygen生成,使用命令make doc。也可以在线阅读API文档, 不幸的是它并不完整,浏览起来很麻烦。以我的观点,开发者最初设想不止提供API文档,但是结果是一样都没达到。假如你真得想理解ALSA如何工作的,那么你最好结合着源代码来看这些文档。

    ALSA Concepts

    声卡和硬件设备

    ALSA用cards,device和subdevices的分层结构表示audio硬件设备和他们的组件。这个分层结构是ALSA看待硬件设备结构和能力的视角。假如声卡这个分层结构和声卡的文档有差别,那么可能是由于驱动没有支持所有的功能。

    ALSA cards和声卡硬件是一一对应的。ALSA cards的主要保存每块卡上的设备列表。一个card可以通过一个ID(字符串)或者从0开始的数字表示。

    大部分ALSA硬件访问发生在device级别。可以从0开始枚举每个卡的devices,不同的devices可以独立的打开和使用。典型的,声卡和设备这两个标识足以决定声音信号从哪里读取,送到哪里。

    Subdevices是ALSA能够区分的更细粒度的对象。最常见的场景是一个device的每个channel都对应一个subdevice或者总共只有一个subdevice。一个device的subdevice理论上可以单独使用,但是在一个subdevice上播放multi-channel信号时,也会使用其余的subdevices。和device一样,subdevices索引标识从0开始。

    PCM参数和配置空间

    数字化声音有一定数目的参数:采样率,通道数和采样值存储格式。假如你已经使用OSS编程,那么你可能习惯于在播放音乐文件之前设置这些参数。类似于ALSA文档中所提到的配置空间。

    现实的答案没有那么简单:比如一些声卡无法结合所有支持的采样格式,采样率和通道数。所以这些参数不是独立的。ALSA考虑到了这种情况,使用一个n维空间的参数集,每一维对应着采样率,采样格式,通道数等等。假如一个给定声卡的参数是独立的,那么所有合法配置就在一个n维盒子中,在这种情况下,我们需要做的就是描述每一维的取值范围。假如参数之间不是独立的,那么允许的配置集比较复杂了。

    当一个硬件设备通过ALSA访问,参数并不总是独立的。进一步说,一个设备由于某些特定参数的限制,它的合法配置空间被相应的压缩小了。这就使得我们可以使用一个较小空间而不是确定的数值。此外,还导致依赖于参数设置顺序的问题。也就是说ALSA plugin能够自动选择最合适的硬件参数并执行格式转换。我们在接下来的小节中会讨论这个plugin和其他的plugin

    ALSA devices and plugins

    为了避免混淆,我们先简单介绍一下ALSA device。这里说的ALSA device和上面提到的hardware devices完全不同。ALSA device用字符串表示。他们定义在ALSA的一个配置文件中。更复杂的是,一些标准的ALSA devices是:属类:card,devicce,subdevice。但是硬件card和device的规范不能做为ALSA设备,事实上有些ALSA devices的参数不是硬件相关的。

    不夸张的说ALSA几乎都是由plugins组成的。不论什么时候一个player或者程序使用ALSA设备时,plugins做脏活累活。plugins的完整列表在ALSA library doxygen 文档的pcm_plugins.html中。注意plugins列表并不等同于ALSA devices列表。一些标准devices的名字和他们使用的plugins同名,但是有些devices并不是这样,有时不同的ALSA devices使用相同的plugin。因此本节我们会给出每一个plugin的名字,假如可能,还会给出特定硬件设备使用这个plugin允许的名字。

    最重要的plugin无疑是hw plugin。它本身不做任何处理,仅仅访问硬件驱动。假如应用选择硬件不支持的PCM参数(sampling rate, channel count或者sample format),hw plugin返回出错信息。因此下一个重要的plugin是’plug’ plugin,plug plugin执行channel复制,采样率转换以及必要的重采样。不像hw plugin被device hw:0,0使用,plug plugin对应的device命名是不同的:plughw:0,0。但二者的设备名都包含要访问的硬件cards,device以及subdevice。(事实上,plug device也存在,也使用plug plugin,并且它的参数SLAVE指明数据要发送到哪里,因此这个plugin一定和其他的plugins链接到一起)

    此外一个很有用的plugin是file plugin,它会把采样数据写到一个文件中。它有两个ALSA devices:file 和 tee。前者有两个参数,文件名和格式。后者传送数据到另外一个device以便写到一个文件中,第一个参数就是那个device。假如第二个设备有任何参数(比如 “plughw:0,0″),那么你要把他的名字用引号括起来,以防止被命令行解释。假定你想使用第一个声卡上的第一个设备播放声音,你可以用如下方式获取输出声音的copy。

    aplay -Dtee:'plughw:0,0', /tmp/alsatee.out, rawxy.wav

    得承认这看起来没什么意义(因为你可以简单的copy xy.wav或者转换为sox),然而使用这个方法,基于ALSA的movie player可以抽取声音内容。tee’s 输出是raw 采样数据没有任何文件头。file plugin也可以用来从文件中读取数据,但是没有预定义的设备使用这种方式。

    现存的许多plugins用来mixer和rerouting channels。由于这些plugins需要大量的参数,没有预定以的ALSA devices使用他们。route plugin是一个mixing矩阵。channels不仅仅可以被交换或者任意赋值,而且可以被混音。多个plugin仅仅允许reroute channels,但是可以有几个slave devices,因此可以在不同声卡的channels上播放。dmix和dshare plugins允许一个device被多个clients(player application)使用。dshare plugin把可用channels分配给需要的clients,而dmix则是把多个clients播放的内容混音到一个channels。

    简短的介绍了最重要的几个plugins以及预定义的ALSA devices。为了使用更复杂的plugins,需要写自己的配置文件,下一节将详细描述配置文件。device定的例子可以参照ALSA项目documentation of its configuration file 以及list of plugins

    Configuring ALSA

    configuration files

    配置文件用来定义ALSA devices。没有这些配置文件,你就无法使用ALSA的任何功能。虽然你并不需要写任何配置文件就可以进行简单的播放和录音,这是因为内建的配置文件alsa.conf包含一些devices的定义。但是假如你有特殊的需求或者碰到了问题,你可能就需要增加自己的定义了。

    ALSA支持三类配置文件。第一个是alsa.conf,位于ALSA 数据目录下,通常是/usr/share/als。这个目录和它的子目录包含了更多的配置文件,关于声卡的或者特定的plugin,他们都被包含进alsa.conf。这个目录下的配置文件通常被看作built-in,所以系统管理员和普通用户都不应该修改它。

    其他两个配置文件也被alsa.conf包含进来,系统范围内的配置文件存储在/etc/asoundrc。用户可以存储他们自己的配置文件到HOME目录下的.asoundrc中。每次打开ALSA devices所有的配置文件都会被重新分析。所以配置文件的变化是立即生效的,不需要重启任何东西。

    Basic Configuration file format

    ALSA配置文件保存着分层结构的参数-值对。分层结构的顶层对应着ALSA提供的接口。一个接口包含着一组ALSA API功能:允许打开一个device,对接口做操作,然后关闭device。不同的接口有不同的作用,比如aplay和其他的player使用PCM接口,程序alsactl使用ctl接口。amixer使用mixer接口,amidi使用rawmidi接口。(事实上他们大部分最终都会使用ctl接口,至少部分功能)。为了让这些程序能够使用device,必须在相应的接口定义他们。

    我给的例子大部分都是和pcm接口相关的,主要因为PCM几乎是最重要的并且我大部分时间也都花在PCM。(PCM代表Pulse code Modulation,是把声音数字化为采样值流)。此外命令aplay -L 允许你列出pcm interface上的所有定义。

    层次结构的第二级保存着ALSA devices的名字,可以通过这个device操作device所在的接口

    让我们看一个例子,假定你想创建一个ALSA PCM device访问你的第一个声卡并且做必要的格式转换。plugin是通过plug plugin实现的自动格式转换。在asoundrc中加入下面几行,创建这个PCM device。

    pcm.plug0 {
        type plug
        slave {
            pcm "hw:0,0"
        }
    }

    解释下这几行的意思:一个新的device plug0,可以通过pcm接口访问。这个device的数据输出将会被plug plugin处理。这个plugin的slave是pcm device hw:0,0。这个device定义是最常用的定义方式。当然,ALSA在语法上允许一定自由度。比如,可以在参数名和值之间放一个等号,或者在赋值语句间增加分号和逗号。所以我们可以改写上面的定义如下

    pcm.plug0 = {
        type = plug;
        slave = {
            pcm = "hw:0,0" ;
        },
    };

    如你所见, 花括号前是参数名,花括号内则是它的参数值。设置在参数体内的最后一个参数赋值可以跟着逗号或者分号。现在我们知道问什么slave PCM要使用分号了,否则slave PCM中的逗号会导致一个语法错误。

    事实上语法还有更大的自由度。子参数名可以通过‘.’定义也可以用括号定义。第一个符号plug0是新设备的名字,也是pcm的一个参数。第二个则定义了所得的子参数。此外配置文件并使面向行的,可以使用空格作为一行的分割。所以上面的定义可以写做如下两种形式

    pcm {
        plug0 {
            type plug slave { pcm "hw:0,0" }
        }
    }

    或者

    pcm.plug0.type = plug; pcm.plug0.slave.pcm = "hw:0,0"

    现在我们总结一下ALSA配置文件的机构。参数名是由字母,数字和下划线组成的(这个结论是调试的结果,实际上并没有文档)。参数值包含字母,数字和下划线并使用引号括起来。参数名和参数值都是大小写敏感的。配置文件的注释以 #开始直到本行的结束。

    为了是slave的定义更清晰,我们应该单独定义slave。这样上面的plug0的定义应该这样。

    pcm_slave.slave0 {
        pcm "hw:0,0"
    }
    pcm.plug0 {
        type plug
        slave slave0
    }

    配置文件还支持别名。我们可以把参数赋值为一个已存在的设备名,这个参数就是别名。

    pcm.alias_plug0 = plug0

    alias_plug0和plug0都是接口pcm的一部分,注意不能定义为(pcm.alias_plug0 = pcm.plug0),因为ALSA devices的别名不能带参数

    现在我们已经有了大概的了解,你可以继续阅读http://alsa.opensrc.org/.asoundrc和ALSA library的doxygen文档,他们提供了更多的例子。

    Advanced configuration file features

    Overriding parameters and parameter data types

    假如你已经阅读了其他的asoundrc,那么你可能已经学会了重新定义ALSA’s default device如下:

    pcm.!default { type hw card 0 }

    叹号使得原来的pcm.default定义被覆盖。这个符号可以在任意配置文件赋值中使用。现在让我们来看看它是如何工作的,正常的赋值是增加一个叶子节点到树结构中。假如叶子节点已经存在,那么他的值就会被覆盖。所以假如你在asoundrc中放入下面两行,那么缺省的声卡就是第二个,而不是第一个

    pcm.!default { type hw card 1 }
    pcm.default.card 1

    假如你把关于default的第一行定义移除,那么你将收到一个error信息default不是一个compund。很明显,参数有几种数据类型,类型不能仅仅通过赋值语句就被修改。通过叹号覆盖一个参数,就可以改变他的类型。叹号使得参数和它的子参数全部被移除。所以不要如下方式使用叹号 !pcm…,这将删除pcm interface的所有定义。

    稍微有点使用经验,就会发现别名实际上是一个字符串,包含他们所指向的PCM device的名字。pcm.default就是alsa.conf中定义的一个别名。

    和叹号类似,其他的前缀字符可以用来修饰参数赋值。问号 会忽略掉参数值已经存在的参数。

    pcm. default {
        type hw card 1
    }

    定义第一个设备的第二个声卡作为default device,但是假如default在之前已经定义过,那么这个声明无效。

    其他的两个前缀是+和-。

    Parameterised device definitions

    在plugins一节中,我们碰到了很多ALSA devices需要给定参数,跟随在device name后使用”,”分割。就像我上面提到的,这些device和他们后面的plugins是完全不同的东西,devices可以看作是plugins的封装。在basic configuration section一节我们使用plug plugin定义了一个device。我们在plugin一节碰到的预定义设备和这种简单的设备是不同的。plughw设备可以被任意的声卡和硬件设备使用,因为我们可以使用card 和device号作为参数。尽管所有的参数化设备都是在alsa.conf中定义的,并且没有ALSA文档说明他们的语法,你仍然可以定义自己的devices

    让我们看一下plughw在alsa.conf中的定义,这里的plughw做了缩略

    plughw {
      @args [ CARD DEV SUBDEV ]
      @args.CARD {
        type string
      }
      @args.DEV {
        type integer
      }
      @args.SUBDEV {
        type integer
      }
      type plug
      slave.pcm {
        type hw
        card $CARD
        device $DEV
        subdevice $SUBDEV
      }
    }

    plughw结构的第一行定义了参数列表。这对于我们是一个新的数据类型:数组。他的元素可以一起赋值。

    plughw {
        @args.0 CARD
        @args.1 DEV
        @args.2 SUBDEV
    }

    和结构赋值一样,元素或组赋值可以插入等号。接下来的几行定义了每个参数的数据类型,在plughw的原始定义中,结构体定义参数时也包括了缺省的定义,假如你对此感兴趣,可以看下alsa.conf。

    Troubleshooting

    Useful tools

    查看声卡设备的最简单方法是调用

    aplay -l 或者arecord -l

    这两个命令会列出可以playback和recording的声卡,硬件设备以及子设备。

    假如你对ALSA解析asoundrc有任何疑问,你可以使用命令aplay -L,打印出pcm接口的所有配置。注意前缀”pcm.”没有出现在参数名中,因为它一直是隐含的。

    aplay的另外一个选项是-v,这个选项在playback时会打印出每个subdevice的硬件参数。不像其他两个提到的选项,这个选项只能在playback时起作用。当你使用plug plugin来播放声音,可以用这个选项来检查是否plug做了resampling。

    但是假如你使用其他的audio或者movie player时怎么办? 可以使用/proc/ file system。当subdevice正在使用时,可以从/proc/asound/card#/pcm#p/sub#/hw_params获取硬件参数。通过比较aplay test.wav -v和/proc/asound/card#/pcm#p/sub#/hw_params的输出结果,我们可以知道哪些参数是模拟的。假如subdevice没有被使用没,那么参数文件hw_params仅仅输出”closed”。假如在播放音乐时,显示的是”closed“,那么说明声音没有流到这个subdevice。例外情况:假如一个ALSA device被一个multi-channel playback使用,那么第一个subdevice记录总channel数,其他的则汇报为closed。假如使用了ALSA’s OSS模拟,那么hw_params文件也包含OSS的参数设置。

    amidi程序使用rawmidi接口,选项-l列出所有可用的MIDI devices,-L选项打印出rawmidi接口的配置。

    speaker-test,当你听不到任何声音,想确定一下是否player有问题,那么可以使用speaker-test做为基准测试程序。这个测试程序可以顺序的给每个speaker发送铃音或者噪声。

    alsacap

    alsacap是作者写的一个小程序,用来抓取一些作者特别关注的一些硬件配置。我认为这个工具对于查找问题很有帮助。源码地址http://www.volkerschatz.com/noise/alsacap.c, 源码顶端的注释有编译说明。这个工具名意思是ALSA capability,用来显示你的声卡和ALSA驱动的能力。

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    正版 Windows 11产品密钥怎么查找/查看?

    还有3个月,微软将停止 Windows 10 的更新

    Windows 10 终止支持后,企业为何要立即升级?

    Windows 10 将于 2025年10 月终止技术支持,建议迁移到 Windows 11

    Windows 12 发布推迟,微软正全力筹备Windows 11 25H2更新

    Linux 退出 mail的命令是什么

    Linux 提醒 No space left on device,但我的空间看起来还有不少空余呢

    hiberfil.sys文件可以删除吗?了解该文件并手把手教你删除C盘的hiberfil.sys文件

    Window 10和 Windows 11哪个好?答案是:看你自己的需求

    盗版软件成公司里的“隐形炸弹”?老板们的“法务噩梦” 有救了!

    IT头条

    公安部:我国在售汽车搭载的“智驾”系统都不具备“自动驾驶”功能

    02:03

    液冷服务器概念股走强,博汇、润泽等液冷概念股票大涨

    01:17

    亚太地区的 AI 驱动型医疗保健:2025 年及以后的下一步是什么?

    16:30

    智能手机市场风云:iPhone领跑销量榜,华为缺席引争议

    15:43

    大数据算法和“老师傅”经验叠加 智慧化收储粮食尽显“科技范”

    15:17

    技术热点

    商业智能成CIO优先关注点 技术落地方显成效(1)

    用linux安装MySQL时产生问题破解

    JAVA中关于Map的九大问题

    windows 7旗舰版无法使用远程登录如何开启telnet服务

    Android View 事件分发机制详解

    MySQL用户变量的用法

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。