在模仿全志例程的时候遇到了一个问题,具体如下:
我可以用aplay播放wav文件,但是在工程中无法播放,每次执行到
err = snd_pcm_writei(playback_handle, buf , BUF_LEN/4);
会弹出错误 write to audio interface failed (Broken pipe) "损坏的管道?"
播放WAV的函数是抄的全志洗衣机那个例子,
网上很多帖子都有提到过类似这段代码,但是没有多余什么讲解 。自己看大概是读出wav文件的wave_header_t,
根据结构成员配置打开的pcm设备,最后snd_pcm_writei实现播放,而我的错误就是该函数返回的。
具体如下:
int play_wav_music(const char * partname)
{
int i; int err;
wav;
int headwavcntp;
snd_pcm_t *playback_handle; snd_pcm_hw_params_t *hw_params;
FILE *fp = NULL;
snd_pcm_format_t pcm_fmt;
char buf[BUF_LEN];
/* 打开 wav 文件 */
fprintf(stderr, "open file : %s\n", partname);
fp = fopen(partname, "r");
if (fp == NULL) {
fprintf(stderr, "open test pcm file err\n");
return -1;
}
/* 读文件头结构体 */
headwavcntp = fread(&wav, 1, sizeof(wave_header_t), fp);
if(headwavcntp != sizeof(wave_header_t)){
printf("read wav file head error!\n");
fclose(fp);
return -1;
}
/* 打印 读到的文件信息 */
printf("read wav file head success \n");
printf("bps = %d\n", wav.uBitsPerSample);
printf("chn = %d\n", wav.uChannels);
printf("fs = %d\n", wav.uSampleRate);
/* 判断 是8bit还是16bit */
if(wav.uBitsPerSample == 8){
pcm_fmt = SND_PCM_FORMAT_S8;
}else if(wav.uBitsPerSample == 16){
pcm_fmt = SND_PCM_FORMAT_S16_LE;
}else{
printf("uBitsPerSample not support!\n");
fclose(fp);
return -1;
}
if((err = snd_pcm_open(&playback_handle, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0){
fprintf(stderr, "cannot open audio device record.pcm (%s)\n", snd_strerror(err));
fclose(fp);
return -1;
}
if((err = snd_pcm_hw_params_malloc(&hw_params)) < 0){
fprintf(stderr, "cannot allocate hardware parameter structure (%s)\n",snd_strerror(err));
goto play_wav_out;
}
if((err = snd_pcm_hw_params_any(playback_handle, hw_params)) < 0){
fprintf(stderr, "cannot initialize hardware parameter structure (%s)\n", snd_strerror(err));
goto play_wav_out;
}
if((err = snd_pcm_hw_params_set_access(playback_handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0){
fprintf(stderr, "cannot allocate hardware parameter structure (%s)\n",snd_strerror(err));
goto play_wav_out;
}
if((err = snd_pcm_hw_params_set_format(playback_handle, hw_params, pcm_fmt)) < 0){
fprintf(stderr, "cannot allocate hardware parameter structure (%s)\n",snd_strerror(err));
goto play_wav_out;
}
if((err = snd_pcm_hw_params_set_rate(playback_handle, hw_params, wav.uSampleRate, 0)) < 0){
fprintf(stderr , "cannot set sample rate (%s)\n", snd_strerror(err));
goto play_wav_out;
}
if((err = snd_pcm_hw_params_set_channels(playback_handle, hw_params, wav.uChannels)) <0){
fprintf(stderr, "cannot set channel count (%s)\n", snd_strerror(err));
goto play_wav_out;
}
if((err = snd_pcm_hw_params(playback_handle, hw_params)) < 0){
fprintf(stderr, "cannot set parameters (%s)\n", snd_strerror(err));
goto play_wav_out;
}
snd_pcm_hw_params_free(hw_params);
while (!feof(fp)) {
err = fread(buf, 1, BUF_LEN, fp);
if (err < 0){
fprintf(stderr, "read pcm from file err\n");
goto play_wav_out;
}
err = snd_pcm_writei(playback_handle, buf , BUF_LEN/4);
if (err < 0){
fprintf(stderr, "write to audio interface failed (%s)\n", /* 我就是在这里弹出的错误 */
snd_strerror(err));
goto play_wav_out;
}
}
play_wav_out:
fprintf(stderr, "close file\n");
fclose(fp);
fprintf(stderr, "close dev\n");
snd_pcm_close(playback_handle); fprintf(stderr, "ok\n");
return 0;
}
/proc/asound/devies 内容如下:
root@TinaLinux:/proc/asound# cat devices
0: [ 0] : control
16: [ 0- 0]: digital audio playback
24: [ 0- 0]: digital audio capture
33: : timer
设备目录下也正常:
root@TinaLinux:/dev/snd# ls -l
crw-rw---- 1 root root 116, 0 Jan 1 00:00 controlC0
crw-rw---- 1 root root 116, 24 Jan 1 00:00 pcmC0D0c
crw-rw---- 1 root root 116, 16 Jan 1 00:00 pcmC0D0p
crw-rw---- 1 root root 116, 33 Jan 1 00:00 timer
也把snd_pcm_open()函数中的设备名 改变过 现在使用的是默认值 ''default",
改过 "hw:0,0" "plughw:0,0" "default:0" 输出错误信息是一样的。
完整的错误信息是这样的/*怕出不必要的问题,没有播放SD卡上的文件,这个开机.wav在启动过程中 通过壳命令播放过*/:
open file : /etc/kaiji.wav
read wav file head success
bps = 16
chn = 1
fs = 32000
write to audio interface failed (Broken pipe)
close file
close dev
现在无从下爪,大佬们帮看下应该怎么处理,或者给个思路也好。为去读aplay的源码看看,2000多行,估计问题比较大!
把报错部分的摘出来:
while (!feof(fp)) {
err = fread(buf, 1, BUF_LEN, fp);
if (err < 0){
fprintf(stderr, "read pcm from file err\n");
goto play_wav_out;
}
err = snd_pcm_writei(playback_handle, buf , BUF_LEN/4);
if (err < 0){
fprintf(stderr, "write to audio interface failed (%s)\n", /*就在这里输出的 str = "Broken pipe"*/
snd_strerror(err));
goto play_wav_out;
}
}
离线
有没有试过 tinyplay 呢?
---------------------------------------------------------------------
可用哦,一切正常!~~~tiny那几个测试程序都可以用,启动时的开机声音就是tinyplay播放的。
aplay也正常工作。
离线
现在怀疑 在调用int play_wav_music(const char * partname) 这个函数前是不是应该有一定的初始化动作。但是,在全志提供的例子中,并没有。并且他的例子在我的板子上也没有声音。。。
怀疑要么需要初始化,或者是某个配置文件没有配置。。。。
现在在看aplay和tinyplay的代码,tinyplay相对代码少一点。但是他是通过函数指针把snd_pcm_......相关函数重新包了一次的。
aplay因为牵扯到命令行解释啥的..代码很多。。先看看tinyplay吧。
离线
@哇酷小二
--------------------------------------
额,这还真的可以试试。
离线