ALSA子系统(四)------Tinyplay流程分析

你好!这里是风筝的博客,
欢迎和我一起交流。

移植tinyalsa工具参考上一篇文章:ALSA子系统(三)------Audio测试工具(tinyalsa)
如果是有 Android 环境,直接在external/tinyalsa目录下mm即可。

使用trace工具可以抓取tinyplay流程。
主要流程如下,附有注释,同时为了方便浏览删除了一些不太重要的log。

# trace tinyplay spring_48K_2ch_16bit.wav                                       <
execve("/system/bin/tinyplay", ["tinyplay", "spring_48K_2ch_16bit.wav"], 0xffe623e4 /* 19 vars */) = 0
set_tls(0xffe951d0)                     = 0
getpid()                                = 3171
openat(AT_FDCWD, "/dev/cpu_variant:arm", O_RDONLY) = 3
read(3, "cortex-a7", 11)                = 9
read(3, "", 2)                          = 0
close(3)                                = 0

openat(AT_FDCWD, "spring_48K_2ch_16bit.wav", O_RDONLY|O_LARGEFILE) = 3

read(3, "RIFFf`E\0WAVEfmt \22\0\0\0\1\0\2\0\200\273\0\0\0\356\2\0"..., 4096) = 4096

read(3, "LIST\32\0\0\0INFOISFT\16\0\0\0Lavf58.45.10"..., 4096) = 4096

read(3, "data,IE\0\377\377\372\377\376\377\372\377\1\0\0\0\2\0\7\0\4\0\4\0\2\0\3\0"..., 4096) = 4096
openat(AT_FDCWD, "/dev/snd/pcmC0D0p", O_RDWR|O_LARGEFILE) = 4


//#define SNDRV_PCM_IOCTL_HW_REFINE	_IOWR('A', 0x10, struct snd_pcm_hw_params)
ioctl(4, _IOC(_IOC_READ|_IOC_WRITE, 0x41, 0x10, 0x25c), 0xed8f6000) = 0
close(4)                                = 0

openat(AT_FDCWD, "/dev/snd/pcmC0D0p", O_RDWR|O_NONBLOCK|O_LARGEFILE) = 4


ioctl(4, SNDRV_PCM_IOCTL_INFO, 0xffe94fe0) = 0
//#define SNDRV_PCM_IOCTL_HW_PARAMS	_IOWR('A', 0x11, struct snd_pcm_hw_params)
ioctl(4, _IOC(_IOC_READ|_IOC_WRITE, 0x41, 0x11, 0x25c), 0xffe94d80) = 0
//#define SNDRV_PCM_IOCTL_SW_PARAMS	_IOWR('A', 0x13, struct snd_pcm_sw_params)
ioctl(4, _IOC(_IOC_READ|_IOC_WRITE, 0x41, 0x13, 0x68), 0xffe94d18) = 0


//#define SNDRV_PCM_IOCTL_SYNC_PTR	_IOWR('A', 0x23, struct snd_pcm_sync_ptr)
ioctl(4, _IOC(_IOC_READ|_IOC_WRITE, 0x41, 0x23, 0x84), 0xed8ef000) = 0

ioctl(1, TCGETS, {B115200 opost isig icanon echo ...}) = 0
write(1, "Playing sample: 2 ch, 48000 hz, "..., 53Playing sample: 2 ch, 48000 hz, 16 bit 4540716 bytes
     ) = 53
rt_sigaction(SIGINT, {sa_handler=0xca9f8d1, sa_mask=[], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0xed7cf980}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
/* 读音频数据 */
read(3, "\4\0\5\0\0\0\2\0\376\377\1\0\10\0\371\377\0\0\363\377\1\0\6\0\4\0\16\0\0\0\376\377"..., 12296) = 12296
ioctl(4, SNDRV_PCM_IOCTL_PREPARE, 0x4000) = 0
/* 写入声卡 */
///#define SNDRV_PCM_IOCTL_WRITEI_FRAMES	_IOW('A', 0x50, struct snd_xferi)
ioctl(4, _IOC(_IOC_WRITE, 0x41, 0x50, 0xc), 0xffe95100) = 0
read(3, "\1\0\17\0\375\377\375\377\3\0\356\377\3\0\373\377\371\377\1\0\3\0\v\0\6\0\23\0\t\0\n\0"..., 16384) = 16384
ioctl(4, _IOC(_IOC_WRITE, 0x41, 0x50, 0xc), 0xffe95100) = 0

/* 一直循环 */

/* 读音频数据 */
read(3, "\204\377\t\372B\377\311\373a\377%\375\356\0\214\375\211\1\177\376\252\1\255\376s\3\326\377\206\3Z\0"..., 16384) = 16384
/* 写入声卡 */
///#define SNDRV_PCM_IOCTL_WRITEI_FRAMES	_IOW('A', 0x50, struct snd_xferi)
ioctl(4, _IOC(_IOC_WRITE, 0x41, 0x50, 0xc), 0xffe95100) = 0
read(3, "\347\372M\376A\372\266\375N\372\361\375^\372\267\375\374\371\23\375<\3723\375X\372E\3753\372C\375"..., 4096) = 4096
ioctl(4, _IOC(_IOC_WRITE, 0x41, 0x50, 0xc), 0xffe95100) = 0
close(4)                                = 0
close(3)                                = 0

exit_group(0)                           = ?
+++ exited with 0 +++

主要都是open ioctl和read/write操作,不难理解。
不过有个值得注意的是,这里发现流程里面会执行了两次openat "/dev/snd/pcmC0D0p"的操作:

openat(AT_FDCWD, "/dev/snd/pcmC0D0p", O_RDWR|O_LARGEFILE) = 4
close(4)                                = 0

openat(AT_FDCWD, "/dev/snd/pcmC0D0p", O_RDWR|O_NONBLOCK|O_LARGEFILE) = 4

这是应为第一次openat(openat和open函数类似)时,设置了 SNDRV_PCM_IOCTL_HW_REFINE :

//#define SNDRV_PCM_IOCTL_HW_REFINE	_IOWR('A', 0x10, struct snd_pcm_hw_params)
ioctl(4, _IOC(_IOC_READ|_IOC_WRITE, 0x41, 0x10, 0x25c), 0xed8f6000) = 0

这是为了重新规范硬件参数,最后就是调用到底层的snd_pcm_hw_refine了。

PS:当我们更改一个参数时,内核驱动程序通过 SNDRV_PCM_IOCTL_HW_REFINE 来调整snd_pcm_hw_params结构中依赖于我们更改的参数的所有其他参数。
将配置空间减少到实际需要的配置之后,接下来才调用snd_pcm_hw_params()(SNDRV_PCM_IOCTL_HW_PARAMS)来实际为这些参数配置设备。

//include/uapi/sound/asound.h
struct snd_pcm_hw_params {
	unsigned int flags;
	struct snd_mask masks[SNDRV_PCM_HW_PARAM_LAST_MASK - 
			       SNDRV_PCM_HW_PARAM_FIRST_MASK + 1];
	struct snd_mask mres[5];	/* reserved masks */
	struct snd_interval intervals[SNDRV_PCM_HW_PARAM_LAST_INTERVAL -
				        SNDRV_PCM_HW_PARAM_FIRST_INTERVAL + 1];
	struct snd_interval ires[9];	/* reserved intervals */
	unsigned int rmask;		/* W: requested masks */
	unsigned int cmask;		/* R: changed masks */
	unsigned int info;		/* R: Info flags for returned setup */
	unsigned int msbits;		/* R: used most significant bits */
	unsigned int rate_num;		/* R: rate numerator */
	unsigned int rate_den;		/* R: rate denominator */
	snd_pcm_uframes_t fifo_size;	/* R: chip FIFO size in frames */
	unsigned char reserved[64];	/* reserved for future */
};

aplay的流程可以参考这篇:ALSA声卡07_分析调用过程_学习笔记

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值