目录
实现步骤
实现思路及遇到的问题
1.未使用alsa库编码
2.使用alsa库编码
3.直接使用linux 自带播放器aplay 播放音频
pulseaudio导致音频播放失败的解决方法
确认使用了哪个声卡
1.硬件是否带声卡
2.确认声卡驱动是否存在
3.确认配置是否正确
注意事项总结
1.确认硬件是否有声卡
2.确认声卡驱动是否正确安装
3.确认声卡配置是否正确
直接用了网上的例子。
http://blog.sina.com.cn/s/blog_3e4774e30100ewoa.html
参考教材:<Linux编程技术详解>杜华编著
页码:P184
程序实现了在Linux下播放Online.wav的功能。程序首先调用fstat函数获得文件相关信息(主要是文件大小信息)。通过malloc函数分配指定的内存空间,并将online.wav读入内存;然后,打开声卡设备文件,设置声卡参数;再调用write函数完成文件的播放。
具体可行的代码如下:
//p6.7.c
#include
#include
#include
#include
#include
#include
#include
#define Audio_Device "/dev/dsp"
//不同的声音有着不同的播放参数,这些参数可以使用file命令获得
#define Sample_Size 16 //there're two kinds of bits,8 bits and 16 bits
#define Sample_Rate 8000 //sampling rate
int play_sound(char *filename){
struct stat stat_buf;
unsigned char * buf = NULL;
int handler,fd;
int result;
int arg,status;
//打开声音文件,将文件读入内存
fd=open(filename,O_RDONLY);
if(fd<0) return -1;
if(fstat(fd,&stat_buf)){
close(fd);
return -1;
}
if(!stat_buf.st_size){
close(fd);
return -1;
}
buf=malloc(stat_buf.st_size);
if(!buf){
close(fd);
return -1;
}
if(read(fd,buf,stat_buf.st_size)<0){
free(buf);
close(fd);
return -1;
}
//打开声卡设备,并设置声卡播放参数,这些参数必须与声音文件参数一致
handler=open(Audio_Device,O_WRONLY);
if(handler==-1){
perror("open Audio_Device fail");
return -1;
}
arg=Sample_Rate;
status=ioctl(handler,SOUND_PCM_WRITE_RATE,&arg);
if(status==-1){
perror("error from SOUND_PCM_WRITE_RATE ioctl");
return -1;
}
arg=Sample_Size;
status=ioctl(handler,SOUND_PCM_WRITE_BITS,&arg);
if(status==-1){
perror("error from SOUND_PCM_WRITE_BITS ioctl");
return -1;
}
result=write(handler,buf,stat_buf.st_size);
if(result==-1){
perror("Fail to play the sound!");
return -1;
}
free(buf);
close(fd);
close(handler);
return result;
}
void main(void)
{
play_sound("/root/Online.wav");
}
编译运行后,我的代码没能通过
[root@localhost ~]#./play_sound
error from SOUND_PCM_WRITE_RATE ioctl: Inappropriate ioctl for device
在我解决这个问题的时候,经音频相关专业人士指点,决定改用alsa库。所以上面这个问题我没解决
同样直接用了网上的例子。
http://blog.chinaunix.net/uid-27106528-id-3328766.html
#include
#include
#include
#include
struct WAV_HEADER
{
char rld[4]; /*riff 标志符号*/
int rLen;
char wld[4]; /*格式类型(wave)*/
char fld[4]; /*"fmt"*/
int fLen; /*sizeof(wave format matex)*/
short wFormatTag; /*编码格式*/
short wChannels; /*声道数*/
int nSamplesPersec ; /*采样频率*/
int nAvgBitsPerSample;/*WAVE文件采样大小*/
short wBlockAlign; /*块对齐*/
short wBitsPerSample; /*WAVE文件采样大小*/
char dld[4]; /*”data“*/
int wSampleLength; /*音频数据的大小*/
} wav_header;
int set_pcm_play(FILE *fp);
int main(int argc,char *argv[])
{
if(argc!=2)
{
printf("Usage:wav-player+wav file name\n");
exit(1);
}
int nread;
FILE *fp;
fp=fopen(argv[1],"rb");
if(fp==NULL)
{
perror("open file failed:\n");
exit(1);
}
nread=fread(&wav_header,1,sizeof(wav_header),fp);
printf("nread=%d\n",nread);
printf("RIFF 标志%s\n",wav_header.rld);
printf("文件大小rLen:%d\n",wav_header.rLen);
printf("wld=%s\n",wav_header.wld);
printf("fld=%s\n",wav_header.fld);
printf("fLen=%d\n",wav_header.fLen);
printf("wFormatTag=%d\n",wav_header.wFormatTag);
printf("声道数:%d\n",wav_header.wChannels);
printf("采样频率:%d\n",wav_header.nSamplesPersec);
printf("nAvgBitsPerSample=%d\n",wav_header.nAvgBitsPerSample);
printf("wBlockAlign=%d\n",wav_header.wBlockAlign);
printf("采样的位数:%d\n",wav_header.wBitsPerSample);
printf("data=%s\n",wav_header.dld);
printf("wSampleLength=%d\n",wav_header.wSampleLength);
set_pcm_play(fp);
return 0;
}
int set_pcm_play(FILE *fp)
{
int rc;
int ret;
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;
char *buffer;
int channels=wav_header.wChannels;
int frequency=wav_header.nSamplesPersec;
int bit=wav_header.wBitsPerSample;
int datablock=wav_header.wBlockAlign;
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);
}
/*采样位数*/
switch(bit/8)
{
case 1:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_U8);
break ;
case 2:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
break ;
case 3:snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S24_LE);
break ;
}
rc=snd_pcm_hw_params_set_channels(handle, params, channels); /*设置声道,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);
}
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 代表数据快长度*/
buffer =(char*)malloc(size);
fseek(fp,58,SEEK_SET); /*定位歌曲到数据区*/
while (1)
{
memset(buffer,0,sizeof(buffer));
ret = fread(buffer, 1, size, fp);
if(ret == 0)
{
printf("歌曲写入结束\n");
break;
}
else if (ret != size)
{
}
/* 写音频数据到PCM设备*/
while(ret = snd_pcm_writei(handle, buffer, frames)<0)
{
usleep(2000);
if (ret == -EPIPE)
{
/* EPIPE means underrun */
fprintf(stderr, "underrun occurred\n");
/*完成硬件参数设置,使设备准备好*/
snd_pcm_prepare(handle);
}
else if (ret < 0)
{
fprintf(stderr,
"error from writei: %s\n",
snd_strerror(ret));
}
}
}
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
return 0;
}
使用gcc -o pcm_play pcm_play.c -L. -lasound编译
运行./pcm_play test.wav
ALSA lib pulse.c:243:(pulse_connect) PulseAudio: Unable to connect: Connection refused
aplay: main:722: audio open error: Connection refused
由此引入了第三个实现方案
但是aplay和方案2遇到的相同的问题
1.卸载pulseaudio
yum remove pulseaudio
2.pulseaudio重新查找声卡
http://my.huhoo.net/archives/2007/04/linux-1.html
但是我在实际使用的时候,这个先删/tmp,再pulseaudio -D & (pulseaudio重新查找声卡)后,aplay只能正常运行几分钟
所以 我选择的方法1,直接卸载
pulseaudio的问题解决了。方案2的alse库实现的编码,也运行通过了
当然了,作为音频编程的新手,怎么能不饶弯路的直接get到音频的声音呢?没可能!!!
cat /proc/asound/cards
硬件存在两个硬件声卡(因为我使用的环境,没有外设,没有音响。所以我使用的card1)
aplay -L(使用该命令,再次确认,硬件上是有alc662的codec硬件声卡)
ll /dev/snd/
(并添加了 所有者 、所在组、其它组的rw权限)(不添加应该也没有影响)
确认该硬件设备使用的声卡是pcmC1D0p
一顿操作,下载安装alse_lib/alse_util(没有实际应用到)
---所以aplay好用,驱动就好用
aplay不好用,网上搜答案
默认声卡使用(card 1 device 0)
cat /etc/asound.conf
defaults.pcm.card 1
defaults.pcm.device 0
defaults.ctl.card 1
1.需要指定指定默认声卡为机器使用的声卡
2.alsamixer设置图形界面--最好测试的时候将声音设置为最大
3.先用的pcm的方式写的、之后改为alsa。无论使用alsa库的程序或aplay工具都可以实现
4.lspci|grep -i audio
00:03.0 Audio device: Intel Corporation Xeon E3-1200 v3/4th Gen Core Processor HD Audio Controller (rev 06)
00:1b.0 Audio device: Intel Corporation 8 Series/C220 Series Chipset High Definition Audio Controller (rev 05)
5.程序设置音频采样率、频道、小端、16bit等信息
6.aplay test.wav
Playing WAVE 'test.wav' : Signed 16 bit Little Endian, Rate 22050 Hz, Stereo
通过aplay命令,可以查看5列出的信息。
7.针对PulseAudio:Unable to connect:Connection terminated
aplay:main:828: audio open error: Connection refused
删除了PulseAudio库
yum remove pulseaudio
8.配置!!!配置!!!默认配置!!!