Alsa-lib实现播放wav音频
1.alsa-lib移植
例程中使用的alsa-lib库是1.2.6版本的,目前最新的release版本已经到1.2.7版本了,可以根据自身需求下载。
具体下载链接可以访问下面alsa官网的下载链接
https://www.alsa-project.org/files/pub/lib/
下载完alsa-lib库后,我们解压后进入文件夹然后执行下列命令,进行交叉编译
mkdir builds
./configure --prefix=$PWD/builds --host=arm cc=arm-linux-gnueabihf-gcc
make
make install
所有的lib库和头文件都会在builds文件夹下,执行file + lib库,查看交叉编译是否完成,下列是32bit 小端模式,表示交叉编译完成
/project/alsa-lib-1.2.6$ file build/lib/libasound.so.2.0.0
build/lib/libasound.so.2.0.0: ELF 32-bit LSB shared object, ARM, EABI5 version 1 (SYSV), dynamically linked, BuildID[sha1]=568ab75e8ab65df19ba5f34b536694ee4449ce6f, not stripped
2.播放wav音频
1.实现流程
alsa-lib具体的播放音频步骤如下,可以参照官网的例程
1.相关变量定义
2.申请hwparams变量内存 snd_pcm_hw_params_alloca(&pcm->hwparams)
3.打开pcm设备snd_pcm_open
4.初始化hwparams的结构体空间
5.设置数据的属性
1.设置数据的读写模式(一般音频双通道分交错访问模式)
2.设置数据的采样格式(每bit的样本长度)
3.设置数据的通道数
4.设置数据的采样速率
5.设置数据的采样周期
每帧的大小 = 采样格式 * 通道数 / 8bit
特定的周期内的帧数 = 周期大小 * 周期数 / 每帧的大小
比如 某个音频的 采样格式是SND_PCM_FORMAT_S16_LE , 通道数是 2 ,所以一帧的音频大小是 16 x 2 /8 = 4个字节,
周期数为20,周期大小为8192,这个周期内帧数一共有 20 x 8192 >> 2 = 40960 帧
6.申请存放buff的空间 (按帧数计算)snd_pcm_hw_params_set_buffer_size
7.读取音频数据
8.调用snd_pcm_writei 进行播放
2.具体实现
具体的代码在,这个例程只实现了播放wav文件,后续继续更新其他功能
git@github.com:lilixinxin/Alsa_example.git
alsa-lib的封装的结构体
typedef struct pcm_params {
//pcm name like plughw:0,0
char pcm_card_name[64];
//pcm device handle
snd_pcm_t *pcm_handle;
//pcm stream direction
snd_pcm_stream_t stream_direction;
//specify configution for pcm
snd_pcm_hw_params_t *hwparams;
//channel num
int channel_num;
//周期数
int periods;
//sample format bit per sample
snd_pcm_format_t sample_format;
//PCM access type 交错模式或者交错
snd_pcm_access_t access_type;
//采样率
int sample_rate;
//每个周期的大小
int period_szie;
//frames 帧数
int frames;
}Pcm_params;
初始化alsa 相关参数
//初始化alsa device
int Alsa_Dev_init(Pcm_params *pcm)
{
int ret;
//allocate snd_pcm_hw_params_t
snd_pcm_hw_params_alloca(&pcm->hwparams);
//open pcm device
if(snd_pcm_open(&pcm->pcm_handle, pcm->pcm_card_name, pcm->stream_direction, 0) < 0)
{
fprintf(stderr, "Error opening PCM device %s\n", pcm->pcm_card_name);
return -1;
}
/* Init hwparams with full configuration space */
if (snd_pcm_hw_params_any(pcm->pcm_handle, pcm->hwparams) < 0) {
fprintf(stderr, "Can not configure this PCM device.\n");
return -1;
}
//设置数据访问模式
if (snd_pcm_hw_params_set_access(pcm->pcm_handle, pcm->hwparams, pcm->access_type) < 0) {
fprintf(stderr, "Can not set hw params access\n");
return -1;
}
//set sample format bit per sample
if(snd_pcm_hw_params_set_format(pcm->pcm_handle, pcm->hwparams, pcm->sample_format) < 0)
{
fprintf(stderr, "snd_pcm_hw_params_set_format fail\n");
return -1;
}
//set channel num
if(snd_pcm_hw_params_set_channels(pcm->pcm_handle, pcm->hwparams, pcm->channel_num) < 0)
{
fprintf(stderr, "snd_pcm_hw_params_set_channels fail\n");
return -1;
}
//set period
if(snd_pcm_hw_params_set_periods(pcm->pcm_handle, pcm->hwparams, pcm->periods, 0) < 0)
{
fprintf(stderr, "snd_pcm_hw_params_set_periods fail\n");
return -1;
}
//set sample rate
if(snd_pcm_hw_params_set_rate_near(pcm->pcm_handle, pcm->hwparams, &pcm->sample_rate, 0) < 0)
{
fprintf(stderr, "snd_pcm_hw_params_set_rate_near fail\n");
return -1;
}
//每帧大小 每bit样本长度 * channel_num / 8bit
//buffer size 按帧计算器 周期数 * 每个周期时间
/* Set buffer size (in frames). The resulting latency is given by */
/* latency = periodsize * periods / (rate * bytes_per_frame) */
//pcm->frames = (pcm->period_szie * pcm->periods) >> 2;
if (snd_pcm_hw_params_set_buffer_size(pcm->pcm_handle, pcm->hwparams, pcm->frames) < 0) {
fprintf(stderr, "Error setting buffersize.\n");
return(-1);
}
/* Apply HW parameter settings to */
/* PCM device and prepare device */
if (snd_pcm_hw_params(pcm->pcm_handle, pcm->hwparams) < 0) {
fprintf(stderr, "Error setting HW params.\n");
return(-1);
}
return 0;
}
//播放
int Alsa_Playback(Pcm_params *pcm, char **buf)
{
int pcmreturn;
while ((pcmreturn = snd_pcm_writei(pcm->pcm_handle, buf, pcm->frames)) < 0) {
snd_pcm_prepare(pcm->pcm_handle);
fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>\n");
}
return 0;
}
实现播放
//申请buff空间
int buffsize = pcm.period_szie * pcm.periods;
buff = (char *)malloc(buffsize);
if(buff == NULL)
{
fprintf(stderr, "malloc fail\n");
return -1;
}
while(1)
{
ret = fread(buff, 1, buffsize, fp);
printf("read buff len, :%d\n", ret);
if(ret == 0){
printf("end of music file input! \n");
exit(1);
}
if(ret < 0){
printf("read pcm from file! \n");
exit(1);
}
while ((ret = snd_pcm_writei(pcm.pcm_handle, buff, pcm.frames)) < 0) {
snd_pcm_prepare(pcm.pcm_handle);
fprintf(stderr, "<<<<<<<<<<<<<<< Buffer Underrun >>>>>>>>>>>>>>>\n");
}
//Alsa_Playback(&pcm, &buff);
}