您的位置:首页 > 其它

在windows下用waveout接口播放音频

2013-07-09 11:09 330 查看
首先需要定义几个对象:
  HWAVEOUT hWaveOut; /* device handle */
  WAVEFORMATEX wfx; /* look this up in your documentation */
  MMRESULT result;/* for waveOut return values */
然后需要设置音频流的参数信息,一下只是给出了我在使用过程中的参数,可以根据个人需求自行调节:
  wfx.nSamplesPerSec = 8000; /* sample rate */
  wfx.wBitsPerSample = 16; /* sample size */
  wfx.nChannels = 1; /* channels*/
另外,还有一些额外的参数需要设置:
  wfx.cbSize = 0; /* size of _extra_ info */
  wfx.wFormatTag = WAVE_FORMAT_PCM;
  wfx.nBlockAlign = (wfx.wBitsPerSample >> 3) * wfx.nChannels;
  wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;

/*WAVE_MAPPER是一个在mmsystem.h中定义的常数,总是指向系统的默认流设备*/
通过函数waveOutOpen(&hWaveOut, WAVE_MAPPER, &wfx, 0, 0, CALLBACK_NULL)打开一个流设备,设置wfx音频流参数,
并使得hWaveOut为该设备的handle,可以通过判断函数返回值是否等于MMSYSERR_NOERROR)判断设备是否打开成功了
相应的可以通过调用waveOutClose(hWaveOut)来关闭一个流设备。

以上几步声明一个流设备对象,完成了打开、关闭一个流设备,并设置音频流参数
接下来完成基本语音播放功能,播放语音需要做两个工作:语音数据写语音数据到流设备中
writeAudioBlock. To write audio data you use up to three functions. These are waveOutPrepareHeader,waveOutWrite,
and waveOutUnprepareHeader and are called in the order I have listed them.

void writeAudioBlock(HWAVEOUT hWaveOut, LPSTR block, DWORD size);函数实现如下说明:

声明一个WAVEHDR对象:WAVEHDR header,结构如下

typedef struct wavehdr_tag {
LPSTR      lpData;
DWORD      dwBufferLength;
DWORD      dwBytesRecorded;
DWORD_PTR  dwUser;
DWORD      dwFlags;
DWORD      dwLoops;
struct wavehdr_tag * lpNext;
DWORD_PTR reserved;
} WAVEHDR, *LPWAVEHDR;

lpData:Pointer to the waveform buffer.dwBufferLength:Length, in bytes, of the buffer.dwUser:User data.dwFlags:Flags supplying information about the buffer. The following values are defined,其中包含了一个WHDR_PREPARED ,Set by Windows to indicate that the buffer has been prepared with the waveOutPrepareHeader function.
然后初始化header为0,并传入参数数据大小数据指针。   
ZeroMemory(&header, sizeof(WAVEHDR));   
header.dwBufferLength = size;   
header.lpData = block;
准备播放数据块:      waveOutPrepareHeader(hWaveOut, &header, sizeof(WAVEHDR));
写数据块到流设备中:   waveOutWrite(hWaveOut, &header, sizeof(WAVEHDR));
等待数据流播放完,释放header 调用函数waveOutUnprepareHeader(hWaveOut, &header, sizeof(WAVEHDR)) 释放掉header,在释放data前一定要调用waveOutUnprepareHeader()
可以根据返回值是否等于WAVERR_STILLPLAYING判断是否播放完毕

函数定义说明:

MMRESULT waveOutPrepareHeader(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);

MMRESULT waveOutWrite(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);

MMRESULT waveOutUnprepareHeader(HWAVEOUT hwo, LPWAVEHDR pwh, UINT cbwh);

hwo:Handle to the waveform-audio output device.pwh:Pointer to a WAVEHDR structure containing information about the data block.cbwh:Size, in bytes, of the WAVEHDR structure.
  至此,将带播放的数据通过传入数据大小、数据指针给函数writeAudioBlock(HWAVEOUT hWaveOut, LPSTR block, DWORD size)就完成了基本的播放功能。
[b]接下来完成播放一个音频流:[/b]
  在上个播放语音实现中有一个大问题就是,每次只能播放一次读取数据,如果文件小的话,可以一次全部读取然后播放,但如果大文件就无法这样做了心所以需要寻找一种方法,
能够像流媒体一样,语音数据能一块一块顺序播放。
  面临的另一个问题是,如果是单纯的顺序读取-播放,回会造成在两次播放之间有一个时间间隔,使得语音出现不连续的现象。解决方法是定义多个buffer,在播放的时候也能
够进行读数据到buffer里,这样每次一个buffer播放完,会有其他buffer已经准备好数据以供播放。
(由于最近事情比较多,回头补全这部分)

 


                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: