ALSA子系统(三)------Audio测试工具(tinyalsa)

你好!这里是风筝的博客,

欢迎和我一起交流。


工欲善其事必先利其器,我们要测试音频时,一般有两个常见的工具:
amixer系列(amixer、aplay、arecord)和tinyalsa系列
amixer功能强大,基本啥都能配置。
tinyplay则比较简单,不足以实现全部功能。
但是!!!!!!
amixer系列工具需要使用alsa-lib和alsa-utils,经过一系列交叉编译后才能移植使用,tinyalsa则不需要依赖太多。

TinyAlsa是 Android 默认的 alsalib, 封装了内核 ALSA 的接口,用于简化用户空 间的 ALSA 编程。
与aplay相比,大大降低了编译和使用难度。
而在linux3.x的版本 android 4.0往后,已经使用TinyAlsa了,代码位置在external/tinyalsa。
libtinyals.so是由mixer.c和pcm.c文件生成的,基于这个库有3个工具可以使用:tinyplay,tinycap,tinymix,编译android系统后就能使用。

当然,我们也可以单独使用,源码在:https://github.com/tinyalsa/tinyalsa

仓库里有两个分支,master和google-origin
google-origin分支就是用在Android里面,不过我看这个分支一年多没人维护了,最新提交在2019年2月。
master分支则一直在维护,各大系统里面也是用的master分支。

我推荐使用google-origin分支,和Android同步。
将代码clone下来加上如下Makefile即可使用:

CFLAGS = -c -fPIC -Wall
INC = include
OBJECTS = mixer.o pcm.o
LIB = libtinyalsa.so
CROSS_COMPILE ?=
CC = $(CROSS_COMPILE)gcc

TARGET = tinyplay tinycap tinymix tinypcminfo

all: $(LIB) $(TARGET)
	rm *.o

tinyplay: $(LIB) tinyplay.o
	$(CC) tinyplay.o -L. -ltinyalsa -o tinyplay

tinycap: $(LIB) tinycap.o
	$(CC) tinycap.o -L. -ltinyalsa -o tinycap

tinymix: $(LIB) tinymix.o
	$(CC) tinymix.o -L. -ltinyalsa -o tinymix

tinypcminfo: $(LIB) tinypcminfo.o
	$(CC) tinypcminfo.o -L. -ltinyalsa -o tinypcminfo

$(LIB): $(OBJECTS)
	$(CC) -shared $(OBJECTS) -o $(LIB)

.c.o:
	$(CC) $(CFLAGS) $< -I$(INC)

.PHONY : clean
clean:
	-rm -f $(LIB) $(OBJECTS) $(TARGET) \
		*.o \

在tinyalsa里面,合理的pcm_config可以做到更好的低时延和功耗,移动设备的开发尤其敏感。

struct pcm_config {
     
    unsigned int channels;
    unsigned int rate;
    unsigned int period_size;
    unsigned int period_count;
    enum pcm_format format;
    unsigned int start_threshold;
    unsigned int stop_threshold;
    unsigned int silence_threshold;
    int avail_min;
};

解释一下结构中的各个参数,每个参数的单位都是frame(1帧 = 通道*采样位深):

  • period_size. 每次传输的数据长度。值越小,时延越小,cpu占用就越高。
  • period_count. 缓之冲区period的个数。缓冲区越大,发生XRUN的机会就越少。
  • format. 定义数据格式,如采样位深,大小端。
  • start_threshold. 缓冲区的数据超过该值时,硬件开始启动数据传输。如果太大, 从开始播放到声音出来时延太长,甚至可导致太短促的声音根本播不出来;如果太小, 又可能容易导致XRUN.
  • stop_threshold. 缓冲区空闲区大于该值时,硬件停止传输。默认情况下,这个数 为整个缓冲区的大小,即整个缓冲区空了,就停止传输。但偶尔的原因导致缓冲区空, 如CPU忙,增大该值,继续播放缓冲区的历史数据,而不关闭再启动硬件传输(一般此 时有明显的声音卡顿),可以达到更好的体验。
  • silence_threshold. 这个值本来是配合stop_threshold使用,往缓冲区填充静音 数据,这样就不会重播历史数据了。
  • avail_min. 缓冲区空闲区大于该值时,pcm_mmap_write()才往缓冲写数据。这个 值越大,往缓冲区写入数据的次数就越少,XRUN的机会就越大。Android samsung tuna 设备在screen_off时增大该值以减小功耗,在screen_on时减小该 值以减小XRUN的机会。

在不同的场景下,合理的参数就是在性能、时延、功耗等之间达到较好的平衡。


一个典型的声音程序(伪代码)包括:

  • 1 打开回放或录音接口
  • 2 设置硬件参数(访问模式,数据格式,信道数,采样率,等等)
  • 3 while 有数据要被处理:
  • 4 读PCM数据(录音) 或 写PCM数据(回放)
  • 5 关闭接口

在aplay中,使用函数宏 snd_pcm_hw_params_alloca分配出一个类型为snd_pcm_hw_param的变量,使用函数snd_pcm_hw_params_any来初始化这个变量。
对于采样率而言,声音硬件并不一定就精确地支持我们所定的采样率,但是我们可以使用函数snd_pcm_hw_params_set_rate_near来设置最接近我们指定的采样率的采样率。
只有当调用函数 snd_pcm_hw_params后,硬件参数才会起作用。

参考:【转】Alsa音频编程【精华】

你可能感兴趣的:(ALSA子系统,tinyalsa,pcm,linux,alsa,asoc)