Click here to Skip to main content
Click here to Skip to main content

CWaveForm

, 24 Feb 2006
Rate this:
Please Sign up or sign in to vote.
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

Share

About the Author

Skeeter
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 Pinmembermikeham8-Dec-06 6:19 
GeneralRe: Major bug Pinmembermikeham8-Dec-06 6:32 
GeneralError 1 error C2143: syntax error : missing ';' before '< Interface.h 272 Pinmemberersany12-Jul-06 1:43 
GeneralNew version is uploaded! PinmemberSkeeter24-Feb-06 8:14 
GeneralRe: New version is uploaded! Pinmemberaks-746-Mar-06 0:28 
GeneralI am back! PinmemberSkeeter21-Feb-06 21:19 
GeneralBug with wave recording Pinmemberaks-7420-Oct-05 18:28 
GeneralRe: Bug with wave recording PinmemberSkeeter24-Feb-06 2:20 
Generalissues Pinmemberstar fish8-May-05 11:36 
GeneralRe: issues Pinmemberstar 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 PinmemberDick.leeSolucky19-Jan-05 19:02 
Questionwhat thread.h file?? Pinmemberpsyco26-Jul-04 1:23 
AnswerRe: what thread.h file?? Pinmemberstar fish19-Apr-05 10:35 
AnswerRe: what thread.h file?? PinmemberSkeeter24-Feb-06 2:21 
Generalduration of the wav file Pinmemberelxharoon13-Jul-04 22:43 
Generalthread.h Pinmemberstar fish3-May-04 5:10 
GeneralRe: thread.h Pinmemberstar fish3-May-04 8:55 
Generalconverting WAV to EBU WAV format Pinmembernmanes26-Nov-02 2:30 
GeneralBorland C++ Builder Pinsussrodrigue7-Nov-02 6:22 
GeneralA minor bug PinsussMike Hamilton5-Aug-02 4:27 
QuestionHow to Store 16 Bit PCM Wave PinmemberMaria Jothi5-May-02 19:22 
AnswerHelp please PinsussLucian M31-Oct-03 2:54 
Questionany example projects? PinmemberSteve Guerreri23-Jan-02 10:15 
QuestionExample code? Pinmemberchen8-Nov-01 22:15 
QuestionAny examples of usage? PinmemberJ.G. Hattingh5-Nov-01 1:24 

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

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

| Advertise | Privacy | Mobile
Web03 | 2.8.140827.1 | Last Updated 24 Feb 2006
Article Copyright 2001 by Skeeter
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid