(from MSDN)
这个函数打开一个给定的波形音频输出装置来进行回放。
(The waveOutOpen function opens the given waveform-audio output device for playback)
URL:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/multimed/htm/_win32_waveoutunprepareheader.asp
原型如下:
MMRESULT waveOutOpen(
LPHWAVEOUT phwo,
UINT_PTR uDeviceID,
LPWAVEFORMATEX pwfx,
DWORD_PTR dwCallback,
DWORD_PTR dwCallbackInstance,
DWORD fdwOpen
);
参数介绍(paramters):
phwo
一个指向接收波形音频输出装置柄的缓冲器。用柄来区别(identify
)装置当呼叫别的波形装置输出装置。如果fdwOpen被设定为WAVE_FORMAT_QUER
Y,那么这个参数可能为NULL 。
uDevideID
将要被打开的波形音频输出装置的ID ,它可以是一个装置ID,也可以
是一个已经打开的波形音频输入装置柄,你可以用以下的值来货替:
值 含义
WAVE_MAPPER 该函数选一个能够播放给定格式的波形音频输出装置
pwfx 一个指向区别将被送到装置的音频数据格式的WAVEFORMATEX结构的指针,你可以FREE这个结构当你一将其传到waveOutOpen 函数;
dwCallback
它指向一个特定的CALLBACK函数,事件柄,窗口柄,或一个将在波形
音频回放时以便处理与回放进度相关的消息的期间呼叫的线程ID,如果无须CALL
BACK函数,可以将其设为0 。更多请参看waveOutProc
dwCallbackInstance
传递到CALLBACK进程的用户实例数据。如果是窗口CALLBACK进程的话,该参数不用(设为0)
fwOpen
用来打开装置的标识(FLAGS),它们的定义如下:
值 含义
CALLBACK_EVENT dwCallback 参数栏是事件柄
CALLBACK_FUNCTION dwCallback 参数栏是CALLBACK过程地址
CALLBACK_NULL 默认的设置,即无CALLBACK进程
CALLBACK_THREAD dwCallback 参数栏是线程ID
CALLBACK_WINDOW dwCallback 参数栏是窗口柄
WAVE_ALLOWSYNC 如果该项被设置,一个同步的装
置能被打开。如果在打开一个同步驱动时没有用该项,装置打开将会失败。
WAVE_FORMAT_DIRECT 如果设定该项,the ACM driver
does not perform conversions on the audio data.
WAVE_FORMAT_QUERY 如果设定该项,waveOutOpen 询
问装置来决定是否支持给定的格式,但装置实际上并没有被打开。
WAVE_MAPPED 该项被设定后uDeviceID参数表示
一个被声波映射装置映射的波形装置。
返回值:
成功后返回MMSYSERR_NOERROR ,否则返回以下值:
值 描述
MMSYSERR_ALLOCATED 表示资源已存在
MMSYSERR_BADDEVICEID 装置ID超出范围
MMSYSERR_NODRIVER 没有驱动
MMSYSERR_NOMEM 不能分配内存
WAVERR_BADFORMAT 企图打开一个不被支持的格式
WAVERR_SYNC 装置是可同步的,但waveOutOpen
没用有WAVE_ALLOWSYNC呼叫。
注:
用waveOutGetNumDevs
函数测定在当前系统中输出装置的数目。如果uDeviceIC参数项是一个装置ID,
它将会表示从0 到总的数目,WAAVE_MAPPER常量也可以用作装置ID。
pwfc所指的结构能够扩展到包含某些数据格式的特殊信息,例如,对
于PCM数据,一个额外的UNIT
类型用来表示取样的位数目。在这个情况下用PCMWAVEFORAMT结构。对于其它的
格式,用WAVEFORMATEX结构来表示额外的数据长度。
如果你选用的是一个窗口或线程来接收CALLBACK信息,如下的信息将
会被送到窗口处理函数中,来表明波形音频输出进程:MM_WOM_OPEN
,MM_WOM_CLOSE ,和MM_WOM_DONE ,
如果你选用的是一个函数来接收CALLBACK信息,如下的信息将会被传
到函数中,来显示波形音频输出进程:WOM_OPEN ,WOM_CLOSE ,WOM_DONE.
要求:
Windows NT/2000/XP: Included in Windows NT 3.1 and later.
Windows 95/98/Me: Included in Windows 95 and later.
Header: Declared in Mmsystem.h; include Windows.h.
Library: Use Winmm.lib.
参见:
Waveform Audio, Waveform Functions, WAVEFORMATEX,
waveOutGetNumDevs, waveOutProc, PCMWAVEFORMAT, MM_WOM_OPEN,
MMRESULT waveOutOpen(
LPHWAVEOUT phwo,
UINT uDeviceID,
LPWAVEFORMATEX pwfx,
DWORD dwCallback,
DWORD dwCallbackInstance,
DWORD fdwOpen
);
dwCallback 放回调函数指针
dwCallbackInstance 放回调函数所在实例句柄(DLL的)
有两个问题
回调函数应该申明成什么样子?
DLL的实例句柄如何取得?
1.回调函数设置:
void CALLBACK waveOutProc(HWAVEOUT hwo,
UINT uMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2);
更多描述见MSDN之waveOutProc。
2.关于dwCallbackInstance:
俺不知道你这里的DLL是什么意思。你的程序要做成DLL?首先这个参数windows是不关心的,它只是在调用你的回调函数时为你原封不动地传回来,也就是说对它没有什么固定的要求,你可以传入任何东西,关键看你需要这么用它。因为回调函数必须声明成全局或静态,所以一般来说都是把指向你当前调用waveOutOpen所在对象的实例的指针(也就是this)传进去,这样在回调函数里,你可以用这个指针来操作该对象所在类的成员。
谢谢你的回答
我刚才在CSDN上也查到了这个声明
是的,我想把它做在DLL中,这个dwCallbackInstance应该怎样给值呢?
还有,利用回调函数后在MM_WIM_DATA
中取出数据是用(PWAVEHDR) dwParam1)-> lpData,还是用(PWAVEHDR) dwParam2)-> lpData取得数据呢?
期望你的回答,马上给分你!
使用心得:首先打开声音输出设备,然后初始化输出内存,并保证不要使用缓存;(调用waveOutPrepareHeader设置内存),然后通过回调函数进行状态通知。通过waveOutWrite进行声音播放;
最后调用waveOutUnprepareHeader释放内存,waveOutReset(m_hWaveOut);
waveOutClose(m_hWaveOut);关闭音频设备
//声明:
waveOutOpen(
lphWaveOut: PHWaveOut; {用于返回设备句柄的指针; 如果 dwFlags=WAVE_FORMAT_QUERY, 这里应是 nil}
uDeviceID: UINT; {设备ID; 可以指定为: WAVE_MAPPER, 这样函数会根据给定的波形格式选择合适的设备}
lpFormat: PWaveFormatEx; {TWaveFormat 结构的指针; TWaveFormat 包含要申请的波形格式}
dwCallback: DWORD {回调函数地址或窗口句柄; 若不使用回调机制, 设为 nil}
dwInstance: DWORD {给回调函数的实例数据; 不用于窗口}
dwFlags: DWORD {打开选项}
): MMRESULT; {成功返回 0; 可能的错误值见下:}
MMSYSERR_BADDEVICEID = 2; {设备ID超界}
MMSYSERR_ALLOCATED = 4; {指定的资源已被分配}
MMSYSERR_NODRIVER = 6; {没有安装驱动程序}
MMSYSERR_NOMEM = 7; {不能分配或锁定内存}
WAVERR_BADFORMAT = 32; {设备不支持请求的波形格式}
//TWaveFormatEx 结构:
TWaveFormatEx = packed record
wFormatTag: Word; {指定格式类型; 默认 WAVE_FORMAT_PCM = 1;}
nChannels: Word; {指出波形数据的通道数; 单声道为 1, 立体声为 2}
nSamplesPerSec: DWORD; {指定样本速率(每秒的样本数)}一般为8000
nAvgBytesPerSec: DWORD; {指定数据传输的平均速率(每秒的字节数)} 每秒的字节数:
nBlockAlign: Word; {指定块对齐(单位字节), 块对齐是数据的最小单位}
wBitsPerSample: Word; {采样大小(字节)}每个样本的BIT数目,一般为16
cbSize: Word; {应该是该结构的大小}
end;
{16 位立体声 PCM 的块对齐是 4 字节(每个样本2字节, 2个通道)}
//打开选项 dwFlags 的可选值:
WAVE_FORMAT_QUERY = $0001; {只是判断设备是否支持给定的格式, 并不打开}
WAVE_ALLOWSYNC = $0002; {当是同步设备时必须指定}
CALLBACK_WINDOW = $00010000; {当 dwCallback 是窗口句柄时指定}
CALLBACK_FUNCTION = $00030000; {当 dwCallback 是函数指针时指定}
//如果选择窗口接受回调信息, 可能会发送到窗口的消息有:
MM_WOM_OPEN = $3BB;
MM_WOM_CLOSE = $3BC;
MM_WOM_DONE = $3BD;
//如果选择函数接受回调信息, 可能会发送给函数的消息有:
WOM_OPEN = MM_WOM_OPEN;
WOM_CLOSE = MM_WOM_CLOSE;
WOM_DONE = MM_WOM_DONE;
举例如下:
//回调函数
static void CALLBACK
SpeakerCallback (HWAVEOUT _waveoutdev, UINT uMsg, DWORD dwInstance,
DWORD dwParam1, DWORD dwParam2)
{
WAVEHDR *wHdr;
streamUtil * parentStream =NULL;
switch (uMsg)
{
case WOM_OPEN:
// ms_message("SpeakerCallback : WOM_OPEN");
DEBUG_HELPER->log("streamUtil",LM_DEBUG,"RECEIVE WOM_OPEN\n");
break;
case WOM_CLOSE:
DEBUG_HELPER->log("streamUtil",LM_DEBUG,"RECEIVE WOM_CLOSE\n");
// ms_message("SpeakerCallback : WOM_CLOSE");
break;
case WOM_DONE:
parentStream = (streamUtil*)dwInstance;
wHdr = (WAVEHDR *) dwParam1;
// waveOutUnprepareHeader (parentStream->m_hWaveOut, wHdr, sizeof (WAVEHDR)) ;
break;
default:
break;
}
}
WAVEFORMATEX waveform;
waveform.wFormatTag = WAVE_FORMAT_PCM;
waveform.nChannels = channel;
waveform.nSamplesPerSec =rate;//8000
waveform.nAvgBytesPerSec=16000;
waveform.nBlockAlign =2;
waveform.wBitsPerSample =bits; //16
waveform.cbSize =0;
//初始化回调标志
dwFlag = CALLBACK_FUNCTION;
if (devNumber != WAVE_MAPPER)
dwFlag = WAVE_MAPPED | CALLBACK_FUNCTION;
//打开设备
if (waveOutOpen(&m_hWaveOut,devNumber,&waveform,(DWORD) SpeakerCallback,(DWORD)this,dwFlag)) {
DEBUG_HELPER->log("streamUtil",LM_ERROR,"Failed to open deice. (waveOutOpen:0x%i)\n", mr);
return -1;
}
//
//缓存的大小
m_bufLength = (rate/8000) * INP_BUFFER_SIZE;
for(int i=0;i<OUT_BUFFER_NUM;i++)
{
//初始化输出缓存
//m_outHdr= reinterpret_cast<PWAVEHDR>(malloc(sizeof(WAVEHDR)));
// m_outBuffer = (PBYTE)malloc(1 * m_bufLength);
memset(m_outBuffer,0,m_bufLength);
m_outHdr.lpData = (LPSTR)(m_outBuffer );
m_outHdr.dwBufferLength = m_bufLength ;
m_outHdr.dwBytesRecorded = 0 ;
m_outHdr.dwUser = 0 ;
m_outHdr.dwFlags = 0 ;
// m_outHdr.lpNext = NULL ;
m_outHdr.reserved = 0 ;
m_outHdr.dwLoops =0;
waveOutPrepareHeader (m_hWaveOut, &(m_outHdr), sizeof (WAVEHDR)) ;
}
文章评论(0条评论)
登录后参与讨论