关闭 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驱动的能力。

    上一篇返回首页 下一篇

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

    别人在看

    电脑屏幕不小心竖起来了?别慌,快捷键搞定

    Destoon 模板存放规则及语法参考

    Destoon系统常量与变量

    Destoon系统目录文件结构说明

    Destoon 系统安装指南

    Destoon会员公司主页模板风格添加方法

    Destoon 二次开发入门

    Microsoft 将于 2026 年 10 月终止对 Windows 11 SE 的支持

    Windows 11 存储感知如何设置?了解Windows 11 存储感知开启的好处

    Windows 11 24H2 更新灾难:系统升级了,SSD固态盘不见了...

    IT头条

    Synology 更新 ActiveProtect Manager 1.1 以增强企业网络弹性和合规性

    00:43

    新的 Rubrik Agent Cloud 加速了可信的企业 AI 代理部署

    00:34

    宇树科技 G1人形机器人,拉动一辆重达1.4吨的汽车

    00:21

    Cloudera 调查发现,96% 的企业已将 AI 集成到核心业务流程中,这表明 AI 已从竞争优势转变为强制性实践

    02:05

    投资者反对马斯克 1 万亿美元薪酬方案,要求重组特斯拉董事会

    01:18

    技术热点

    大型网站的 HTTPS 实践(三):基于协议和配置的优化

    ubuntu下右键菜单添加新建word、excel文档等快捷方式

    Sublime Text 简明教程

    用户定义SQL Server函数的描述

    怎么在windows 7开始菜单中添加下载选项?

    SQL Server 2016将有哪些功能改进?

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

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