Linux Centos 播放wav音频

目录

实现步骤

实现思路及遇到的问题

1.未使用alsa库编码

2.使用alsa库编码

3.直接使用linux 自带播放器aplay 播放音频

pulseaudio导致音频播放失败的解决方法

确认使用了哪个声卡

1.硬件是否带声卡

2.确认声卡驱动是否存在

3.确认配置是否正确

注意事项总结


 

实现步骤

1.确认硬件是否有声卡

2.确认声卡驱动是否正确安装

3.确认声卡配置是否正确

 

实现思路及遇到的问题

 

 

1.未使用alsa库编码

直接用了网上的例子。

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库。所以上面这个问题我没解决

2.使用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(&params); /*分配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

由此引入了第三个实现方案

3.直接使用linux 自带播放器aplay 播放音频

但是aplay和方案2遇到的相同的问题

pulseaudio导致音频播放失败的解决方法

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到音频的声音呢?没可能!!!

确认使用了哪个声卡

 

1.硬件是否带声卡

cat /proc/asound/cards

硬件存在两个硬件声卡(因为我使用的环境,没有外设,没有音响。所以我使用的card1)


aplay -L(使用该命令,再次确认,硬件上是有alc662的codec硬件声卡)

ll /dev/snd/


(并添加了 所有者 、所在组、其它组的rw权限)(不添加应该也没有影响)

确认该硬件设备使用的声卡是pcmC1D0p

2.确认声卡驱动是否存在


一顿操作,下载安装alse_lib/alse_util(没有实际应用到)

---所以aplay好用,驱动就好用

   aplay不好用,网上搜答案

 

3.确认配置是否正确


默认声卡使用(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.配置!!!配置!!!默认配置!!!
 

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值