winaudio.cpp
上传用户:dangjiwu
上传日期:2013-07-19
资源大小:42019k
文件大小:37k
源码类别:

Symbian

开发平台:

Visual C++

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