|
Here is my implementation of this application with modifications. This implementation is specific for my needs. You will have to discover the changes. Sorry, I am not maintaining this, I just fixed the code for my own use. It does run smoother and hanging issues are resolved.
quickly:
- callback proc now adds wave frames to a processlist and signals an event
- the event feeds the wave frames to the OnWaveInData() and OnWaveOutDone() methods
- the waitlist and freelist headers are now unprepared in a timely fashion
- "a minor bug" from below is fixed
// header file
//---------------------------------------------------------------------
/*
+===========================================================================+
| Notes: |
| |
| 1. Wave device sequence : open()->start()->stop()->close(). |
| 2. Support seperate operation on wave in and out object. |
| |
+===========================================================================+
*/
#ifndef _WAVEFORM_H_
#define _WAVEFORM_H_
#include "WaveInterface.h"
#include <Mmsystem.h>
#include <Mmreg.h>
#include <Msacm.h>
/****************************************************************************
* Limitation for number of wave buffer can be queued in list.
****************************************************************************
*/
#define MIN_WAVE_NUM 4
#define MAX_WAVE_NUM 8
#define MAX_WAVE_BUFFER_LEN 8192
#define MAX_BUFFER_IN_QUEUE MAX_WAVE_BUFFER_LEN * (MAX_WAVE_NUM / 2)
#define WAVE_FORM_FLOW_IN 0x00000001
#define WAVE_FORM_FLOW_OUT 0x00000002
#define WAVE_FORM_FLOW_BOTH 0x00000003
#define VALIDATE(x,y) x > y ? (x = y) : (y = x)
/****************************************************************************
* External messages borrowed from [Thread.h].
****************************************************************************
*/
#define WM_STREAM_NOTIFY WM_USER + 1
#define SUB_EVENT_WAVE_IN 0x00000001
#define SUB_EVENT_SOCKET_IN 0x00000002
#define WM_STREAM_CONTROL WM_USER + 2
#define SUB_EVENT_WAVE_QUIT 0x00000001
#define SUB_EVENT_SOCKET_QUIT 0x00000002
/****************************************************************************
* Internal wave frame structure.
****************************************************************************
*/
typedef struct stWaveFrame
{
WAVEHDR waveHdr;
CHAR Data[MAX_WAVE_BUFFER_LEN];
} WAVEFRAME, *PWAVEFRAME;
#define PPWAVEFRAME PWAVEFRAME *
/****************************************************************************
* Wave device state.
****************************************************************************
*/
#define WAVE_STATE_OPEN 0x0001
#define WAVE_STATE_CLOSE 0x0002
#define WAVE_STATE_START 0x0003
#define WAVE_STATE_STOP 0x0004
#define WAVE_STATE_RESET 0x0005
#define WAVE_STATE_PAUSE 0x0006
#define WAVE_STATE_RESTART 0x0007
/****************************************************************************
* Wave device callback routines.
****************************************************************************
*/
static void CALLBACK WaveInCallBackRoutine
(
HWAVEIN hwi,
UINT uMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2
);
static void CALLBACK WaveOutCallBackRoutine
(
HWAVEOUT hwo,
UINT uMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2
);
/****************************************************************************
* CWaveForm class definition.
****************************************************************************
*
*/
class CWaveForm : public IIUnknown,
public IIStreamDevice,
public IIDataSource<PWAVEFRAME>,
public IIDataSink<PWAVEFRAME>,
public CAdvise
{
public:
CWaveForm
(
UINT uDirection,
UINT uWaveInDeviceID,
UINT uWaveOutDeviceID,
WAVEFORMATEX * lpWaveInFormatEx,
WAVEFORMATEX * lpWaveOutFormatEx,
DWORD dwWaveInVolume,
DWORD dwWaveOutVolume
);
~CWaveForm();
/////////////////////////////////////////////////////////////////////////
// Standard interface implementation.
/////////////////////////////////////////////////////////////////////////
IMP_IIUNKNOWN();
IMP_IISTREAMDEVICE();
IMP_IIDATASOURCE(PWAVEFRAME);
IMP_IIDATASINK(PWAVEFRAME);
/////////////////////////////////////////////////////////////////////////
// WaveForm spefific APIs.
/////////////////////////////////////////////////////////////////////////
BOOL GetVolume(UINT uDirection, PDWORD pVolume);
BOOL SetVolume(UINT uDirection, DWORD dwVolume);
void OnWaveInData(PWAVEFRAME waveFrame);
void OnWaveOutDone(PWAVEFRAME waveFrame);
void WaveInProcess();
void WaveOutProcess();
bool SetOutput( DWORD dwVolume );
void SelectSource(char *sourcename);
bool SetMasterVolume( DWORD dwVolume );
UINT32 GetWaitCount() { return (UINT32)m_waveInFrameWaitingList.GetCount(); }
UINT32 GetMaxWaveNum() { return MAX_WAVE_NUM;}
BOOL SoundCardCheck();
BOOL isInSupported (UINT idDev,WAVEFORMATEX * lpWaveInFormatEx);
private:
static void __cdecl ThreadProcIn(void *) ;
static void __cdecl ThreadProcOut(void *) ;
bool m_bWaveInProcessFlag;
bool m_bWaveOutProcessFlag;
bool m_bWaveInProcessState;
bool m_bWaveOutProcessState;
HANDLE m_hWaveInProcessEvent;
HANDLE m_hWaveOutProcessEvent;
HANDLE m_hWaveInProcessThread;
HANDLE m_hWaveOutProcessThread;
private:
LONG m_RefCount;
UINT m_uDirection;
UINT m_waveInState;
UINT m_waveOutState;
UINT m_waveInDeviceID;
UINT m_waveOutDeviceID;
WAVEFORMATEX m_waveInFormatEx;
WAVEFORMATEX m_waveOutFormatEx;
HWAVEIN m_hWaveIn;
HWAVEOUT m_hWaveOut;
DWORD m_waveInVolume;
DWORD m_waveOutVolume;
DWORD m_dwWaveInByteInDevice;
DWORD m_dwWaveOutByteInDevice;
CRITICAL_SECTION m_waveInFrameFreeListLock;
CRITICAL_SECTION m_waveInFrameWaitingListLock;
CList<PWAVEFRAME,PWAVEFRAME&> m_waveInFrameFreeList;
CList<PWAVEFRAME,PWAVEFRAME&> m_waveInFrameWaitingList;
CRITICAL_SECTION m_waveOutFrameFreeListLock;
CRITICAL_SECTION m_waveOutFrameWaitingListLock;
CList<PWAVEFRAME,PWAVEFRAME&> m_waveOutFrameFreeList;
CList<PWAVEFRAME,PWAVEFRAME&> m_waveOutFrameWaitingList;
CRITICAL_SECTION m_waveInFrameProcessListLock;
CList<PWAVEFRAME,PWAVEFRAME&> m_waveInFrameProcessList;
CRITICAL_SECTION m_waveOutFrameProcessListLock;
CList<PWAVEFRAME,PWAVEFRAME&> m_waveOutFrameProcessList;
friend static void CALLBACK WaveInCallBackRoutine
(
HWAVEIN hwi,
UINT uMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2
);
friend static void CALLBACK WaveOutCallBackRoutine
(
HWAVEOUT hwo,
UINT uMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2
);
};
#endif // _WAVEFORM_H_
// implementation file
//---------------------------------------------------------------------
/*
+===========================================================================+
| Notes: |
| |
| 1. Wave device open sequence : open()->start()->stop()->close(). |
| 2. Support seperate operation on wave in and out object. |
| 3. Use standard stream device interface. |
| |
+===========================================================================+
*/
#include "Stdafx.h"
#include "WaveForm.h"
#include <string>
/****************************************************************************
* CWaveForm::CWaveForm()
****************************************************************************
* CWaveForm constructor.
*/
CWaveForm::CWaveForm
(
UINT uDirection,
UINT uWaveInDeviceID,
UINT uWaveOutDeviceID,
WAVEFORMATEX * lpWaveInFormatEx,
WAVEFORMATEX * lpWaveOutFormatEx,
DWORD dwWaveInVolume,
DWORD dwWaveOutVolume
)
{
/////////////////////////////////////////////////////////////////////////
// Init wave format related variables.
/////////////////////////////////////////////////////////////////////////
m_RefCount = 0;
/////////////////////////////////////////////////////////////////////////
// Preset wave in/out device info.
/////////////////////////////////////////////////////////////////////////
m_uDirection = uDirection;
m_waveInDeviceID = uWaveInDeviceID;
m_waveOutDeviceID = uWaveOutDeviceID;
if ((m_uDirection & WAVE_FORM_FLOW_IN) && (lpWaveInFormatEx != NULL))
{
memcpy(&m_waveInFormatEx, lpWaveInFormatEx, sizeof(WAVEFORMATEX));
}
if ((m_uDirection & WAVE_FORM_FLOW_OUT) && (lpWaveOutFormatEx != NULL))
{
memcpy(&m_waveOutFormatEx, lpWaveOutFormatEx, sizeof(WAVEFORMATEX));
}
m_hWaveIn = NULL;
m_hWaveOut = NULL;
m_waveInState = WAVE_STATE_CLOSE;
m_waveOutState = WAVE_STATE_CLOSE;
/////////////////////////////////////////////////////////////////////////
// Init wave in critical section locks & free list.
/////////////////////////////////////////////////////////////////////////
if (m_uDirection & WAVE_FORM_FLOW_IN)
{
InitializeCriticalSection(&m_waveInFrameFreeListLock);
InitializeCriticalSection(&m_waveInFrameWaitingListLock);
InitializeCriticalSection(&m_waveInFrameProcessListLock);
// Preallocate some wave in free frames.
EnterCriticalSection(&m_waveInFrameFreeListLock);
for (UINT i = 0; i < MIN_WAVE_NUM; i++)
{
PWAVEFRAME waveFrame = new WAVEFRAME;
if (waveFrame)
{
m_waveInFrameFreeList.AddTail(waveFrame);
}
}
LeaveCriticalSection(&m_waveInFrameFreeListLock);
//Create an event for the process thread to wait on
m_hWaveInProcessEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
}
/////////////////////////////////////////////////////////////////////////
// Init wave out critical section locks & free list.
/////////////////////////////////////////////////////////////////////////
if (m_uDirection & WAVE_FORM_FLOW_OUT)
{
InitializeCriticalSection(&m_waveOutFrameFreeListLock);
InitializeCriticalSection(&m_waveOutFrameWaitingListLock);
InitializeCriticalSection(&m_waveOutFrameProcessListLock);
//Create an event for the process thread to wait on
m_hWaveOutProcessEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
}
/////////////////////////////////////////////////////////////////////////
// Save wave in/out volumes.
/////////////////////////////////////////////////////////////////////////
m_waveInVolume = dwWaveInVolume;
m_waveOutVolume = dwWaveOutVolume;
/////////////////////////////////////////////////////////////////////////
// Set the process flags to false
/////////////////////////////////////////////////////////////////////////
m_bWaveInProcessFlag = false;
m_bWaveOutProcessFlag = false;
m_bWaveInProcessState = false;
m_bWaveOutProcessState = false;
/////////////////////////////////////////////////////////////////////////
// Setup wave in/out outstanding monitor.
/////////////////////////////////////////////////////////////////////////
m_dwWaveInByteInDevice = 0;
m_dwWaveOutByteInDevice = 0;
}
/****************************************************************************
* CWaveForm::~CWaveForm()
****************************************************************************
* CWaveForm destructor.
*/
CWaveForm::~CWaveForm()
{
/////////////////////////////////////////////////////////////////////////
// Delete wave in list lock & free free/waiting list.
/////////////////////////////////////////////////////////////////////////
if (m_uDirection & WAVE_FORM_FLOW_IN)
{
DeleteCriticalSection(&m_waveInFrameFreeListLock);
DeleteCriticalSection(&m_waveInFrameWaitingListLock);
DeleteCriticalSection(&m_waveInFrameProcessListLock);
while (!m_waveInFrameFreeList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveInFrameFreeList.RemoveHead();
delete waveFrame;
}
while (!m_waveInFrameWaitingList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveInFrameWaitingList.RemoveHead();
delete waveFrame;
}
while (!m_waveInFrameProcessList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveInFrameProcessList.RemoveHead();
delete waveFrame;
}
// close handles
CloseHandle(m_hWaveInProcessEvent);
CloseHandle(m_hWaveInProcessThread);
}
/////////////////////////////////////////////////////////////////////////
// Delete wave out list lock & free free/waiting list.
/////////////////////////////////////////////////////////////////////////
if (m_uDirection & WAVE_FORM_FLOW_OUT)
{
DeleteCriticalSection(&m_waveOutFrameFreeListLock);
DeleteCriticalSection(&m_waveOutFrameWaitingListLock);
DeleteCriticalSection(&m_waveOutFrameProcessListLock);
while (!m_waveOutFrameFreeList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveOutFrameFreeList.RemoveHead();
delete waveFrame;
}
while (!m_waveOutFrameWaitingList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveOutFrameWaitingList.RemoveHead();
delete waveFrame;
}
while (!m_waveOutFrameProcessList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveOutFrameProcessList.RemoveHead();
delete waveFrame;
}
// close handles
CloseHandle(m_hWaveOutProcessEvent);
CloseHandle(m_hWaveOutProcessThread);
}
}
/****************************************************************************
* CWaveForm::AddRef()
****************************************************************************
* Increase reference count.
*/
long
CWaveForm::AddRef()
{
::InterlockedIncrement(&m_RefCount);
return m_RefCount;
}
/****************************************************************************
* CWaveForm::Release()
****************************************************************************
* Decrease reference count, if 0, delete object.
*/
long
CWaveForm::Release()
{
if (::InterlockedDecrement(&m_RefCount) == 0)
{
delete this;
return 0;
}
return m_RefCount;
}
/****************************************************************************
* CWaveForm::Open()
****************************************************************************
* Open wave in/out device.
*/
BOOL
CWaveForm::Open
(
UINT uDirection
)
{
MMRESULT ret = MMSYSERR_INVALPARAM;
/////////////////////////////////////////////////////////////////////////
// Try to open wave in device, which support requested wave format.
/////////////////////////////////////////////////////////////////////////
if ((uDirection & WAVE_FORM_FLOW_IN) && (m_uDirection & WAVE_FORM_FLOW_IN))
{
if (m_waveInState == WAVE_STATE_CLOSE)
{
ret = ::waveInOpen
(
&m_hWaveIn,
WAVE_MAPPER, //m_waveInDeviceID,
&m_waveInFormatEx,
DWORD(WaveInCallBackRoutine),
DWORD(this),
CALLBACK_FUNCTION
);
if (ret == MMSYSERR_NOERROR)
{
m_waveInState = WAVE_STATE_OPEN;
// set volume of waveOut device
SetVolume(WAVE_FORM_FLOW_IN, m_waveInVolume);
SetMasterVolume( m_waveOutVolume );
// set volume of waveIn device
SetOutput( m_waveInVolume );
}
}
else
{
// This object doesn't support request wave device or already opened.
::MessageBox
(
NULL,
_T("Fail to open Wave In Device!!!"),
_T("Direct Line Service"),
MB_OK | MB_ICONWARNING
);
return FALSE;
}
}
/////////////////////////////////////////////////////////////////////////
// Try to open wave out device, which support requested wave format.
/////////////////////////////////////////////////////////////////////////
if ((uDirection & WAVE_FORM_FLOW_OUT) && (m_uDirection & WAVE_FORM_FLOW_OUT))
{
if (m_waveOutState == WAVE_STATE_CLOSE)
{
ret = ::waveOutOpen
(
&m_hWaveOut,
m_waveOutDeviceID,
&m_waveOutFormatEx,
DWORD(WaveOutCallBackRoutine),
DWORD(this),
CALLBACK_FUNCTION
);
if (ret == MMSYSERR_NOERROR)
{
m_waveOutState = WAVE_STATE_OPEN;
DWORD NewVolume = 2621480000;
SetVolume(WAVE_FORM_FLOW_OUT, NewVolume);
}
}
else
{
// This object doesn't support request wave device or already opened.
::MessageBox
(
NULL,
_T("Fail to open Wave Out Device!!!"),
_T("Direct Line Service"),
MB_OK | MB_ICONWARNING
);
return FALSE;
}
}
return TRUE;
}
/****************************************************************************
* CWaveForm::Close()
****************************************************************************
* Close wave in/out device.
*/
BOOL
CWaveForm::Close
(
UINT uDirection
)
{
MMRESULT ret = MMSYSERR_INVALPARAM;
/////////////////////////////////////////////////////////////////////////
// Try to close wave in device.
/////////////////////////////////////////////////////////////////////////
if ((uDirection & WAVE_FORM_FLOW_IN) && (m_uDirection & WAVE_FORM_FLOW_IN))
{
if (m_waveInState == WAVE_STATE_STOP)
{
// Check wave in waiting frame list.
if (m_hWaveIn)
{
// unprepare wavein waiting list headers
while (!m_waveInFrameWaitingList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveInFrameWaitingList.RemoveHead();
if (waveFrame)
{
ret = ::waveInUnprepareHeader
(
m_hWaveIn,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
}
// unprepare wavein free list headers
while (!m_waveInFrameFreeList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveInFrameFreeList.RemoveHead();
if (waveFrame)
{
ret = ::waveInUnprepareHeader
(
m_hWaveIn,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
}
::waveInClose(m_hWaveIn);
m_hWaveIn = NULL;
m_waveInState = WAVE_STATE_CLOSE;
}
}
else
{
::MessageBox
(
NULL,
_T("Fail to close Wave In Device!!!"),
_T("Direct Line Service"),
MB_OK | MB_ICONWARNING
);
TCHAR szText[MAXERRORLENGTH + 1] = {'\0'};
waveInGetErrorText(ret,szText,MAXERRORLENGTH);
return FALSE;
}
}
/////////////////////////////////////////////////////////////////////////
// Try to close wave out device.
/////////////////////////////////////////////////////////////////////////
if ((uDirection & WAVE_FORM_FLOW_OUT) && (m_uDirection & WAVE_FORM_FLOW_OUT))
{
if (m_waveOutState == WAVE_STATE_STOP)
{
// Check wave out waiting frame list.
if (m_hWaveOut)
{
// unprepare wave out waitlist headers
while (!m_waveOutFrameWaitingList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveOutFrameWaitingList.RemoveHead();
if (waveFrame)
{
ret = ::waveOutUnprepareHeader
(
m_hWaveOut,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
}
/// unprepare waveout freelist headers
while (!m_waveOutFrameWaitingList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveOutFrameWaitingList.RemoveHead();
if (waveFrame)
{
ret = ::waveOutUnprepareHeader
(
m_hWaveOut,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
}
::waveOutClose(m_hWaveOut);
m_hWaveOut = NULL;
m_waveOutState = WAVE_STATE_CLOSE;
}
}
else
{
::MessageBox
(
NULL,
_T("Fail to close Wave Out Device!!!"),
_T("Direct Line Service"),
MB_OK | MB_ICONWARNING
);
return FALSE;
}
}
return TRUE;
}
/****************************************************************************
* CWaveForm::Start()
****************************************************************************
* Start wave device.
*/
BOOL
CWaveForm::Start
(
UINT uDirection
)
{
MMRESULT ret = MMSYSERR_INVALPARAM;
/////////////////////////////////////////////////////////////////////////
// Start wave in stream.
/////////////////////////////////////////////////////////////////////////
if ((uDirection & WAVE_FORM_FLOW_IN) && (m_uDirection & WAVE_FORM_FLOW_IN))
{
// create a thread which will wait on the waveInProcessEvent and process the incoming buffers
m_bWaveInProcessFlag = true;
m_hWaveInProcessThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) CWaveForm::ThreadProcIn, (LPVOID)this, 0, 0);
if (m_waveInState == WAVE_STATE_OPEN)
{
if (m_hWaveIn)
{
while (!m_waveInFrameFreeList.IsEmpty())
{
PWAVEFRAME waveFrame = m_waveInFrameFreeList.RemoveHead();
if (waveFrame)
{
waveFrame->waveHdr.lpData = waveFrame->Data;
waveFrame->waveHdr.dwBufferLength = MAX_WAVE_BUFFER_LEN;
waveFrame->waveHdr.dwBytesRecorded = 0;
waveFrame->waveHdr.dwFlags = 0;
waveFrame->waveHdr.dwLoops = 0;
waveFrame->waveHdr.dwUser = 0;
waveFrame->waveHdr.lpNext = 0;
ret = ::waveInPrepareHeader
(
m_hWaveIn,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
ret = ::waveInAddBuffer
(
m_hWaveIn,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
m_dwWaveInByteInDevice += waveFrame->waveHdr.dwBufferLength;
}
}
ret = ::waveInStart(m_hWaveIn);
m_waveInState = WAVE_STATE_START;
}
}
else
{
::MessageBox
(
NULL,
_T("Fail to start Wave In Device!!!"),
_T("Direct Line Service"),
MB_OK | MB_ICONWARNING
);
return FALSE;
}
}
/////////////////////////////////////////////////////////////////////////
// Start wave out stream.
/////////////////////////////////////////////////////////////////////////
if ((uDirection & WAVE_FORM_FLOW_OUT) && (m_uDirection & WAVE_FORM_FLOW_OUT))
{
// create a thread which will wait on the waveInProcessEvent and process the incoming buffers
m_bWaveOutProcessFlag = true;
m_hWaveOutProcessThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) CWaveForm::ThreadProcOut, (LPVOID)this, 0, 0);
if (m_waveOutState == WAVE_STATE_OPEN)
{
if (m_hWaveOut)
{
while (!m_waveOutFrameWaitingList.IsEmpty())
{
PWAVEFRAME waveFrame = NULL;
waveFrame = m_waveOutFrameWaitingList.RemoveHead();
if (waveFrame)
{
ret = ::waveOutWrite
(
m_hWaveOut,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
m_dwWaveOutByteInDevice += waveFrame->waveHdr.dwBufferLength;
}
}
m_waveOutState = WAVE_STATE_START;
}
}
else
{
::MessageBox
(
NULL,
_T("Fail to start Wave Out Device!!!"),
_T("Direct Line Service"),
MB_OK | MB_ICONWARNING
);
return FALSE;
}
}
return TRUE;
}
/****************************************************************************
* CWaveForm::Stop()
****************************************************************************
* Stop wave device.
*/
BOOL
CWaveForm::Stop
(
UINT uDirection
)
{
MMRESULT ret = MMSYSERR_INVALPARAM;
/////////////////////////////////////////////////////////////////////////
// Stop wave in stream.
/////////////////////////////////////////////////////////////////////////
if ((uDirection & WAVE_FORM_FLOW_IN) && (m_uDirection & WAVE_FORM_FLOW_IN))
{
if (m_waveInState == WAVE_STATE_START)
{
if (m_hWaveIn)
{
m_waveInState = WAVE_STATE_RESET;
ret = ::waveInReset(m_hWaveIn);
// allow buffers to be returned via the callback function (WIM_DATA messages)
// waveInReset results in a message for each outstanding buffer
while(m_dwWaveInByteInDevice > 0)
Sleep(100);
// release the wavein process thread
m_bWaveInProcessFlag = false;
SetEvent(m_hWaveInProcessEvent);
// the waveInStop call is causing certain boxes to block (hang)
// waveInStop causes outstanding buffers to be filled with 0's
// these buffers cannot be unprepared??
// it is not neccessary to call waveInStop
// on exit m_waveInState must be set to WAVE_STATE_STOP
// or else close will fail
// alternatively the close function can be altered to reflect the desired state
m_waveInState = WAVE_STATE_STOP;
}
}
else
{
::MessageBox
(
NULL,
_T("Fail to stop Wave In Device!!!"),
_T("Direct Line Service"),
MB_OK | MB_ICONWARNING
);
TCHAR szText[MAXERRORLENGTH + 1] = {'\0'};
waveInGetErrorText(ret,szText,MAXERRORLENGTH);
return FALSE;
}
}
/////////////////////////////////////////////////////////////////////////
// Stop wave out stream.
/////////////////////////////////////////////////////////////////////////
if ((uDirection & WAVE_FORM_FLOW_OUT) && (m_uDirection & WAVE_FORM_FLOW_OUT))
{
if (m_waveOutState == WAVE_STATE_START)
{
if (m_hWaveOut)
{
m_waveOutState = WAVE_STATE_RESET;
ret = ::waveOutReset(m_hWaveOut);
// allow buffers to be returned via the callback function (WIM_DATA messages)
// waveoutReset results in a message for each outstanding buffer
while(m_dwWaveOutByteInDevice > 0)
Sleep(100);
// release the waveout process thread
m_bWaveOutProcessFlag = false;
SetEvent(m_hWaveOutProcessEvent);
m_waveOutState = WAVE_STATE_STOP;
}
}
else
{
::MessageBox
(
NULL,
_T("Fail to stop Wave Out Device!!!"),
_T("Direct Line Service"),
MB_OK | MB_ICONWARNING
);
return FALSE;
}
}
return TRUE;
}
/****************************************************************************
* CWaveForm::GetVolume()
****************************************************************************
* Get wave form volume.
*/
BOOL
CWaveForm::GetVolume
(
UINT uDirection,
PDWORD pVolume
)
{
MMRESULT ret = MMSYSERR_INVALPARAM;
if (uDirection & WAVE_FORM_FLOW_IN)
{
if (m_hWaveIn)
{
HMIXER hMixer = NULL;
ret = mixerOpen(&hMixer, (UINT)m_hWaveIn, NULL, NULL, MIXER_OBJECTF_HWAVEIN);
if (ret == MMSYSERR_NOERROR)
{
// Get mixer recording dest line.
MIXERLINE mixerDestLine;
memset(&mixerDestLine, 0, sizeof(MIXERLINE));
mixerDestLine.cbStruct = sizeof(MIXERLINE);
mixerDestLine.dwDestination = 1; // 0 - Playback , 1 - Recording.
ret = mixerGetLineInfo
(
(HMIXEROBJ)hMixer,
&mixerDestLine,
MIXER_GETLINEINFOF_DESTINATION
);
if (ret == MMSYSERR_NOERROR)
{
// Enumerate mixer recording source lines.
UINT srcConnection = 0;
MIXERLINE mixerSrcLine;
for (; srcConnection < mixerDestLine.cConnections; srcConnection++)
{
memset(&mixerSrcLine, 0, sizeof(MIXERLINE));
mixerSrcLine.cbStruct = sizeof(MIXERLINE);
mixerSrcLine.dwDestination = 1; // 0 - Playback , 1 - Recording.
mixerSrcLine.dwSource = srcConnection;
ret = mixerGetLineInfo
(
(HMIXEROBJ)hMixer,
&mixerSrcLine,
MIXER_GETLINEINFOF_SOURCE
);
if (mixerSrcLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE)
{
MIXERCONTROL mixerMicVolumeControl;
memset(&mixerMicVolumeControl, 0, sizeof(MIXERCONTROL));
mixerMicVolumeControl.cbStruct = sizeof(MIXERCONTROL);
MIXERLINECONTROLS mixerMicLineControls;
memset(&mixerMicLineControls, 0, sizeof(MIXERLINECONTROLS));
mixerMicLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
mixerMicLineControls.dwLineID = mixerSrcLine.dwLineID;
mixerMicLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mixerMicLineControls.cControls = 1;
mixerMicLineControls.pamxctrl = &mixerMicVolumeControl;
mixerMicLineControls.cbmxctrl = sizeof(MIXERCONTROL);
ret = mixerGetLineControls
(
(HMIXEROBJ)hMixer,
&mixerMicLineControls,
MIXER_GETLINECONTROLSF_ONEBYTYPE
);
if (ret == MMSYSERR_NOERROR)
{
MIXERCONTROLDETAILS_UNSIGNED volumeLevel[2];
volumeLevel[0].dwValue = 0;
volumeLevel[1].dwValue = 0;
MIXERCONTROLDETAILS mixerControlDetails;
mixerControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
mixerControlDetails.dwControlID = mixerMicLineControls.pamxctrl->dwControlID;
mixerControlDetails.cMultipleItems = 0;
mixerControlDetails.cChannels = mixerSrcLine.cChannels;
mixerControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED) * mixerSrcLine.cChannels;
mixerControlDetails.paDetails = volumeLevel;
ret = mixerGetControlDetails
(
(HMIXEROBJ)hMixer,
&mixerControlDetails,
MIXER_GETCONTROLDETAILSF_VALUE
);
*pVolume = volumeLevel[0].dwValue;
*pVolume |= volumeLevel[1].dwValue << 16;
}
break;
}
}
}
ret = mixerClose(hMixer);
}
}
}
if (uDirection & WAVE_FORM_FLOW_OUT)
{
if (m_hWaveOut)
{
ret = waveOutGetVolume(m_hWaveOut, pVolume);
}
}
if (ret == MMSYSERR_NOERROR)
{
return TRUE;
}
else
{
return FALSE;
}
}
/****************************************************************************
* CWaveForm::SetVolume()
****************************************************************************
* Set wave form volume.
*/
BOOL
CWaveForm::SetVolume
(
UINT uDirection,
DWORD dwVolume
)
{
MMRESULT ret = MMSYSERR_INVALPARAM;
if (uDirection & WAVE_FORM_FLOW_IN)
{
if (m_hWaveIn)
{
HMIXER hMixer = NULL;
ret = mixerOpen(&hMixer, (UINT)m_hWaveIn, NULL, NULL, MIXER_OBJECTF_HWAVEIN);
if (ret == MMSYSERR_NOERROR)
{
// Get mixer recording dest line.
MIXERLINE mixerDestLine;
memset(&mixerDestLine, 0, sizeof(MIXERLINE));
mixerDestLine.cbStruct = sizeof(MIXERLINE);
mixerDestLine.dwDestination = 0; // 0 - Playback , 1 - Recording.
ret = mixerGetLineInfo
(
(HMIXEROBJ)hMixer,
&mixerDestLine,
MIXER_GETLINEINFOF_DESTINATION
);
if (ret == MMSYSERR_NOERROR)
{
// Enumerate mixer recording source lines.
UINT srcConnection = 0;
MIXERLINE mixerSrcLine;
for (; srcConnection < mixerDestLine.cConnections; srcConnection++)
{
memset(&mixerSrcLine, 0, sizeof(MIXERLINE));
mixerSrcLine.cbStruct = sizeof(MIXERLINE);
mixerSrcLine.dwDestination = 0; // 0 - Playback , 1 - Recording.
mixerSrcLine.dwSource = srcConnection;
ret = mixerGetLineInfo
(
(HMIXEROBJ)hMixer,
&mixerSrcLine,
MIXER_GETLINEINFOF_SOURCE
);
if ( mixerSrcLine.dwComponentType == MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT )
{
MIXERCONTROL mixerMicVolumeControl;
memset(&mixerMicVolumeControl, 0, sizeof(MIXERCONTROL));
mixerMicVolumeControl.cbStruct = sizeof(MIXERCONTROL);
MIXERLINECONTROLS mixerMicLineControls;
memset(&mixerMicLineControls, 0, sizeof(MIXERLINECONTROLS));
mixerMicLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
mixerMicLineControls.dwLineID = mixerSrcLine.dwLineID;
mixerMicLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mixerMicLineControls.cControls = 1;
mixerMicLineControls.pamxctrl = &mixerMicVolumeControl;
mixerMicLineControls.cbmxctrl = sizeof(MIXERCONTROL);
ret = mixerGetLineControls
(
(HMIXEROBJ)hMixer,
&mixerMicLineControls,
MIXER_GETLINECONTROLSF_ONEBYTYPE
);
if (ret == MMSYSERR_NOERROR)
{
MIXERCONTROLDETAILS_UNSIGNED volumeLevel[2];
volumeLevel[0].dwValue = dwVolume & 0x0ffff;
volumeLevel[1].dwValue = volumeLevel[0].dwValue;
MIXERCONTROLDETAILS mixerControlDetails;
mixerControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
mixerControlDetails.dwControlID = mixerMicLineControls.pamxctrl->dwControlID;
mixerControlDetails.cMultipleItems = 0;
mixerControlDetails.cChannels = mixerSrcLine.cChannels;
mixerControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED) * mixerSrcLine.cChannels;
mixerControlDetails.paDetails = volumeLevel;
ret = mixerSetControlDetails
(
(HMIXEROBJ)hMixer,
&mixerControlDetails,
MIXER_SETCONTROLDETAILSF_VALUE
);
m_waveInVolume = dwVolume;
}
break;
} // end if
}// end for
}
ret = mixerClose(hMixer);
}
}
}
if (uDirection & WAVE_FORM_FLOW_OUT)
{
if (m_hWaveOut)
{
ret = waveOutSetVolume(m_hWaveOut, dwVolume);
m_waveOutVolume = dwVolume;
}
}
if (ret == MMSYSERR_NOERROR)
{
return TRUE;
}
else
{
return FALSE;
}
}
/****************************************************************************
* CWaveForm::Read()
****************************************************************************
* Read wave frames in waiting list.
*/
BOOL
CWaveForm::Read
(
PPWAVEFRAME ppwaveFrame
)
{
if (m_waveInState == WAVE_STATE_START)
{
if ((m_uDirection & WAVE_FORM_FLOW_IN) && m_hWaveIn)
{
EnterCriticalSection(&m_waveInFrameWaitingListLock);
if (!m_waveInFrameWaitingList.IsEmpty())
{
*ppwaveFrame = m_waveInFrameWaitingList.RemoveHead();
}
else
{
*ppwaveFrame = NULL;
}
LeaveCriticalSection(&m_waveInFrameWaitingListLock);
return TRUE;
}
}
else
{
*ppwaveFrame = NULL;
}
return FALSE;
}
/****************************************************************************
* CWaveForm::ReadDone()
****************************************************************************
* Return used wave frames.
*/
BOOL
CWaveForm::ReadDone
(
PWAVEFRAME waveFrame
)
{
if (waveFrame)
{
if ((m_uDirection & WAVE_FORM_FLOW_IN) && m_hWaveIn)
{
// Clear used frame.
waveFrame->waveHdr.dwBytesRecorded = 0;
// Reuse it in free list.
EnterCriticalSection(&m_waveInFrameFreeListLock);
m_waveInFrameFreeList.AddTail(waveFrame);
LeaveCriticalSection(&m_waveInFrameFreeListLock);
return TRUE;
}
}
return FALSE;
}
/****************************************************************************
* CWaveForm::Write()
****************************************************************************
* Ask to allocate wave frame.
*/
BOOL
CWaveForm::Write
(
PPWAVEFRAME ppwaveFrame
)
{
if ((m_uDirection & WAVE_FORM_FLOW_OUT) && m_hWaveOut)
{
EnterCriticalSection(&m_waveOutFrameFreeListLock);
if (!m_waveOutFrameFreeList.IsEmpty())
{
*ppwaveFrame = m_waveOutFrameFreeList.RemoveHead();
}
else
{
PWAVEFRAME waveFrame = NULL;
waveFrame = new WAVEFRAME;
if (waveFrame)
{
waveFrame->waveHdr.lpData = waveFrame->Data;
waveFrame->waveHdr.dwBufferLength = MAX_WAVE_BUFFER_LEN;
waveFrame->waveHdr.dwBytesRecorded = 0;
waveFrame->waveHdr.dwFlags = 0;
waveFrame->waveHdr.dwLoops = 0;
waveFrame->waveHdr.dwUser = 0;
waveFrame->waveHdr.lpNext = 0;
MMRESULT ret = ::waveOutPrepareHeader
(
m_hWaveOut,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
*ppwaveFrame = waveFrame;
}
}
LeaveCriticalSection(&m_waveOutFrameFreeListLock);
return TRUE;
}
return FALSE;
}
/****************************************************************************
* CWaveForm::Write()
****************************************************************************
* Write data to preallocated wave frame.
*/
BOOL
CWaveForm::Write
(
PWAVEFRAME waveFrame
)
{
if (waveFrame)
{
if (m_waveOutState == WAVE_STATE_START)
{
if ((m_uDirection & WAVE_FORM_FLOW_OUT) && m_hWaveOut)
{
EnterCriticalSection(&m_waveOutFrameWaitingListLock);
// Queue this coming frame.
if (m_waveOutFrameWaitingList.GetCount() < MAX_WAVE_NUM)
{
m_waveOutFrameWaitingList.AddTail(waveFrame);
}
else // Waiting list is full.
{
EnterCriticalSection(&m_waveOutFrameFreeListLock);
if (m_waveOutFrameFreeList.GetCount() < MAX_WAVE_NUM)
{
m_waveOutFrameFreeList.AddTail(waveFrame);
}
else // Free list is also full.
{
MMRESULT ret = ::waveOutUnprepareHeader
(
m_hWaveOut,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
LeaveCriticalSection(&m_waveOutFrameFreeListLock);
}
// Fetch new frame from waiting list and send to device.
if (!m_waveOutFrameWaitingList.IsEmpty() &&
(m_dwWaveOutByteInDevice < MAX_BUFFER_IN_QUEUE))
{
PWAVEFRAME newWaveFrame = NULL;
newWaveFrame = m_waveOutFrameWaitingList.RemoveHead();
if (newWaveFrame)
{
MMRESULT ret = ::waveOutWrite
(
m_hWaveOut,
(LPWAVEHDR)newWaveFrame,
sizeof(WAVEHDR)
);
m_dwWaveOutByteInDevice += newWaveFrame->waveHdr.dwBufferLength;
}
}
LeaveCriticalSection(&m_waveOutFrameWaitingListLock);
return TRUE;
}
}
else
{
EnterCriticalSection(&m_waveOutFrameFreeListLock);
if (m_waveOutFrameFreeList.GetCount() < MAX_WAVE_NUM)
{
m_waveOutFrameFreeList.AddTail(waveFrame);
}
else // Free list is full.
{
MMRESULT ret = ::waveOutUnprepareHeader
(
m_hWaveOut,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
LeaveCriticalSection(&m_waveOutFrameFreeListLock);
}
}
return FALSE;
}
/****************************************************************************
* CWaveForm::OnWaveInData()
****************************************************************************
* Wave in data handler.
*/
void
CWaveForm::OnWaveInData
(
PWAVEFRAME waveFrame
)
{
if (m_waveInState != WAVE_STATE_START){
}
/////////////////////////////////////////////////////////////////////////
// Processing recorded wave in frame.
/////////////////////////////////////////////////////////////////////////
if(waveFrame){
if (m_dwWaveInByteInDevice != 0)
{
m_dwWaveInByteInDevice -= waveFrame->waveHdr.dwBufferLength;
}
}
if (m_waveInState == WAVE_STATE_START)
{
if (waveFrame->waveHdr.dwBytesRecorded != 0)
{
EnterCriticalSection(&m_waveInFrameWaitingListLock);
if (m_waveInFrameWaitingList.GetCount() < MAX_WAVE_NUM)
{
m_waveInFrameWaitingList.AddTail(waveFrame);
}
else
{
// Waiting list is full.
EnterCriticalSection(&m_waveInFrameFreeListLock);
if (m_waveInFrameFreeList.GetCount() < MAX_WAVE_NUM)
{
waveFrame->waveHdr.dwBytesRecorded = 0;
m_waveInFrameFreeList.AddTail(waveFrame);
}
else
{
// Free list is also full.
MMRESULT ret = ::waveInUnprepareHeader
(
m_hWaveIn,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
LeaveCriticalSection(&m_waveInFrameFreeListLock);
}
LeaveCriticalSection(&m_waveInFrameWaitingListLock);
// Notify client.
Invoke(WM_STREAM_NOTIFY, SUB_EVENT_WAVE_IN, 0);
}
else
{
// else waveFrame->waveHdr.dwBytesRecorded == 0
EnterCriticalSection(&m_waveInFrameFreeListLock);
if (m_waveInFrameFreeList.GetCount() < MAX_WAVE_NUM)
{
waveFrame->waveHdr.dwBytesRecorded = 0;
m_waveInFrameFreeList.AddTail(waveFrame);
}
else // Free list is full.
{
MMRESULT ret = ::waveInUnprepareHeader
(
m_hWaveIn,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
LeaveCriticalSection(&m_waveInFrameFreeListLock);
}// end if (waveFrame->waveHdr.dwBytesRecorded != 0)
}
else
{
//else m_waveInState != WAVE_STATE_START
EnterCriticalSection(&m_waveInFrameFreeListLock);
if (m_waveInFrameFreeList.GetCount() < MAX_WAVE_NUM)
{
waveFrame->waveHdr.dwBytesRecorded = 0;
m_waveInFrameFreeList.AddTail(waveFrame);
}
else
{
// Free list is full.
MMRESULT ret = ::waveInUnprepareHeader
(
m_hWaveIn,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
LeaveCriticalSection(&m_waveInFrameFreeListLock);
} // end m_waveInState == WAVE_STATE_START
/////////////////////////////////////////////////////////////////////////
// Find new free wave in frame, otherwise allocate a new one.
/////////////////////////////////////////////////////////////////////////
if ((m_waveInState == WAVE_STATE_START) &&
(m_dwWaveInByteInDevice < MAX_BUFFER_IN_QUEUE))
{
MMRESULT ret;
PWAVEFRAME newWaveFrame = NULL;
EnterCriticalSection(&m_waveInFrameFreeListLock);
if (!m_waveInFrameFreeList.IsEmpty())
{
newWaveFrame = m_waveInFrameFreeList.RemoveHead();
}
else
{
newWaveFrame = new WAVEFRAME;
if (newWaveFrame)
{
newWaveFrame->waveHdr.lpData = newWaveFrame->Data;
newWaveFrame->waveHdr.dwBufferLength = MAX_WAVE_BUFFER_LEN;
newWaveFrame->waveHdr.dwBytesRecorded = 0;
newWaveFrame->waveHdr.dwFlags = 0;
newWaveFrame->waveHdr.dwLoops = 0;
newWaveFrame->waveHdr.dwUser = 0;
newWaveFrame->waveHdr.lpNext = 0;
ret = ::waveInPrepareHeader
(
m_hWaveIn,
(LPWAVEHDR)newWaveFrame,
sizeof(WAVEHDR)
);
}
}
LeaveCriticalSection(&m_waveInFrameFreeListLock);
// Add buffer to wave in device.
if (newWaveFrame)
{
ret = waveInAddBuffer
(
m_hWaveIn,
(LPWAVEHDR)newWaveFrame,
sizeof(WAVEHDR)
);
m_dwWaveInByteInDevice += newWaveFrame->waveHdr.dwBufferLength;
}
}
if (m_waveInState != WAVE_STATE_START){
}
}
/****************************************************************************
* CWaveForm::OnWaveOutDone()
****************************************************************************
* Wave out done handler.
*/
void
CWaveForm::OnWaveOutDone
(
PWAVEFRAME waveFrame
)
{
/////////////////////////////////////////////////////////////////////////
// Processing used wave out frame.
/////////////////////////////////////////////////////////////////////////
if(waveFrame){
if (m_dwWaveOutByteInDevice != 0)
{
m_dwWaveOutByteInDevice -= waveFrame->waveHdr.dwBufferLength;
}
}
EnterCriticalSection(&m_waveOutFrameFreeListLock);
if (m_waveOutFrameFreeList.GetCount() < MAX_WAVE_NUM)
{
m_waveOutFrameFreeList.AddTail(waveFrame);
}
else // Free list is full.
{
MMRESULT ret = ::waveOutUnprepareHeader
(
m_hWaveOut,
(LPWAVEHDR)waveFrame,
sizeof(WAVEHDR)
);
delete waveFrame;
}
LeaveCriticalSection(&m_waveOutFrameFreeListLock);
/////////////////////////////////////////////////////////////////////////
// If device is running, fetch new data from waiting list.
/////////////////////////////////////////////////////////////////////////
if ((m_waveOutState == WAVE_STATE_START) &&
(m_dwWaveOutByteInDevice < MAX_BUFFER_IN_QUEUE))
{
PWAVEFRAME newWaveFrame = NULL;
EnterCriticalSection(&m_waveOutFrameWaitingListLock);
if (!m_waveOutFrameWaitingList.IsEmpty())
{
newWaveFrame = m_waveOutFrameWaitingList.RemoveHead();
}
LeaveCriticalSection(&m_waveOutFrameWaitingListLock);
// Write buffer to wave out device.
if (newWaveFrame)
{
MMRESULT ret = ::waveOutWrite
(
m_hWaveOut,
(LPWAVEHDR)newWaveFrame,
sizeof(WAVEHDR)
);
m_dwWaveOutByteInDevice += newWaveFrame->waveHdr.dwBufferLength;
}
}
if (m_waveOutState != WAVE_STATE_START){
}
}
/****************************************************************************
* WaveInCallBackRoutine()
****************************************************************************
* Wave in callback routine.
*/
void
CALLBACK
WaveInCallBackRoutine
(
HWAVEIN hwi,
UINT uMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2
)
{
CWaveForm * that = (CWaveForm *)dwInstance;
PWAVEFRAME waveFrame = NULL;
if (hwi == that->m_hWaveIn)
{
switch (uMsg)
{
case WIM_OPEN:
break;
case WIM_DATA:
EnterCriticalSection(&that->m_waveInFrameProcessListLock);
waveFrame = (PWAVEFRAME)dwParam1;
if (waveFrame)
that->m_waveInFrameProcessList.AddTail(waveFrame);
LeaveCriticalSection(&that->m_waveInFrameProcessListLock);
SetEvent(that->m_hWaveInProcessEvent);
break;
case WIM_CLOSE:
break;
}
}
}
/****************************************************************************
* WaveOutCallBackRoutine()
****************************************************************************
* Wave out call back routine.
*/
void
CALLBACK
WaveOutCallBackRoutine
(
HWAVEOUT hwo,
UINT uMsg,
DWORD dwInstance,
DWORD dwParam1,
DWORD dwParam2
)
{
CWaveForm * that = (CWaveForm *)dwInstance;
PWAVEFRAME waveFrame = NULL;
if (hwo == that->m_hWaveOut)
{
switch (uMsg)
{
case WOM_OPEN:
break;
case WOM_DONE:
EnterCriticalSection(&that->m_waveOutFrameProcessListLock);
waveFrame = (PWAVEFRAME)dwParam1;
if (waveFrame)
that->m_waveOutFrameProcessList.AddTail(waveFrame);
LeaveCriticalSection(&that->m_waveOutFrameProcessListLock);
SetEvent(that->m_hWaveOutProcessEvent);
break;
case WOM_CLOSE:
break;
}
}
}
/****************************************************************************
* CWaveForm::WaveInProcess()
****************************************************************************
* process buffers.
*/
void
CWaveForm::WaveInProcess()
{
m_bWaveInProcessState = true;
while(m_bWaveInProcessFlag){
WaitForSingleObject( m_hWaveInProcessEvent, INFINITE );
while(0 < m_waveInFrameProcessList.GetCount()){
PWAVEFRAME newWaveFrame = NULL;
EnterCriticalSection(&m_waveInFrameProcessListLock);
newWaveFrame = m_waveInFrameProcessList.RemoveHead();
LeaveCriticalSection(&m_waveInFrameProcessListLock);
OnWaveInData( newWaveFrame );
}
}
m_bWaveInProcessState = false;
}
/****************************************************************************
* CWaveForm::WaveOutProcess()
****************************************************************************
* process buffers.
*/
void
CWaveForm::WaveOutProcess()
{
m_bWaveOutProcessState = true;
while(m_bWaveOutProcessFlag){
WaitForSingleObject( m_hWaveOutProcessEvent, INFINITE );
while(0 < m_waveOutFrameProcessList.GetCount()){
PWAVEFRAME newWaveFrame = NULL;
EnterCriticalSection(&m_waveOutFrameProcessListLock);
newWaveFrame = m_waveOutFrameProcessList.RemoveHead();
LeaveCriticalSection(&m_waveOutFrameProcessListLock);
OnWaveOutDone( newWaveFrame );
}
}
m_bWaveOutProcessState = false;
}
// -----------------------------------------------------------------------------
void __cdecl CWaveForm::ThreadProcIn(void *data)
{
CWaveForm &pi = *reinterpret_cast<CWaveForm*>(data);
pi.WaveInProcess();
}
// -----------------------------------------------------------------------------
void __cdecl CWaveForm::ThreadProcOut(void *data)
{
CWaveForm &po = *reinterpret_cast<CWaveForm*>(data);
po.WaveOutProcess();
}
bool CWaveForm::SetOutput( DWORD dwVolume ){
MMRESULT ret = MMSYSERR_INVALPARAM;
char * sourceName = "";
bool sourceNameFlag = false;
MIXERLINE mixLine;
HMIXER hMixer = NULL;
ret = mixerOpen(&hMixer, (UINT)m_hWaveIn, NULL, NULL, MIXER_OBJECTF_HWAVEIN);
MIXERLINE mixerDestLine;
if (ret == MMSYSERR_NOERROR)
{
// Get mixer recording dest line.
memset(&mixerDestLine, 0, sizeof(MIXERLINE));
mixerDestLine.cbStruct = sizeof(MIXERLINE);
mixerDestLine.dwDestination = 1; // 0 - Playback , 1 - Recording.
ret = mixerGetLineInfo
(
(HMIXEROBJ)hMixer,
&mixerDestLine,
MIXER_GETLINEINFOF_DESTINATION
);
// find the source name for the recording mixer control
// Stereo Mixer, Wave Mixer, or Record Mixer are common
// use a tiered approach
for (UINT iS=0;iS<mixerDestLine.cConnections && !sourceNameFlag;iS++) {
mixLine.cbStruct = sizeof(MIXERLINE);
mixLine.dwDestination = 1;
mixLine.dwSource = (DWORD) iS;
mixerGetLineInfo((HMIXEROBJ)hMixer, (LPMIXERLINE) &mixLine, MIXER_GETLINEINFOF_SOURCE);
const char * wrkStr = "";
int posMixer = false;
bool isMixer = false;
if(mixLine.dwComponentType == 4106){
std::string shortName = mixLine.szShortName;
int posItem = 0;
// try by using explicit control names
std::string tmpShortName = mixLine.szShortName;
wrkStr = "Stereo Mix";
posItem = tmpShortName.find(wrkStr);
bool isStereoMixer = (posMixer > -1 && posMixer < 50);
wrkStr = "Wave Mix";
posItem = tmpShortName.find(wrkStr);
bool isWaveMixer = (posMixer > -1 && posMixer < 50);
wrkStr = "Record Mix";
posItem = tmpShortName.find(wrkStr);
bool isRecordMixer = (posMixer > -1 && posMixer < 50);
if(isStereoMixer || isWaveMixer || isRecordMixer){
sourceName = mixLine.szName;
sourceNameFlag = true;
break;
}
// try line id = 1 and shortName combination
if(!sourceNameFlag){
posMixer = shortName.find("Mix");
isMixer = (posMixer > -1 && posMixer < 50);
if( isMixer && (mixLine.dwLineID == 1)){
sourceName = mixLine.szName;
sourceNameFlag = true;
break;
}
}
// try shortName and elimination combinations
if(!sourceNameFlag){
posMixer = shortName.find("Mix");
isMixer = (posMixer > -1 && posMixer < 50);
wrkStr = "Auxiliary";
posItem = tmpShortName.find(wrkStr);
bool isAux = (posMixer > -1 && posMixer < 50);
wrkStr = "Aux";
posItem = tmpShortName.find(wrkStr);
bool isAux2 = (posMixer > -1 && posMixer < 50);
wrkStr = "Video";
posItem = tmpShortName.find(wrkStr);
bool isVideo = (posMixer > -1 && posMixer < 50);
wrkStr = "IIS";
posItem = tmpShortName.find(wrkStr);
bool isIIS = (posMixer > -1 && posMixer < 50);
bool isWaveMixer = ( isAux || isVideo || isIIS || isAux2 );
if ( isMixer == true && isWaveMixer == true ){
sourceName = mixLine.szName;
sourceNameFlag = true;
break;
}
}
}
}
} // end for mixerDestLine
// if we found a record mixer control
if( sourceNameFlag ){
// Select wave mixer as the recording source.
// Get the line info for the wave in destination line
MIXERLINE mixerLine;
mixerLine.cbStruct = sizeof(mixerLine);
mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
mixerGetLineInfo((HMIXEROBJ)hMixer, &mixerLine,MIXER_GETLINEINFOF_COMPONENTTYPE);
// Find a LIST control, if any, for the wave in line
LPMIXERCONTROL pMixerControls = (LPMIXERCONTROL)malloc(mixerLine.cControls * sizeof(MIXERCONTROL));
MIXERLINECONTROLS mixerLinectrl = {sizeof mixerLinectrl, mixerLine.dwLineID, 0,mixerLine.cControls, sizeof MIXERCONTROL, pMixerControls};
ret = mixerGetLineControls((HMIXEROBJ) hMixer, &mixerLinectrl,MIXER_GETLINECONTROLSF_ALL);
// Now walk through each control to find a type of LIST control. This
// can be either Mux, Single-select, Mixer or Multiple-select.
DWORD i;
for(i=0; i < mixerLine.cControls; i++)
if (MIXERCONTROL_CT_CLASS_LIST == (pMixerControls[i].dwControlType &MIXERCONTROL_CT_CLASS_MASK))
break;
if (i < mixerLine.cControls)
{
// Found a LIST control
// Check if the LIST control is a Mux or Single-select type
BOOL bOneItemOnly = FALSE;
switch (pMixerControls[i].dwControlType) {
case MIXERCONTROL_CONTROLTYPE_MUX:
case MIXERCONTROL_CONTROLTYPE_SINGLESELECT:
bOneItemOnly = TRUE;
}
DWORD cChannels = mixerLine.cChannels, cMultipleItems = 0;
if (MIXERCONTROL_CONTROLF_UNIFORM & pMixerControls[i].fdwControl)
cChannels = 1;
if (MIXERCONTROL_CONTROLF_MULTIPLE & pMixerControls[i].fdwControl)
cMultipleItems = pMixerControls[i].cMultipleItems;
// Get the text description of each item
LPMIXERCONTROLDETAILS_LISTTEXT plisttext = (LPMIXERCONTROLDETAILS_LISTTEXT)malloc(cChannels * cMultipleItems * sizeof(MIXERCONTROLDETAILS_LISTTEXT));
MIXERCONTROLDETAILS mixerControlDetail = {sizeof(mixerControlDetail),pMixerControls[i].dwControlID,cChannels,(HWND)cMultipleItems, sizeof MIXERCONTROLDETAILS_LISTTEXT,(LPVOID) plisttext};
ret = mixerGetControlDetails((HMIXEROBJ)hMixer, &mixerControlDetail,MIXER_GETCONTROLDETAILSF_LISTTEXT);
// Now get the value for each item
LPMIXERCONTROLDETAILS_BOOLEAN plistbool=(LPMIXERCONTROLDETAILS_BOOLEAN)malloc(cChannels * cMultipleItems * sizeof(MIXERCONTROLDETAILS_BOOLEAN));
mixerControlDetail.cbDetails = sizeof MIXERCONTROLDETAILS_BOOLEAN;
mixerControlDetail.paDetails = plistbool;
ret = mixerGetControlDetails((HMIXEROBJ)hMixer,&mixerControlDetail,MIXER_GETCONTROLDETAILSF_VALUE);
// Select the "Mixer" (sourceName) item
for (DWORD j=0; j<cMultipleItems; j = j + cChannels)
if (0 == strcmp(plisttext[j].szName, sourceName))
// Select it for both left and right channels
plistbool[j].fValue = plistbool[j+ cChannels - 1].fValue = 1;
//else if (bOneItemOnly) ---- deselect the others
else
// Mux or Single-select allows only one item to be selected
// so clear other items as necessary
plistbool[j].fValue = plistbool[j+ cChannels - 1].fValue = 0;
if (ret == MMSYSERR_NOERROR){
// Now actually set the new values in
ret = mixerSetControlDetails((HMIXEROBJ)hMixer, &mixerControlDetail,MIXER_GETCONTROLDETAILSF_VALUE);
}
free(pMixerControls);
free(plisttext);
free(plistbool);
} else {
free(pMixerControls);
} // end if mixerLine.cControls
// END Select wave mixer as the recording source.
// Set the volume on the recording source.
MIXERCONTROL mixerMicVolumeControl;
memset(&mixerMicVolumeControl, 0, sizeof(MIXERCONTROL));
mixerMicVolumeControl.cbStruct = sizeof(MIXERCONTROL);
MIXERLINECONTROLS mixerMicLineControls;
memset(&mixerMicLineControls, 0, sizeof(MIXERLINECONTROLS));
mixerMicLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
mixerMicLineControls.dwLineID = mixLine.dwLineID;
mixerMicLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mixerMicLineControls.cControls = 1;
mixerMicLineControls.pamxctrl = &mixerMicVolumeControl;
mixerMicLineControls.cbmxctrl = sizeof(MIXERCONTROL);
ret = mixerGetLineControls
(
(HMIXEROBJ)hMixer,
&mixerMicLineControls,
MIXER_GETLINECONTROLSF_ONEBYTYPE
);
if (ret == MMSYSERR_NOERROR)
{
MIXERCONTROLDETAILS_UNSIGNED volumeLevel[2];
volumeLevel[0].dwValue = dwVolume & 0x0ffff;
volumeLevel[1].dwValue = volumeLevel[0].dwValue;
MIXERCONTROLDETAILS mixerControlDetails;
mixerControlDetails.cbStruct = sizeof(MIXERCONTROLDETAILS);
mixerControlDetails.dwControlID = mixerMicLineControls.pamxctrl->dwControlID;
mixerControlDetails.cMultipleItems = 0;
mixerControlDetails.cChannels = mixLine.cChannels;
mixerControlDetails.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED) * mixLine.cChannels;
mixerControlDetails.paDetails = volumeLevel;
ret = mixerSetControlDetails
(
(HMIXEROBJ)hMixer,
&mixerControlDetails,
MIXER_SETCONTROLDETAILSF_VALUE
);
}
ret = mixerClose(hMixer);
} // END if sourceNameFlag
if (ret == MMSYSERR_NOERROR)
{
return TRUE;
}
else
{
return FALSE;
}
}
void CWaveForm::SelectSource(char *sourcename)
{
HMIXER hMixer = NULL;
mixerOpen(&hMixer, (UINT)m_hWaveIn, NULL, NULL, MIXER_OBJECTF_HWAVEIN);
// Get the line info for the wave in destination line
MIXERLINE mixerLine;
mixerLine.cbStruct = sizeof(mixerLine);
mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
mixerGetLineInfo((HMIXEROBJ)hMixer, &mixerLine,MIXER_GETLINEINFOF_COMPONENTTYPE);
// Find a LIST control, if any, for the wave in line
LPMIXERCONTROL pMixerControls = (LPMIXERCONTROL)malloc(mixerLine.cControls * sizeof(MIXERCONTROL));
MIXERLINECONTROLS mixerLinectrl = {sizeof mixerLinectrl, mixerLine.dwLineID, 0,mixerLine.cControls, sizeof MIXERCONTROL, pMixerControls};
mixerGetLineControls((HMIXEROBJ) hMixer, &mixerLinectrl,MIXER_GETLINECONTROLSF_ALL);
// Now walk through each control to find a type of LIST control. This
// can be either Mux, Single-select, Mixer or Multiple-select.
DWORD i;
for(i=0; i < mixerLine.cControls; i++)
if (MIXERCONTROL_CT_CLASS_LIST == (pMixerControls[i].dwControlType &MIXERCONTROL_CT_CLASS_MASK))
break;
if (i < mixerLine.cControls)
{ // Found a LIST control
// Check if the LIST control is a Mux or Single-select type
BOOL bOneItemOnly = FALSE;
switch (pMixerControls[i].dwControlType) {
case MIXERCONTROL_CONTROLTYPE_MUX:
case MIXERCONTROL_CONTROLTYPE_SINGLESELECT:
bOneItemOnly = TRUE;
}
DWORD cChannels = mixerLine.cChannels, cMultipleItems = 0;
if (MIXERCONTROL_CONTROLF_UNIFORM & pMixerControls[i].fdwControl)
cChannels = 1;
if (MIXERCONTROL_CONTROLF_MULTIPLE & pMixerControls[i].fdwControl)
cMultipleItems = pMixerControls[i].cMultipleItems;
// Get the text description of each item
LPMIXERCONTROLDETAILS_LISTTEXT plisttext =
(LPMIXERCONTROLDETAILS_LISTTEXT)malloc(cChannels * cMultipleItems *
sizeof(MIXERCONTROLDETAILS_LISTTEXT));
MIXERCONTROLDETAILS mixerControlDetail = {sizeof(mixerControlDetail),
pMixerControls[i].dwControlID,cChannels,
(HWND)cMultipleItems, sizeof MIXERCONTROLDETAILS_LISTTEXT,(LPVOID)
plisttext};
mixerGetControlDetails((HMIXEROBJ)hMixer, &mixerControlDetail,
MIXER_GETCONTROLDETAILSF_LISTTEXT);
// Now get the value for each item
LPMIXERCONTROLDETAILS_BOOLEAN plistbool
=(LPMIXERCONTROLDETAILS_BOOLEAN)malloc(cChannels * cMultipleItems *
sizeof(MIXERCONTROLDETAILS_BOOLEAN));
mixerControlDetail.cbDetails = sizeof MIXERCONTROLDETAILS_BOOLEAN;
mixerControlDetail.paDetails = plistbool;
mixerGetControlDetails((HMIXEROBJ)hMixer,
&mixerControlDetail,MIXER_GETCONTROLDETAILSF_VALUE);
// Select the "Mixer" item
for (DWORD j=0; j<cMultipleItems; j = j + cChannels)
if (0 == strcmp(plisttext[j].szName, sourcename))
// Select it for both left and right channels
plistbool[j].fValue = plistbool[j+ cChannels - 1].fValue = 1;
//else if (bOneItemOnly) ---- deselect the others
else
// Mux or Single-select allows only one item to be selected
// so clear other items as necessary
plistbool[j].fValue = plistbool[j+ cChannels - 1].fValue = 0;
// Now actually set the new values in
mixerSetControlDetails((HMIXEROBJ)hMixer,
&mixerControlDetail,MIXER_GETCONTROLDETAILSF_VALUE);
free(pMixerControls);
free(plisttext);
free(plistbool);
}
else
free(pMixerControls);
mixerClose(hMixer);
}
bool CWaveForm::SetMasterVolume( DWORD dwVolume ){
// set only if audio via ip
// else is set in dial up speaker
MMRESULT result;
HMIXER hMixer;
MIXERLINE ml = {0};
MIXERLINECONTROLS mlc = {0};
MIXERCONTROL mc = {0};
MIXERCONTROLDETAILS mcd = {0};
MIXERCONTROLDETAILS_UNSIGNED mcdu = {0};
// get a handle to the mixer device
result = mixerOpen(&hMixer, MIXER_OBJECTF_MIXER, 0, 0, 0);
if (MMSYSERR_NOERROR == result)
{
ml.cbStruct = sizeof(MIXERLINE);
ml.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
// get the speaker line of the mixer device
result = mixerGetLineInfo((HMIXEROBJ) hMixer, &ml, MIXER_GETLINEINFOF_COMPONENTTYPE);
if (MMSYSERR_NOERROR == result)
{
mlc.cbStruct = sizeof(MIXERLINECONTROLS);
mlc.dwLineID = ml.dwLineID;
mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
mlc.cControls = 1;
mlc.pamxctrl = &mc;
mlc.cbmxctrl = sizeof(MIXERCONTROL);
// get the volume controls associated with the speaker line
result = mixerGetLineControls((HMIXEROBJ) hMixer, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
if (MMSYSERR_NOERROR == result)
{
mcdu.dwValue = dwVolume;
mcd.cbStruct = sizeof(MIXERCONTROLDETAILS);
mcd.hwndOwner = 0;
mcd.dwControlID = mc.dwControlID;
mcd.paDetails = &mcdu;
mcd.cbDetails = sizeof(MIXERCONTROLDETAILS_UNSIGNED);
mcd.cChannels = 1;
// set the volume
result = mixerSetControlDetails((HMIXEROBJ) hMixer, &mcd, MIXER_SETCONTROLDETAILSF_VALUE);
if (MMSYSERR_NOERROR == result)
else
printf("wave->setmastervolume->mixerSetControlDetails() failed\n");
}
else
{
printf("wave->setmastervolume->mixerGetLineControls() failed\n");
}
}
else
{
printf("wave->setmastervolume->mixerGetLineInfo() failed\n");
}
mixerClose(hMixer);
}
else
{
printf("wave->setmastervolume->mixerOpen() failed\n");
}
if (result == MMSYSERR_NOERROR)
{
return TRUE;
}
else
{
return FALSE;
}
}
/****************************************************************************
* CWaveForm::SoundCardCheck()
****************************************************************************
* Ensure the system has a working soundcard.
*/
BOOL
CWaveForm::SoundCardCheck()
{
if (waveInGetNumDevs() == 0){
MessageBox (0, "No sound card installed",
"WaveForm", MB_OK);
return false;
}
WAVEINCAPS waveInCaps;
if (waveInGetDevCaps (0,
&waveInCaps,
sizeof(WAVEINCAPS))
!= MMSYSERR_NOERROR)
{
MessageBox (0, "Cannot determine sound card capabilities",
"WaveForm", MB_OK);
return false;
}
return true;
}
/****************************************************************************
* CWaveForm::isInSupported()
****************************************************************************
* Emsure the requested format is supported
*/
BOOL
CWaveForm::isInSupported (UINT idDev, WAVEFORMATEX * lpWaveInFormatEx)
{
MMRESULT result = ::waveInOpen(0, idDev, lpWaveInFormatEx, 0, 0, WAVE_FORMAT_QUERY);
return result == MMSYSERR_NOERROR;
}
// unused functions
UINT CWaveForm::GetDirection(){ return 0;}
void CWaveForm::SetDirection(UINT uDirection){}
BOOL CWaveForm::Reset(UINT uDirection){return FALSE;}
BOOL CWaveForm::Pause(UINT uDirection){return FALSE;}
BOOL CWaveForm::Restart(UINT uDirection){return FALSE;}
|
|
|
|