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

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