ALSA音频架构 -- aplay播放流程分析

引言

上文ALSA音频架构 – snd_pcm_open函数分析已经获取了aplay中对应的播放API writei_func = snd_pcm_writei;,本文将具体分析该API在哪里调用。

aplay处理数据流顺序图

在这里插入图片描述

代码详细分析

1、对参数进行解析,存储在全局变量hwparams,配置回调writei_func = snd_pcm_writei;
2、调用snd_pcm_open打开PCM设备,将回调关联具体的写入接口snd_pcm_hw_writei
3、调用playback根据文件类型选择具体的播放API,本文以PCM数据流为例,所以具体的接口为playback_raw
4、playback_raw对具体的数据进行解析
playback_raw的函数原型如下

static int playback_raw(char *name, int *loaded)
{
    
    
	init_raw_data();
	pbrec_count = calc_count();
	playback_go(fd, *loaded, pbrec_count, FORMAT_RAW, name);

	return 0;
}

playback_raw主要完成的工作
调用calc_count获取数据流大小
调用playback_go进行具体的操作

5、playback_go首先会调用set_params进行具体的参数配置,然后调用pcm_write进行写入数据流
set_params主要设置了播放的数据流的文件格式、通道数、采样率等,函数原型如下

static void set_params(void)
{
    
    
	snd_pcm_hw_params_t *params;
	snd_pcm_sw_params_t *swparams;
	snd_pcm_uframes_t buffer_size;
	int err;
	size_t n;
	unsigned int rate;
	snd_pcm_uframes_t start_threshold, stop_threshold;
	snd_pcm_hw_params_alloca(&params); // 分配结构体snd_pcm_hw_params_t 
	snd_pcm_sw_params_alloca(&swparams);
	err = snd_pcm_hw_params_any(handle, params);
	...
		err = snd_pcm_hw_params_set_access(handle, params,  // 设置存取权限
						   SND_PCM_ACCESS_RW_INTERLEAVED);
	...
	err = snd_pcm_hw_params_set_format(handle, params, hwparams.format);  // 设置文件格式
	if (err < 0) {
    
    
		error(_("Sample format non available"));
		show_available_sample_formats(params);
		prg_exit(EXIT_FAILURE);
	}
	err = snd_pcm_hw_params_set_channels(handle, params, hwparams.channels);  // 设置通道数
	if (err < 0) {
    
    
		error(_("Channels count non available"));
		prg_exit(EXIT_FAILURE);
	}
	rate = hwparams.rate;
	err = snd_pcm_hw_params_set_rate_near(handle, params, &hwparams.rate, 0);  // 设置码率
...
err = snd_pcm_hw_params(handle, params);
...
snd_pcm_hw_params_get_period_size(params, &chunk_size, 0);
snd_pcm_hw_params_get_buffer_size(params, &buffer_size);  // 获取一个周期有多少帧数据

pcm_write调用函数指针writei_func snd_pcm_hw_writei完成数据流的写入,函数原型如下

static ssize_t pcm_write(u_char *data, size_t count)
{
    
    
	...
	while (count > 0 && !in_aborting) {
    
    
		if (test_position)
			do_test_position();
		check_stdin();
		r = writei_func(handle, data, count); //写入数据
		...
	}
}

至此aplay的播放在用户空间层面的操作已经完成,接下来即进入驱动层进行具体的操作。

aplay的播放流程

1、snd_pcm_open通过SND_PCM_STREAM_PLAYBACK打开设备获取snd_pcm_t句柄
2、snd_pcm_hw_params_alloca分配snd_pcm_hw_params_t PCM设备属性
3、snd_pcm_hw_params_any 初始化PCM设备属性
4、snd_pcm_hw_params_set_access设置存取权限
5、snd_pcm_hw_params_set_format设置格式
6、snd_pcm_hw_params_set_channels设置通道
7、snd_pcm_hw_params_set_rate_near设置码率
8、snd_pcm_hw_paramssnd_pcm_hw_params_t PCM设备属性回写设备
9、snd_pcm_hw_params_get_period_size获取每周期的数据帧数
10、snd_pcm_writei按帧写入数据
11、snd_pcm_drainsnd_pcm_close关闭PCM设备

猜你喜欢

转载自blog.csdn.net/liang_zhaocong/article/details/126208430