菜鸟修炼笔记-alsa-录制和播放的详细过程

前言

网上很多资料都提到怎么录制和播放wav音频文件,但是很少提及原始pcm音频文件的录制和播放,下面我将结合网上资料和自己的理解梳理用alsa录制和播放原始pcm音频文件的原理和过程。

一。播放基本原理和过程(伪代码)

1. 打开pcm音频文件

fp = fopen(DEFAULT_PATH, "rb");//DEFAULT_PATH为pcm音频文件的地址

2. 打开音频设备

snd_pcm_t*       handle = NULL;
//以音频模式打开,handle为音频设备的句柄
snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);

3. 设置播放的参数

snd_pcm_hw_params_t*      params = NULL;
snd_pcm_hw_params_alloca(&params); //分配params结构体
snd_pcm_hw_params_any(handle, params);//初始化params
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);	//设置访问类型
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);//设置数据格式
snd_pcm_hw_params_set_channels(handle, params, channels);	//设置声道,1表示单声道,2表示立体声
unsigned int       val = 44100;
int                dir=0;
snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);  //设置频率
  • 补充说明:

一。 snd_pcm_hw_params_set_access:设置访问类型:

  1. SND_PCM_ACCESS_RW_INTERLEAVED
    交错访问。在缓冲区的每个 PCM 帧都包含所有设置的声道的连续的采样数据。比如声卡要播放采样长度是 16-bit 的 PCM立体声数据,表示每个 PCM 帧中有 16-bit 的左声道数据,然后是 16-bit 右声道数据。

  2. SND_PCM_ACCESS_RW_NONINTERLEAVED
    非交错访问。每个 PCM 帧只是一个声道需要的数据,如果使用多个声道,那么第一帧是第一个声道的数据,第二帧是第二个声道的数据,依此类推。

二。snd_pcm_hw_params_set_format:设置数据格式:
主要控制输入的音频数据的类型、无符号还是有符号、是little-endian 还是 bit-endian:

比如对于 16-bit 长度的采样数据可以设置为:
SND_PCM_FORMAT_S16_LE 有符号16 bit Little Endian
SND_PCM_FORMAT_S16_BE 有符号16 bit Big Endian
SND_PCM_FORMAT_U16_LE 无符号16 bit Little Endian
SND_PCM_FORMAT_U16_BE 无符号 16 bit Big Endian
比如对于 32-bit 长度的采样数据可以设置为:
SND_PCM_FORMAT_S32_LE 有符号32 bit Little Endian
SND_PCM_FORMAT_S32_BE 有符号32 bit Big Endian
SND_PCM_FORMAT_U32_LE 无符号32 bit Little Endian
SND_PCM_FORMAT_U32_BE 无符号 32 bit Big Endian

4.将设置好的参数写入设备

snd_pcm_hw_params(handle, params);

5. 计算每个周期的音频数据大小

//获取一个周期有多少帧数据,一个周期一个周期方式处理音频数据。
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
int    size;
//每帧数据4个字节,每个周期的数据大小为size
size = frames * 4;

6. 把音频文件的数据全部读出到缓存中

char *buf; 
int file_size;//用ls -al等其他方式去获取到音频文件的大小
buf = (char*)malloc(file_size+ 4096);//分配缓存,这里+4096是确保可以完全读出音频文件
memset(buf, 0x00, file_size);//将缓存区清零
fread(buf , 1, file_size, fp);//将音频文件的数据全部读取到缓存区

7. 循环写入数据

int count_value = 0;//count_value 是用来协助“按顺序将缓存写入文件”
while1{
	snd_pcm_writei(handle, buf + count_value, frames)//按顺序将缓存写入文件
	count_value = count_value + size;//更新下一帧存储的位置
	if(count_value > file_size) 	//缓存区的数据全部写入完成,则退出循环。
		{			
			break;
		}
	usleep(5);				//每一帧数据写入完成,需要等待5ms再写入下一帧。
	
}

8. 关闭音频设备并初始化

	close(fp);//关闭打开的源文件
	snd_pcm_drop(handle);//关闭音频设备
	snd_pcm_close(handle);
	free(buf);//清空缓存

二。录音的基本原理和过程(伪代码)

1. 打开pcm音频文件

	FILE * out_fd;
	out_fd = fopen("./out_pcm.raw","wb+");//"./out_pcm.raw"为将要录制的音频文件的存储地址

其中.raw代表着音频文件为原始的pcm音频文件。

2. 打开音频设备

snd_pcm_t*       handle = NULL;
//以录音模式打开,handle为音频设备的句柄
snd_pcm_open(&handle, "default", SND_PCM_STREAM_CAPTURE, 0);

3. 设置录制的参数

snd_pcm_hw_params_t*      params = NULL;
snd_pcm_hw_params_alloca(&params); //分配params结构体
snd_pcm_hw_params_any(handle, params);//初始化params
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);	//设置访问类型
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);//设置数据格式
snd_pcm_hw_params_set_channels(handle, params, channels);	//设置声道,1表示单声道,2表示立体声
unsigned int       val = 44100;
int                dir=0;
snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);  //设置频率
frames = 256;
snd_pcm_hw_params_set_period_size_near(handle,params,&frames,&dir);//设置周期的数量(帧数)
  • 补充说明:

一。 snd_pcm_hw_params_set_access:设置访问类型:

  1. SND_PCM_ACCESS_RW_INTERLEAVED
    交错访问。在缓冲区的每个 PCM 帧都包含所有设置的声道的连续的采样数据。比如声卡要播放采样长度是 16-bit 的 PCM立体声数据,表示每个 PCM 帧中有 16-bit 的左声道数据,然后是 16-bit 右声道数据。

  2. SND_PCM_ACCESS_RW_NONINTERLEAVED
    非交错访问。每个 PCM 帧只是一个声道需要的数据,如果使用多个声道,那么第一帧是第一个声道的数据,第二帧是第二个声道的数据,依此类推。

二。snd_pcm_hw_params_set_format:设置数据格式:
主要控制输入的音频数据的类型、无符号还是有符号、是little-endian 还是 bit-endian:

比如对于 16-bit 长度的采样数据可以设置为:
SND_PCM_FORMAT_S16_LE 有符号16 bit Little Endian
SND_PCM_FORMAT_S16_BE 有符号16 bit Big Endian
SND_PCM_FORMAT_U16_LE 无符号16 bit Little Endian
SND_PCM_FORMAT_U16_BE 无符号 16 bit Big Endian
比如对于 32-bit 长度的采样数据可以设置为:
SND_PCM_FORMAT_S32_LE 有符号32 bit Little Endian
SND_PCM_FORMAT_S32_BE 有符号32 bit Big Endian
SND_PCM_FORMAT_U32_LE 无符号32 bit Little Endian
SND_PCM_FORMAT_U32_BE 无符号 32 bit Big Endian

4.将设置好的参数写入设备

snd_pcm_hw_params(handle, params);

5. 计算每个周期的音频数据大小

//获取一个周期有多少帧数据,一个周期一个周期方式处理音频数据。
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
int    size;
//每帧数据4个字节,每个周期的数据大小为size
size = frames * 4;

6. 为读取的每一帧音频分配缓存

char *buf; 
int file_size;
buf = (char*)malloc(file_size);//分配缓存

7. 循环写入数据

snd_pcm_hw_params_get_period_time(params, &val, &dir);//将每一帧(每个周期)的时间获取到val
long loops = 5000000 / val;		   // 记录5秒长的声音 
	while( loops > 0 )
   {
       loops--;
       snd_pcm_readi(handle,buffer,frames); //读取音频设备的数据于缓存  
		// 将音频数据写入文件
	   fwrite(buffer, 1, size, out_fd);
   }

8. 关闭音频设备并初始化

	snd_pcm_drop(handle);//关闭音频设备
	snd_pcm_close(handle);
	free(buffer);//清空缓存
    fclose(out_fd);//关闭打开的源文件

参考资料

  1. alsa学习–4.用alsa播放wav文件
  2. PCM音频设备的操作(转)
  3. c语言实现ALSA录音
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值