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

Symbian

开发平台:

Visual C++

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  * Source last modified: $Id: hxaudevds.cpp,v 1.13.2.3 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. #if defined( _WINDOWS ) || defined( _WIN32 )
  51. #include <windows.h>
  52. #include <tchar.h>
  53. #include <mmsystem.h>
  54. #include "mmreg.h"
  55. #endif /*defined( _WINDOWS ) || defined( _WIN32 )*/
  56. #include <stdio.h>
  57. #include <string.h>
  58. #include "hxresult.h"
  59. #include "cbqueue.h"
  60. #include "cpqueue.h"
  61. #include "hxslist.h"
  62. #include "hxcom.h"
  63. #include "hxengin.h"
  64. #include "ihxpckts.h"
  65. #include "hxausvc.h"
  66. #include "auderrs.h"
  67. #include "math.h"   
  68. #include "hxaudev.h"
  69. #include "tsconvrt.h"
  70. #include "hxaudevds.h"
  71. extern HINSTANCE g_hInstance;
  72. #include "hxheap.h"
  73. #ifdef _DEBUG
  74. #undef HX_THIS_FILE
  75. static const char HX_THIS_FILE[] = __FILE__;
  76. #endif
  77. #include "hlxosstr.h"
  78. #ifndef TEXT
  79. #define TEXT(w)  OS_STRING(w)
  80. #endif
  81. #ifndef _WINDOWS
  82. #define TCHAR  char
  83. #endif
  84. typedef HRESULT (WINAPI* FPDIRECTSOUNDCREATE)(LPGUID lpGuid, LPDIRECTSOUND * ppDS, IUnknown FAR * pUnkOuter);
  85. static LRESULT CALLBACK HXDSWndProc(HWND, UINT, WPARAM, LPARAM);
  86. UINT CHXAudioDeviceDS::zm_uDestroyMessage = 0;
  87. const UINT32 kExitThreadWaitTime = 3000; // ms
  88. #define HXMSG_TIMESYNC WM_USER+501
  89. const TCHAR* szTitle = TEXT("Helix DSWnd");
  90. const TCHAR* szWindowClass = TEXT("Helix DSWndClass");
  91. const TCHAR* kDSWaitEvent = TEXT("HelixDirectSoundNotifyWait");
  92. const TCHAR* kDSDestroyMessage = TEXT("HX_DestroyDSWindowInternal");
  93. const int BUFFER_TIME = 8;
  94. extern BOOL RMEnableLogging();
  95. extern void RMDSLog(const char* pFormatString, ...);
  96. #define RMDS_LOG RMDSLog
  97. CHXAudioDeviceDS::CHXAudioDeviceDS():
  98. m_ulLastPlayCursor(0)
  99.     , m_ulLastWriteCursor(0)
  100.     , m_ulCurrPlayTime(0)
  101. , m_ulCurrLoopTime(0)
  102.     , m_pDSDev(NULL)
  103.     , m_pPrimaryBuffer(NULL)
  104.     , m_pSecondaryBuffer(NULL)
  105.     , m_hwnd(NULL)
  106.     , m_pAudioPtrStart(NULL)
  107.     , m_hSoundDll(NULL)
  108.     , m_ulLoops(0)
  109.     , m_ulLoopTime(0)
  110.     , m_hDSNotifyEvent(NULL)
  111.     , m_hWaitThread(NULL)
  112.     , m_nBlocksPerBuffer(0)
  113.     , m_bExitThread(FALSE)
  114.     , m_ulOriginalThreadId(0)
  115. {
  116.     // Create a unique message for destroying the audio window
  117.     if (!zm_uDestroyMessage)
  118.     {
  119. zm_uDestroyMessage = RegisterWindowMessage(kDSDestroyMessage);
  120.     }
  121. #ifdef _WINCE
  122. WNDCLASS wcex;
  123. #else
  124. WNDCLASSEX wcex;
  125. wcex.cbSize  = sizeof(WNDCLASSEX); 
  126. wcex.hIconSm = NULL;
  127. #endif
  128.     wcex.style = CS_HREDRAW | CS_VREDRAW;
  129.     wcex.lpfnWndProc = (WNDPROC)HXDSWndProc;
  130.     wcex.cbClsExtra = 0;
  131.     wcex.cbWndExtra = 0;
  132.     wcex.hInstance = g_hInstance;
  133.     wcex.hIcon = NULL;
  134.     wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
  135.     wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  136.     wcex.lpszMenuName = NULL;
  137.     wcex.lpszClassName = szWindowClass;
  138. #ifdef _WINCE
  139. RegisterClass(&wcex);
  140. #else
  141. RegisterClassEx(&wcex);
  142. #endif
  143. #ifdef _WINCE
  144. m_hwnd = ::CreateWindow(szWindowClass, szTitle, 
  145. WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_SYSMENU,
  146. -5000, -5000, 1, 1, NULL, NULL, g_hInstance, NULL );
  147. #else
  148. m_hwnd = ::CreateWindow(szWindowClass, szTitle, 
  149. WS_OVERLAPPEDWINDOW,
  150. -5000, -5000, 1, 1, NULL, NULL, g_hInstance, NULL );
  151. #endif
  152.     m_ulOriginalThreadId = GetCurrentThreadId();
  153.     
  154.     m_hSoundDll = ::LoadLibrary( TEXT("dsound.dll") );
  155. }
  156. CHXAudioDeviceDS::~CHXAudioDeviceDS()
  157. {
  158.     if (m_hSoundDll)
  159.     {
  160. FreeLibrary(m_hSoundDll);
  161. m_hSoundDll = NULL;
  162.     }
  163.     if (m_hwnd) 
  164.     {
  165. #if defined(_WIN32)
  166. if (m_ulOriginalThreadId == GetCurrentThreadId())
  167. {
  168.     SendMessage(m_hwnd, zm_uDestroyMessage, 0, 0);
  169. }
  170. else
  171. {
  172.     PostMessage(m_hwnd, zm_uDestroyMessage, 0, 0);
  173.     Sleep(0);
  174. }
  175. #else
  176. SendMessage(m_hwnd, zm_uDestroyMessage, 0, 0);
  177. #endif
  178. m_hwnd = NULL;
  179.     }
  180. }
  181. /*
  182.  * Set the format of the primary buffer, if possible. On WDM drivers, this has
  183.  * no effect -- the kernel mixer determines that format.
  184.  */
  185. HX_RESULT CHXAudioDeviceDS::SetPrimaryBufferFormat()
  186. {
  187.     HX_RESULT res = HXR_OK ;
  188.     DSBUFFERDESC bufferDesc;
  189.     ::memset(&bufferDesc, 0, sizeof(DSBUFFERDESC));
  190.     bufferDesc.dwSize    = sizeof(DSBUFFERDESC);
  191.     bufferDesc.lpwfxFormat = 0 ;
  192.     bufferDesc.dwBufferBytes = 0 ;
  193.     bufferDesc.dwFlags =  DSBCAPS_PRIMARYBUFFER ;
  194.     /* close the primary buffer if we had one open before. */
  195.     HX_RELEASE(m_pPrimaryBuffer) ;
  196.     /* try to open with WAVE_FORMAT_EXTENSIBLE */
  197.     res = m_pDSDev->CreateSoundBuffer(&bufferDesc, &m_pPrimaryBuffer, NULL);
  198.     if (res == DS_OK)
  199.     {
  200.         res = !DS_OK ;
  201.         if (m_WaveFormat.Format.nChannels > 2)
  202.         {
  203.             res = m_pPrimaryBuffer->SetFormat(&m_WaveFormat.Format) ;
  204.         }
  205.         if (res != DS_OK)
  206.         {
  207.     /* if that fails, try to open with WAVE_FORMAT_PCM */
  208.     m_WaveFormat.Format.wFormatTag = WAVE_FORMAT_PCM ;
  209.     res = m_pPrimaryBuffer->SetFormat(&m_WaveFormat.Format) ;
  210.         }
  211.     }
  212.     return res ;
  213. }
  214. /*
  215.  *  IHXAudioDevice override methods
  216.  */
  217. HX_RESULT CHXAudioDeviceDS::_Imp_Open(const HXAudioFormat* pFormat)
  218. {
  219.     HX_RESULT theErr = HXR_FAIL;
  220.     if(!m_hwnd || !m_hSoundDll)
  221. return theErr;
  222.     // close open resources
  223.     _Imp_Close() ;
  224.     /* Get the IDirectSound interface */
  225.     FPDIRECTSOUNDCREATE fpCreateDS = (FPDIRECTSOUNDCREATE) ::GetProcAddress(m_hSoundDll, TEXT("DirectSoundCreate") );
  226.     if(!fpCreateDS)
  227. return theErr;
  228.     theErr = fpCreateDS(NULL, &m_pDSDev, NULL);
  229.     if (FAILED(theErr))
  230. return theErr;
  231.     /* set the cooperative level. Because we want control over the format of the
  232.        primary buffer (16 bit, multichannel!), we need DSSCL_PRIORITY. */
  233.     m_pDSDev->SetCooperativeLevel(m_hwnd, DSSCL_PRIORITY );
  234.     /* fill out the wave format structure */
  235.     ::memset(&m_WaveFormat, 0, sizeof(m_WaveFormat));
  236.     m_WaveFormat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
  237.     m_WaveFormat.Format.nChannels = pFormat->uChannels;
  238.     m_WaveFormat.Format.nSamplesPerSec = pFormat->ulSamplesPerSec;
  239.     m_WaveFormat.Format.wBitsPerSample = pFormat->uBitsPerSample;
  240.     m_WaveFormat.Format.nBlockAlign = pFormat->uBitsPerSample/8 * pFormat->uChannels;
  241.     m_WaveFormat.Format.nAvgBytesPerSec = m_WaveFormat.Format.nBlockAlign * pFormat->ulSamplesPerSec ;
  242.     m_WaveFormat.Format.cbSize = 22;
  243.     m_WaveFormat.Samples.wValidBitsPerSample = pFormat->uBitsPerSample;
  244.     m_WaveFormat.SubFormat = KSDATAFORMAT_SUBTYPE_PCM ;
  245.     m_WaveFormat.dwChannelMask = defaultChannelMapping(pFormat->uChannels) ;
  246.     /* set the format of the primary buffer. This will fail on WDM systems (because
  247.        the kernel mixer termines the primary buffer format), but is important on
  248.        non-WDM systems.
  249.     
  250.        This might change the m_WaveFormat structure from a WAVE_FORMAT_EXTENSIBLE
  251.        to a WAVEFORMATEX.
  252.        Ignore the result.
  253.     */
  254.     SetPrimaryBufferFormat() ;
  255.     /* Now open a secondary buffer. */
  256.     DSBUFFERDESC bufferDesc;
  257.     ::memset(&bufferDesc, 0, sizeof(DSBUFFERDESC));
  258.     bufferDesc.dwSize    = sizeof(DSBUFFERDESC);
  259.     bufferDesc.lpwfxFormat = &m_WaveFormat.Format;
  260.     // Manipulate the buffer size so that is is an exact multiple of the block size.
  261.     // This will ensure that our write positions on the buffer are the same in every loop.
  262.     // We need to do this so that we have fixed playback notification positions marking the end each write block.
  263.     m_nBlocksPerBuffer = (m_WaveFormat.Format.nAvgBytesPerSec*BUFFER_TIME)/pFormat->uMaxBlockSize;
  264.     m_ulTotalBuffer = pFormat->uMaxBlockSize*m_nBlocksPerBuffer;
  265.     m_ulLoopTime = (double)m_ulTotalBuffer / (double)m_WaveFormat.Format.nAvgBytesPerSec;
  266.     bufferDesc.dwBufferBytes = m_ulTotalBuffer ;
  267.     bufferDesc.dwFlags =
  268.       DSBCAPS_CTRLVOLUME | // so we can control the volume
  269.       DSBCAPS_GETCURRENTPOSITION2 | // finer position reports
  270.       DSBCAPS_CTRLPOSITIONNOTIFY | // have them reported here
  271.       DSBCAPS_GLOBALFOCUS | // take control!
  272.       DSBCAPS_STICKYFOCUS ;
  273.     /* Again, try with WAVE_FORMAT_EXTENSIBLE first, but only if multichannel. */
  274.     theErr = !DS_OK ;
  275.     if (m_WaveFormat.Format.nChannels > 2)
  276.     {
  277.         m_WaveFormat.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
  278.         theErr = m_pDSDev->CreateSoundBuffer(&bufferDesc, &m_pSecondaryBuffer, NULL);
  279.     }
  280.     if (theErr != DS_OK)
  281.     {
  282. /* and if that fails, try WAVEFORMATEX */
  283. m_WaveFormat.Format.wFormatTag = WAVE_FORMAT_PCM;
  284. theErr = m_pDSDev->CreateSoundBuffer(&bufferDesc, &m_pSecondaryBuffer, NULL);
  285.     }
  286.     /* call it a day and count our blessings. */
  287.     switch (theErr)
  288.     {
  289. case DS_OK: 
  290.     theErr = HXR_OK;
  291.     break;
  292. case DSERR_OUTOFMEMORY:
  293.     theErr = HXR_OUTOFMEMORY;
  294.     break;
  295. default:
  296.     theErr = HXR_FAIL;
  297.     break;
  298.     }
  299.     if (SUCCEEDED(theErr) && m_pSecondaryBuffer)
  300.     {
  301. m_eState = E_DEV_OPENED;
  302. KillThreadAndEvent();
  303. SetWindowLong(m_hwnd, GWL_USERDATA, (LONG)this);
  304. // Create the event to be signalled on playback position notifications and the thread to wait for those events to be signalled.
  305. m_hDSNotifyEvent = CreateEvent(NULL, TRUE, FALSE, kDSWaitEvent);
  306. // now set the notification positions for direct sound playback.
  307. IDirectSoundNotify* pNotify = NULL;
  308. m_pSecondaryBuffer->QueryInterface(IID_IDirectSoundNotify, (void**)&pNotify);
  309. if(pNotify && m_hDSNotifyEvent)
  310. {
  311.     DSBPOSITIONNOTIFY* aPositionNotify = new DSBPOSITIONNOTIFY[m_nBlocksPerBuffer];
  312.     if(aPositionNotify)
  313.     {
  314. for(int i = 0; i < m_nBlocksPerBuffer; i++)
  315. {
  316.     aPositionNotify[i].dwOffset = i * pFormat->uMaxBlockSize;
  317.     aPositionNotify[i].hEventNotify = m_hDSNotifyEvent;
  318. }
  319.     }
  320.     pNotify->SetNotificationPositions(m_nBlocksPerBuffer, aPositionNotify);
  321.     delete[] aPositionNotify;
  322.     DWORD dwWaitThreadID(0);
  323.     m_hWaitThread = CreateThread(NULL, 0, EventThreadProc, (LPVOID)this, 0, &dwWaitThreadID);
  324. }
  325. HX_RELEASE(pNotify);
  326. m_pSecondaryBuffer->SetVolume(DSBVOLUME_MAX);
  327. m_pSecondaryBuffer->SetCurrentPosition(0);
  328.     }
  329.     m_ulCurrPlayTime = 0;
  330. m_ulCurrLoopTime = 0;
  331.     m_ulLoops = 0;
  332.     // Setup converter to convert from samples/sec to milliseconds
  333.     m_TSConverter.SetBase(m_WaveFormat.Format.nSamplesPerSec, 1000);
  334.     return theErr;
  335. }
  336. HX_RESULT CHXAudioDeviceDS::_Imp_Close()
  337. {
  338.     HX_RESULT theErr = HXR_OK;
  339.     KillThreadAndEvent();
  340.     HX_RELEASE(m_pPrimaryBuffer);
  341.     HX_RELEASE(m_pSecondaryBuffer);
  342.     HX_RELEASE(m_pDSDev);
  343.     m_pAudioPtrStart = NULL;
  344.     m_ulLastPlayCursor = 0;
  345.     m_ulLastWriteCursor =0;
  346.     m_eState = E_DEV_CLOSED;
  347.     m_ulLoops = 0;
  348.     m_ulLoopTime = 0;
  349.     m_nBlocksPerBuffer = 0;
  350.     m_ulCurrPlayTime = 0;
  351. m_ulCurrLoopTime = 0;
  352.     if (m_hwnd)
  353.     {
  354. SetWindowLong(m_hwnd, GWL_USERDATA, NULL);
  355.     }
  356.     return HXR_OK;
  357. }
  358. HX_RESULT CHXAudioDeviceDS::_Imp_Pause()
  359. {
  360.     HX_RESULT theErr = HXR_OK;
  361.     m_bPaused = TRUE;
  362.     if (m_pSecondaryBuffer)
  363.     {
  364. m_pSecondaryBuffer->Stop();
  365.     }
  366.     m_eState = E_DEV_PAUSED;
  367.     return HXR_OK;
  368. }
  369. HX_RESULT CHXAudioDeviceDS::_Imp_Resume()
  370. {
  371.     if (m_pSecondaryBuffer && m_pAudioPtrStart)
  372.     {
  373. m_pSecondaryBuffer->Play(0, 0, DSBPLAY_LOOPING);
  374. if(m_bPaused)
  375. {
  376.     m_bPaused = FALSE;
  377. }
  378. OnTimeSync();
  379.     }
  380.     m_eState = E_DEV_RESUMED;
  381.     return HXR_OK;
  382. }
  383. HX_RESULT CHXAudioDeviceDS::_Imp_Write(const HXAudioData* pAudioHdr)
  384. {
  385.     HRESULT res ;
  386.     IHXBuffer* pBuffer;
  387.     pBuffer = pAudioHdr->pData;
  388.     UINT32 ulBufSize = pBuffer->GetSize();
  389.     void* pAudioPtr1 = NULL;
  390.     void* pAudioPtr2 = NULL;
  391.     DWORD ulAudioBytes1 = 0;
  392.     DWORD ulAudioBytes2 = 0;
  393.     res = m_pSecondaryBuffer->Lock(m_ulLastWriteCursor, ulBufSize, &pAudioPtr1, &ulAudioBytes1, 
  394. &pAudioPtr2, &ulAudioBytes2, 0);
  395.     if(res != DS_OK)
  396.     {
  397. RMDS_LOG(" Lock failed ulBufSize = %ld pAudioPtr1 = %ld ulAudioBytes1 = %ld pAudioPtr2 = %ld ulAudioBytes2 = %ld n", ulBufSize, pAudioPtr1, ulAudioBytes1, pAudioPtr2, ulAudioBytes2);
  398. return HXR_FAIL ;
  399.     }
  400.     HX_ASSERT(ulBufSize = ulAudioBytes1+ulAudioBytes2);
  401.     m_ulLastWriteCursor += ulBufSize ;
  402.     if (m_ulLastWriteCursor >= m_ulTotalBuffer)
  403. m_ulLastWriteCursor -= m_ulTotalBuffer;
  404.     if(pAudioPtr1)
  405.     {
  406. ::memcpy(pAudioPtr1, (void*) pBuffer->GetBuffer(), ulAudioBytes1); /* Flawfinder: ignore */
  407. if(!m_pAudioPtrStart)
  408. {
  409.     m_pAudioPtrStart = pAudioPtr1;
  410.     m_ulLoops = 0;
  411.     m_pSecondaryBuffer->SetCurrentPosition(0);
  412. }
  413.     }
  414.     if (pAudioPtr2)
  415. ::memcpy(pAudioPtr2, ((char*)pBuffer->GetBuffer()) + ulAudioBytes1 , ulAudioBytes2); /* Flawfinder: ignore */
  416.     res = m_pSecondaryBuffer->Unlock(pAudioPtr1, ulAudioBytes1, pAudioPtr2, ulAudioBytes2);
  417.     if(res != DS_OK)
  418.     {
  419. RMDS_LOG(" Unlock failed ulBufSize = %ld pAudioPtr1 = %ld ulAudioBytes1 = %ld pAudioPtr2 = %ld ulAudioBytes2 = %ld n", ulBufSize, pAudioPtr1, ulAudioBytes1, pAudioPtr2, ulAudioBytes2);
  420. return HXR_FAIL ;
  421.     }
  422.     return HXR_OK;
  423. }
  424. HX_RESULT CHXAudioDeviceDS::_Imp_SetVolume(const UINT16 uVolume)
  425. {
  426.     LONG lVol = 0;
  427.     m_uCurVolume = uVolume;
  428.     if( m_uCurVolume == 0)
  429. lVol = DSBVOLUME_MIN;
  430.     else
  431.     {
  432. double dVolFromMin = (double)m_uCurVolume - m_uMinVolume;
  433. double dVolFrac = (dVolFromMin/(m_uMaxVolume - m_uMinVolume));
  434. lVol = (LONG)(1055.0 * log(dVolFrac));
  435.     }
  436.     if(m_pSecondaryBuffer)
  437. m_pSecondaryBuffer->SetVolume(lVol);
  438.     return HXR_OK;
  439. }
  440. UINT16 CHXAudioDeviceDS::_Imp_GetVolume()
  441. {
  442.     LONG lVolume;
  443.     if (!m_pSecondaryBuffer)
  444. return m_uMaxVolume ;
  445.     m_pSecondaryBuffer->GetVolume(&lVolume);
  446.     return (UINT16)(exp(lVolume / 1055.0) * (m_uMaxVolume - m_uMinVolume) + m_uMinVolume) ;
  447. }
  448. HX_RESULT CHXAudioDeviceDS::_Imp_Reset()
  449. {
  450.     if ( NULL == m_pSecondaryBuffer )
  451.     {
  452. return HXR_OK;
  453.     }
  454.     void* pAudioPtr1 = NULL;
  455.     void* pAudioPtr2 = NULL;
  456.     DWORD ulAudioBytes1 = 0;
  457.     DWORD ulAudioBytes2 = 0;
  458.     HRESULT result = m_pSecondaryBuffer->Lock(0, 0, &pAudioPtr1, &ulAudioBytes1,&pAudioPtr2, &ulAudioBytes2, DSBLOCK_ENTIREBUFFER);
  459.     if(result == DS_OK)
  460.     {
  461. ::ZeroMemory(pAudioPtr1, ulAudioBytes1);
  462. ::ZeroMemory(pAudioPtr2, ulAudioBytes2);
  463. m_ulLastWriteCursor = 0;
  464. m_pSecondaryBuffer->Unlock(pAudioPtr1, ulAudioBytes1, pAudioPtr2, ulAudioBytes2);
  465. m_ulCurrPlayTime = 0;
  466.         m_ulCurrLoopTime = 0;
  467. m_ulLoops = 0;
  468. m_ulLastPlayCursor = 0;
  469. m_pAudioPtrStart = pAudioPtr1;
  470. m_pSecondaryBuffer->SetCurrentPosition(0);
  471. RMDS_LOG("RESET  n n n n");
  472.     }
  473.     else
  474.     {
  475. RMDS_LOG(" Reset - Lock failed n");
  476.     }
  477.     return HXR_OK;
  478. }
  479. HX_RESULT CHXAudioDeviceDS::_Imp_Drain()
  480. {
  481.     return HXR_OK;
  482. }
  483. HX_RESULT CHXAudioDeviceDS::_Imp_CheckFormat( const HXAudioFormat* pFormat )
  484. {
  485.     return HXR_OK;
  486. }
  487. HX_RESULT CHXAudioDeviceDS::_Imp_GetCurrentTime(ULONG32& ulCurrentTime)
  488. {
  489.     DWORD dwCurrentPlayCursor = 0;
  490.     DWORD dwCurrentWriteCursor = 0;
  491.     HRESULT result;
  492.     ulCurrentTime = m_ulCurrPlayTime;
  493.     if (m_pSecondaryBuffer)
  494.     {
  495. result = m_pSecondaryBuffer->GetCurrentPosition(&dwCurrentPlayCursor, 
  496. &dwCurrentWriteCursor);
  497. if (result == DS_OK)
  498. {
  499.     UINT32 uLast = m_ulCurrPlayTime;
  500.     if(dwCurrentPlayCursor != m_ulLastPlayCursor)
  501.     {
  502. if( (dwCurrentPlayCursor < m_ulLastPlayCursor) && ((m_ulLastPlayCursor-dwCurrentPlayCursor) > (m_ulTotalBuffer/2))  )
  503. {
  504.     RMDS_LOG(" m_ulLastPlayCursor = %ld ; dwCurrentPlayCursor = %ld n", m_ulLastPlayCursor, dwCurrentPlayCursor);
  505.     m_ulLoops++;
  506.     m_ulCurrPlayTime = m_ulCurrLoopTime = (UINT32) (m_ulLoopTime * 1000.0 * m_ulLoops);
  507.     m_ulLastPlayCursor = 0;
  508. }
  509. // Time can only move forward
  510. if (dwCurrentPlayCursor > m_ulLastPlayCursor)
  511. {
  512.     ULONG32 ulSamplesPlayedThisLoop = 
  513. dwCurrentPlayCursor / m_WaveFormat.Format.nBlockAlign;
  514.     m_ulCurrPlayTime = m_ulCurrLoopTime + 
  515. m_TSConverter.ConvertVector(ulSamplesPlayedThisLoop);
  516.     m_ulLastPlayCursor = dwCurrentPlayCursor;
  517. }
  518. ulCurrentTime = m_ulCurrPlayTime;
  519.     }
  520.     RMDS_LOG(" ulCurrentTime = %ld n", ulCurrentTime);
  521. }
  522. else
  523. {
  524.     RMDS_LOG(" GetCurrentPosition failed n");
  525. }
  526.     }
  527.     return HXR_OK;
  528. }
  529. UINT32 
  530. CHXAudioDeviceDS::CalcMs(UINT32 ulNumBytes)
  531. {
  532.     return (ulNumBytes * 1000UL ) / m_WaveFormat.Format.nAvgBytesPerSec ;
  533. }
  534. DWORD
  535. CHXAudioDeviceDS::defaultChannelMapping(UINT32 ulChannels) const
  536. {
  537.     switch (ulChannels)
  538.     {
  539.     case 1:
  540. return SPEAKER_FRONT_CENTER ;
  541.     case 2:
  542. return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT ;
  543.     case 5:
  544. return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
  545.     SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_CENTER ;
  546.     case 6:
  547. return SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT |
  548.     SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_FRONT_CENTER |
  549.     SPEAKER_LOW_FREQUENCY;
  550.     }
  551.     return 0 ;
  552. }
  553. void 
  554. CHXAudioDeviceDS::KillThreadAndEvent()
  555. {
  556.     DWORD dwThreadWaitResult = WAIT_FAILED;
  557.     if(m_hDSNotifyEvent)
  558.     {
  559. m_bExitThread = TRUE;
  560. ::SetEvent(m_hDSNotifyEvent);
  561. // Wait for thread to exit
  562. if ( m_hWaitThread )
  563. {
  564.     dwThreadWaitResult = WaitForSingleObject(m_hWaitThread, kExitThreadWaitTime);
  565. }
  566. CloseHandle(m_hDSNotifyEvent);
  567. m_hDSNotifyEvent = NULL;
  568.     }
  569.     if(m_hWaitThread)
  570.     {
  571. if ( dwThreadWaitResult != WAIT_OBJECT_0 )
  572. {
  573.     ::TerminateThread(m_hWaitThread, -1 );
  574. }
  575. CloseHandle(m_hWaitThread);
  576. m_hWaitThread = NULL;
  577.     }
  578.     m_bExitThread = FALSE;
  579. }
  580. void 
  581. CHXAudioDeviceDS::PostTimeSyncMessage()
  582. {
  583.     ::PostMessage(m_hwnd, HXMSG_TIMESYNC, 0, 0);
  584. }
  585. DWORD WINAPI CHXAudioDeviceDS::EventThreadProc(LPVOID pVoid)
  586. {
  587.     CHXAudioDeviceDS* pThis = (CHXAudioDeviceDS*)pVoid;
  588.     if(!pThis)
  589. return 0;
  590.     HANDLE hWaitEvent = pThis->GetEventHandle();
  591.     if(!hWaitEvent)
  592. return 0;
  593.     while(1)
  594.     {
  595. DWORD dwReturn = WaitForMultipleObjects(1, &hWaitEvent, FALSE, INFINITE);
  596.    
  597. if(pThis->GetExitCode())
  598. {
  599.     return 0;
  600. }
  601. if (dwReturn != (WAIT_OBJECT_0 + 1))
  602. {
  603.     // Post message to the window so that it can call OnTimeSync on the audio thread( on which the window was created )
  604.     // and then reset the event
  605.     pThis->PostTimeSyncMessage();
  606.     ResetEvent(hWaitEvent);
  607. }
  608.     }
  609.     return 0;
  610. }
  611. static LRESULT CALLBACK HXDSWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
  612. {
  613.     if(message == HXMSG_TIMESYNC)
  614.     {
  615. CHXAudioDeviceDS* pThis = (CHXAudioDeviceDS*)GetWindowLong(hWnd, GWL_USERDATA);
  616. if(pThis)
  617.     pThis->OnTimeSync();
  618. return 0;
  619.     }
  620.     else if (message == CHXAudioDeviceDS::zm_uDestroyMessage)
  621.     {
  622. LRESULT result = (LRESULT)DestroyWindow(hWnd);
  623. // free the memory used by this class now that our window is destroyed
  624. UnregisterClass(szWindowClass, g_hInstance);
  625. return result;
  626.     }
  627.     return DefWindowProc(hWnd, message, wParam, lParam);
  628. }