alsa播放pcm音频

调用alsa库实现pcm音频的简单播放:

#include <stdio.h>
#include <stdlib.h>
#include <alsa/asoundlib.h>

#define PCM_FORMAT SND_PCM_FORMAT_S16_LE
#define CHANNEL 1
#define SAMPLE_RATE 16000

int main(int argc,char *argv[])
{
	/* Handle for the PCM device */ 
    	snd_pcm_t *handle;          
    	/* Playback stream */
    	snd_pcm_stream_t stream = SND_PCM_STREAM_PLAYBACK;
    	snd_pcm_hw_params_t *hwparams;
    	char *pcm_name = "default";
    	int err;
	int dir = 0;
	snd_pcm_format_t format = PCM_FORMAT;
	unsigned int nChannels = CHANNEL;
	unsigned int rate = SAMPLE_RATE;
	snd_pcm_uframes_t psize_frames = 32;
	snd_pcm_uframes_t bsize_frames = 64;

	char *filename = NULL;
	int fd;
	char *buffer = NULL;
	int count;
	unsigned int buffer_time;

	if(argc < 2)
	{
		printf("Usage: ./playback pcmfile\n");
		return -1;
	}
	filename = argv[1];
	fd = open(filename,O_RDONLY);
	if(fd < 0)
	{
		perror("open file failed!\n");
		return -1;
	}

	//open PCM
    	if (snd_pcm_open(&handle, pcm_name, stream, 0) < 0) 
    	{
      		printf(stderr, "Error opening PCM device %s\n", pcm_name);
      		return -1;
    	}

    	//Allocate the snd_pcm_hw_params_t structure on the stack. 
    	err = snd_pcm_hw_params_malloc(&hwparams);
	if(err < 0)
	{
		perror("malloc space for snd_pcm_hw_params_t structure failed !\n");
		return -1;
	}

	//initial hwparams
    	err = snd_pcm_hw_params_any(handle, hwparams);
    	if (err < 0) 
    	{
		printf("Broken configuration for this PCM\n");
		return err;
    	}

	//set access type
    	err = snd_pcm_hw_params_set_access(handle, hwparams,SND_PCM_ACCESS_RW_INTERLEAVED);
	if (err < 0) 
	{
		printf("Access type not available\n");
		return err;
	}

	//set pcm format
	err = snd_pcm_hw_params_set_format(handle, hwparams, format);
	if (err < 0) 
	{
		printf("Sample format non available\n");
		return err;
	}

	//set pcm channels
	err = snd_pcm_hw_params_set_channels(handle, hwparams, 1);
	if (err < 0) 
	{
		printf("Channels count non available\n");
		return err;
	}

	//set pcm sample rate
	err = snd_pcm_hw_params_set_rate_near(handle, hwparams, &rate, &dir);
	if (err < 0) 
	{
		printf("Set rate failed\n");
		return err;
	}

	//set buffer size
	err = snd_pcm_hw_params_set_buffer_size_near(handle,hwparams,&bsize_frames);
	if(err < 0)
	{
		printf("Set period size failed\n");
		return err;
	}

	//set period size
	err = snd_pcm_hw_params_set_period_size_near(handle,hwparams,&psize_frames,0);
	if(err < 0)
	{
		printf("Set buffer size failed\n");
		return err;
	}

	//set the hwparams to driver
	err = snd_pcm_hw_params(handle,hwparams);
	if(err<0)
	{
		printf("failed to set hardware parameters:%s\n",snd_strerror(err));
		return err;
	}

	//Print information about buffer and period
	printf("Print information about buffer and period:\n");

	err = snd_pcm_hw_params_get_period_size_min(hwparams,&psize_frames,&dir);
	if(err < 0)
	{
		printf("get period size min falied!\n");
		return -1;
	}
	else
	{
		printf("period size min is %d.\n",psize_frames);
	}

	err = snd_pcm_hw_params_get_period_size(hwparams, &psize_frames, &dir);
	if (err < 0) 
	{
		printf("get period size fail\n");
		return err;
	}
	else
	{
		printf("period size is %d frames.\n",psize_frames);
	}

	err = snd_pcm_hw_params_get_buffer_size_min(hwparams,&bsize_frames);
	if(err < 0)
	{
		printf("get buffer size min falied!\n");
		return -1;
	}
	else
	{
		printf("buffer size min is %d.\n",bsize_frames);
	}

	err = snd_pcm_hw_params_get_buffer_size(hwparams, &bsize_frames);
	if (err < 0) 
	{
		printf("get buffer size failed\n");
		return err;
	}
	else
	{
		printf("buffer size is %d frames.\n",bsize_frames);
	}

	err = snd_pcm_hw_params_get_buffer_time_max(hwparams,&buffer_time,0);
	if(err < 0)
	{
		printf("Get buffer time failed!\n");
		return err;
	}
	else
	{
		printf("buffer time is %d us.\n",buffer_time);
	}

	
	//play
	buffer = (char*)malloc(psize_frames*2);//1 channel,sizeof(frame) = 2*1 byte;
	while(1)
	{
		count = read(fd,buffer,psize_frames*2);
		if(count <= 0)
			break;
		
		while(err = snd_pcm_writei(handle,buffer,psize_frames)<0)
		{

			if(err == -EAGAIN)
			{
				printf("again");
				snd_pcm_wait(handle,1000);
			}
			else if(err == -EPIPE)
			{
				snd_pcm_prepare(handle);
				printf("buffer underrun!!!!\n");
			}
			else if(err == -ESTRPIPE)
			{
				printf("Need suspend!\n");
			}
			else if(err < 0)
			{
				printf("snd_pcm_writei error:%s\n",snd_strerror(err));
			}
		}
	}

	snd_pcm_drain(handle);
  	snd_pcm_close(handle);
	free(buffer);

	return 0;
}

另附wav音频转pcm格式:

#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>

/* wav音频头部格式 */
typedef struct _wave_pcm_hdr
{
	char            riff[4];                // = "RIFF"
	int				size_8;                 // = FileSize - 8
	char            wave[4];                // = "WAVE"
	char            fmt[4];                 // = "fmt "
	int				fmt_size;				// = 下一个结构体的大小 : 16

	short int       format_tag;             // = PCM : 1
	short int       channels;               // = 通道数 : 1
	int				samples_per_sec;        // = 采样率 : 8000 | 6000 | 11025 | 16000
	int				avg_bytes_per_sec;      // = 每秒字节数 : samples_per_sec * bits_per_sample / 8
	short int       block_align;            // = 每采样点字节数 : wBitsPerSample / 8
	short int       bits_per_sample;        // = 量化比特数: 8 | 16

	char            data[4];                // = "data";
	int				data_size;              // = 纯数据长度 : FileSize - 44 
} wave_pcm_hdr;


int main(int argc, char* argv[])
{
	const char* pcm_file_name             = "output.pcm"; //合成的语音文件名称
	const char* wav_file_name	      = argv[1];
	int fd1;
	int fd2;
	int ret;
	char buffer[2048];

	if(argc < 2)
	{
		printf("Usage:./wav_to_pcm wavfile\n");
		return -1;
	}

	fd1 = open(wav_file_name,O_RDONLY);
	if(fd1 < 0)
	{
		printf("open %s failed!\n",wav_file_name);
		return -1;
	}
	fd2 = open(pcm_file_name,O_RDWR|O_CREAT);
	if(fd2 < 0)
	{
		printf("open %s failed!\n",pcm_file_name);
		return -1;
	}

	ret = lseek(fd1,sizeof(wave_pcm_hdr),SEEK_SET);
	if(ret == -1)
	{
		perror("lseek failed:\n");
		goto error;
	}

	while(read(fd1,buffer,sizeof(buffer)))
		ret = write(fd2,buffer,sizeof(buffer));
	if(ret)
	{
		printf("transform finished!\n");
		return 0;
	}

error:
	close(fd1);
	close(fd2);
	return -1;
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值