set_pcm_play函數用於播放長度爲datalen的buffer中的字符串,其中buffer中字符串爲除去WAV文件頭得到的二進制歌曲文件。
int demo_sound::set_pcm_play(char *buffer,int datalen)
{
int rc;
int ret=0;
int size;
snd_pcm_t* handle; //PCI設備句柄
snd_pcm_hw_params_t* params;//硬件信息和PCM流配置
unsigned int val;
int dir=0;
snd_pcm_uframes_t frames;
int channels=1;
int frequency=16000;
int bit=16;
int datablock=2;
unsigned char ch[100]; //用來存儲wav文件的頭信息
rc=snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
if(rc<0)
{
perror("\nopen PCM device failed:");
exit(1);
}
snd_pcm_hw_params_alloca(¶ms); //分配params結構體
if(rc<0)
{
perror("\nsnd_pcm_hw_params_alloca:");
exit(1);
}
rc=snd_pcm_hw_params_any(handle, params);//初始化params
if(rc<0)
{
perror("\nsnd_pcm_hw_params_any:");
exit(1);
}
rc=snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); //初始化訪問權限
if(rc<0)
{
perror("\nsed_pcm_hw_set_access:");
exit(1);
}
/* Signed 16-bit little-endian format */
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
rc=snd_pcm_hw_params_set_channels(handle, params, 1); //設置聲道,1表示單聲>道,2表示立體聲
if(rc<0)
{
perror("\nsnd_pcm_hw_params_set_channels:");
exit(1);
}
val = frequency;
rc=snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir); //設置>頻率
if(rc<0)
{
perror("\nsnd_pcm_hw_params_set_rate_near:");
exit(1);
}
rc = snd_pcm_hw_params(handle, params);
if(rc<0)
{
perror("\nsnd_pcm_hw_params: ");
exit(1);
}
if ((rc = snd_pcm_set_params(handle,
SND_PCM_FORMAT_S16_LE,
SND_PCM_ACCESS_RW_INTERLEAVED,
1,
16000,
1,
500000)) < 0) { /* 0.5sec */
printf("Playback open error: %s\n", snd_strerror(rc));
exit(EXIT_FAILURE);
}
rc=snd_pcm_hw_params_get_period_size(params, &frames, &dir); /*獲取週期長度*/
if(rc<0)
{
perror("\nsnd_pcm_hw_params_get_period_size:");
exit(1);
}
size = frames * datablock; /*4 代表數據快長度*/
int readlen=0;
while (1)
{
// 寫音頻數據到PCM設備
int try_count=0; //錯誤重試計數
while((ret = snd_pcm_writei(handle, buffer+readlen, frames))<0)
{
// usleep(2000);
if (ret == -EPIPE) /*設備被搶佔,重新配置設備*/
{
SYS_LOG(INFO,"underrun occurred\n");
int err = snd_pcm_prepare(handle); //完成硬件參數設置,使設備準備好
if (err < 0){
printf("Can't recovery from underrun, prepare failed: %s\n", snd_strerror(err));
goto ERROR_MASK;
}
err = snd_pcm_recover(handle, ret, 0);
if (err < 0){
printf("snd_pcm_recover prepare failed: %s\n", snd_strerror(err));
goto ERROR_MASK;
}
printf("err %d",err);
}
else if (ret < 0)
{
SYS_LOG(INFO,"error from writei: %s\n",snd_strerror(ret));
}
printf("try_count %d ",try_count);
/*寫設備出錯,重試10次,避免死循環*/
{
try_count++;
if(try_count>10)
{
SYS_LOG(INFO,"the count of retry out of time !\n");
try_count=0;
goto ERROR_MASK;
break;
}
}
}
readlen+=size;
if(readlen+size>datalen)
break;
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
return 0;
ERROR_MASK:
snd_pcm_drain(handle);
snd_pcm_close(handle);
return -1;
}
錯誤:出現underrun的原因是:初始化配置有問題。