ALSA音量调节功能架构分析
- 格式:pdf
- 大小:146.71 KB
- 文档页数:10
ALSA框架介绍——音频通路陈金泉2011-3-3 内容:1、简单介绍android音频状态与音频通路、codec。
2、通过ALSA的controls控制codec实现通路切换。
2.1、control2.2、widget2.3、audio_map2.4、通路切换2.5、alsa_amixer1、简单介绍android音频状态与音频通路、codec、声卡注册1.1、android音频状态与音频通路Android的音频通路管理主要是在AudioPolicyManager中完成的,包括音量管理,音频策略(strategy)管理,输入输出设备管理。
Android音频模式状态图:Android的音频模式状态包括:NORMAL、IN_CALL、RINGTONE。
AudioPolicyManager的mPhoneState成员变量记录了当前音频模式状态,在音频通路切换时的设备选择时会使用到。
在这3种音频模式状态下一共有10种音频数据流,定义如下:VOICE_CALL = 0,SYSTEM = 1,RING = 2,MUSIC = 3,ALARM = 4,NOTIFICATION = 5,BLUETOOTH_SCO = 6,ENFORCED_AUDIBLE = 7,DTMF = 8,TTS = 9,Android把10种stream type归纳为4种路由策略,getStrategy(stream_type)根据stream_type,返回对应的routing_strategy值,也就是返回stream_type对应的路由策略。
AudioPolicyManager中有两个成员变量:mAvailableOutputDevices和mAvailableInputDevices,他们记录了当前可用的输入和输出设备。
getDeviceForStrategy()则结合routing_strategy、mPhoneState以及mAvailableOutputDevices或mAvailableInputDevices,返回可用的device。
alsa-utils工具包的使用一.alsa-utils介绍ALSA是kernel中的一个声音驱动程序.它包括alsa核心和其他声卡的驱动. alsa-utils是alsa的一个工具包,里面包含有声卡测试和音频编辑的工具.二.alsa-utils的安装1.RPM包方式Turbolinux 10.5,11版本已经包含有alsa-utils的rpm包,你可以直接安装: # rpm -ivh alsa-utils-xxx.rpm2.源码包方式下载地址:/main/index.php/Download源码包安装方法:# tar zxvf alsa-utils-1.0.6.tar.gz# cd alsa-utils-1.0.6# ./configure# make install三.alsa-utils工具的使用alsa-utils包含的工具有:alsactl, aconnect, alsamixer, amidi, amixer, aplay, aplaymidi, arecord, arecordmidi,aseqnet, iecset, speaker-test1.alsactl的使用alsactl用来对alsa声卡驱动进行一些高级的设置.系统中装有多个声卡,它也可以支持.有时在音量控制面板无法调整的选项,可以使用alsactl来实现.alsactl可以将指定声卡的驱动程序设置信息保存到配置文件.或从配置文件中恢复指定声卡的驱动程序的设置信息.alsactl格式:alsactl [options] [store|restore] <card # or id>选项:-h, --help打印帮助信息-f, --file指定使用的配置文件,默认为/etc/asound.state.Select the configuration file to use. The default is/etc/asound.state-F, --force与恢复命令一起使用.表示最大限度的恢复设置值.-d, --debug调试模式,输出更多细节信息.-v, --version打印alsactl版本号.文件:/etc/asound.state(或使用-f指定的文件)保存有声卡所有混合器的设置信息.示例:# rm /etc/asound.state -f# alsactl store2.aconnect的使用aconnect是ALSA音序器的连接管理器.用来连接或断开ALSA音序器上的端口.端口是可以随意定义的.如,使用aconnect可以连接到任何由aseqview建立的设备端口.命令格式:aconnect [-d] [-options] sender receiveraconnect -i|-o [-options]aconnect -x选项:连接管理-d, --disconnect断开连接.-e, --exclusive使用独占模式连接端口.发送和接收端口将不能再与其他端口相连.-r, --real queue将时间包的时间戳,转换为真实时间队列的当前值.显示端口-i, --input显示存在的输入端口.-o, --output显示存在的输出端口.-l, --list显示当前的连接状态.删除连接-x, --removeall删除所有连接.示例:连接端口64:0到65:0:% aconnect 64:0 65:0这个连接是单向的,所有到发送端口64:0的数据,将被重定向到接收65:0端口.如果有另一个端口65:1,也使用64:0作为发送端口,则数据会同时发送到2个接收端口.端口连接时,使用:% aconnect -d 64:0 65:0地址也可以使用客户端的名字来代替:% aconnect External:0 Emu8000:1使用-i打印出输入端口信息.-o打印出输出端口信息.% aconnect -iclient 0: ’System’ [type=kernel]0 ’Timer ’1 ’Announce ’client 64: ’External MIDI-0’ [typ e=kernel]0 ’MIDI 0-0 ’可以使用-x选项来清除所有的连接.% aconnect -x3.alsamixer的使用alsamixer是一个终端界面的声卡音量调节器.如图:命令格式:alsamixer [options]选项:-h, -help显示帮助信息.-c <card number or idenfication>指定需要设置的声卡.默认为0.-D <device identification>选择需要控制的调节器.-g设置界面颜色.-s最小化界面窗口.快捷键:进入alsamixer界面后,可以使用下面快捷键进行控制:常规控制:左右箭头或n,p 用来选择通道.上下箭头或+,- 同时调整选定通道的左右声道的音量.B,= 设置左右声道音量相同.M 静音当前通道.<,>分别对左,右声道静音.空格选择录音源.在选定的通道上按"空格",可以标记此通道为录音源.此操作仅限输入设备.插入键或";",删除键或"'"分别选定左右通道.L 刷新屏幕.快捷设置PageUp 增大5格音量.PageDown 减小5格音量.End 设置音量为0.分别调整左,右或整个通道的音量.Q,W,E 增大左,右,通道的音量.Z,X,C 减小左,右,通道的音量.alt-q,ESC 退出.4.amidi的使用amidi的作用是对ALSA的RawMIDI端口进行读写.amidi是一个命令行工具,允许你以独占模式向MIDI设备读/写数据. 命令格式:amidi options选项:-h,-V,-l,-L 用于显示信息.-s,-r,-S,-d 用于发送/接收数据.-h, --help打印帮助信息.-V, --version打印版本号.-l, --list-devices打印所有硬件MIDI端口的列表.-L, --list-rawmidis打印所有RawMIDI定义.-p, --port=name设置要使用的ALSA RawMIDI端口.若不指定,则使用声卡0的端口0.-s, --send=filename发送指定文件的内容到MIDI端口.文件中必须包含raw MIDI 命令(.syx,.mid文件).-r, --receive=filename将MIDI端口接收的数据写入指定文件.-S, --send-hex="..."发送十六进制字节到MIDI端口.-d, --dump从MIDI端口接收数据,然后以十六进制形式打印出来.-t, --timeout=秒指定超时,当端口无数据输出达到超时时长时,将停止接收数据.示例:amidi -p hw:0 -s my_settings.syx发送my_settings.syx终端MIDI命令到端口 hw:0.amidi -S ’发送XG复位到默认端口.amidi -p virtual -d建立一个虚拟RawMIDI端口,然后发送所有数据到这个端口.5.amixer的使用amixer是命令行的ALSA声卡驱动调节器工具.amixer用来在命令行控制ALSA的调节器,并且支持多声卡.amixer不加参数时,将打印默认声卡的设置信息.命令格式:amixer [-c card] [cmd]命令:help 显示语法帮助.info 显示调节器设备的信息.scontrols 显示调节器器的完整列表 .scontents 显示包含详细信息的调节器的完整列表.set or sset <SCONTROL> <PARAMETER> ...设置调节器信息.get or sget <SCONTROL>显示调节器的信息.controls 显示声卡控制器的信息.contents 显示完整的声卡控制器信息.cset <CONTROL> <PARAMETER> ...设置声卡控制器信息.cget <CONTROL> 显示声卡控制器的信息.选项:[-c card]选择指定的声卡.[-D device]选择需要控制的设备名.默认是 default.-h Help显示帮助信息.-q安静模式.不输出设置结果.示例:# amixer -c 1 sset Line,0 80%,40% unmute cap设置第2块声卡的"line"的左声道音量为80%,右声道为40%,取消静音,并设置它为声音源.# amixer -c 2 cset numid=34 40%设置第34个声卡元素为40%.6.arecord,aplay的使用arecord,aplay是命令行的ALSA声卡驱动的录音和播放工具.arecord是命令行ALSA声卡驱动的录音程序.支持多种文件格式和多个声卡. aplay是命令行播放工具,支持多种文件格式.命令格式:arecord [flags] [filename]aplay [flags] [filename [filename]] ...选项:-h, --help帮助.--version打印版本信息.-l, --list-devices列出全部声卡和数字音频设备.-L, --list-pcms列出全部PCM定义.-D, --device=NAME指定PCM设备名称.-q --quiet安静模式.-t, --file-type TYPE文件类型(voc,wav,raw或au).-c, --channels=#设置通道号.-f --format=FORMAT设置格式.格式包括:S8 U8 S16_LE S16_BE U16_LEU16_BE S24_LE S24_BE U24_LE U24_BE S32_LE S32_BE U32_LE U32_BEFLOAT_LE FLOAT_BE FLOAT64_LE FLOAT64_BEIEC958_SUBFRAME_LEIEC958_SUBFRAME_BE MU_LAW A_LAW IMA_ADPCM MPEG GSM-r, --rate=#<Hz>设置频率.-d, --duration=#设置持续时间,单位为秒.-s, --sleep-min=#设置最小休眠时间.-M, --mmapmmap流.-N, --nonblock设置为非块模式.-B, --buffer-time=#缓冲持续时长.单位为微妙.-v, --verbose显示PCM结构和设置.-I, --separate-channels设置为每个通道一个单独文件.示例:aplay -c 1 -t raw -r 22050 -f mu_law foobar播放raw文件foobar.以22050Hz,单声道,8位,mu_law格式.arecord -d 10 -f cd -t wav -D copy foobar.wav以CD质量录制foobar.wav文件10秒钟.使用PCM的"copy".7.aplaymidi的使用aplaymidi用来播放标准的MIDI文件.aplaymidi是一个命令行工具,可以在一个或多个ALSA端口上播放MIDI 文件.命令格式:aplaymidi -p client:port[,...] [-d delay] midifile ...选项:-h, --help输出帮助信息.-V, --version输出版本信息.-l, --list输出可以使用的输出端口列表.-p, --port=client:port,...设置端口.-d, --delay=seconds设置MIDI文件结束后,等待时长.8.arecordmidi的使用arecordmidi用于录制标准的MIDI文件.arecordmidi可以从一个或多个ALSA端口上,录制一个标准MIDI文件. 命令格式:arecordmidi -p client:port[,...] [options] midifile选项:-h,--help打印帮助信息.-V,--version打印版本号.-l,--list打印可以使用的输入端口.-p,--port=client:port,...设置端口.-b,--bpm=beats设置MIDI文件的速率,默认为120 BPM.-f,--fps=frames设置帧率.-s,--split-channels设置每个通道将录制成一个单独的MIDI文件.-d,--dump在标准输出上,以文本形式显示接受到的事件信息9.aseqnet的使用aseqnet是ALSA调节器的网络连接工具.aseqnet是ALSA调节器的客户端程序,可以从网络上发送和接收事件数据包. 网络上有主机A,主机B.A为服务器端,B为客户端.ALSA调节器系统必须同事运行在两个服务器上.然后建立服务器端口:hostA% aseqnetsequencer opened: 128:0在HostB上执行:hostB% aseqnet hostAsequencer opened: 132:0现在所有发送到HostA:128:0的数据将被传送到HostB:132:0上,反之亦然. 命令格式:aseqnet [remotehost]选项:-p port指定TCP端口号或服务名.-s addr设置指定地址用于读操作.-d addr设置指定地址用于写操作.-v详细输出模式.10.iecset的使用设置或输出IEC958状态位.iecset是个小工具,通过ALSA的API,设置或输出IEC958(或称S/PDIF)状态位信息.直接运行iecset将输出当前IEC958的状态信息. 命令格式:iecset [options] [cmd arg...]选项:-D device设置需要打开的设备名.-c card设置需要打开的网卡名.-x输出AESx字节格式的状态信息.-i从标准输入读取命令信息,每行一个命令.命令:professional <bool>专业模式(true)或用户模式(false).audio <bool>音频模式(true).rate <int>采样频率,单位Hz.emphasis <int>设置加强值.0 = none, 1 = 50/15us, 2 = CCITT.lock <bool>速率锁.sbits <int>采样位:2 = 20bit, 4 = 24bit, 6 = undefined.wordlength <int>设置字长:0 = No, 2 = 22-18 bit, 4 = 23-19 bit, 5 = 24-20bit, 6 = 20-16 bit.category <int>分类:值从0到0x7f.copyright <bool>设置是否包含版权.original <boo>原始标记:示例:输出当前IEC958信息.$ iecsetMode: consumerData: audioRate: 44100 HzCopyright: permittedEmphasis: noneCategory: generalOriginal: 1st generationClock: 1000 ppm显示当前第1块声卡的IEC958状态位.$ iecset -Dhw:0Mode: consumerData: non-audioRate: 44100 HzCopyright: permittedEmphasis: noneCategory: generalOriginal: 1st generationClock: 1000 ppm设置当前为用户模式,并打开"非音频"位.$ iecset pro off audio offMode: consumerData: non-audioRate: 44100 HzCopyright: permittedEmphasis: noneCategory: generalOriginal: 1st generationClock: 1000 ppm11.speaker-test的使用speaker-test是一个针对 ALSA驱动的声音测试工具. speaker-test可以分别对左右声道进行单独的测试. 命令格式:speaker-test [-options]选项:-c | --channels NUM设置通道数目.-D | --device NAME设置使用的PCM设备名.-f | --frequency FREQ设置声音频率.--help输出帮助信息.-b | --buffer TIME设置缓冲区时长.0为使用最大的缓冲区大小.-p | --period TIME设置节拍为多少微秒.-r | --rate RATE设置音频率.-t | --test pink|sine|wav-t pink 表示测试时使用噪声.-t sine 表示测试时使用音频信号声.-t wav 表示测试时使用WAV文件.-l | --nloops COUNT设置测试循环的次数.-w | --wavfile设置测试时播放的wav文件.-W | --wavdir设置一个包含wav文件的目录.默认为/usr/share/sounds/alsa.示例:在一个音频接口上进行立体声测试# speaker-test -Dplug:front -c2在两个音频接口上进行4声道测试.# speaker-test -Dplug:surround40 -c4在立体声接口上进行5.1声道测试.# speaker-test -Dplug:surround51 -c6测试低音扬声器.# speaker-test -Dplug:surround51 -c6 -s1 -f75。
嵌入式ALSA音频框架介绍与应用张明俊;魏瑾【期刊名称】《电脑开发与应用》【年(卷),期】2013(000)009【摘要】针对嵌入式系统开发中对音频功能的各种应用需要,介绍了相关Android系统下音频系统的原理知识和功能,讨论了基于DA9034的驱动架构和实现流程,以及与上层应用软件的接口实现,通过该应用案例调试与分析,验证了ALSA音频系统能够在DA9034上稳定运行。
%In this thesis,Considering onthe request of transplantation and credibility in developing embeddedAlsa system,it introduces some content and function about alsa on android platform and discuss the driver framework and implementation ofDA9034,besides,also implement the interface between driver and application level,based on the analysis on this application,we verify that alsa system can run stability based on DA9034.【总页数】2页(P63-64)【作者】张明俊;魏瑾【作者单位】富士康南京通讯有限公司,南京210000;富士康南京通讯有限公司,南京 210000【正文语种】中文【中图分类】TP368【相关文献】1.基于TCC8801的嵌入式Linux ALSA音频驱动设计与研究 [J], 颜玮;郑晋2.嵌入式数字音频系统在车载导航统中的应用研究 [J], 吴记群;李双科3.SOPC技术在嵌入式音频播放系统中的应用 [J], 金震;梁睿;陈玮;陈玲玲4.面向Wi-Fi音频应用的嵌入式Linux音频驱动设计 [J], 陈熹;程鹏;梁作坤;吴斌5.适合嵌入式音频和语音应用的SoC [J],因版权原因,仅展示原文概要,查看原文内容请购买。
深入了解ALSA原文Intro任何人如果经常的使用linux机器处理音乐,那么他迟早会和ALSA打交道。
ALSA是Advanced Linux Sound Architecture的简称,和过时的Open Sound System(OSS)比起来更强大功能更多。
事实上,你可能已经不知不觉的使用了ALSA,比如ALSA的OSS模拟功能。
当在web上搜索关于ALSA的答案时,我发现都是提问和自相矛盾的声明,鲜有确切的答案。
我想有两个原因:首先,有些声音问题不像看起来那么简单,此外ALSA文档简直是一团糟。
本文会尝试解决这些声音问题,并矫正一团糟的ALSA文档。
在我们正式开始之前,你最好先浏览一下其他资源。
他们有的包含一些例子程序,可以用这些程序执行调用ALSA来播放或者录音;此外他们可能也包含了你要找的答案。
我首先特别推荐一篇信息全面的页面/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 用法
ALSA(Advanced Linux Sound Architecture)是一种音频驱动架构,用于在Linux系统上管理音频设备和提供音频功能。
下面是一些ALSA常用的用法:
1. 查看音频设备列表:可以使用以下命令查看系统中可用的音频设备列表:
```
cat /proc/asound/cards
```
2. 音频播放:使用`aplay`命令来播放音频文件。
例如:
```
aplay filename.wav
```
3. 音频录制:使用`arecord`命令录制音频。
例如:
```
arecord -f cd -d 10 -t wav filename.wav
```
4. 调整音量:使用`amixer`命令来调整音量。
例如,将音量设置为50%:
```
amixer set Master 50%
```
5. 调整音频设置:使用`alsamixer`命令在终端界面中调整音频设置,包括音量、通道等。
以上仅为一些常见的ALSA用法,更多用法可以参考ALSA 的文档和相关资料。
alsa 原理ALSA原理解析什么是ALSA?ALSA(Advanced Linux Sound Architecture)是Linux操作系统中的一种音频处理架构。
它提供了一种标准的音频设备驱动程序接口,用于操作和控制音频设备,如声卡、麦克风、扬声器等。
ALSA的组成部分ALSA由以下几个主要的组成部分组成:1.音频设备驱动程序:负责与硬件之间的通信,将音频设备的输入输出转换为数字信号,并通过内核提供的接口向应用程序提供访问。
2.音频库:提供高级的音频操作接口,为应用程序提供简化的音频处理功能。
3.控制工具:用于配置和控制音频设备的命令行工具,如alsactl和amixer。
ALSA的工作原理ALSA的工作原理可以简单概括为以下几个步骤:1.设备检测:当系统启动或插入音频设备时,ALSA会进行设备检测,并加载相应的设备驱动程序。
2.设备配置:ALSA会自动对音频设备进行配置,包括设定采样率、位深度、声道数等参数。
3.应用程序访问:应用程序通过调用ALSA提供的API接口来访问音频设备。
应用程序可以使用ALSA提供的库函数来进行音频采集、播放、混音等操作。
4.数据传输:ALSA通过DMA(Direct Memory Access)技术将音频数据从内存传输到音频设备,或者从音频设备传输到内存。
5.数据处理:音频数据在传输过程中,可以经过一系列的处理,例如音频编码、解码、混音等。
6.音量控制:ALSA提供了音量控制接口,应用程序可以通过调用API来调整音频设备的输入和输出音量。
7.音频事件处理:ALSA可以捕捉音频设备发出的事件,并通过回调函数通知应用程序。
例如,当音频设备的状态发生变化时,应用程序可以接收到相应的通知。
总结通过以上解析,我们了解了ALSA的基本原理和工作流程。
ALSA提供了一个标准的音频处理框架,使应用程序能够方便地访问和控制音频设备。
它的底层驱动程序负责和硬件进行通信,而高级的音频库则提供了简化和抽象的接口,方便应用程序进行音频处理。
alsa中pulseaudio的工作原理1. 概述PulseAudio 是 Linux 系统上的一款音频服务器,他的主要作用是为应用程序提供音频输入输出的服务,提供音频的混音、重采样等功能。
PulseAudio 可以与 ALSA(Advanced Linux Sound Architecture)配合使用,将音频数据传递给硬件设备进行播放。
2. ALSA 和 PulseAudio 的关系在 Linux 系统中, ALSA 是默认的音频框架。
它负责管理硬件设备以及音频流的输入输出。
PulseAudio 则是在 ALSA 的基础上提供了更强大的音频处理能力,比如支持多应用程序同时播放音频、应用级别的音量控制和音频混音等功能。
3. PulseAudio 的工作原理PulseAudio 通过客户端-服务器的模式工作。
当用户在应用程序中播放音频时,音频数据首先被传递给 PulseAudio 客户端,然后经过PulseAudio 服务器进行处理,最终再由 ALSA 将数据传递给硬件设备进行播放。
4. PulseAudio 的主要组件PulseAudio 主要由以下几个组件组成:- 客户端库(libpulse):提供给应用程序使用的接口,用于将音频数据传递给 PulseAudio 服务器。
- 服务器守护进程(pulseaudio):负责管理音频的输入输出,包括混音、重采样、音量控制等功能。
- 控制面板(pavucontrol):提供了一个图形化的用户界面,用于用户对音频设备进行配置和控制。
- 模块(module):提供了各种功能模块,包括网络音频传输、蓝牙音频支持、JACK 集成等。
5. PulseAudio 的工作流程PulseAudio 的工作流程可以概括为以下几个步骤:- 应用程序向 PulseAudio 客户端库注册音频流。
- PulseAudio 客户端库将音频数据传递给 PulseAudio 服务器。
我在MTK平台下调试⾳频ALSA#硬件原理图因为是我们公司的项⽬,我就不能把完整的原理图给出来。
因为两个MIC不涉及机密,跟MTK的公版是⼀样的。
可以给出来⼤家看看。
这个MIC是⼀个数字MIC,直接输出的就是数字信号,接在MTK8167S的⼀个数字通路上。
#MTK⾳频通路框图嵌⼊式设备和平台关系很⼤,所以做什么平台⼀定要弄清楚平台设备的框图。
MTK8167s⾳频的框图如下不同平台的差异也有不同,不要硬套,需要确认清楚。
图⽚上看到很多通路没?这些通路⾥⾯的东西都是需要根据tinymix来设置的,当然也有其他办法设置。
#通过tinymix配置通路我们正常的tinymix查看配置39 BOOL 1 O00 I05 Switch Off40 BOOL 1 O00 I07 Switch Off41 BOOL 1 O01 I06 Switch Off42 BOOL 1 O01 I08 Switch Off43 BOOL 1 O02 I05 Switch Off44 BOOL 1 O02 I06 Switch Off45 BOOL 1 O03 I05 Switch On46 BOOL 1 O03 I07 Switch On47 BOOL 1 O03 I10 Switch Off48 BOOL 1 O04 I06 Switch On49 BOOL 1 O04 I08 Switch On50 BOOL 1 O04 I11 Switch Off51 BOOL 1 O05 I00 Switch On52 BOOL 1 O05 I03 Switch Off53 BOOL 1 O05 I05 Switch Off54 BOOL 1 O05 I07 Switch Off55 BOOL 1 O05 I15 Switch Off56 BOOL 1 O06 I01 Switch On57 BOOL 1 O06 I04 Switch Off58 BOOL 1 O06 I06 Switch Off59 BOOL 1 O06 I08 Switch Off60 BOOL 1 O06 I16 Switch Off61 BOOL 1 O09 I00 Switch Off62 BOOL 1 O09 I03 Switch On63 BOOL 1 O10 I01 Switch Off64 BOOL 1 O10 I04 Switch On65 BOOL 1 O11 I02 Switch On66 BOOL 1 O11 I05 Switch Off67 BOOL 1 O13 I15 Switch Off68 BOOL 1 O14 I16 Switch Off69 ENUM 1 AIN Mux INT ADC70 ENUM 1 DAIBT Mux MRG71 BOOL 1 I2S O03_O04 Switch Off72 BOOL 1 INT ADDA O03_O04 Switch On73 BOOL 1 MRG BT O02 Switch On74 BOOL 1 PCM0 O02 Switch Off75 ENUM 1 Left PGA Mux OPEN76 ENUM 1 Right PGA Mux OPEN77 ENUM 1 AIF TX Mux Digital MIC78 ENUM 1 HPOUT Mux OPEN79 ENUM 1 LINEOUT Mux OPEN80 BOOL 1 DMIC Data Gen Switch Off81 BOOL 1 AMIC Data Gen Switch Off82 BOOL 1 SDM Tone Gen Switch Offaiv8167sm3_bsp:/ #⾥⾯已经有很多开关了,我们要做的时候通过tinymix把in 和 out对接起来。
在移植alsa-lib和alsa-utils之前首先要移植alsa-device,保证系统支持alsa 驱动,移好alsa-device后再dev/snd后出现相应的设备:∙controlC0 --> 用于声卡的控制,例如通道选择,混音,麦克风的控制等∙midiC0D0 --> 用于播放midi音频∙pcmC0D0c --〉用于录音的pcm设备∙pcmC0D0p --〉用于播放的pcm设备∙seq --〉音序器∙timer --〉定时器1. tar -xvf alsa-lib_1.0.23.orig.tar.bz2(1)配置alsa-lib./configure --host=arm-fsl-linux-gnueabi--prefix=/opt/ALSA/alsa_libCC=/opt/gcc-4.4.4-glibc-2.11.1-multilib-1.0/arm-fsl-linux-gnueabi/bin/a rm-fsl-linux-gnueabi-gccerror:configure error required courses helper header not found安装libncursesw5-dev。
apt-get install libncursesw5-devconfigure: error: panelw library not found./configure加入--with-curses=ncurses/bin/bash: xmlto: command not found安装xmlto/bin/rm: cannot remove `libtoolt': No such file or directory强制make!(2)makemake install生成的库alsa_lib$ lsbin include lib share在这个文件lib下的库*.so.*是要发布到板子上去的,可以直接copy到开发板的根目录lib下(这里只是copy,不要剪贴,后面还要用到,注意的是有些软连接不能copy,只能自己到板子上创建。
ALSA子系统放音录音调节驱动架构分析2013年3月2日LK version:2.6.35.3调音量static const struct file_operations snd_ctl_f_ops ={.read = snd_ctl_read,.open = snd_ctl_open,.unlocked_ioctl = snd_ctl_ioctl,... ... ,};snd_minors{}[0]... ...snd_minors{}[minor ]snd_minors{}[256]snd_minor{}void *private_data struct list_head files_list snd_card{}dev_t i_rdev... ...inode{}... ...snd_minors{}[255]MINOR()... ...struct list_head list struct file *file snd_monitor_file{}... ...struct list_head ctl_filesvoid *private_datafile{}struct list_head list struct snd_card *card int prefer_pcm_subdevice snd_ctl_file{}int prefer_rawmidi_subdevice struct pid *pid ... ...... ...... ...static int snd_ctl_open (struct inode *inode, struct file *file) { unsigned long flags; struct snd_card *card; struct snd_ctl_file *ctl; ... ... ; nonseekable_open(inode, file); ... ... ;//通过次设备号获取对应snd_minor{}的私有数据,其中该私有数据对应snd_card{}card = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_CONTROL); ... ... ;//创建snd_monitor_file{},将snd_monitor_file{}添加到snd_card{}的files_list 链表snd_card_file_add(card, file);... ... ;ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); ... ... ;INIT_LIST_HEAD(&ctl->events);init_waitqueue_head(&ctl->change_sleep); ... ... ;//创建snd_ctl_file{}ctl->card = card;ctl->prefer_pcm_subdevice = -1;ctl->prefer_rawmidi_subdevice = -1;ctl->pid = get_pid(task_pid(current));//将snd_ctl_file{}添加到file{}的私有数据file->private_data = ctl;... ... ;//将snd_ctl_file{}添加到snd_card{}的ctl_files链表list_add_tail(&ctl->list, &card->ctl_files);... ... ;}void *private_datafile{}struct list_head events snd_ctl_file{}... ...... ...struct list_head list struct snd_ctl_elem_id id unsigned int masksnd_kctl_event{}int typesnd_ctl_event {}data{} ... ...struct snd_ctl_elem_id idunsigned int maskelem{}#define snd_kctl_event (n) list_entry(n, struct snd_kctl_event, list)static ssize_t snd_ctl_read (struct file *file, char __user *buffer, size_t count, loff_t * offset) { struct snd_ctl_file *ctl; ssize_t result = 0;... ... ; ctl = file->private_data; //file{}的私有数据对应snd_ctl_file{} ... ... ; while (count >= sizeof(struct snd_ctl_event)) { struct snd_ctl_event ev; struct snd_kctl_event *kev;//执行条件:当snd_ctl_file{}的events 链表为空 while (list_empty(&ctl->events)) { //该段函数的执行流程??? wait_queue_t wait; ... ... ; init_waitqueue_entry(&wait, current); add_wait_queue(&ctl->change_sleep, &wait); set_current_state(TASK_INTERRUPTIBLE); ... ... ; schedule(); //调度 remove_wait_queue(&ctl->change_sleep, &wait);... ... ;}//获取snd_kctl_event{}kev = snd_kctl_event (ctl->events.next);//构建snd_ctl_event{}ev.type = SNDRV_CTL_EVENT_ELEM;ev.data.elem.mask = kev->mask;ev.data.elem.id = kev->id;//删除该snd_kctl_event{}list_del(&kev->list);... ... ;kfree(kev);//复制snd_ctl_event{}到用户空间copy_to_user(buffer, &ev, sizeof(struct snd_ctl_event));... ... ;buffer += sizeof(struct snd_ctl_event);count -= sizeof(struct snd_ctl_event);result += sizeof(struct snd_ctl_event);}... ... ;}static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg){struct snd_ctl_file *ctl;struct snd_card *card;struct snd_kctl_ioctl *p;void __user *argp = (void __user *)arg;int __user *ip = argp;... ... ;ctl = file->private_data;card = ctl->card;... ... ;switch (cmd) {... ... ;case SNDRV_CTL_IOCTL_ELEM_READ:return snd_ctl_elem_read_user(card, argp);case SNDRV_CTL_IOCTL_ELEM_WRITE:return snd_ctl_elem_write_user(ctl, argp);... ... ;}... ... ;}//获取音量static int snd_ctl_elem_read_user(struct snd_card *card,struct snd_ctl_elem_value __user *_control){struct snd_ctl_elem_value *control;int result;//从用户空间复制大小为sizeof(snd_ctl_elem_value{})的内存区域control = memdup_user(_control, sizeof(*control));... ... ;// 等待电源变为“SNDRV_CTL_POWER_D0”状态,即“full on”状态result = snd_power_wait(card, SNDRV_CTL_POWER_D0);用意?if (result >= 0)result = snd_ctl_elem_read(card, control);... ... ;if (result >= 0)//把大小为sizeof(snd_ctl_elem_value{})的内存区域复制到用户空间copy_to_user(_control, control, sizeof(*control));kfree(control);return result;}void *memdup_user(const void __user *src, size_t len){void *p;p = kmalloc_track_caller(len, GFP_KERNEL);#define kmalloc_track_caller(size, flags) __kmalloc(size, flags) ... ... ;copy_from_user(p, src, len);... ... ;return p;}static int snd_ctl_elem_read(struct snd_card *card, struct snd_ctl_elem_value *control){struct snd_kcontrol *kctl;struct snd_kcontrol_volatile *vd;unsigned int index_offset;int result;... ... ;//通过给定的id,判定snd_kcontrol{}是否已经被保存在snd_card{}.controls链表中kctl = snd_ctl_find_id(card, &control->id);//确定从用户空间获取的snd_ctl_elem_value{}对应的snd_kcontrol{}为该同类元素中的第几个index_offset = snd_ctl_get_ioff(kctl, &control->id);vd = &kctl->vd[index_offset];if ((vd->access & SNDRV_CTL_ELEM_ACCESS_READ) && kctl->get != NULL) {snd_ctl_build_ioff(&control->id, kctl, index_offset);result = kctl->get(kctl, control);} else... ... ; //程序退出... ... ;return result;}static inline unsigned int snd_ctl_get_ioff(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id){if (id->numid) {return snd_ctl_get_ioffnum(kctl, id);return snd_ctl_get_ioffidx(kctl, id);}}static inline unsigned int snd_ctl_get_ioffnum(struct snd_kcontrol *kctl,struct snd_ctl_elem_id *id){return id->numid - kctl->id.numid;}static inline unsigned int snd_ctl_get_ioffidx(struct snd_kcontrol *kctl,struct snd_ctl_elem_id *id){return id->index - kctl->id.index;}static inline struct snd_ctl_elem_id *snd_ctl_build_ioff(struct snd_ctl_elem_id *dst_id,struct snd_kcontrol *src_kctl,unsigned int offset){*dst_id = src_kctl->id;dst_id->index += offset;dst_id->numid += offset;return dst_id;}//调节音量static int snd_ctl_elem_write_user(struct snd_ctl_file *file,struct snd_ctl_elem_value __user *_control){struct snd_ctl_elem_value *control;struct snd_card *card;int result;control = memdup_user(_control, sizeof(*control));... ... ;card = file->card;... ... ;result = snd_power_wait(card, SNDRV_CTL_POWER_D0);result = snd_ctl_elem_write(card, file, control);if (result >= 0)copy_to_user(_control, control, sizeof(*control));... ... ;kfree(control);return result;}static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,struct snd_ctl_elem_value *control){struct snd_kcontrol *kctl;struct snd_kcontrol_volatile *vd;unsigned int index_offset;int result;... ... ;kctl = snd_ctl_find_id(card, &control->id);index_offset = snd_ctl_get_ioff(kctl, &control->id);vd = &kctl->vd[index_offset];if (!(vd->access & SNDRV_CTL_ELEM_ACCESS_WRITE) ||kctl->put == NULL ||(file && vd->owner && vd->owner != file)) {... ... ; //程序退出} else {snd_ctl_build_ioff(&control->id, kctl, index_offset);result = kctl->put(kctl, control);}if (result > 0) {... ... ;//通知音量值发生变化snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_V ALUE, &control->id);return 0;}... ... ;return result;}前端例子/sound/drivers/dummy.cmodule_init(alsa_card_dummy_init)→alsa_card_dummy_init()→platform_driver_register():snd_dummy_driver→snd_dummy_probe()→snd_card_dummy_new_mixer()→snd_ctl_add(card, snd_ctl_new1(&snd_dummy_controls[idx], dummy))static struct snd_kcontrol_new snd_dummy_controls[] = {DUMMY_VOLUME("Master Volume", 0, MIXER_ADDR_MASTER),DUMMY_CAPSRC("Master Capture Switch", 0, MIXER_ADDR_MASTER),DUMMY_VOLUME("Synth V olume", 0, MIXER_ADDR_SYNTH),DUMMY_CAPSRC("Synth Capture Switch", 0, MIXER_ADDR_SYNTH),DUMMY_VOLUME("Line V olume", 0, MIXER_ADDR_LINE),DUMMY_CAPSRC("Line Capture Switch", 0, MIXER_ADDR_LINE),DUMMY_VOLUME("Mic V olume", 0, MIXER_ADDR_MIC),DUMMY_CAPSRC("Mic Capture Switch", 0, MIXER_ADDR_MIC),DUMMY_VOLUME("CD V olume", 0, MIXER_ADDR_CD),DUMMY_CAPSRC("CD Capture Switch", 0, MIXER_ADDR_CD)};#define DUMMY_VOLUME(xname, xindex, addr) \{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \.access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \.name = xname, .index = xindex, \.info = snd_dummy_volume_info, \.get = snd_dummy_volume_get, .put = snd_dummy_volume_put, \.private_value = addr, \.tlv = { .p = db_scale_dummy } }static int snd_dummy_volume_get(struct snd_kcontrol *kcontrol,struct snd_ctl_elem_value *ucontrol){//寄存器相关操作... ... ;}static int snd_dummy_volume_put(struct snd_kcontrol *kcontrol,struct snd_ctl_elem_value *ucontrol){//寄存器相关操作... ... ;}。