winaudio.cpp
上传用户:zhongxx05
上传日期:2007-06-06
资源大小:33641k
文件大小:36k
源码类别:

Symbian

开发平台:

C/C++

  1. /* ***** BEGIN LICENSE BLOCK ***** 
  2.  * Version: RCSL 1.0/RPSL 1.0 
  3.  *  
  4.  * Portions Copyright (c) 1995-2002 RealNetworks, Inc. All Rights Reserved. 
  5.  *      
  6.  * The contents of this file, and the files included with this file, are 
  7.  * subject to the current version of the RealNetworks Public Source License 
  8.  * Version 1.0 (the "RPSL") available at 
  9.  * http://www.helixcommunity.org/content/rpsl unless you have licensed 
  10.  * the file under the RealNetworks Community Source License Version 1.0 
  11.  * (the "RCSL") available at http://www.helixcommunity.org/content/rcsl, 
  12.  * in which case the RCSL will apply. You may also obtain the license terms 
  13.  * directly from RealNetworks.  You may not use this file except in 
  14.  * compliance with the RPSL or, if you have a valid RCSL with RealNetworks 
  15.  * applicable to this file, the RCSL.  Please see the applicable RPSL or 
  16.  * RCSL for the rights, obligations and limitations governing use of the 
  17.  * contents of the file.  
  18.  *  
  19.  * This file is part of the Helix DNA Technology. RealNetworks is the 
  20.  * developer of the Original Code and owns the copyrights in the portions 
  21.  * it created. 
  22.  *  
  23.  * This file, and the files included with this file, is distributed and made 
  24.  * available on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  25.  * EXPRESS OR IMPLIED, AND REALNETWORKS HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  26.  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS 
  27.  * FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  28.  * 
  29.  * Technology Compatibility Kit Test Suite(s) Location: 
  30.  *    http://www.helixcommunity.org/content/tck 
  31.  * 
  32.  * Contributor(s): 
  33.  *  
  34.  * ***** END LICENSE BLOCK ***** */ 
  35. #include "hxtypes.h"
  36. #include "hlxclib/windows.h"
  37. #include <mmsystem.h>
  38. #include <tchar.h> 
  39. #include <stdio.h>
  40. #ifdef _TESTING
  41. #include <fcntl.h>
  42. #include <sys/types.h>
  43. #include <sys/stat.h>
  44. #if defined (_WINDOWS) || defined (_WIN32)
  45. #include <io.h>
  46. #endif
  47. #endif
  48. #include "hxresult.h"
  49. #include "hxcom.h"
  50. #include "hxausvc.h"
  51. #include "auderrs.h"
  52. #include "ihxpckts.h"
  53. #include "hxengin.h"
  54. #include "timeval.h"
  55. #include "hxaudev.h"
  56. #include "hxslist.h"
  57. #include "hxtick.h"
  58. //#include "hxaudses.h"
  59. #include "cbqueue.h"
  60. #include "cpqueue.h"
  61. #include "hxthread.h"
  62. #include "winaudio.h"
  63. #ifdef WIN32_PLATFORM_PSPC
  64. #define WM_NCCREATE WM_CREATE
  65. #define WM_NCDESTROY WM_DESTROY
  66. #endif
  67. struct IHXCallback;
  68. extern HINSTANCE g_hInstance;
  69. #define OFFSET_THIS 0
  70. #ifdef _TESTING
  71. int m_audfile = -1;
  72. #endif
  73. BOOL CAudioOutWindows::zm_bVolSupport = FALSE;
  74. BOOL CAudioOutWindows::zm_bLRVolSupport = FALSE;
  75. WORD CAudioOutWindows::zm_uMaxVolume = 100;
  76. BOOL CAudioOutWindows::zm_bMixerVolSupport = FALSE;
  77. BOOL CAudioOutWindows::zm_bMixerVolSupportChecked = FALSE;
  78. UINT CAudioOutWindows::zm_uDestroyMessage = 0;
  79. BOOL CAudioOutWindows::zm_bClosed = TRUE;
  80. CAudioOutWindows* zm_pCurrentAudioDevice = NULL;
  81. // BAD drivers which need to call waveOutSetVolume directly
  82. const UINT16 g_nBadDrivers = 1;
  83. const TCHAR* g_badDrivers[] = {_T("Crystal Audio System")};
  84. audioDevice CAudioOutWindows::zm_audioDevice = HXAUDIO_UNKNOWN;
  85. //CRITICAL_SECTION CAudioOutWindows::zm_AudioCritSection;
  86. #define MAX_REASONABLE_BUFFS 40
  87. #define PUSH_DOWN_TIME 400    /* push down 400 ms  */
  88. #define LIKELY_PUSH_COUNT 10
  89. CAudioOutWindows::CAudioOutWindows()
  90.     : m_hWave(NULL)
  91.     , m_unAllocedBufferCnt(0)
  92.     , m_unAllocedBuffSize(0)
  93.     , m_ppAllocedBuffers(NULL)
  94.     , m_pWaveHdrs(NULL)
  95.     , m_rAvailBuffers(MAX_REASONABLE_BUFFS)
  96.     , m_bInitialized(FALSE)
  97.     , m_bResetting(FALSE)
  98.     , m_bIsFirstPacket(TRUE)
  99.     , m_hWnd(NULL)
  100.     , m_bClassRegistered(FALSE)
  101.     , m_ulDevPosRollOver(0)
  102.     , m_ulLastDeviceBytesPlayed(0)
  103.     , m_ulLastDeviceSamplesPlayed(0)
  104.     , m_llDeviceBytesPlayed(0)
  105.     , m_llDeviceSamplesPlayed(0)
  106. #if defined(_WIN32)
  107.     , m_ulOriginalThreadId(0)
  108. #endif /*_WIN32*/
  109. {
  110.     zm_bClosed = TRUE;    
  111.     zm_pCurrentAudioDevice = this;
  112. #if defined(_WIN32) && !defined(_WINCE)
  113.     m_hMixer = NULL;  
  114.     memset(&m_VolumeControlDetails, 0 , sizeof(MIXERCONTROLDETAILS));
  115. #endif // _WIN32
  116.     // Create a unique message for destroying the audio window
  117.     if (!zm_uDestroyMessage)
  118.     {
  119. zm_uDestroyMessage = RegisterWindowMessage(_T("HX_DestroyAudioServicesInternal"));
  120.     }
  121.     
  122. #ifdef THREADS_SUPPORTED
  123.     HXMutex::MakeMutex(m_pMutex);
  124. #else
  125.     HXMutex::MakeStubMutex(m_pMutex);
  126. #endif
  127. }    
  128. CAudioOutWindows::~CAudioOutWindows()
  129. {
  130. //    OutputDebugString("BEFORE CALL TO:CAudioOutWindows::~CAudioOutWindowsrn");
  131.     // this gives us one last chance to recover packets that are still in the device
  132.     Reset();
  133.     // We might as well consider the device closed!
  134.     zm_bClosed = TRUE;
  135. #if defined(_WIN32) && !defined(_WINCE)
  136.     /* This sleep is added to fix a hang bug that ONLY happens on
  137.      * Darren's machine if you adjust audio volume. His machine
  138.      * has a really old audio driver
  139.      * 
  140.      * I have no clue what this bug is and how this Sleep(0)
  141.      * fixes it. Obviously, there was some race condition.
  142.      *
  143.      * Sound Driver Info:
  144.      *
  145.      * Version 2.03.0 Build 1
  146.      * Creative Sound Blaster 16 Driver (Windows NT)
  147.      * 
  148.      */
  149.     Sleep(0);
  150.     if(m_hMixer)
  151.     {
  152.         mixerClose(m_hMixer);
  153.     }
  154. #endif // _WIN32
  155.     _Imp_Close();
  156.     zm_pCurrentAudioDevice = NULL;
  157.     HX_DELETE(m_pMutex);
  158. }
  159. UINT16 CAudioOutWindows::_Imp_GetVolume()
  160. {
  161.     DWORD dwVol     = 0;                          
  162.     BOOL bSuccess   = FALSE;
  163. #if defined(_WIN32) && !defined(_WINCE)
  164.     if (!zm_bMixerVolSupportChecked)
  165.     {
  166. CheckForVolumeSupport();
  167.     }
  168.     if(zm_bMixerVolSupport)
  169.     {
  170. if (!m_hMixer)
  171. {
  172.     CheckForVolumeSupport();
  173. }
  174.         PMIXERCONTROLDETAILS_UNSIGNED pmxVolume;
  175.         UINT16 nItems = 1;
  176.         if(m_VolumeControlDetails.cMultipleItems)
  177.             nItems = (UINT16)m_VolumeControlDetails.cMultipleItems;
  178.         pmxVolume = new MIXERCONTROLDETAILS_UNSIGNED[nItems];
  179.         m_VolumeControlDetails.cbDetails = nItems * sizeof(MIXERCONTROLDETAILS_UNSIGNED);
  180.         m_VolumeControlDetails.paDetails = pmxVolume;
  181.         if(mixerGetControlDetails((HMIXEROBJ)m_hMixer, &m_VolumeControlDetails, 
  182.            MIXER_GETCONTROLDETAILSF_VALUE | MIXER_OBJECTF_HMIXER) == MMSYSERR_NOERROR)
  183.         {
  184.             dwVol = pmxVolume[0].dwValue;
  185.             bSuccess = TRUE;
  186.         }
  187.         delete[] pmxVolume;
  188.     }
  189. #endif
  190.     if (!bSuccess)
  191.     {
  192. if (!zm_bVolSupport)
  193. {
  194.     return 0;
  195. }
  196. MMRESULT hResult = waveOutGetVolume( m_hWave, &dwVol );
  197. if (hResult != MMSYSERR_NOERROR && m_hWave != NULL)
  198. {
  199.     hResult = waveOutGetVolume( NULL, &dwVol );
  200. }
  201. if (hResult != MMSYSERR_NOERROR)
  202. {
  203.     return 0;
  204. }
  205.     }
  206.     return ( (UINT16)((DWORD)LOWORD( dwVol ) * zm_uMaxVolume / 0xFFFF ) );
  207. }
  208. HX_RESULT CAudioOutWindows::_Imp_SetVolume
  209.     const UINT16 uVolume
  210. )
  211. {
  212.     DWORD dwVol = 0;
  213.     BOOL bSuccess = FALSE;
  214.     if (uVolume > zm_uMaxVolume)
  215.     {
  216.         return HXR_OK;
  217.     }
  218.     dwVol = (DWORD)uVolume * 0xFFFF / zm_uMaxVolume;
  219.     
  220.     // Here we are avoiding rounding error
  221.     if(dwVol * zm_uMaxVolume / 0xFFFF < uVolume)
  222. dwVol += 0xFFFF / zm_uMaxVolume;
  223.     if (zm_audioDevice == HXAUDIO_BADDEVICE)
  224.     {
  225. goto noMixer;
  226.     }
  227. #if defined(_WIN32) && !defined(_WINCE)
  228.     if (!zm_bMixerVolSupportChecked)
  229.     {
  230. CheckForVolumeSupport();
  231.     }
  232.     if(zm_bMixerVolSupport)
  233.     {
  234. if (!m_hMixer)
  235. {
  236.     CheckForVolumeSupport();
  237. }
  238.         PMIXERCONTROLDETAILS_UNSIGNED pmxVolume;
  239.         UINT16 nItems = 1;
  240.         if(m_VolumeControlDetails.cMultipleItems)
  241.             nItems = (UINT16)m_VolumeControlDetails.cMultipleItems;
  242.         pmxVolume = new MIXERCONTROLDETAILS_UNSIGNED[nItems];
  243.         for(UINT16 nIndex = 0; nIndex < nItems; nIndex++)
  244.             pmxVolume[nIndex].dwValue = dwVol;
  245.         m_VolumeControlDetails.cbDetails = nItems * sizeof(MIXERCONTROLDETAILS_UNSIGNED);
  246.         m_VolumeControlDetails.paDetails = pmxVolume;
  247.         if(mixerSetControlDetails((HMIXEROBJ)m_hMixer, &m_VolumeControlDetails, 
  248.            MIXER_GETCONTROLDETAILSF_VALUE | MIXER_OBJECTF_HMIXER) == MMSYSERR_NOERROR)
  249. {
  250. bSuccess = TRUE;
  251.         }
  252.         delete[] pmxVolume;
  253.     }
  254. #endif
  255. noMixer:
  256.     if ( !bSuccess )
  257.     {
  258. DWORD dwLRVol = MAKELONG(dwVol, dwVol) ;
  259. // fix of bug 4965, in which the balance is thrown to one side.  My speculation is that the
  260. // driver incorrectly reports MONO here when stereo is in use.  To fix the bug, set both
  261. // channels equally.  john dempsey
  262. /* related information: 
  263. "If a devicedoes not support both left and right volume control, the low-order
  264.  word of the dwVolume argument specifies the volume level and the
  265.  high-order word is ignored." -- some DEC document on waveOutSetVolume.
  266. */
  267. HX_ASSERT(LOWORD(dwLRVol) == HIWORD(dwLRVol)) ;
  268. if (!zm_bVolSupport)
  269. {
  270.     return HXR_FAILED;
  271. }
  272. MMRESULT hResult    = waveOutSetVolume(m_hWave, dwLRVol);
  273. MMRESULT hResult2 = hResult;
  274. /* 
  275.  * always set the volume on NULL device. 
  276.  * Needed to attach volume control on win98 SE, Creative SB Live! Value sound card.
  277.  */
  278. if (m_hWave != NULL)
  279. {
  280.      hResult2 = waveOutSetVolume(NULL, dwLRVol);
  281. }
  282. if (hResult != MMSYSERR_NOERROR && hResult2 != MMSYSERR_NOERROR)
  283. {
  284.     return HXR_FAILED;
  285. }
  286.     }
  287.     return HXR_OK;
  288. }
  289. BOOL CAudioOutWindows::_Imp_SupportsVolume()
  290. {
  291.     MMRESULT wSuccess;
  292.     WAVEOUTCAPS auxcap; 
  293. #if defined(_WIN32) && !defined(_WINCE)
  294.     if (!zm_bMixerVolSupportChecked)
  295.     {
  296. CheckForVolumeSupport();
  297.     }
  298. #endif
  299. #if defined(_WIN32) || defined(_WINCE)
  300. // Gonna have to make VolSupport static  
  301.     if ( zm_bVolSupport )
  302.     {
  303.         return (zm_bVolSupport);
  304.     }
  305.     wSuccess = waveOutGetDevCaps( 0, &auxcap, sizeof(WAVEOUTCAPS) );
  306.     if ( MMSYSERR_NOERROR == wSuccess )
  307.     { 
  308.         if (auxcap.dwSupport & WAVECAPS_VOLUME)
  309. {
  310.     zm_bVolSupport=TRUE;
  311. }
  312. if (auxcap.dwSupport & WAVECAPS_LRVOLUME)
  313. {
  314. zm_bLRVolSupport = TRUE;
  315. }
  316. zm_uMaxVolume = 100;
  317. }                   
  318.     else
  319.     {
  320.         zm_bVolSupport = FALSE;
  321.         zm_bLRVolSupport = FALSE;
  322.     }
  323.     return zm_bVolSupport;
  324. #else
  325.     return FALSE;
  326. #endif /*_WIN32*/
  327. }
  328. HX_RESULT CAudioOutWindows:: _Imp_Open
  329.     const HXAudioFormat* pFormat
  330. )
  331. {
  332.     HX_RESULT theErr = HXR_OK;
  333. #if defined(_WIN32)
  334.     LPWAVEFORMATEX wavePtr;
  335. #elif defined( _WINDOWS )
  336.     LPWAVEFORMAT wavePtr;
  337. #endif
  338.     theErr = Register();
  339.     if (theErr)
  340.     {
  341. return theErr;
  342.     }
  343. #ifdef _TESTING
  344.     m_audfile =  open("e:\auddev.raw", O_WRONLY | O_CREAT);
  345. #endif
  346.     m_WaveFormat.SetFormat(pFormat->ulSamplesPerSec, pFormat->uChannels, pFormat->uBitsPerSample);
  347.     // Get the Windows style wave format!
  348.     wavePtr = m_WaveFormat.GetWaveFormat();
  349.     // We ain't closed now
  350.     zm_bClosed = FALSE;
  351.     // Open the wave driver.
  352. #ifdef _WIN16
  353.     MMRESULT wRet = waveOutOpen( &m_hWave, WAVE_MAPPER, wavePtr,
  354. (UINT16)m_hWnd, (DWORD)this, CALLBACK_WINDOW);
  355. #else
  356.     MMRESULT wRet = waveOutOpen( &m_hWave, WAVE_MAPPER, wavePtr,
  357. (DWORD)m_hWnd, (DWORD)this, CALLBACK_WINDOW);
  358. #endif
  359.     // Okay, translate any error returns and get out if there was an error
  360.     switch (wRet)
  361.     {
  362. case MMSYSERR_NOERROR:     theErr = HXR_OK; break;
  363. case MMSYSERR_ALLOCATED:    theErr = HXR_AUDIO_DRIVER; break;
  364. case MMSYSERR_NOMEM:     theErr = HXR_OUTOFMEMORY; break;
  365. case MMSYSERR_BADDEVICEID:  theErr = HXR_AUDIO_DRIVER; break;
  366. case WAVERR_BADFORMAT:     theErr = HXR_AUDIO_DRIVER; break;
  367. case WAVERR_SYNC:     theErr = HXR_AUDIO_DRIVER; break;
  368. default:     theErr = HXR_OUTOFMEMORY; break;
  369.     }
  370. #if defined(_WIN32) && !defined(_WINCE)
  371. if ( !theErr )
  372. {
  373.     if (!zm_bMixerVolSupportChecked)
  374.     {
  375. CheckForVolumeSupport();
  376.     }
  377. }
  378. #endif
  379.     return theErr;
  380. }
  381. HX_RESULT CAudioOutWindows::_Imp_Close()
  382. {
  383. #ifdef _TESTING
  384. if ( m_audfile > 0 ) 
  385. close(m_audfile);
  386. m_audfile = -1;
  387. #endif
  388.  zm_bClosed = TRUE;
  389.     if (m_hWave) 
  390.     {
  391. // NOTE: Before we can close, we need to reset!
  392. Reset();
  393. m_pMutex->Lock();
  394. if (m_pWaveHdrs)
  395. {
  396.     UINT16 unWHIndex;
  397.     // Unprepare the individual headers
  398.     for (unWHIndex = 0; unWHIndex < m_unAllocedBufferCnt; ++unWHIndex)
  399.     {
  400.      CWaveHeader* pWaveHeader = &m_pWaveHdrs[unWHIndex];
  401. if (pWaveHeader->m_pPrepared)
  402. {
  403.     LPWAVEHDR lpwHeader = LPWAVEHDR(&pWaveHeader->m_WAVEHDR);
  404.     
  405.     // By now all headers should be marked as done because they
  406.     // are back from the audio device or prepared because we
  407.     // prepared them but never used them
  408.     HX_ASSERT(lpwHeader->dwFlags & WHDR_DONE ||
  409. lpwHeader->dwFlags & WHDR_PREPARED);
  410.     //OutputDebugString("BEFORE CALL TO:waveOutUnprepareHeaderrn");
  411.     HX_VERIFY(MMSYSERR_NOERROR == waveOutUnprepareHeader(m_hWave, 
  412. LPWAVEHDR(&pWaveHeader->m_WAVEHDR), sizeof(WAVEHDR)));
  413.     //OutputDebugString("AFTER CALL TO:waveOutUnprepareHeaderrn");
  414.     pWaveHeader->m_pPrepared = FALSE;
  415. }
  416.     }
  417. }
  418. if (m_ppAllocedBuffers)
  419. {
  420.     UINT16 unIndex;
  421.     for (unIndex = 0; unIndex < m_unAllocedBufferCnt; unIndex++)
  422.     {
  423. delete[] m_ppAllocedBuffers[unIndex];
  424.     }
  425.     delete[] m_ppAllocedBuffers;
  426.     m_ppAllocedBuffers = NULL;
  427. }
  428. m_rAvailBuffers.FlushQueue();
  429. m_UsedBuffersList.RemoveAll();
  430. m_unAllocedBufferCnt = 0;
  431. m_pMutex->Unlock();
  432. for (int i = 0; 
  433. i < 5 && (WAVERR_STILLPLAYING == waveOutClose( m_hWave )); ++i)
  434. {
  435.     waveOutReset( m_hWave );
  436. }
  437. m_hWave = NULL;
  438. if (m_pWaveHdrs)
  439. {
  440.     delete[] m_pWaveHdrs;
  441.     m_pWaveHdrs = NULL;
  442. }
  443.     }
  444.     UnRegister();
  445.     m_bIsFirstPacket = TRUE;
  446.     m_bInitialized = FALSE;
  447.     return HXR_OK;
  448. }
  449. HX_RESULT CAudioOutWindows::_Imp_Write
  450.     const HXAudioData* pAudioOutHdr 
  451. )
  452. {
  453.     BOOL     bTemp;
  454.     CWaveHeader*    pWaveHeader;
  455.     MMRESULT     res;
  456.     ULONG32     ulBufLen = 0;
  457.     UCHAR*     pBuffer = 0;
  458.     if (pAudioOutHdr->pData)
  459.     {
  460. pBuffer  = pAudioOutHdr->pData->GetBuffer();
  461. ulBufLen = pAudioOutHdr->pData->GetSize();
  462.     }
  463.     if (!m_bInitialized)
  464.     {
  465. m_bInitialized = AllocateBuffers(MAX_REASONABLE_BUFFS,(UINT16)ulBufLen);
  466.     }
  467.     if (!m_bInitialized) return HXR_FAILED;
  468.     m_pMutex->Lock();
  469.     pWaveHeader = (CWaveHeader*)m_rAvailBuffers.DeQueuePtr(bTemp);
  470.     m_pMutex->Unlock();
  471.     if (!bTemp) 
  472.     {
  473. return HXR_WOULD_BLOCK;
  474.     }
  475. #ifdef _TESTING
  476.     if ( m_audfile > 0 )
  477.         write(m_audfile, pBuffer,ulBufLen); 
  478. #endif
  479.     UINT32 ulBytesToCopy = ulBufLen;
  480.     HX_ASSERT(ulBytesToCopy <= pWaveHeader->m_WAVEHDR.dwBufferLength);
  481.     if (ulBytesToCopy > pWaveHeader->m_WAVEHDR.dwBufferLength)
  482.         ulBytesToCopy = pWaveHeader->m_WAVEHDR.dwBufferLength;
  483.     pWaveHeader->m_bAvail = FALSE;
  484.         memcpy(pWaveHeader->m_WAVEHDR.lpData, pBuffer, HX_SAFESIZE_T(ulBytesToCopy)); /* Flawfinder: ignore */
  485.     pWaveHeader->m_ulTimeEnd = pAudioOutHdr->ulAudioTime;
  486.     /* This is needed for LIVE where audio packets may not start
  487.      * from timestamp 0
  488.      */
  489.     if (m_bIsFirstPacket)
  490.     {
  491. m_bIsFirstPacket = FALSE;
  492.     }
  493.     //OutputDebugString("BEFORE CALL TO:waveOutWritern");
  494.     res = waveOutWrite(m_hWave, LPWAVEHDR(&pWaveHeader->m_WAVEHDR), sizeof(WAVEHDR));
  495.     m_pMutex->Lock();
  496.     m_UsedBuffersList.AddTail(pWaveHeader);
  497.     m_pMutex->Unlock();
  498.     //OutputDebugString("AFTER CALL TO:waveOutWritern");
  499.     return HXR_OK;
  500. }
  501. HX_RESULT CAudioOutWindows::_Imp_Seek(ULONG32 ulSeekTime)
  502. {
  503.     return HXR_OK;
  504. }
  505. HX_RESULT CAudioOutWindows::_Imp_Pause()
  506. {
  507.     MMRESULT res;
  508.     if (m_hWave) 
  509.     {
  510. // OutputDebugString("BEFORE CALL TO:waveOutRestartrn");
  511.         res = waveOutPause(m_hWave);
  512.     }
  513.     return HXR_OK;
  514. }
  515. HX_RESULT CAudioOutWindows::_Imp_Resume()
  516. {
  517.     MMRESULT res;
  518.     if (m_hWave) 
  519.     {
  520. // OutputDebugString("BEFORE CALL TO:waveOutRestartrn");
  521.         res = waveOutRestart(m_hWave);
  522. //OutputDebugString("AFTER CALL TO:waveOutRestartrn");
  523.     }
  524.     OnTimeSync();
  525.     return HXR_OK;
  526. }
  527. HX_RESULT CAudioOutWindows::_Imp_Reset()
  528. {
  529. //{FILE* f1 = ::fopen("c:\audio.txt", "a+"); ::fprintf(f1, "Reset: n");::fclose(f1);}
  530.     MMRESULT res;
  531.     m_bResetting = TRUE;
  532.     if (m_hWave) 
  533.     {
  534. // OutputDebugString("BEFORE CALL TO:waveOutResetrn");
  535. res = waveOutReset(m_hWave);
  536. // Need to be turned on after RC2000 XXXRA
  537. // commenting it out for safety reasons.
  538. //_Imp_Pause();
  539. //OutputDebugString("AFTER CALL TO:waveOutResetrn");
  540. m_bIsFirstPacket = TRUE;
  541. m_llDeviceBytesPlayed = 0;
  542. m_llDeviceSamplesPlayed = 0;
  543. m_ulLastDeviceBytesPlayed = 0;
  544. m_ulLastDeviceSamplesPlayed = 0;
  545. m_ulDevPosRollOver = 0;
  546.     }
  547.     // First return the unused buffers to the available queue
  548.     // Then pump out the wom_dones.
  549.     //
  550.     _NumberOfBlocksRemainingToPlay();
  551.     // Make sure we handle all the wave-done messages,
  552.     // but establish a time limit to cope with the 
  553.     // unpredictable nature of Windows. Wait for up
  554.     // to 1 second.
  555.     DWORD start = HX_GET_TICKCOUNT();
  556.     if (m_hWnd)
  557.     {
  558. do
  559. {
  560.     MSG msg;
  561.     // Yield, and try to pump WOM_DONE's to the Async Window!
  562.     while (PeekMessage(&msg, m_hWnd, MM_WOM_DONE, MM_WOM_DONE, PM_REMOVE))
  563.     {
  564. if(msg.message == WM_QUIT) 
  565. {   
  566.     // When peeking WM_QUIT message in the main thread of an application 
  567.     // we have to put it back into message queue to allow the application 
  568.     // to exit correctly. SB
  569.     PostQuitMessage(0);
  570.     break;
  571. }
  572. else
  573. {
  574.     DispatchMessage(&msg);
  575. }
  576.     }
  577.     if (CALCULATE_ELAPSED_TICKS(start, HX_GET_TICKCOUNT()) >= 1000)
  578.     {
  579. // Brute force, mark them as free... We probably 
  580. // could do something better here, like close and
  581. // reopen the wave device... but this is what the
  582. // old code did, so lets try it as well!
  583. ULONG32 lTmp;
  584. m_pMutex->Lock();
  585. for (lTmp = 0; m_pWaveHdrs && (lTmp < m_unAllocedBufferCnt); ++lTmp)
  586. {
  587.     CWaveHeader *pwhDone = &m_pWaveHdrs[lTmp];
  588.     if (pwhDone && pwhDone->m_bAvail == FALSE)
  589.     {
  590. pwhDone->m_bAvail = TRUE;
  591. m_rAvailBuffers.EnQueuePtr(pwhDone);
  592.     }
  593. }
  594. m_pMutex->Unlock();
  595. //OutputDebugString("Bail WOM_DONE vacuum, passed timeout!rn");
  596. break;
  597.     }
  598. }
  599. while (_NumberOfBlocksRemainingToPlay());
  600.     }
  601.     //OutputDebugString("END: WOM_DONE vacuum!rn");
  602.     m_bResetting = FALSE;
  603.     return HXR_OK;
  604. }
  605. HX_RESULT CAudioOutWindows::_Imp_Drain()
  606. {
  607.     return HXR_OK;
  608. }
  609. HX_RESULT CAudioOutWindows::_Imp_CheckFormat
  610.     const HXAudioFormat* pFormat 
  611. )
  612. {
  613. #if defined(_WIN32)
  614.     LPWAVEFORMATEX wavePtr;
  615. #elif defined( _WINDOWS )
  616.     LPWAVEFORMAT wavePtr;
  617. #endif
  618.     m_WaveFormat.SetFormat(pFormat->ulSamplesPerSec, pFormat->uChannels, pFormat->uBitsPerSample);
  619.    
  620. // Get the Windows style wave format!
  621.     wavePtr = m_WaveFormat.GetWaveFormat();
  622.     MMRESULT wRet = waveOutOpen(&m_hWave,WAVE_MAPPER,wavePtr,
  623.         0, (DWORD)this,WAVE_FORMAT_QUERY);
  624.     switch (wRet)
  625.     {
  626. case MMSYSERR_NOERROR:     return( HXR_OK );
  627. case MMSYSERR_ALLOCATED:    return( HXR_AUDIO_DRIVER );
  628. case MMSYSERR_NOMEM:     return( HXR_OUTOFMEMORY );
  629. case MMSYSERR_BADDEVICEID:  return( HXR_AUDIO_DRIVER );
  630. case WAVERR_BADFORMAT:     return( HXR_AUDIO_DRIVER );
  631. case WAVERR_SYNC:     return( HXR_AUDIO_DRIVER );
  632. case MMSYSERR_NODRIVER:     return( HXR_AUDIO_DRIVER );
  633. default:     return( HXR_AUDIO_DRIVER );
  634.     }
  635. }
  636. BOOL CAudioOutWindows::AllocateBuffers(UINT16 unNumBuffers, UINT16 unBufSize)
  637. {
  638.     UCHAR**     ppWaveBuffers;
  639.     CWaveHeader*    pWaveHdrs;
  640.     MMRESULT     tRes;
  641.     UINT16     unWHIndex;
  642.     ppWaveBuffers = NULL;
  643.     pWaveHdrs = NULL;
  644.     // Allocate memory for wave block headers and for wave data.
  645.     if (!(pWaveHdrs = new CWaveHeader [unNumBuffers]))
  646.     {
  647.         goto OnError;
  648.     }
  649.     // This array holds the buffer pointers so we can free them later
  650.     // There NO other purpose for this array.
  651.     if (!(ppWaveBuffers = new UCHAR*[unNumBuffers]))
  652.     {
  653. goto OnError;
  654.     }
  655.     memset( ppWaveBuffers, 0, unNumBuffers * sizeof( UCHAR* ) );
  656.     
  657.     // Mark all wave block headers as available, and point them
  658.     // at their respective wave data blocks.
  659.     // AND enqueue them in the AvailableBuffers Queue.
  660.     // AND allocate their buffers!!!
  661.     for (unWHIndex = 0; unWHIndex < unNumBuffers; unWHIndex++) 
  662.     {
  663.         UCHAR* pBuff;
  664. // Try to allocate the individual audio buffers
  665.      pBuff = new UCHAR [unBufSize];
  666. if (!pBuff)
  667. {
  668.     goto OnError;
  669.      }
  670. ppWaveBuffers[unWHIndex] = pBuff;
  671. CWaveHeader* pWaveHeader = &pWaveHdrs[unWHIndex];
  672. // Init some header data before Preparing the header
  673. pWaveHeader->m_WAVEHDR.lpData = (char *)pBuff;
  674. pWaveHeader->m_WAVEHDR.dwUser = DWORD(pWaveHeader);
  675. pWaveHeader->m_WAVEHDR.dwFlags = 0L;
  676. pWaveHeader->m_WAVEHDR.dwBufferLength = unBufSize;
  677. pWaveHeader->m_WAVEHDR.dwLoops = 0L;
  678. pWaveHeader->m_bAvail = TRUE;
  679. pWaveHeader->m_pUser = this;
  680. m_pMutex->Lock();
  681. m_rAvailBuffers.EnQueuePtr(pWaveHeader);
  682. m_pMutex->Unlock();
  683. //OutputDebugString("BEFORE CALL TO:waveOutPrepareHeaderrn");
  684.         tRes = waveOutPrepareHeader(m_hWave, LPWAVEHDR(&pWaveHeader->m_WAVEHDR), sizeof(WAVEHDR));
  685. //OutputDebugString("AFTER CALL TO:waveOutPrepareHeaderrn");
  686. if (tRes != MMSYSERR_NOERROR)
  687. {
  688.     goto OnError;
  689. }
  690. else
  691. {
  692.     pWaveHeader->m_pPrepared = TRUE;
  693.      }
  694.     }
  695.     m_unAllocedBufferCnt = unNumBuffers;
  696.     m_unAllocedBuffSize = unBufSize;
  697.     m_pWaveHdrs = pWaveHdrs;
  698.     m_ppAllocedBuffers = ppWaveBuffers;
  699.     return TRUE;
  700. OnError:
  701.     if (pWaveHdrs)
  702.     {
  703. // Unprepare the individual headers
  704. for (unWHIndex = 0; unWHIndex < unNumBuffers; ++unWHIndex)
  705. {
  706.          CWaveHeader* pWaveHeader = &pWaveHdrs[unWHIndex];
  707.     if (pWaveHeader->m_pPrepared)
  708.     {
  709. //OutputDebugString("BEFORE CALL TO:waveOutUnprepareHeaderrn");
  710. tRes = waveOutUnprepareHeader(m_hWave, 
  711.     LPWAVEHDR(&pWaveHeader->m_WAVEHDR), sizeof(WAVEHDR));
  712. //OutputDebugString("AFTER CALL TO:waveOutUnprepareHeaderrn");
  713. pWaveHeader->m_pPrepared = FALSE;
  714.     }
  715. }
  716. delete[] pWaveHdrs;
  717. pWaveHdrs = NULL;
  718.     }
  719.     // ppWaveBuffers actually points at an array of pointers that need to be free'd
  720.     if (ppWaveBuffers)
  721.     {
  722. // Free the individual buffers
  723. for (unWHIndex = 0; unWHIndex < unNumBuffers; ++unWHIndex)
  724. {
  725.     UCHAR* pBuff;
  726.     pBuff = ppWaveBuffers[unWHIndex];
  727.     if (pBuff)
  728.     {
  729.      delete[] pBuff;
  730.     }
  731. }
  732. // Now free ppWaveBuffers itself
  733. delete[] ppWaveBuffers;
  734. ppWaveBuffers = NULL;
  735.     }
  736.     return FALSE;
  737. }
  738. /************************************************************************
  739.  *  Method:
  740.  *              CAudioOutWindows::_Imp_GetCurrentTime
  741.  *      Purpose:
  742.  *              Get the current time from the audio device.
  743.  *              We added this to support the clock available in the
  744.  *              Window's audio driver.
  745.  */
  746. HX_RESULT CAudioOutWindows::_Imp_GetCurrentTime
  747.         ULONG32& ulCurrentTime
  748. )
  749. {
  750. ULONG32 ulDeviceTime = 0;
  751. ULONG32 ulDeviceBytesPlayed = 0;
  752. UINT32 ulDeviceSamplesPlayed = 0;
  753. WAVEFMTPTR pWFmt = m_WaveFormat.GetWaveFormat();
  754. // Set the time to the playback time of the
  755. // wave device since it's the most accurate.
  756. MMTIME mmTime;
  757. // we want MS if we can get them
  758. mmTime.wType = TIME_MS;
  759. MMRESULT res = waveOutGetPosition(m_hWave, &mmTime, sizeof(MMTIME));
  760. if (MMSYSERR_NOERROR == res)
  761. {
  762. // We must check the output format and convert to MS if possible
  763. switch (mmTime.wType)
  764. {
  765. case TIME_MS:
  766. {
  767. ulDeviceTime = mmTime.u.ms;
  768. #if defined(_WIN32)
  769. ULONG32 BitsPerSample = (pWFmt->nChannels * pWFmt->wBitsPerSample);
  770. #elif _WIN16
  771. ULONG32 BitsPerSample = (pWFmt->nAvgBytesPerSec * 8 / pWFmt->nSamplesPerSec);
  772. #endif
  773. ULONG32 BitsPerSecond = (BitsPerSample * pWFmt->nSamplesPerSec);
  774. ulDeviceBytesPlayed = (mmTime.u.ms * BitsPerSecond) / 8000;
  775. }
  776. break;
  777. case TIME_SAMPLES:
  778. {
  779. // Convert samples to MS
  780. ulDeviceSamplesPlayed = mmTime.u.sample;
  781. if (m_ulLastDeviceSamplesPlayed > ulDeviceSamplesPlayed &&
  782.     ((m_ulLastDeviceSamplesPlayed - ulDeviceSamplesPlayed) > MAX_TIMESTAMP_GAP))
  783. {
  784.     m_ulDevPosRollOver++;
  785. }
  786.  
  787. m_ulLastDeviceSamplesPlayed = ulDeviceSamplesPlayed;
  788. m_llDeviceSamplesPlayed = (INT64)ulDeviceSamplesPlayed + (INT64)m_ulDevPosRollOver * (INT64)MAX_UINT32;
  789. ulDeviceTime = (ULONG32)(((float)m_llDeviceSamplesPlayed/(float)pWFmt->nSamplesPerSec)*1000.f);
  790. #if defined(_WIN32)
  791. ULONG32 BitsPerSample = (pWFmt->nChannels * pWFmt->wBitsPerSample);
  792. #elif _WIN16
  793. ULONG32 BitsPerSample = (pWFmt->nAvgBytesPerSec * 8 / pWFmt->nSamplesPerSec);
  794. #endif
  795. ulDeviceBytesPlayed = (ULONG32)(mmTime.u.sample * 8.0f) / BitsPerSample;
  796. }
  797. break;
  798. case TIME_BYTES:
  799. {
  800. // Convert Bytes to MS
  801. ulDeviceBytesPlayed = mmTime.u.cb;
  802. if (m_ulLastDeviceBytesPlayed > ulDeviceBytesPlayed &&
  803.     ((m_ulLastDeviceBytesPlayed - ulDeviceBytesPlayed) > MAX_TIMESTAMP_GAP))
  804. {
  805.     m_ulDevPosRollOver++;
  806. }
  807. m_ulLastDeviceBytesPlayed = ulDeviceBytesPlayed;
  808. m_llDeviceBytesPlayed = (INT64)ulDeviceBytesPlayed + (INT64)m_ulDevPosRollOver * (INT64)MAX_UINT32;
  809. //{FILE* f1 = ::fopen("c:\audio.txt", "a+"); ::fprintf(f1, "ulDeviceBytesPlayed: %lun", ulDeviceBytesPlayed);::fclose(f1);}
  810. #if defined(_WIN32)
  811. ULONG32 BitsPerSample = (pWFmt->nChannels * pWFmt->wBitsPerSample);
  812. #elif _WIN16
  813. ULONG32 BitsPerSample = (pWFmt->nAvgBytesPerSec * 8 / pWFmt->nSamplesPerSec);
  814. #endif
  815. ULONG32 BitsPerSecond = (BitsPerSample * pWFmt->nSamplesPerSec);
  816. ulDeviceTime = (ULONG32)((m_llDeviceBytesPlayed * 8000)/(INT64)BitsPerSecond); }
  817. break;
  818. }
  819. // ?? ulCurrentTime = ulDeviceTime + m_StreamTimeOffset + m_CorrectionOffset;
  820. ulCurrentTime = m_ulCurrentTime = ulDeviceTime;
  821. }
  822. else
  823. {
  824. ulCurrentTime = m_ulCurrentTime = 0;
  825. }
  826. //{FILE* f1 = ::fopen("c:\audio.txt", "a+"); ::fprintf(f1, "%lut%lun", HX_GET_TICKCOUNT(), m_ulCurrentTime);::fclose(f1);}
  827. return HXR_OK;
  828. }
  829. /************************************************************************
  830.  *  Method:
  831.  *              CAudioOutWindows::WaveOutProc
  832.  *      Purpose:
  833.  *              This static member function is called when the wave 
  834.  *              device is finished playing its audio buffer.  We use 
  835.  *              it to tell audio services that we're ready for more.
  836.  */
  837. #if defined(_WIN32)
  838. LRESULT __declspec(dllexport) CALLBACK 
  839. #else
  840. LRESULT CALLBACK __export 
  841. #endif
  842. CAudioOutWindows::WaveOutWndProc(HWND hWnd, // handle of window
  843. UINT uMsg, // message identifier
  844. WPARAM wParam, // first message parameter
  845. LPARAM lParam)  // second message parameter)
  846. {
  847.     DWORD dwParam1 = lParam;
  848.     CAudioOutWindows* pThis = 0;
  849.     if (uMsg == WM_NCCREATE)
  850.     {
  851. CREATESTRUCT* lpCreate = 0;
  852. // Set our this pointer, so our WndProc can find us again
  853. lpCreate = (CREATESTRUCT FAR*) lParam;
  854. pThis = (CAudioOutWindows*) lpCreate->lpCreateParams;
  855. SetWindowLong(hWnd, OFFSET_THIS, (long) pThis);
  856.     }
  857.     else if (uMsg == WM_NCDESTROY)
  858.     {
  859. // remove our this pointer so if somebody calls this function
  860. // again after the window is gone (and the object is gone
  861. // too) we don't try to call a method from the pointer
  862. SetWindowLong(hWnd, OFFSET_THIS, 0L);
  863.     }
  864.     else
  865.     {
  866. pThis = (CAudioOutWindows*) (LPHANDLE)GetWindowLong(hWnd, OFFSET_THIS);
  867.     }
  868.     if (!pThis)
  869.     {
  870. goto exit;
  871.     }
  872.     switch (uMsg)
  873.     {
  874.     case MM_WOM_DONE:
  875.     HX_ASSERT(zm_bClosed || zm_pCurrentAudioDevice == pThis);
  876.     if (!zm_bClosed && zm_pCurrentAudioDevice == pThis)
  877.     {
  878.     // Only do this on WOM_DONE, note there are other messages sent to this
  879.     // callback function, like WOM_OPEN and WOM_CLOSE
  880.     //DWORD dwTime1 = timeGetTime();
  881.     //OutputDebugString("START:(uMsg == MM_WOM_DONE) in WaveOutThreadProcrn");
  882.     pThis->m_pMutex->Lock();
  883.     if (zm_bClosed)
  884.     {
  885. pThis->m_pMutex->Unlock();
  886. goto exit;
  887.     }
  888.     WAVEHDR* pWAVEHDR;
  889.     CWaveHeader* pWaveHeader;
  890.     
  891.     pWAVEHDR = (WAVEHDR*)dwParam1;
  892.     pWaveHeader = (CWaveHeader*)pWAVEHDR->dwUser;
  893.     /* We may have already removed it from the queue
  894.      * while checking for _NumberOfBlocksRemainingToPlay
  895.      */
  896.     if ((pWAVEHDR->dwFlags & WHDR_DONE) &&
  897.                                 !pThis->m_UsedBuffersList.IsEmpty() &&
  898. pThis->m_UsedBuffersList.GetHead() == (void*) pWaveHeader)
  899.     {
  900. // put it back in the queue
  901. pWaveHeader->m_bAvail = TRUE;
  902. pThis->m_rAvailBuffers.EnQueuePtr(pWaveHeader);
  903. /* This is assuming that we get WOM_DONEs sequentially
  904.  * There seems to be a bug in WIN16 where it may return
  905.  * WOM_DONEs out of order. Need to be fixed for that
  906.  * XXX Rahul
  907.  */
  908. pThis->m_UsedBuffersList.RemoveHead();
  909.     }
  910.     pThis->m_pMutex->Unlock();
  911.     if (pThis &&
  912. !pThis->m_bResetting)
  913.     {
  914. //  Call the base class's  OnTimeSync to let it know that we're done playing
  915. //  the current chunk of audio
  916. //OutputDebugString("BEFORE:pThis->OnTimeSync()rn");
  917. pThis->OnTimeSync();
  918.     }
  919.     }
  920.     break;
  921.     case MM_WOM_OPEN:
  922.     break;
  923.             
  924.     case MM_WOM_CLOSE:   
  925.     break;
  926.     
  927.     default:
  928.     break;
  929.     }
  930.     if (uMsg == zm_uDestroyMessage)
  931.     {
  932. LRESULT result = (LRESULT)DestroyWindow(hWnd);
  933. // free the memory used by this class now that our window is destroyed
  934. UnregisterClass(WND_CLASS, g_hInstance);
  935. return result;
  936.     }
  937. exit:
  938.     return ( DefWindowProc(hWnd, uMsg, wParam, lParam) );    
  939. }
  940. UINT16 CAudioOutWindows::_NumberOfBlocksRemainingToPlay(void)
  941. {
  942.     m_pMutex->Lock();
  943.     UINT16 unRemaining = m_UsedBuffersList.GetCount();
  944.     /* There may be some buffers for which we have not receoved WOM_DONEs
  945.      * but they have already been played
  946.      */
  947.     if (unRemaining > 0)
  948.     {
  949. LISTPOSITION ndxLastUsed = NULL;
  950. LISTPOSITION ndxUsed = m_UsedBuffersList.GetHeadPosition();
  951. while (ndxUsed != NULL)
  952. {
  953.     ndxLastUsed = ndxUsed;
  954.     CWaveHeader* pWaveHeader = 
  955.     (CWaveHeader*) m_UsedBuffersList.GetNext(ndxUsed);
  956.     if (pWaveHeader->m_WAVEHDR.dwFlags & WHDR_DONE)
  957.     {
  958. if (unRemaining > 0)
  959.     unRemaining--;
  960. // put it back in the queue
  961. pWaveHeader->m_bAvail = TRUE;
  962. m_rAvailBuffers.EnQueuePtr(pWaveHeader);
  963. m_UsedBuffersList.RemoveAt(ndxLastUsed);
  964.     }
  965.     else
  966.     {
  967. /* We assume that subsequent blocks are also not done playing */
  968. break;
  969.     }
  970. }
  971.     }
  972.     m_pMutex->Unlock();
  973.     return unRemaining;
  974. }
  975. #if defined(_WIN32) && !defined(_WINCE)
  976. void
  977. CAudioOutWindows::CheckForVolumeSupport()
  978. {
  979.     zm_bMixerVolSupportChecked = TRUE;
  980.     if (!m_hWnd)
  981.     {
  982. Register();
  983.     }
  984.     // if there is more than 1 mixer, we need to find out which is the current one
  985.     // we do this by determining the mixer being used by the current wave device
  986.     int startIndex = 0;
  987.     if (m_hWave != NULL && mixerGetNumDevs() > 1)
  988.     {
  989. UINT nId = -1;   
  990. if ((mixerGetID((HMIXEROBJ)m_hWave, &nId, MIXER_OBJECTF_HWAVEOUT) == MMSYSERR_NOERROR) && nId != -1)
  991. {
  992.     startIndex = nId;
  993. }
  994.     }
  995.     for(UINT index = startIndex; index < mixerGetNumDevs(); index++)
  996.     {
  997. if(mixerOpen(&m_hMixer, index, (DWORD)m_hWnd, 0, CALLBACK_WINDOW) 
  998. == MMSYSERR_NOERROR)
  999. {
  1000.     MIXERLINE mxLine;
  1001.     mxLine.cbStruct = sizeof(MIXERLINE);
  1002.     mxLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
  1003.     if(mixerGetLineInfo((HMIXEROBJ)m_hMixer, &mxLine, 
  1004.        MIXER_GETLINEINFOF_COMPONENTTYPE | MIXER_OBJECTF_HMIXER) 
  1005.     == MMSYSERR_NOERROR)
  1006.     {
  1007. // use waveOutSetVolume for bad device(i.e. crystal audio)
  1008. if (zm_audioDevice == HXAUDIO_UNKNOWN && mxLine.Target.szPname)
  1009. {
  1010.     for (int i = 0; i < g_nBadDrivers; i++)
  1011.     {
  1012. if (_tcsstr(mxLine.Target.szPname, g_badDrivers[i]))
  1013. {
  1014.     zm_audioDevice = HXAUDIO_BADDEVICE;
  1015.     break;
  1016. }
  1017.     }
  1018.     if (zm_audioDevice == HXAUDIO_UNKNOWN)
  1019.     {
  1020. zm_audioDevice = HXAUDIO_GOODDEVICE;
  1021.     }
  1022. }
  1023. if (zm_audioDevice != HXAUDIO_BADDEVICE)
  1024. {
  1025.     MIXERCONTROL mxControl;
  1026.     mxControl.cbStruct = sizeof(MIXERCONTROL);
  1027.     MIXERLINECONTROLS mxLineControls;
  1028.     mxLineControls.cbStruct = sizeof(MIXERLINECONTROLS);
  1029.     mxLineControls.dwLineID = mxLine.dwLineID;
  1030.     mxLineControls.cControls = 1;
  1031.     mxLineControls.cbmxctrl = mxControl.cbStruct;
  1032.     mxLineControls.pamxctrl = &mxControl;
  1033.     mxLineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME | 
  1034.    MIXERCONTROL_CONTROLF_UNIFORM;
  1035.     if(mixerGetLineControls((HMIXEROBJ)m_hMixer, &mxLineControls, 
  1036.        MIXER_GETLINECONTROLSF_ONEBYTYPE | MIXER_OBJECTF_HMIXER) 
  1037.     == MMSYSERR_NOERROR)
  1038.     {
  1039. if(mxLineControls.cControls)
  1040. {
  1041.     zm_bVolSupport = TRUE;
  1042.     zm_bMixerVolSupport = TRUE;
  1043.     m_VolumeControlDetails.cbStruct = 
  1044. sizeof(MIXERCONTROLDETAILS); 
  1045.     m_VolumeControlDetails.dwControlID = 
  1046. mxControl.dwControlID; 
  1047.     m_VolumeControlDetails.cChannels = 1; 
  1048.     m_VolumeControlDetails.cMultipleItems = 
  1049. mxControl.cMultipleItems; 
  1050. }
  1051.     }   
  1052. }
  1053.     }
  1054.     break;
  1055. }
  1056.     }
  1057. }
  1058. #endif /*_WIN32*/
  1059. HX_RESULT
  1060. CAudioOutWindows::Register()
  1061. {
  1062.     WNDCLASS internalClass;
  1063. //    OutputDebugString("BEFORE CALL TO:Registerrn");
  1064.     if (m_hWnd)
  1065.     {
  1066. return HXR_OK;
  1067.     }
  1068. //m_hInst = hInst;
  1069. m_hInst = g_hInstance;
  1070. if (!m_hInst)
  1071. {
  1072. #ifdef _DEBUG
  1073. MessageBox(NULL, _T("Don't have a valid handle"), NULL, MB_OK);
  1074. #endif
  1075.   return HXR_OUTOFMEMORY;
  1076. }
  1077. // XXXKM - let's see if we can get the class info first; added this additional
  1078. // check due to a strange problem when registering a class that seems to already
  1079. // be registered.  For some reason, under some circumstance, RegisterClass returns
  1080. // NULL and GetLastError returns 0x57 (invalid parameter), however the class
  1081. // is already registered
  1082. if (!::GetClassInfo(m_hInst, WND_CLASS, &internalClass))
  1083. {
  1084. // First register our window class                                  
  1085. internalClass.style  = 0;
  1086. internalClass.lpfnWndProc  = CAudioOutWindows::WaveOutWndProc;
  1087. internalClass.cbClsExtra    = 0;
  1088. internalClass.cbWndExtra    = sizeof( this );
  1089. internalClass.hInstance     = m_hInst; // Use app's instance
  1090. internalClass.hIcon         = 0;
  1091. internalClass.hCursor       = 0;
  1092. internalClass.hbrBackground = 0;
  1093. internalClass.lpszMenuName  = NULL;
  1094. internalClass.lpszClassName = WND_CLASS;
  1095. #ifdef _WIN16
  1096. if (!RegisterClass( &internalClass ))
  1097. #else
  1098. if (!RegisterClass( &internalClass ) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS)
  1099. #endif /* _WIN16 */    
  1100. {
  1101. #ifdef _DEBUG
  1102. MessageBox(NULL, _T("Could Not register class"), NULL, MB_OK);
  1103. #endif
  1104. return(HXR_OUTOFMEMORY);
  1105. }
  1106. m_bClassRegistered = TRUE;
  1107. }
  1108. //    OutputDebugString("BEFORE CALL TO:CreateWindowrn");
  1109.     // Now create an instance of the window
  1110.     m_hWnd = CreateWindow( WND_CLASS /*"AudioServicesInternal"*/, _T("Audio Services Internal Messages"), 
  1111. WS_OVERLAPPED, 0, 0, 0, 0, NULL, NULL, m_hInst, this);
  1112. #if defined(_WIN32)
  1113.     m_ulOriginalThreadId = GetCurrentThreadId();
  1114. #endif
  1115.     if (!m_hWnd)
  1116.     {
  1117. #ifdef _DEBUG
  1118. MessageBox(NULL, _T("Could Not create messageWindow"), NULL, MB_OK);
  1119. #endif
  1120. return HXR_OUTOFMEMORY;
  1121.     }
  1122.     return HXR_OK;
  1123. }
  1124. void
  1125. CAudioOutWindows::UnRegister()
  1126. {
  1127. //    OutputDebugString("BEFORE CALL TO:UnRegisterrn");
  1128.     // Ask the window to destroy itself
  1129.     if (m_hWnd) 
  1130.     {
  1131. #if defined(_WIN32)
  1132. if (m_ulOriginalThreadId == GetCurrentThreadId())
  1133. {
  1134.     SendMessage(m_hWnd, zm_uDestroyMessage, 0, 0);
  1135. }
  1136. else
  1137. {
  1138.     PostMessage(m_hWnd, zm_uDestroyMessage, 0, 0);
  1139.     Sleep(0);
  1140. }
  1141. #else
  1142. SendMessage(m_hWnd, zm_uDestroyMessage, 0, 0);
  1143. #endif
  1144. m_hWnd = NULL;
  1145.     }
  1146. /*
  1147.     // Ask the window to destroy itself
  1148.     if (m_hWnd && SendMessage(m_hWnd, zm_uDestroyMessage, 0, 0)) 
  1149.     {
  1150. m_hWnd = NULL;
  1151.     }
  1152.     // free the memory used by this class now that our window is destroyed
  1153.     UnregisterClass(WND_CLASS, g_hInstance);
  1154. */
  1155. }