您的位置:首页 > 移动开发 > Android开发

Android下音频的测试程序tinyalsa(录音,放音,查看声卡信息)

2017-05-21 15:35 2871 查看
audio代码比较复杂,除了音频参数,我们平时客制化的地方不多。所以没有太深入了解。

建议先抽空看看如下代码:

kernel,linuxalsa架构:
kernel-3.10/sound/soc/mediatek/
kernel-3.10/Documentation/sound/alsa/soc/

android上层alsa接口
external/tinyalsa/

hal:
vendor/mediatek/proprietary/platform/common/hardware/audio/
vendor/mediatek/proprietary/platform/mt6735/hardware/audio/

andoridaudioflinger:
frameworks/av/services/audioflinger/

tinyalsa位于Android源码的external/tinyalsa位置。

关于tinyalsa,tinyalsa是Google在Android4.0之后推的基于alsa内核的用户层音频接口。在Android4.0之前还一直是使用这alsa-lib接口。Google之所以推出tinyalsa,我认为有可能是因为alsa使用了GPL许可证的缘故,也有可能是因为alsa-lib的库过于复杂繁琐大部分功能在Android平台没有实际实用意义却依然占用屈指可数的内存空间。
关于alsa在Android中,在Android4.0及之后只要你愿意还是可以使用原版alsa的,因为内核中依然是使用alsa的驱动,只需要把alsa的用户层接口alsa-lib移植到源码中即可。
tinyalsa中主要的头文件和数据结构如下,通过ioctrl和内核的alsa驱动交互。




pcm设备,通过阅读tinyalsa的代码和查看Android下的音频设备节点,可知在Android中一个pcm设备最多可有一个mixer设备"/dev/snd/controlC%u"(一般是controlC0)和32个/dev/snd/pcmC%uD%uc(一般是pcmC0D0c)、/dev/snd/pcmC%uD%u%p(一般是pcmC0D0p),pcm设备中的C代表card,D代表device,c代表capture,p代表playback。当我们新增一个pcm声卡C的值会+1,D还是从0开始,可能只有c(pcmC1D0c例如麦克风),可能只有p(pcmC1D0p例如音响),可能同时存在c和p(pcmC1D0cpcmC1D0p)。
tinyalsa的对外提供的头文件就我上图提到的一个"asoundlib.h",提供最基础的pcm和mixer操作。实现文件为pcm.c(实现pcmapi)和mixer.c(实现mixerapi)。根据asoundlib.h编写了四个小工具tinypcminfotinyplaytinycaptinymix,这四个小工具作为系统命令存放在系统中,可以很方便的使用。tinyasla作为精简版的alsa-lib可能会有人想把它移植到Linux使用,tinyasla依赖的库有libcutils&&libutils,如果能把依赖的这两个库的一些方法使用Linux接口实现那么剩下的问题应该不大了吧,这个仅仅是我的猜想。tinypcminfo的实现文件tinypcminfo.c(查看pcm设备能力)tinyplay的实现文件tinyplay.c(使用pcm设备播放wav格式的音频文件)tinycap的实现文件tinycap.c(使用pcm设备采集pcm格式的码流,并保存为wav格式的文件)tinymix的实现文件tinymix.c(对pcm设备的控制,包括音量调节、设备切换)这几个命令使用时可以先使用tinypcminfo查看pcm设备的能力,要不当我们使用其他三个命令时使用了不合理的配置会出现parameterinvalid的错误。
PCMAPI
/*对pcm设备节点的操作*/
structpcm*pcm_open(unsignedintcard,unsignedintdevice,unsignedintflags,structpcm_config*config);
intpcm_close(structpcm*pcm);
intpcm_is_ready(structpcm*pcm);
/*获取pcm设备的能力*/
structpcm_params*pcm_params_get(unsignedintcard,unsignedintdevice,unsignedintflags);
voidpcm_params_free(structpcm_params*pcm_params);
unsignedintpcm_params_get_min(structpcm_params*pcm_params,enumpcm_paramparam);
unsignedintpcm_params_get_max(structpcm_params*pcm_params,enumpcm_paramparam);
/*配置pcm设备capture和playback的规格*/
intpcm_get_config(structpcm*pcm,structpcm_config*config);
intpcm_set_config(structpcm*pcm,structpcm_config*config);
/*返回调用tinyalsa最后的错误信息*/
constchar*pcm_get_error(structpcm*pcm);
/*设置pcm设备采集和播放的位数,位数越高越接近真实声音*/
unsignedintpcm_format_to_bits(enumpcm_formatformat);
/*pcm设备的内置缓冲之间大小、帧数、时间的转换*/
unsignedintpcm_get_buffer_size(structpcm*pcm);
unsignedintpcm_frames_to_bytes(structpcm*pcm,unsignedintframes);
unsignedintpcm_bytes_to_frames(structpcm*pcm,unsignedintbytes);
unsignedintpcm_get_latency(structpcm*pcm);//inms
/*返回下一帧的有效帧指针和该帧时间戳,时间戳有CLOCK_MONOTONIC和CLOCK_REALTIME可选,里面使用的是CLOCK_REALTIME*/
/*我认为应该需要两个时间戳,一个用于播放的时间戳(CLOCK_MONOTONIC)不受系统时间的影响,一个用于记录当前音频采集的时间戳(CLOCK_REALTIME)*/
intpcm_get_htimestamp(structpcm*pcm,unsignedint*avail,structtimespec*tstamp);
/*通过FIFO把数据写入硬件用于playback或者从硬件中读取capture数据*/
intpcm_write(structpcm*pcm,constvoid*data,unsignedintcount);
intpcm_read(structpcm*pcm,void*data,unsignedintcount);
/*这是一个可选的和hardware通信的方式。*/
intpcm_mmap_write(structpcm*pcm,constvoid*data,unsignedintcount);
intpcm_mmap_read(structpcm*pcm,void*data,unsignedintcount);
intpcm_mmap_begin(structpcm*pcm,void**areas,unsignedint*offset,unsignedint*frames);
intpcm_mmap_commit(structpcm*pcm,unsignedintoffset,unsignedintframes);
intpcm_start(structpcm*pcm);
intpcm_stop(structpcm*pcm);
intpcm_wait(structpcm*pcm,inttimeout);
intpcm_set_avail_min(structpcm*pcm,intavail_min);
[/code]对于pcm设备的操作只需要注意所操作的设备是否存在,以及设备的能力问题不要设置设备所不能及的能力设备就可以正常工作了,其实就是需要注意channels、rate、format、period_size和period_count。
MIXERAPI
/*对mixer设备的操作*/
structmixer*mixer_open(unsignedintcard);
voidmixer_close(structmixer*mixer);
/*获取mixer设备信息name*/
constchar*mixer_get_name(structmixer*mixer);
/*获取mixer设备的控制句柄structmixer_ctl*/
unsignedintmixer_get_num_ctls(structmixer*mixer);
structmixer_ctl*mixer_get_ctl(structmixer*mixer,unsignedintid);
structmixer_ctl*mixer_get_ctl_by_name(structmixer*mixer,constchar*name);
/*取mixer设备的控制信息*/
constchar*mixer_ctl_get_name(structmixer_ctl*ctl);
enummixer_ctl_typemixer_ctl_get_type(structmixer_ctl*ctl);
constchar*mixer_ctl_get_type_string(structmixer_ctl*ctl);
unsignedintmixer_ctl_get_num_values(structmixer_ctl*ctl);
unsignedintmixer_ctl_get_num_enums(structmixer_ctl*ctl);
constchar*mixer_ctl_get_enum_string(structmixer_ctl*ctl,unsignedintenum_id);
/*Somesoundcardsupdatetheircontrolsduetoexternalevents,
*suchasHDMIEDIDbytedatachangingwhenanHDMIcableis
*connected.ThisAPIallowsthecountofelementstobeupdated.
*/
voidmixer_ctl_update(structmixer_ctl*ctl);
/*设置和获取可控制的信息,方式有比例、数组、范围、固定值*/
/*id通过mixer_get_num_ctls获得*/
intmixer_ctl_get_percent(structmixer_ctl*ctl,unsignedintid);
intmixer_ctl_set_percent(structmixer_ctl*ctl,unsignedintid,intpercent);
intmixer_ctl_get_value(structmixer_ctl*ctl,unsignedintid);
intmixer_ctl_get_array(structmixer_ctl*ctl,void*array,size_tcount);
intmixer_ctl_set_value(structmixer_ctl*ctl,unsignedintid,intvalue);
intmixer_ctl_set_array(structmixer_ctl*ctl,constvoid*array,size_tcount);
intmixer_ctl_set_enum_by_string(structmixer_ctl*ctl,constchar*string);
intmixer_ctl_get_range_min(structmixer_ctl*ctl);
intmixer_ctl_get_range_max(structmixer_ctl*ctl);
[/code]MIXER使用,有哪些属性,干什么用的,看名字就已经很清楚了。
//原始状态
root@pone:/data/local/tmp#tinymix-D1
Mixername:'mixer_name_xx'
Numberofcontrols:2
ctl	type	num	namevalue
0	BOOL	1	MicCaptureSwitchOff
1	INT	1	MicCaptureVolume256
//详细信息
root@pone:/data/local/tmp#tinymix-D10
MicCaptureSwitch:Off
root@pone:/data/local/tmp#tinymix-D11
MicCaptureVolume:256(range0->256)
//设置
root@pone:/data/local/tmp#tinymix-D101
root@pone:/data/local/tmp#tinymix-D11250
//修改后的状态
root@pone:/data/local/tmp#tinymix-D1
Mixername:'mixer_name_xx'
Numberofcontrols:2
ctl	type	num	namevalue
0	BOOL	1	MicCaptureSwitchOn
1	INT	1	MicCaptureVolume250
[/code]

扩展:1.什么是pcmhttp://en.wikipedia.org/wiki/Pulse-code_modulation2.音频采样http://baike.baidu.com/link?url=b9CLvaPgU4A0e0X3y5cLU4ADOI0eBuUeCys05m5unE7G-0eR2sQMBVhNxkCEvOf-Ot2CLAw2wWX5ZLhqi3D2t_#1
目前Linux中主流的音频体系结构是ALSA(AdvancedLinuxSoundArchitecture),ALSA在内核驱动层提供了alsa-driver,在应用层提供了alsa-lib,应用程序只需要调用alsa-lib提供的API就可以完成对底层硬件的操作。说的这么好,但是Android中没有使用标准的ALSA,而是一个ALSA的简化版叫做tinyalsa。Android中使用tinyalsa控制管理所有模式的音频通路,我们也可以使用tinyalsa提供的工具进行查看、调试。编译tinyalsa后生成四个小工具:[objc]viewplaincopytinymix
tinyplay
tinycap
tinypcminfo
编译命令:[objc]viewplaincopymmmexternal/tinyalsa/



下面依次演示一下四个小工具的使用:(以下使用联芯科技的LC1860平台配合LC1160电源+音频芯片,截图及演示效果均来自M7301P5测试机)1,tinypcminfotinypcminfo用于查看pcm通道的相关信息输入:[objc]viewplaincopytinypcminfo-D/proc/asound/cards
结果如下:


从上面获得的信息中可以知道PCM的采样率,通道个数,采样点数等信息。其中–D后边跟的参数为声卡文件,一般位于/proc/asound/cards。可以使用
[objc]viewplaincopycat/proc/asound/cards
查看当前声卡



2,tinymix如下图所示,直接输入tinymix可以得到音频通路相关的各项配置参数。也可以通过添加参数修改其中的配置,如希望提高ADC1Gain值到110,输入tinymix12110即可。


单独查看上述信息比较难以梳理,配合音频通路图会更加清晰。


上图中红色字体标明了LC1160与麦克风、耳机等硬件设备的连接关系。(注:M73xx项目由于内部ClassD不满足要求,喇叭连在了AUX通路上)各个通路上的增益调节部分使用绿色字体标出了与tinymix中选项的对应关系。图中加号与Mux是通路选择开关,对应tinymix中的其它的选项,用于在各种模式下切换音频通道。此部分比较多没有在图中一一标出,但根据已知的通路名是比较容易对应的。图中黄色箭头标出的是通话时下行音频数据流,从PCM接口进入到LC1160,然后经过MonoDAC进行数模转化后送到听筒。图中紫色箭头标出的是通话时上行音频数据流,从主MIC采集声音后,经过ADC1进行模数转换后由PMC的DO线送出
3,tinyplaytinyplay是一个简易的音乐播放器,一般用于播放测试。tinyplay只能播放wav原始格式的音乐,不能进行Mp3等格式的解码,支持44.1kHz,48kHz采样率的wav音乐。在调用tinyplay播放音乐之前需要先使用tinymix切换好音频通路:[objc]viewplaincopytinymix0I2SR//选择StereoDACR的音源为i2s
tinymix1I2SL//选择StereoDACL的音源为i2s
tinymix200//将StereoDAC左右声道的mute关闭
tinymix241//开启喇叭的外部PA芯片
tinymix401//将StereoDACR的声音路由到AUX口输出(因为实验机器喇叭挂载AUX接口上)
tinymix411//将StereoDACR的声音路由到AUX口输出(因为实验机器喇叭挂载AUX接口上)
tinyplayz.wav



4,tinycaptinycap是一个简易的录音软件,一般用于录音测试。在调用tinycap录音之前需要先调整好音频通路:[objc]viewplaincopytinymix1430//mic1volume
tinymix191//mic1booston
tinymix261//adc1->mic1
tinymix50ADC1//i2sRout->adc1
tinymix51ADC1//i2sLout->adc2
echo"0xfb0x01">/sys/devices/platform/comip_codec/lc1160_reg//biaspoweron
echo"0xad0x08">/sys/devices/platform/comip_codec/lc1160_reg//adc1enable
echo"0xac0x01">/sys/devices/platform/comip_codec/lc1160_reg//mic1pgaenable
echo"0x3b0xcc">/sys/devices/platform/comip_codec/lc1160_reg//ldo
echo2>/sys/bus/i2c/drivers/fm2018/0-0060/mode//bypass外部的回声消除音频芯片(M730x项目特有)

tinycap/sdcard/Music/l.wav
录音结束通过ctrl+C强行退出即可,之后在/sdcard/Music/路径下查看到l.wav音频文件

使用adbpull到本地电脑中,使用goldwave播放、查看。[objc]viewplaincopyadbpull/sdcard/Music/l.wavd:\



另外:LC1160的寄存器是分页的,即同一个地址上存在两个不同含义的寄存器,通过控制0xFC寄存器中的值来切换到第二功能页
[objc]viewplaincopyecho"0xfc0x01">/sys/devices/platform/comip_codec/lc1160_reg
cat/sys/devices/platform/comip_codec/lc1160_reg
echo"0xfc0x00">/sys/devices/platform/comip_codec/lc1160_reg
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: