赞
踩
目录
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<unistd.h>
- #include<fcntl.h>
- #include<sys/types.h>
- #include<sys/stat.h>
- #include<stdlib.h>
- #include<stdio.h>
- #include<linux/soundcard.h>
-
- #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<stdio.h>
- #include<stdlib.h>
- #include <string.h>
- #include <alsa/asoundlib.h>
-
- 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.配置!!!配置!!!默认配置!!!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。