waveout播放pcm文件总结

花了2天的时间研究了一下windows下播放pcm的waveout接口,http://blog.csdn.net/nokianasty/article/details/8558151这个帖子对windows音频播放说的比较详细,我自己另外重新写了一个循环缓冲的播放demo,在main主线程中开了一个decode线程,decode线程负责解码和送数据到waveout,(目前是pcm数据所以解码部分可以忽略),decode线程一直填数据到waveout直到循环缓冲中没有空闲块就挂起等待空闲块,waveoutproc函数负责通知哪个数据块播放完成,他们之前的通信和同步我采用了queue+semaphore。对windows进程通信方式不熟所以先暂时用这个了,只要能实现有空闲数据块唤醒decode线程,同时不阻塞waveout音乐播放进程就可以了。期间碰到fread读文件采用“r”方式时,读取不完的问题,这个windows下有这个问题,当读取到0x1a时会认为文件结束了,当遇到0x0d0a时读取出来的是0x0a ,linux下r/rb是一样的。代码如下:

#include<windows.h>
#include<mmsystem.h>
#include<stdio.h>
#include<queue>
using std::queue;
#pragma comment(lib,"winmm.lib") 

/*
* some good values for block size and count
*/
#define BLOCK_SIZE 4096
#define BLOCK_COUNT 3
/*
*waveoutprocdecodethread share vars
*/
static CRITICAL_SECTION waveCriticalSection;
static HANDLE freeBufferSema;
static queue<WAVEHDR*> qWHDR;

typedef struct decodeThreadParam
{
	char *filename;
	HWAVEOUT *device;
}decThreadParmT;

static DWORD decodeThreadProc(LPVOID lpdwThreadParam );
static void CALLBACK waveOutProc(HWAVEOUT hwo,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2);

int main()
{
	HWAVEOUT hWaveOut;
	MMRESULT ret;
	WAVEFORMATEX wfx;
	
	DWORD decodeThreadId;
	HANDLE hDecodeThread;
	char filename[]="../test.pcm";
	decThreadParmT decThreadData;

	int i;

	freeBufferSema = CreateSemaphore(0,
					0,
					BLOCK_COUNT,
					"bufferSema"
					);

	if(freeBufferSema==NULL)
	{
		printf("Create Buffer Sema ERROR!\n");
		return 1;
	}

	InitializeCriticalSection(&waveCriticalSection);

	
	wfx.nSamplesPerSec	= 48000;
	wfx.wBitsPerSample	= 16;
	wfx.nChannels		= 2;
	wfx.cbSize			= 0;
	wfx.wFormatTag		=WAVE_FORMAT_PCM;
	wfx.nBlockAlign		=(wfx.wBitsPerSample*wfx.nChannels)>>3;
	wfx.nAvgBytesPerSec	=wfx.nSamplesPerSec*wfx.nBlockAlign;
	ret = waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, (DWORD_PTR)waveOutProc,  0, CALLBACK_FUNCTION);
	if(ret!=MMSYSERR_NOERROR)
	{
		printf("waveoutopen ERR!\n");
		return 1;
	}
	printf("waveout open successfully!\n");
	decThreadData.device	= &hWaveOut;
	decThreadData.filename	= filename;

	hDecodeThread=CreateThread(NULL, //Choose default security
		0, //Default stack size
		(LPTHREAD_START_ROUTINE)&decodeThreadProc,
		//Routine to execute
		(LPVOID) &decThreadData, //Thread parameter
		0, //Immediately run the thread
		&decodeThreadId //Thread Id
		);

	if(hDecodeThread==NULL)
	{
		printf("Error Creating Decode Thread\n");
		return 1;
	}

	WaitForSingleObject(hDecodeThread, INFINITE);
	
	Sleep(1000);

	waveOutClose(hWaveOut);
	CloseHandle(freeBufferSema);
	CloseHandle(hDecodeThread);
	DeleteCriticalSection(&waveCriticalSection);
	
}


static DWORD decodeThreadProc(LPVOID lpdwThreadParam )
{
	char *filename=((decThreadParmT*)lpdwThreadParam)->filename;
	HWAVEOUT *hWaveOut=((decThreadParmT*)lpdwThreadParam)->device;
	WAVEHDR* current=NULL;
	WAVEHDR* waveBlocks=NULL;
	char *audioBuf=NULL;
	FILE *fp=NULL;
	int i;

	audioBuf   = (char*)malloc(BLOCK_SIZE*BLOCK_COUNT);
	memset(audioBuf, 0, BLOCK_SIZE*BLOCK_COUNT);
	waveBlocks = (WAVEHDR*)malloc(BLOCK_COUNT*sizeof(WAVEHDR));
	memset(waveBlocks, 0, BLOCK_COUNT*sizeof(WAVEHDR));
	for(i=0;i<BLOCK_COUNT;i++)
	{
		waveBlocks[i].lpData = (audioBuf+i*BLOCK_SIZE);
		waveBlocks[i].dwBufferLength = BLOCK_SIZE;
	}

	fp= fopen(filename, "rb");
	if(fp==NULL)
	{
		printf("open file :%s error\n",filename);
		return -1;
	}

	//preread BLOCK_COUNT data to buffer
	for(i=0; i<BLOCK_COUNT; i++)
	{
		current = &waveBlocks[i];
		fread(current->lpData, 1, BLOCK_SIZE,  fp);
		waveOutPrepareHeader(*hWaveOut, current, sizeof(WAVEHDR));
		
	}
	for(i=0; i<BLOCK_COUNT; i++)
	{
		current = &waveBlocks[i];
		printf("i:%x\n",current);
		waveOutWrite(*hWaveOut, current, sizeof(WAVEHDR));
	}

	while(1)
	{
		int size=0;
		//wait a free pcm buf
		WaitForSingleObject(
			freeBufferSema, // event handle
			INFINITE);    // indefinite wait
		
		//read data to pcm buf,then write to waveout
		//
		EnterCriticalSection(&waveCriticalSection);
		current = qWHDR.front();
		qWHDR.pop();
		LeaveCriticalSection(&waveCriticalSection);
		printf("f:%x\n",current);
		waveOutUnprepareHeader(*hWaveOut, current, sizeof(WAVEHDR));
		size=fread(current->lpData, 1,BLOCK_SIZE, fp);
		//printf("size:%d\n",size);
		if(size>0)
		{
			waveOutPrepareHeader(*hWaveOut, current, sizeof(WAVEHDR));
			waveOutWrite(*hWaveOut, current, sizeof(WAVEHDR));
		}
		else
		{
			printf("play over!%d\n",size);
			break;
		}
	}
	printf("decode finished!\n");
	fclose(fp);
	free(audioBuf);
	free(waveBlocks);
}

static void CALLBACK waveOutProc(HWAVEOUT hwo,UINT uMsg,DWORD_PTR dwInstance,DWORD_PTR dwParam1,DWORD_PTR dwParam2)
{
	WAVEHDR *freeWaveHdr=NULL;
	switch(uMsg)
	{
	case WOM_DONE:
		EnterCriticalSection(&waveCriticalSection);
		freeWaveHdr = (WAVEHDR*)dwParam1;
		printf("o:%x\n",freeWaveHdr);
		qWHDR.push(freeWaveHdr);
		LeaveCriticalSection(&waveCriticalSection);
		ReleaseSemaphore(freeBufferSema, 1, NULL);
		break;
	case WOM_OPEN:
		printf("open waveout\n");
		break;
	case WOM_CLOSE:
		printf("close waveout\n");
		break;
	default:
		printf("ERROR MSG!\n");
	}

}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值