Click here to Skip to main content
15,886,055 members
Articles / Desktop Programming / MFC
Article

CWaveForm

Rate me:
Please Sign up or sign in to vote.
3.46/5 (7 votes)
24 Feb 20062 min read 189.8K   2.4K   57   27
A simple wave form API wrapper class

Introduction

This wrapper class implements standard waveform APIs in object oriented way. It supports following features :

  • Supports both wave_in and wave_out object in one class. You can indicate which type of stream to use by setting Direction.
  • Use my own private stream device interface to abstract the real world stream behavior. This  interface is still under development.
  • All memory allocation and deallocation is managed by theobject itself. That is, the caller never worries about memory. This is achieved by using IIDataSource & IIDataSink interface defined by myself.
  • The use of callback functions instead of callback windows. This is especially suitable for drawing intensive programs.
  • The use of the private IIAdvise interface, through which you can notify the client by window, thread ID, event and callback function. Very flexible. In my own project I use a separate thread to process the wave data.
  • Support volume control on wave_in and wave_out stream.
  • The use of AddRef()/Release() to manage the object life cycle. (Similar to COM)

The package includes three files. 

  • CWaveForm.cpp
  • CWaveForm.h
  • Interface.h

How to use my classes:

  1. Create a wave object 
    new CWaveForm(...)

    This contractor has couples parameters. Stream direction (in or out), wave in device id, wave out device id, wave in format, wave out format, wave in volume, wave out volume. Remember to call AddRef()

  2. Wave device operation sequence : open()->start()->stop()->close().
  3. Whenever wave in data is incoming, the object itself will invoke, that is, callback to the client. Then client calls the Read(ppData) function to get data buffer. After processing, client calls ReadDone(pData) to return data buffer.
  4. Whenever the client wants to send data to the wave out device, it can call Write() twice. The first call should provides an empty pointer, which will be filled with a valid buffer address. Then the client can write any data to this buffer, then call Write() again to queue this buffer back to wave out object.
  5. Please call Release() to free wave object.

Example

  1. Create new wave object:
    WaveForm = new CWaveForm
    (
    	WAVE_FORM_FLOW_BOTH, // Support both WAVE_IN and WAVE_OUT
    	m_waveInDeviceID,
    	m_waveOutDeviceID,
    	&m_waveInFormatEx,
    	&m_waveOutFormatEx,
    	m_waveInVolume,
    	m_waveOutVolume
    );
    
    WaveForm->AddRef(); // For wave_in.
    WaveForm->AddRef(); // For wave_out.
  2. Client advises call back interface:
    WaveForm->Advise
    (
    (DWORD)m_hThread, // I use seperate THREAD to processing wave data.
    0, // dwInstance is 0
    WM_STREAM_NOTIFY, // My private window message mask
    CALLBACK_THREAD // Callback type.
    );
  3. Whenever wave in data is coming:
    // Notify client.
    Invoke(WM_STREAM_NOTIFY, SUB_EVENT_WAVE_IN, 0);
  4. Client reading data:
    PWAVEFRAME pWaveFrame;
    WaveForm->Read(&pWaveFrame); // Get wave in data.
    .
    .
    // Client processing wave in data.
    .
    .
    WaveForm->ReadDone(pWaveFrame); // Return wave in data.
  5. Client write data to wave out device:
    PWAVEFRAME pWaveFrame = NULL;
    WaveForm->Write(&pWaveFrame); // Ask wave out object to allocate memory.
    .
    .
    // Client fill up this buffer with any data.
    .
    .
    WaveForm->Write(pWaveFrame); // Write data to wave out device.
  6. After using wave object:
    WaveForm->Release(); // For wave_in.
    WaveForm->Release(); // For wave_out.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Program Manager Microsoft
China China
Graduated from Shanghai Tongji university in 1997 with bachelor degree in computer science, Wenbin got his first job as a system engineer at Bell Alcatel Mobile Shanghai office responsible for telcom-class mobile system development and deployment. Since then, Wenbin has in turn worked for Intel and Microsoft both inside and outside China, first as senior engineer, later project manager and then senior product manager.

With 15-year experience working with the world top IT companies, Wenbin has developed solid skill in C/C++, C#, Java, software engineering, agile development, etc, and multiple talents in product management, public presentation and speech, etc. He has always been an active member at PMI (Project Management Institution) and a regular lecture at Intel Developer Forum, Microsoft TechED conference as well as many other world-class industrial conferences. His wide-ranged industrial practice and high-level personal maturity have made him one of the best in public speech and professional training.

Over the years, Wenbin has cultivated his very own style in public speech, which is considered informative, engaging and refined. Since last year, Wenbin has also taken new adventure in project and product management consulting business and has proven high capacity through his work with many local emergent IT firms. Wenbin’s specialty in management consulting is on project management methodologies and processes, project management tools (e.g. MS Project), and team recruitment, build, and motivation.

In addition, Wenbin has received many professional qualifications including MCSE (Microsoft Certified System Engineer), MCSD (Microsoft Certified System Developer), MCDBA (Microsoft Certified Database Administrator), SCJP 2 (Sun Certified Java Programmer 2), and PMP (PMI Certified Project Management Professional). On top of that, Wenbin has got several on-duty inventions and one of them was successfully patented by United States Patent and Trademark Office.

Comments and Discussions

 
GeneralMajor bug Pin
mikeham8-Dec-06 6:19
mikeham8-Dec-06 6:19 
GeneralRe: Major bug Pin
mikeham8-Dec-06 6:32
mikeham8-Dec-06 6:32 
GeneralError 1 error C2143: syntax error : missing ';' before '< Interface.h 272 Pin
ersany12-Jul-06 1:43
ersany12-Jul-06 1:43 
GeneralNew version is uploaded! Pin
Skeeter24-Feb-06 8:14
Skeeter24-Feb-06 8:14 
GeneralRe: New version is uploaded! Pin
aks-746-Mar-06 0:28
aks-746-Mar-06 0:28 
GeneralI am back! Pin
Skeeter21-Feb-06 21:19
Skeeter21-Feb-06 21:19 
GeneralBug with wave recording Pin
aks-7420-Oct-05 18:28
aks-7420-Oct-05 18:28 
GeneralRe: Bug with wave recording Pin
Skeeter24-Feb-06 2:20
Skeeter24-Feb-06 2:20 
Generalissues Pin
star fish8-May-05 11:36
star fish8-May-05 11:36 
GeneralRe: issues Pin
star fish9-May-05 2:08
star fish9-May-05 2:08 
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;}


GeneralWave Format Transforming Question Pin
IsaacLitingjun19-Jan-05 19:02
IsaacLitingjun19-Jan-05 19:02 
Questionwhat thread.h file?? Pin
psyco26-Jul-04 1:23
psyco26-Jul-04 1:23 
AnswerRe: what thread.h file?? Pin
star fish19-Apr-05 10:35
star fish19-Apr-05 10:35 
AnswerRe: what thread.h file?? Pin
Skeeter24-Feb-06 2:21
Skeeter24-Feb-06 2:21 
Generalduration of the wav file Pin
elxharoon13-Jul-04 22:43
elxharoon13-Jul-04 22:43 
Generalthread.h Pin
star fish3-May-04 5:10
star fish3-May-04 5:10 
GeneralRe: thread.h Pin
star fish3-May-04 8:55
star fish3-May-04 8:55 
Generalconverting WAV to EBU WAV format Pin
nmanes26-Nov-02 2:30
nmanes26-Nov-02 2:30 
GeneralBorland C++ Builder Pin
Rodrigue7-Nov-02 6:22
Rodrigue7-Nov-02 6:22 
GeneralA minor bug Pin
Mike Hamilton5-Aug-02 4:27
Mike Hamilton5-Aug-02 4:27 
QuestionHow to Store 16 Bit PCM Wave Pin
Maria Jothi5-May-02 19:22
Maria Jothi5-May-02 19:22 
AnswerHelp please Pin
Lucian M31-Oct-03 2:54
sussLucian M31-Oct-03 2:54 
Questionany example projects? Pin
ewasta23-Jan-02 10:15
ewasta23-Jan-02 10:15 
QuestionExample code? Pin
chen8-Nov-01 22:15
chen8-Nov-01 22:15 
QuestionAny examples of usage? Pin
Jason Troitsky (was Hattingh)5-Nov-01 1:24
Jason Troitsky (was Hattingh)5-Nov-01 1:24 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.