Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1569 lines
46 KiB

  1. //
  2. // Copyright (c) 1996-2001 Microsoft Corporation
  3. // DSLink.cpp
  4. //
  5. // READ THIS!!!!!!!!!!!!!!!!!!!!!!!!!!!
  6. //
  7. // 4530: C++ exception handler used, but unwind semantics are not enabled. Specify -GX
  8. //
  9. // We disable this because we use exceptions and do *not* specify -GX (USE_NATIVE_EH in
  10. // sources).
  11. //
  12. // The one place we use exceptions is around construction of objects that call
  13. // InitializeCriticalSection. We guarantee that it is safe to use in this case with
  14. // the restriction given by not using -GX (automatic objects in the call chain between
  15. // throw and handler are not destructed). Turning on -GX buys us nothing but +10% to code
  16. // size because of the unwind code.
  17. //
  18. // Any other use of exceptions must follow these restrictions or -GX must be turned on.
  19. //
  20. // READ THIS!!!!!!!!!!!!!!!!!!!!!!!!!!!
  21. //
  22. #pragma warning(disable:4530)
  23. #include <objbase.h>
  24. #include <ks.h>
  25. #include <ksproxy.h>
  26. #include "debug.h"
  27. #include "dmusicc.h"
  28. #include "dmusics.h"
  29. #include "..\shared\validate.h"
  30. #include "synth.h"
  31. #include "DSLink.h"
  32. #include "float.h"
  33. #include "misc.h"
  34. #include "dmksctrl.h"
  35. #define DSBUFFER_LENGTH_SEC 2
  36. extern long g_cComponent;
  37. CDSLinkList g_DSLinkList; // Master list of DSLinks.
  38. void CDSLink::SynthProc()
  39. {
  40. HRESULT hr;
  41. DWORD dwPlayCursor; // current play head (driven by streaming wave crystal)
  42. DWORD dwWriteFromCursor; // current write head
  43. ::EnterCriticalSection(&m_CriticalSection);
  44. if (!m_fActive || !m_pBuffer || !m_pIMasterClock)
  45. {
  46. Trace(2, "Warning: SynthSink - Thread in invalid state\n");
  47. ::LeaveCriticalSection(&m_CriticalSection);
  48. return;
  49. }
  50. hr = m_pBuffer->GetCurrentPosition(&dwPlayCursor, &dwWriteFromCursor);
  51. if (hr == DS_OK)
  52. {
  53. DWORD dwDeltaFilter = m_dwBufferSize >> 1;
  54. DWORD dwCursorDelta;
  55. if (dwWriteFromCursor >= dwPlayCursor)
  56. dwCursorDelta = dwWriteFromCursor - dwPlayCursor;
  57. else
  58. dwCursorDelta = (dwWriteFromCursor + m_dwBufferSize) - dwPlayCursor;
  59. if (dwCursorDelta > m_dwWriteFromMax)
  60. {
  61. if (dwCursorDelta < dwDeltaFilter)
  62. {
  63. TraceI(2, "Warning: SynthSink - Play to Write cursor distance increased from %lu to %lu\n", m_dwWriteFromMax, dwCursorDelta);
  64. m_dwWriteFromMax = dwCursorDelta;
  65. }
  66. else
  67. {
  68. TraceI(2, "Warning: SynthSink - Play to Write cursor delta value rejected:%lu\n", dwCursorDelta);
  69. SetEvent(g_DSLinkList.m_hEvent);
  70. ::LeaveCriticalSection(&m_CriticalSection);
  71. return;
  72. }
  73. }
  74. else
  75. {
  76. m_dwWriteFromMax -= ((m_dwWriteFromMax - dwCursorDelta) / 100);
  77. m_dwWriteFromMax = SampleAlign(m_dwWriteFromMax);
  78. dwCursorDelta = m_dwWriteFromMax;
  79. }
  80. dwWriteFromCursor = (dwPlayCursor + dwCursorDelta) % m_dwBufferSize;
  81. if (m_llAbsWrite == 0)
  82. {
  83. // we just started
  84. m_dwLastPlay = dwPlayCursor;
  85. m_dwLastWrite = dwWriteFromCursor;
  86. m_llAbsWrite = dwCursorDelta;
  87. m_SampleClock.Start(m_pIMasterClock, m_wfSynth.nSamplesPerSec, 0);
  88. m_Clock.Start(); // don't want anybody getting latency time until this thread is running
  89. }
  90. // check for overrun with master clock
  91. REFERENCE_TIME rtMaster;
  92. LONGLONG llMasterSampleTime;
  93. LONGLONG llMasterBytes;
  94. LONGLONG llMasterAhead; // how far master clock is ahead of last known play time
  95. LONGLONG llAbsWriteFrom;
  96. m_pIMasterClock->GetTime(&rtMaster);
  97. RefTimeToSample(rtMaster, &llMasterSampleTime);
  98. llMasterBytes = SampleToByte(llMasterSampleTime);
  99. llMasterAhead = (llMasterBytes > m_llAbsPlay) ? llMasterBytes - m_llAbsPlay : 0;
  100. // check for half-buffer underruns, so backward-moving play cursors can be detected
  101. if (llMasterAhead > dwDeltaFilter)
  102. {
  103. Trace(2, "Warning: SynthSink - Buffer underrun by %lu\n", (long) llMasterAhead - dwDeltaFilter);
  104. m_llAbsPlay = llMasterBytes;
  105. m_dwLastWrite = dwWriteFromCursor;
  106. m_llAbsWrite = llAbsWriteFrom = m_llAbsPlay + dwCursorDelta;
  107. }
  108. else
  109. {
  110. DWORD dwPlayed;
  111. if (dwPlayCursor >= m_dwLastPlay)
  112. dwPlayed = dwPlayCursor - m_dwLastPlay;
  113. else
  114. dwPlayed = (dwPlayCursor + m_dwBufferSize) - m_dwLastPlay;
  115. if (dwPlayed > dwDeltaFilter)
  116. {
  117. Trace(2, "Warning: SynthSink - Play Cursor %lu looks invalid, rejecting it.\n", dwPlayed);
  118. SetEvent(g_DSLinkList.m_hEvent);
  119. ::LeaveCriticalSection(&m_CriticalSection);
  120. return;
  121. }
  122. m_llAbsPlay += dwPlayed;
  123. llAbsWriteFrom = m_llAbsPlay + dwCursorDelta;
  124. // how far ahead of the write head are we?
  125. if (llAbsWriteFrom > m_llAbsWrite)
  126. {
  127. DWORD dwWriteMissed;
  128. // we are behind-- let's catch up
  129. dwWriteMissed = DWORD(llAbsWriteFrom - m_llAbsWrite);
  130. Trace(2, "Warning: SynthSink - Write underrun, missed %lu bytes\n", dwWriteMissed);
  131. m_dwLastWrite = dwWriteFromCursor;
  132. m_llAbsWrite += dwWriteMissed;
  133. }
  134. }
  135. m_dwLastPlay = dwPlayCursor;
  136. m_SampleClock.SyncToMaster(ByteToSample(m_llAbsPlay), m_pIMasterClock);
  137. // how much to write?
  138. LONGLONG llAbsWriteTo;
  139. DWORD dwBytesToFill;
  140. llAbsWriteTo = llAbsWriteFrom + m_dwWriteTo;
  141. if (llAbsWriteTo > m_llAbsWrite)
  142. {
  143. dwBytesToFill = DWORD(llAbsWriteTo - m_llAbsWrite);
  144. }
  145. else
  146. {
  147. dwBytesToFill = 0;
  148. }
  149. if (dwBytesToFill)
  150. {
  151. LPVOID lpStart, lpEnd; // Buffer pointers, filled by Lock command.
  152. DWORD dwStart, dwEnd; // For Lock.
  153. hr = m_pBuffer->Lock(m_dwLastWrite, dwBytesToFill, &lpStart, &dwStart, &lpEnd, &dwEnd, 0);
  154. if (hr == DSERR_BUFFERLOST)
  155. {
  156. Trace(2, "Warning: SynthSink - Buffer lost\n");
  157. hr = m_pBuffer->Restore();
  158. if (hr == DS_OK)
  159. {
  160. Trace(2, "Warning: SynthSink - Buffer restored\n");
  161. hr = m_pBuffer->Play(0, 0, DSBPLAY_LOOPING);
  162. if (hr == DS_OK)
  163. {
  164. Trace(2, "Warning: SynthSink - Play restarted\n");
  165. hr = m_pBuffer->Lock(m_dwLastWrite, dwBytesToFill, &lpStart, &dwStart, &lpEnd, &dwEnd, 0);
  166. }
  167. }
  168. }
  169. if (hr == DS_OK)
  170. {
  171. if (dwStart)
  172. {
  173. memset(lpStart, 0, dwStart);
  174. if (m_pSynth)
  175. {
  176. m_pSynth->Render((short*)lpStart, ByteToSample(dwStart), ByteToSample(m_llAbsWrite));
  177. }
  178. m_dwLastWrite += dwStart;
  179. m_llAbsWrite += dwStart;
  180. if (m_dwLastWrite == m_dwBufferSize)
  181. {
  182. m_dwLastWrite = 0;
  183. }
  184. }
  185. if (dwEnd)
  186. {
  187. memset(lpEnd, 0, dwEnd);
  188. if (m_pSynth)
  189. {
  190. m_pSynth->Render((short*)lpEnd, ByteToSample(dwEnd), ByteToSample(m_llAbsWrite));
  191. }
  192. m_dwLastWrite = dwEnd;
  193. m_llAbsWrite += dwEnd;
  194. }
  195. m_pBuffer->Unlock(lpStart, dwStart, lpEnd, dwEnd);
  196. // write silence into unplayed buffer
  197. if (m_dwLastWrite >= dwPlayCursor)
  198. dwBytesToFill = m_dwBufferSize - m_dwLastWrite + dwPlayCursor;
  199. else
  200. dwBytesToFill = dwPlayCursor - m_dwLastWrite;
  201. hr = m_pBuffer->Lock(m_dwLastWrite, dwBytesToFill, &lpStart, &dwStart, &lpEnd, &dwEnd, 0);
  202. if (hr == DSERR_BUFFERLOST)
  203. {
  204. Trace(2, "Warning: SynthSink - Buffer lost\n");
  205. hr = m_pBuffer->Restore();
  206. if (hr == DS_OK)
  207. {
  208. Trace(2, "Warning: SynthSink - Buffer restored\n");
  209. hr = m_pBuffer->Play(0, 0, DSBPLAY_LOOPING);
  210. if (hr == DS_OK)
  211. {
  212. Trace(2, "Warning: SynthSink - Play restarted\n");
  213. hr = m_pBuffer->Lock(m_dwLastWrite, dwBytesToFill, &lpStart, &dwStart, &lpEnd, &dwEnd, 0);
  214. }
  215. }
  216. }
  217. if (hr == DS_OK)
  218. {
  219. if (dwStart)
  220. {
  221. memset(lpStart, 0, dwStart);
  222. }
  223. if (dwEnd)
  224. {
  225. memset(lpEnd, 0, dwEnd);
  226. }
  227. m_pBuffer->Unlock(lpStart, dwStart, lpEnd, dwEnd);
  228. }
  229. else
  230. {
  231. Trace(2, "Warning: SynthSink - Failed to lock DS buffer: %x\n", hr);
  232. }
  233. }
  234. else
  235. {
  236. Trace(2, "Warning: SynthSink - Failed to lock DS buffer: %x\n", hr);
  237. }
  238. }
  239. }
  240. else
  241. {
  242. if (hr == DSERR_BUFFERLOST)
  243. {
  244. Trace(2, "Warning: SynthSink - Buffer lost on GetCurrentPosition\n");
  245. hr = m_pBuffer->Restore();
  246. if (hr == DS_OK)
  247. {
  248. Trace(2, "Warning: SynthSink - Buffer restored\n");
  249. hr = m_pBuffer->Play(0, 0, DSBPLAY_LOOPING);
  250. if (hr == DS_OK)
  251. {
  252. Trace(2, "Warning: SynthSink - Play restarted\n");
  253. }
  254. }
  255. }
  256. else
  257. {
  258. Trace(0, "Error: SynthSink - Failed to get DS buffer position, error code: %lx\n", hr);
  259. }
  260. }
  261. ::LeaveCriticalSection(&m_CriticalSection);
  262. }
  263. void CDSLinkList::SynthProc()
  264. {
  265. for (;;)
  266. {
  267. if (m_fPleaseDie)
  268. {
  269. m_fPleaseDie = FALSE;
  270. break;
  271. }
  272. for (DWORD dwX = 0; dwX < m_dwCount; dwX++)
  273. {
  274. ::EnterCriticalSection(&m_CriticalSection);
  275. CDSLink *pLink = GetItem(dwX);
  276. ::LeaveCriticalSection(&m_CriticalSection);
  277. if (pLink)
  278. {
  279. if (pLink->m_fActive)
  280. {
  281. pLink->SynthProc();
  282. }
  283. }
  284. }
  285. if (m_dwResolution < 2) m_dwResolution = 2;
  286. if (m_dwResolution > 100) m_dwResolution = 100;
  287. WaitForSingleObject(m_hEvent, m_dwResolution);
  288. }
  289. }
  290. static DWORD WINAPI SynthThread (LPVOID lpThreadParameter)
  291. {
  292. CDSLinkList *pLinkList = (CDSLinkList *) lpThreadParameter;
  293. pLinkList->SynthProc();
  294. return 0;
  295. }
  296. HRESULT CDSLink::Connect()
  297. {
  298. if (!m_pSynth)
  299. {
  300. Trace(0, "Error: SynthSink - Activation failed, SynthSink not initialized\n");
  301. return DMUS_E_SYNTHNOTCONFIGURED;
  302. }
  303. if (!m_pDSound)
  304. {
  305. Trace(0, "Error: SynthSink - Activation failed, IDirectSound not set\n");
  306. return DMUS_E_DSOUND_NOT_SET;
  307. }
  308. if (!IsValidFormat(&m_wfSynth))
  309. {
  310. Trace(0, "Error: SynthSink - Activation failed, format not initialized/valid\n");
  311. return DMUS_E_SYNTHNOTCONFIGURED;
  312. }
  313. if (!m_pIMasterClock)
  314. {
  315. Trace(0, "Error: SynthSink - Activation failed, master clock not set\n");
  316. return DMUS_E_NO_MASTER_CLOCK;
  317. }
  318. if (m_fActive)
  319. {
  320. Trace(0, "Error: SynthSink - Activation failed, already active\n");
  321. return DMUS_E_SYNTHACTIVE;
  322. }
  323. assert(!m_pBuffer);
  324. HRESULT hr = E_FAIL;
  325. ::EnterCriticalSection(&m_CriticalSection);
  326. if (!m_pExtBuffer)
  327. {
  328. DSBUFFERDESC dsbdesc;
  329. memset(&dsbdesc, 0, sizeof(dsbdesc));
  330. dsbdesc.dwSize = sizeof(dsbdesc);
  331. dsbdesc.dwFlags = DSBCAPS_PRIMARYBUFFER;
  332. // create primary buffer
  333. if (SUCCEEDED(m_pDSound->CreateSoundBuffer(&dsbdesc, &m_pPrimary, NULL)))
  334. {
  335. WAVEFORMATEX wfPrimary;
  336. memset(&wfPrimary, 0, sizeof(wfPrimary));
  337. if (SUCCEEDED(m_pPrimary->GetFormat(&wfPrimary, sizeof(wfPrimary), NULL)))
  338. {
  339. assert(wfPrimary.wFormatTag == WAVE_FORMAT_PCM);
  340. BOOL fUpgrade = FALSE;
  341. if (wfPrimary.nChannels < m_wfSynth.nChannels)
  342. {
  343. wfPrimary.nChannels = m_wfSynth.nChannels;
  344. fUpgrade = TRUE;
  345. }
  346. if (wfPrimary.nSamplesPerSec < m_wfSynth.nSamplesPerSec)
  347. {
  348. wfPrimary.nSamplesPerSec = m_wfSynth.nSamplesPerSec;
  349. fUpgrade = TRUE;
  350. }
  351. if (wfPrimary.wBitsPerSample < m_wfSynth.wBitsPerSample)
  352. {
  353. wfPrimary.wBitsPerSample = m_wfSynth.wBitsPerSample;
  354. fUpgrade = TRUE;
  355. }
  356. if (fUpgrade)
  357. {
  358. wfPrimary.nBlockAlign = wfPrimary.nChannels * (wfPrimary.wBitsPerSample / 8);
  359. wfPrimary.nAvgBytesPerSec = wfPrimary.nSamplesPerSec * wfPrimary.nBlockAlign;
  360. // the existing format is of lesser quality than we desire, so let's upgrade it
  361. if (FAILED(hr = m_pPrimary->SetFormat( &wfPrimary )))
  362. {
  363. if (hr == DSERR_PRIOLEVELNEEDED)
  364. {
  365. // okay, so maybe the app doen't want us changing primary buffer
  366. Trace(2, "Error: SynthSink - SetFormat on primary buffer failed, lacking priority\n");
  367. hr = S_OK;
  368. }
  369. else
  370. {
  371. Trace(0, "Error: SynthSink - Activation failed, couldn't set primary buffer format\n");
  372. m_pPrimary->Release();
  373. m_pPrimary = NULL;
  374. m_pBuffer = NULL;
  375. hr = E_UNEXPECTED;
  376. }
  377. }
  378. }
  379. else
  380. {
  381. hr = S_OK;
  382. }
  383. if (SUCCEEDED(hr))
  384. {
  385. hr = E_FAIL;
  386. memset(&dsbdesc, 0, sizeof(dsbdesc));
  387. dsbdesc.dwSize = sizeof(dsbdesc);
  388. // need default controls (pan, volume, frequency).
  389. dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_GLOBALFOCUS;
  390. // N-second buffer.
  391. dsbdesc.dwBufferBytes = DSBUFFER_LENGTH_SEC * m_wfSynth.nAvgBytesPerSec;
  392. dsbdesc.lpwfxFormat = (LPWAVEFORMATEX)&m_wfSynth;
  393. if (SUCCEEDED(m_pDSound->CreateSoundBuffer(&dsbdesc, &m_pBuffer, NULL)))
  394. {
  395. hr = S_OK;
  396. }
  397. else
  398. {
  399. m_pBuffer = NULL;
  400. if (m_pPrimary)
  401. {
  402. m_pPrimary->Release(); m_pPrimary = NULL;
  403. }
  404. Trace(0, "Error: SynthSink - Activation failed, couldn't create secondary buffer\n");
  405. hr = E_UNEXPECTED;
  406. }
  407. }
  408. }
  409. else
  410. {
  411. Trace(0, "Error: SynthSink - Activation failed, couldn't get primary buffer format\n");
  412. hr = E_UNEXPECTED;
  413. }
  414. }
  415. else
  416. {
  417. Trace(0, "Error: SynthSink - Activation failed, couldn't create primary buffer\n");
  418. hr = E_UNEXPECTED;
  419. }
  420. }
  421. else
  422. {
  423. m_pBuffer = m_pExtBuffer;
  424. m_pBuffer->AddRef();
  425. }
  426. if (m_pBuffer)
  427. {
  428. DSBCAPS dsbcaps;
  429. memset(&dsbcaps, 0, sizeof(dsbcaps));
  430. dsbcaps.dwSize = sizeof(dsbcaps);
  431. if (SUCCEEDED(m_pBuffer->GetCaps(&dsbcaps)))
  432. {
  433. DSCAPS dsCaps ;
  434. memset( &dsCaps, 0, sizeof(DSCAPS) );
  435. dsCaps.dwSize = sizeof(DSCAPS);
  436. if (SUCCEEDED(m_pDSound->GetCaps(&dsCaps)))
  437. {
  438. DWORD dwMinLatency; // ms
  439. // Check for Dsound on top of Wave...
  440. if (dsCaps.dwFlags & DSCAPS_EMULDRIVER)
  441. {
  442. dwMinLatency = 240;
  443. }
  444. else
  445. {
  446. dwMinLatency = 80;
  447. }
  448. DWORD dwGetLatency = dwMinLatency;
  449. if (GetRegValueDword(TEXT("Software\\Microsoft\\DirectMusic"),
  450. TEXT("DSLMinLatency"),
  451. &dwGetLatency))
  452. {
  453. Trace(4, "SynthSink: Registry set to change latency to %ld\n", dwGetLatency);
  454. dwMinLatency = dwGetLatency;
  455. }
  456. m_dwWriteTo = SampleAlign((500 + (m_wfSynth.nAvgBytesPerSec * dwMinLatency)) / 1000);
  457. Trace(4, "SynthSink: Set Latency to %lu\n", dwMinLatency);
  458. m_dwBufferSize = dsbcaps.dwBufferBytes;
  459. m_dwLastWrite = 0;
  460. m_dwLastPlay = 0;
  461. m_llAbsPlay = 0;
  462. // fill initial buffer with silence
  463. LPVOID lpStart, lpEnd;
  464. DWORD dwStart, dwEnd;
  465. if (SUCCEEDED(m_pBuffer->Lock(0, m_dwBufferSize, &lpStart, &dwStart, &lpEnd, &dwEnd, 0)))
  466. {
  467. if (dwStart)
  468. {
  469. memset(lpStart, 0, dwStart);
  470. }
  471. if (dwEnd)
  472. {
  473. memset(lpEnd, 0, dwEnd);
  474. }
  475. m_pBuffer->Unlock(lpStart, dwStart, lpEnd, dwEnd);
  476. if (SUCCEEDED(m_pBuffer->Play(0, 0, DSBPLAY_LOOPING)))
  477. {
  478. g_DSLinkList.ActivateLink(this);
  479. hr = S_OK;
  480. }
  481. else
  482. {
  483. Trace(0, "Error: SynthSink - Activation failed, couldn't start buffer\n");
  484. hr = E_UNEXPECTED;
  485. }
  486. }
  487. else
  488. {
  489. Trace(0, "Error: SynthSink - Activation failed, couldn't lock buffer\n");
  490. hr = E_UNEXPECTED;
  491. }
  492. }
  493. else
  494. {
  495. Trace(0, "Error: SynthSink - Activation failed, couldn't get DS caps\n");
  496. hr = E_UNEXPECTED;
  497. }
  498. }
  499. else
  500. {
  501. Trace(0, "Error: SynthSink - Activation failed, couldn't get buffer caps\n");
  502. hr = E_UNEXPECTED;
  503. }
  504. }
  505. if (FAILED(hr))
  506. {
  507. // Clean up
  508. //
  509. if (m_pBuffer)
  510. {
  511. m_pBuffer->Stop();
  512. m_pBuffer->Release();
  513. m_pBuffer = NULL;
  514. }
  515. if (m_pPrimary)
  516. {
  517. m_pPrimary->Release();
  518. m_pPrimary = NULL;
  519. }
  520. m_Clock.Stop();
  521. Clear();
  522. }
  523. ::LeaveCriticalSection(&m_CriticalSection);
  524. if (SUCCEEDED(hr))
  525. {
  526. // wait until the pump is primed
  527. for (WORD wRetry = 0; wRetry < 10 && !m_llAbsWrite; wRetry++)
  528. {
  529. Sleep(10);
  530. }
  531. if (m_llAbsWrite)
  532. {
  533. Trace(3, "Warning: SynthSink - Pump is primed\n");
  534. }
  535. else
  536. {
  537. Trace(0, "Error: SynthSink - Pump is NOT primed\n");
  538. }
  539. }
  540. return hr;
  541. }
  542. HRESULT CDSLink::Disconnect()
  543. {
  544. // stop the buffer right away!
  545. ::EnterCriticalSection(&m_CriticalSection);
  546. if (m_pBuffer)
  547. {
  548. // write silence to prevent DSound blip bug if reactivated
  549. LPVOID lpStart, lpEnd;
  550. DWORD dwStart, dwEnd;
  551. if (SUCCEEDED(m_pBuffer->Lock(0, m_dwBufferSize, &lpStart, &dwStart, &lpEnd, &dwEnd, 0))) // REVIEW: don't need full buffer size
  552. {
  553. if (dwStart)
  554. {
  555. memset(lpStart, 0, dwStart);
  556. }
  557. if (dwEnd)
  558. {
  559. memset(lpEnd, 0, dwEnd);
  560. }
  561. m_pBuffer->Unlock(lpStart, dwStart, lpEnd, dwEnd);
  562. Sleep(50); // found experimentally
  563. }
  564. m_pBuffer->Stop();
  565. }
  566. m_Clock.Stop();
  567. ::LeaveCriticalSection(&m_CriticalSection);
  568. g_DSLinkList.DeactivateLink(this);
  569. ::EnterCriticalSection(&m_CriticalSection);
  570. if (m_pBuffer)
  571. {
  572. m_pBuffer->Release(); m_pBuffer = NULL;
  573. }
  574. if (m_pPrimary)
  575. {
  576. m_pPrimary->Release(); m_pPrimary = NULL;
  577. }
  578. Clear();
  579. ::LeaveCriticalSection(&m_CriticalSection);
  580. return S_OK;
  581. }
  582. void CDSLink::Clear()
  583. {
  584. m_llAbsPlay = 0; // Absolute point where play head is.
  585. m_dwLastPlay = 0; // Last point where play head was.
  586. m_llAbsWrite = 0; // Absolute point we've written up to.
  587. m_dwBufferSize = 0; // Size of buffer.
  588. m_dwLastWrite = 0; // Last position we wrote to in buffer.
  589. m_dwWriteTo = 1000; // Distance between write head and where we are writing.
  590. }
  591. CDSLink::CDSLink()
  592. {
  593. InterlockedIncrement(&g_cComponent);
  594. m_fCSInitialized = FALSE;
  595. ::InitializeCriticalSection(&m_CriticalSection);
  596. m_fCSInitialized = TRUE;
  597. memset(&m_wfSynth, 0, sizeof(m_wfSynth));
  598. m_pIMasterClock = NULL;
  599. m_cRef = 0;
  600. m_pSynth = NULL; // Reference back to parent Synth.
  601. m_pDSound = NULL;
  602. m_pPrimary = NULL;
  603. m_pBuffer = NULL;
  604. m_pExtBuffer = NULL;
  605. m_dwWriteFromMax = 0;
  606. Clear();
  607. m_Clock.Stop();
  608. m_fActive = FALSE;
  609. }
  610. CDSLink::~CDSLink()
  611. {
  612. if (m_fCSInitialized)
  613. {
  614. ::EnterCriticalSection(&m_CriticalSection);
  615. if (m_pIMasterClock)
  616. {
  617. m_pIMasterClock->Release(); m_pIMasterClock = NULL;
  618. }
  619. ::LeaveCriticalSection(&m_CriticalSection);
  620. Disconnect();
  621. if (m_pExtBuffer)
  622. {
  623. m_pExtBuffer->Release(); m_pExtBuffer = NULL;
  624. }
  625. if (m_pDSound)
  626. {
  627. m_pDSound->Release(); m_pDSound = NULL;
  628. }
  629. ::DeleteCriticalSection(&m_CriticalSection);
  630. }
  631. InterlockedDecrement(&g_cComponent);
  632. }
  633. CDSLinkList::CDSLinkList()
  634. {
  635. m_fOpened = FALSE;
  636. m_fPleaseDie = FALSE;
  637. m_hThread = NULL; // Handle for synth thread.
  638. m_dwThread = 0; // ID for thread.
  639. m_hEvent = NULL; // Used to signal thread.
  640. m_dwCount = 0;
  641. m_dwResolution = 20;
  642. }
  643. BOOL CDSLinkList::OpenUp()
  644. {
  645. if (m_fOpened)
  646. {
  647. Trace(1, "Warning: SynthSink - Already opened\n");
  648. return TRUE;
  649. }
  650. m_fOpened = TRUE;
  651. if (!GetRegValueDword(TEXT("Software\\Microsoft\\DirectMusic"),
  652. TEXT("DSLResolution"),
  653. &m_dwResolution))
  654. {
  655. m_dwResolution = 20;
  656. }
  657. try
  658. {
  659. ::InitializeCriticalSection(&m_CriticalSection);
  660. }
  661. catch( ... )
  662. {
  663. m_fOpened = FALSE;
  664. return FALSE;
  665. }
  666. return TRUE;
  667. }
  668. void CDSLinkList::CloseDown()
  669. {
  670. if (m_dwCount)
  671. {
  672. CDSLink *pLink;
  673. if (pLink = GetHead())
  674. {
  675. Trace(0, "Error: SynthSink - Process Detach with port still active. May crash on exit.\n");
  676. }
  677. }
  678. if (!m_fOpened)
  679. {
  680. Trace(2, "Warning: SynthSink - Process Detach, ports all deactivated\n");
  681. }
  682. else
  683. {
  684. m_fOpened = FALSE;
  685. ::DeleteCriticalSection(&m_CriticalSection);
  686. }
  687. }
  688. void CDSLinkList::ActivateLink(CDSLink *pLink)
  689. {
  690. ::EnterCriticalSection(&m_CriticalSection);
  691. if (!pLink->m_fActive)
  692. {
  693. if (m_dwCount == 0)
  694. {
  695. m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  696. m_hThread = CreateThread(NULL, 0, SynthThread, this, 0, &m_dwThread);
  697. if (m_hThread)
  698. {
  699. if (!SetThreadPriority(m_hThread, THREAD_PRIORITY_TIME_CRITICAL))
  700. {
  701. Trace(0, "Error: SynthSink - Activate couldn't set thread priority\n");
  702. }
  703. }
  704. else
  705. {
  706. Trace(0, "Error: SynthSink - Activate couldn't create thread\n");
  707. }
  708. }
  709. if (!IsMember(pLink))
  710. {
  711. m_dwCount++;
  712. AddTail(pLink);
  713. }
  714. pLink->m_fActive = TRUE;
  715. }
  716. ::LeaveCriticalSection(&m_CriticalSection);
  717. }
  718. void CDSLinkList::DeactivateLink(CDSLink *pLink)
  719. {
  720. ::EnterCriticalSection(&m_CriticalSection);
  721. if (pLink->m_fActive)
  722. {
  723. if (m_dwCount)
  724. {
  725. Remove(pLink);
  726. m_dwCount--;
  727. }
  728. pLink->m_fActive = FALSE;
  729. if (m_dwCount == 0)
  730. {
  731. if (m_hThread && m_hEvent)
  732. {
  733. m_fPleaseDie = TRUE;
  734. SetEvent(m_hEvent);
  735. if (WaitForSingleObject(m_hThread, 10000) == WAIT_TIMEOUT)
  736. {
  737. Trace(0, "Error: SynthSink - Deactivate, thread did not exit\n");
  738. }
  739. }
  740. if (m_hEvent)
  741. {
  742. CloseHandle(m_hEvent);
  743. m_hEvent = NULL;
  744. }
  745. if(m_hThread)
  746. {
  747. CloseHandle(m_hThread);
  748. m_hThread = NULL;
  749. }
  750. }
  751. }
  752. ::LeaveCriticalSection(&m_CriticalSection);
  753. }
  754. CDSLink * CDSLink::GetNext()
  755. {
  756. return (CDSLink *) CListItem::GetNext();
  757. }
  758. void CDSLinkList::AddTail(CDSLink *pNode)
  759. {
  760. CList::AddTail((CListItem *) pNode);
  761. }
  762. void CDSLinkList::Remove(CDSLink *pNode)
  763. {
  764. CList::Remove((CListItem *) pNode);
  765. }
  766. CDSLink * CDSLinkList::GetHead()
  767. {
  768. return (CDSLink *)CList::GetHead();
  769. }
  770. CDSLink * CDSLinkList::RemoveHead()
  771. {
  772. return (CDSLink *)CList::RemoveHead();
  773. }
  774. CDSLink * CDSLinkList::GetItem(LONG index)
  775. {
  776. return (CDSLink *)CList::GetItem(index);
  777. }
  778. STDMETHODIMP CDSLink::QueryInterface(const IID &iid, void **ppv)
  779. {
  780. V_INAME(IDirectMusicSynthSink::QueryInterface);
  781. V_REFGUID(iid);
  782. V_PTRPTR_WRITE(ppv);
  783. if (iid == IID_IUnknown || iid == IID_IDirectMusicSynthSink) {
  784. *ppv = static_cast<IDirectMusicSynthSink*>(this);
  785. }
  786. else if (iid == IID_IKsControl)
  787. {
  788. *ppv = static_cast<IKsControl*>(this);
  789. }
  790. else
  791. {
  792. *ppv = NULL;
  793. return E_NOINTERFACE;
  794. }
  795. reinterpret_cast<IUnknown*>(this)->AddRef();
  796. return S_OK;
  797. }
  798. STDMETHODIMP_(ULONG) CDSLink::AddRef()
  799. {
  800. return InterlockedIncrement(&m_cRef);
  801. }
  802. STDMETHODIMP_(ULONG) CDSLink::Release()
  803. {
  804. if (!InterlockedDecrement(&m_cRef)) {
  805. delete this;
  806. return 0;
  807. }
  808. return m_cRef;
  809. }
  810. STDMETHODIMP CDSLink::Init(
  811. IDirectMusicSynth *pSynth) // <i IDirectMusicSynth> to connect to.
  812. {
  813. m_pSynth = pSynth;
  814. m_Clock.Init(this);
  815. return S_OK;
  816. }
  817. STDMETHODIMP CDSLink::SetMasterClock(
  818. IReferenceClock *pClock) // Master clock to synchronize to.
  819. {
  820. V_INAME(IDirectMusicSynthSink::SetMasterClock);
  821. V_INTERFACE(pClock);
  822. if (m_pIMasterClock)
  823. {
  824. m_pIMasterClock->Release(); m_pIMasterClock = NULL;
  825. }
  826. m_pIMasterClock = pClock;
  827. if (pClock)
  828. {
  829. pClock->AddRef();
  830. }
  831. return S_OK;
  832. }
  833. STDMETHODIMP CDSLink::GetLatencyClock(
  834. IReferenceClock **ppClock) // Returned <i IReferenceClock> interface for latency clock.
  835. {
  836. V_INAME(IDirectMusicSynthSink::GetLatencyClock);
  837. V_PTR_WRITE(ppClock, IReferenceClock *);
  838. return m_Clock.QueryInterface(IID_IReferenceClock, (void **)ppClock);
  839. }
  840. STDMETHODIMP CDSLink::Activate(
  841. BOOL fEnable) // Whether to activate or deactivate audio.
  842. {
  843. if (fEnable)
  844. {
  845. return Connect();
  846. }
  847. return Disconnect();
  848. }
  849. STDMETHODIMP CDSLink::SampleToRefTime(
  850. LONGLONG llSampleTime, // Incoming time, in sample position.
  851. REFERENCE_TIME *prfTime) // Outgoing time, in REFERENCE_TIME units, relative to master clock.
  852. {
  853. V_INAME(IDirectMusicSynthSink::SampleToRefTime);
  854. V_PTR_WRITE(prfTime, REFERENCE_TIME);
  855. m_SampleClock.SampleToRefTime(llSampleTime, prfTime);
  856. return S_OK;
  857. }
  858. STDMETHODIMP CDSLink::RefTimeToSample(
  859. REFERENCE_TIME rfTime, // Incoming time, in REFERENCE_TIME units.
  860. LONGLONG *pllSampleTime) // Outgoing equivalent sample position.
  861. {
  862. V_INAME(IDirectMusicSynthSink::RefTimeToSample);
  863. V_PTR_WRITE(pllSampleTime, LONGLONG);
  864. *pllSampleTime = m_SampleClock.RefTimeToSample(rfTime);
  865. return S_OK;
  866. }
  867. STDMETHODIMP CDSLink::SetDirectSound(
  868. LPDIRECTSOUND pDirectSound, // IDirectSound instance (required).
  869. LPDIRECTSOUNDBUFFER pDirectSoundBuffer) // DirectSound buffer to render to (optional).
  870. {
  871. V_INAME(IDirectMusicSynthSink::SetDirectSound);
  872. V_INTERFACE_OPT(pDirectSound);
  873. V_INTERFACE_OPT(pDirectSoundBuffer);
  874. if (m_fActive)
  875. {
  876. Trace(0, "Error: SynthSink - SetDirectSound failed, can't call while sink is active\n");
  877. return DMUS_E_SYNTHACTIVE;
  878. }
  879. HRESULT hr = E_FAIL;
  880. ::EnterCriticalSection(&m_CriticalSection);
  881. if (m_pExtBuffer)
  882. {
  883. m_pExtBuffer->Release(); m_pExtBuffer = NULL;
  884. }
  885. if (m_pDSound)
  886. {
  887. m_pDSound->Release();
  888. }
  889. m_pDSound = pDirectSound;
  890. if (m_pDSound)
  891. {
  892. m_pDSound->AddRef();
  893. if (m_pSynth)
  894. {
  895. DWORD dwWaveFormatExSize = sizeof(m_wfSynth);
  896. if (SUCCEEDED(m_pSynth->GetFormat(&m_wfSynth, &dwWaveFormatExSize))) // update current synth format
  897. {
  898. if (IsValidFormat(&m_wfSynth))
  899. {
  900. m_pExtBuffer = pDirectSoundBuffer;
  901. if (m_pExtBuffer)
  902. {
  903. m_pExtBuffer->AddRef();
  904. // check format
  905. WAVEFORMATEX wfExt;
  906. memset(&wfExt, 0, sizeof(wfExt));
  907. if (SUCCEEDED(m_pExtBuffer->GetFormat(&wfExt, sizeof(wfExt), NULL)))
  908. {
  909. // must exactly match synth format
  910. if (wfExt.wFormatTag == m_wfSynth.wFormatTag &&
  911. wfExt.nChannels == m_wfSynth.nChannels &&
  912. wfExt.nSamplesPerSec == m_wfSynth.nSamplesPerSec &&
  913. wfExt.nBlockAlign == m_wfSynth.nBlockAlign &&
  914. wfExt.nAvgBytesPerSec == m_wfSynth.nAvgBytesPerSec &&
  915. wfExt.wBitsPerSample == m_wfSynth.wBitsPerSample)
  916. {
  917. DSBCAPS dsbcaps;
  918. dsbcaps.dwSize = sizeof(dsbcaps);
  919. if (SUCCEEDED(m_pExtBuffer->GetCaps(&dsbcaps)))
  920. {
  921. // check for invalid flags
  922. if (dsbcaps.dwFlags & (DSBCAPS_PRIMARYBUFFER | DSBCAPS_STATIC))
  923. {
  924. Trace(0, "Error: SynthSink - SetDirectSound failed, buffer not secondary streaming\n");
  925. hr = DMUS_E_INVALIDBUFFER;
  926. }
  927. // is buffer too small?
  928. else if (dsbcaps.dwBufferBytes < m_wfSynth.nAvgBytesPerSec)
  929. {
  930. Trace(0, "Error: SynthSink - SetDirectSound failed, buffer too small\n");
  931. hr = DMUS_E_INSUFFICIENTBUFFER;
  932. }
  933. else
  934. {
  935. hr = S_OK;
  936. }
  937. }
  938. else
  939. {
  940. Trace(0, "Error: SynthSink - SetDirectSound failed, couldn't get buffer caps\n");
  941. hr = E_UNEXPECTED;
  942. }
  943. }
  944. else
  945. {
  946. Trace(0, "Error: SynthSink - SetDirectSound failed, format doesn't match synth\n");
  947. hr = DMUS_E_WAVEFORMATNOTSUPPORTED;
  948. }
  949. }
  950. else
  951. {
  952. Trace(0, "Error: SynthSink - SetDirectSound failed, couldn't get buffer format\n");
  953. hr = E_UNEXPECTED;
  954. }
  955. }
  956. else
  957. {
  958. hr = S_OK;
  959. }
  960. }
  961. else
  962. {
  963. Trace(0, "Error: SynthSink - SetDirectSound failed, synth format not valid for this sink\n");
  964. hr = E_UNEXPECTED;
  965. }
  966. }
  967. else
  968. {
  969. Trace(0, "Error: SynthSink - SetDirectSound failed, couldn't get synth format\n");
  970. hr = E_UNEXPECTED;
  971. }
  972. }
  973. else
  974. {
  975. Trace(0, "Error: SynthSink - SetDirectSound failed, sink not initialized\n");
  976. hr = DMUS_E_SYNTHNOTCONFIGURED;
  977. }
  978. if (FAILED(hr))
  979. {
  980. if (m_pExtBuffer)
  981. {
  982. m_pExtBuffer->Release(); m_pExtBuffer = NULL;
  983. }
  984. m_pDSound->Release(); m_pDSound = NULL;
  985. }
  986. }
  987. else
  988. {
  989. hr = S_OK;
  990. }
  991. ::LeaveCriticalSection(&m_CriticalSection);
  992. return hr;
  993. }
  994. STDMETHODIMP CDSLink::GetDesiredBufferSize(
  995. LPDWORD pdwBufferSizeInSamples)
  996. {
  997. V_INAME(IDirectMusicSynthSink::GetDesiredBufferSize);
  998. V_PTR_WRITE(pdwBufferSizeInSamples, DWORD);
  999. if (!m_pSynth)
  1000. {
  1001. Trace(0, "Error: SynthSink - GetDesiredBufferSize, sink not initialized\n");
  1002. return DMUS_E_SYNTHNOTCONFIGURED;
  1003. }
  1004. HRESULT hr = E_FAIL;
  1005. WAVEFORMATEX wfx;
  1006. DWORD dwWaveFormatExSize = sizeof(wfx);
  1007. memset(&wfx, 0, sizeof(wfx));
  1008. ::EnterCriticalSection(&m_CriticalSection);
  1009. if (SUCCEEDED(m_pSynth->GetFormat(&wfx, &dwWaveFormatExSize)))
  1010. {
  1011. *pdwBufferSizeInSamples = DSBUFFER_LENGTH_SEC * wfx.nAvgBytesPerSec;
  1012. hr = S_OK;
  1013. }
  1014. else
  1015. {
  1016. Trace(0, "Error: SynthSink - GetDesiredBufferSize, couldn't get synth format\n");
  1017. hr = E_UNEXPECTED;
  1018. }
  1019. ::LeaveCriticalSection(&m_CriticalSection);
  1020. return hr;
  1021. }
  1022. CClock::CClock()
  1023. {
  1024. m_pDSLink = NULL;
  1025. m_fStopped = TRUE;
  1026. }
  1027. void CClock::Init(CDSLink *pDSLink)
  1028. {
  1029. m_pDSLink = pDSLink;
  1030. }
  1031. HRESULT CClock::QueryInterface( REFIID riid, LPVOID FAR* ppvObj )
  1032. {
  1033. V_INAME(IReferenceClock::QueryInterface);
  1034. V_REFGUID(riid);
  1035. V_PTRPTR_WRITE(ppvObj);
  1036. if( ::IsEqualIID( riid, IID_IReferenceClock ) ||
  1037. ::IsEqualIID( riid, IID_IUnknown ) )
  1038. {
  1039. AddRef();
  1040. *ppvObj = this;
  1041. return S_OK;
  1042. }
  1043. *ppvObj = NULL;
  1044. return E_NOINTERFACE;
  1045. }
  1046. ULONG CClock::AddRef()
  1047. {
  1048. if (m_pDSLink)
  1049. {
  1050. return m_pDSLink->AddRef();
  1051. }
  1052. else return 0;
  1053. }
  1054. ULONG CClock::Release()
  1055. {
  1056. if (m_pDSLink)
  1057. {
  1058. return m_pDSLink->Release();
  1059. }
  1060. else return 0;
  1061. }
  1062. HRESULT STDMETHODCALLTYPE CClock::AdviseTime( REFERENCE_TIME /*baseTime*/,
  1063. REFERENCE_TIME /*streamTime*/,
  1064. HANDLE /*hEvent*/,
  1065. DWORD __RPC_FAR* /*pdwAdviseCookie*/)
  1066. {
  1067. return E_NOTIMPL;
  1068. }
  1069. HRESULT STDMETHODCALLTYPE CClock::AdvisePeriodic( REFERENCE_TIME /*startTime*/,
  1070. REFERENCE_TIME /*periodTime*/,
  1071. HANDLE /*hSemaphore*/,
  1072. DWORD __RPC_FAR* /*pdwAdviseCookie*/)
  1073. {
  1074. return E_NOTIMPL;
  1075. }
  1076. HRESULT STDMETHODCALLTYPE CClock::Unadvise( DWORD /*dwAdviseCookie*/ )
  1077. {
  1078. return E_NOTIMPL;
  1079. }
  1080. HRESULT STDMETHODCALLTYPE CClock::GetTime(
  1081. REFERENCE_TIME __RPC_FAR* pTime ) // <t ReferenceTime> structure to hold returned time.
  1082. {
  1083. HRESULT hr = E_FAIL;
  1084. if( pTime == NULL )
  1085. {
  1086. return E_INVALIDARG;
  1087. }
  1088. if (m_pDSLink != NULL)
  1089. {
  1090. if (m_pDSLink->m_fActive && !m_fStopped)
  1091. {
  1092. REFERENCE_TIME rtCompare;
  1093. if (m_pDSLink->m_pIMasterClock)
  1094. {
  1095. m_pDSLink->m_pIMasterClock->GetTime(&rtCompare);
  1096. ::EnterCriticalSection(&m_pDSLink->m_CriticalSection); // make sure SynthProc is not about to update
  1097. hr = m_pDSLink->SampleToRefTime(m_pDSLink->ByteToSample(m_pDSLink->m_llAbsWrite), pTime);
  1098. ::LeaveCriticalSection(&m_pDSLink->m_CriticalSection);
  1099. if (FAILED(hr))
  1100. {
  1101. Trace(1, "Error: SynthSink Latency Clock: SampleToRefTime failed\n");
  1102. return hr;
  1103. }
  1104. if (*pTime < rtCompare)
  1105. {
  1106. Trace(3, "Warning: SynthSink Latency Clock off. Latency time is %ldms, Master time is %ldms\n",
  1107. (long) (*pTime / 10000), (long) (rtCompare / 10000));
  1108. *pTime = rtCompare;
  1109. }
  1110. else if (*pTime > (rtCompare + (10000 * 1000)))
  1111. {
  1112. Trace(3, "Warning: SynthSink Latency Clock off. Latency time is %ldms, Master time is %ldms\n",
  1113. (long) (*pTime / 10000), (long) (rtCompare / 10000));
  1114. *pTime = rtCompare + (10000 * 1000);
  1115. }
  1116. hr = S_OK;
  1117. }
  1118. else
  1119. {
  1120. Trace(2, "Warning: SynthSink Latency Clock - GetTime called with no master clock\n");
  1121. }
  1122. }
  1123. else
  1124. {
  1125. Trace(2, "Warning: SynthSink Latency Clock - GetTime called with synth sink not active\n");
  1126. }
  1127. }
  1128. return hr;
  1129. }
  1130. void CClock::Stop()
  1131. {
  1132. m_fStopped = TRUE;
  1133. }
  1134. void CClock::Start()
  1135. {
  1136. m_fStopped = FALSE;
  1137. }
  1138. static DWORD g_dwPropFalse = FALSE;
  1139. static DWORD g_dwPropTrue = TRUE;
  1140. SINKPROPERTY CDSLink::m_aProperty[] =
  1141. {
  1142. {
  1143. &GUID_DMUS_PROP_SynthSink_DSOUND,
  1144. 0,
  1145. KSPROPERTY_SUPPORT_GET,
  1146. SINKPROP_F_STATIC,
  1147. &g_dwPropTrue,
  1148. sizeof(g_dwPropTrue),
  1149. NULL
  1150. },
  1151. {
  1152. &GUID_DMUS_PROP_SynthSink_WAVE,
  1153. 0,
  1154. KSPROPERTY_SUPPORT_GET,
  1155. SINKPROP_F_STATIC,
  1156. &g_dwPropFalse,
  1157. sizeof(g_dwPropFalse),
  1158. NULL
  1159. },
  1160. {
  1161. &GUID_DMUS_PROP_WriteLatency,
  1162. 0,
  1163. KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET,
  1164. SINKPROP_F_FNHANDLER,
  1165. NULL,
  1166. 0,
  1167. HandleLatency
  1168. },
  1169. {
  1170. &GUID_DMUS_PROP_WritePeriod,
  1171. 0,
  1172. KSPROPERTY_SUPPORT_GET | KSPROPERTY_SUPPORT_SET,
  1173. SINKPROP_F_STATIC,
  1174. &g_DSLinkList.m_dwResolution,
  1175. sizeof(g_DSLinkList.m_dwResolution),
  1176. NULL
  1177. },
  1178. {
  1179. &GUID_DMUS_PROP_SinkUsesDSound,
  1180. 0,
  1181. KSPROPERTY_SUPPORT_GET,
  1182. SINKPROP_F_STATIC,
  1183. &g_dwPropTrue,
  1184. sizeof(g_dwPropTrue),
  1185. NULL
  1186. }
  1187. };
  1188. HRESULT CDSLink::HandleLatency(ULONG ulId, BOOL fSet, LPVOID pbBuffer, PULONG pcbBuffer)
  1189. {
  1190. DWORD dwLatency;
  1191. if (*pcbBuffer != sizeof(dwLatency))
  1192. {
  1193. return E_INVALIDARG;
  1194. }
  1195. if (!m_pSynth || !IsValidFormat(&m_wfSynth))
  1196. {
  1197. return DMUS_E_SYNTHNOTCONFIGURED;
  1198. }
  1199. if (fSet)
  1200. {
  1201. dwLatency = *(DWORD*)pbBuffer;
  1202. if (dwLatency < 5) dwLatency = 5;
  1203. if (dwLatency > 1000) dwLatency = 1000;
  1204. m_dwWriteTo = SampleAlign((500 + (m_wfSynth.nAvgBytesPerSec * dwLatency)) / 1000);
  1205. }
  1206. else
  1207. {
  1208. dwLatency = m_dwWriteTo * 1000;
  1209. if (m_wfSynth.nAvgBytesPerSec)
  1210. {
  1211. dwLatency += m_wfSynth.nAvgBytesPerSec / 2; // Correct rounding error.
  1212. dwLatency /= m_wfSynth.nAvgBytesPerSec;
  1213. }
  1214. else
  1215. {
  1216. dwLatency = 300; // Should never happen, trapped by IsValidFormat().
  1217. }
  1218. *(DWORD*)pbBuffer = dwLatency;
  1219. }
  1220. return S_OK;
  1221. }
  1222. const int CDSLink::m_nProperty = sizeof(m_aProperty) / sizeof(m_aProperty[0]);
  1223. /*
  1224. CDSLink::FindPropertyItem
  1225. Given a GUID and an item ID, find the associated property item in the synth's
  1226. table of SYNPROPERTY's.
  1227. Returns a pointer to the entry or NULL if the item was not found.
  1228. */
  1229. SINKPROPERTY *CDSLink::FindPropertyItem(REFGUID rguid, ULONG ulId)
  1230. {
  1231. SINKPROPERTY *pPropertyItem = &m_aProperty[0];
  1232. SINKPROPERTY *pEndOfItems = pPropertyItem + m_nProperty;
  1233. for (; pPropertyItem != pEndOfItems; pPropertyItem++)
  1234. {
  1235. if (*pPropertyItem->pguidPropertySet == rguid &&
  1236. pPropertyItem->ulId == ulId)
  1237. {
  1238. return pPropertyItem;
  1239. }
  1240. }
  1241. return NULL;
  1242. }
  1243. #define KS_VALID_FLAGS (KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_GET| KSPROPERTY_TYPE_BASICSUPPORT)
  1244. STDMETHODIMP CDSLink::KsProperty(
  1245. PKSPROPERTY pPropertyIn, ULONG ulPropertyLength,
  1246. LPVOID pvPropertyData, ULONG ulDataLength,
  1247. PULONG pulBytesReturned)
  1248. {
  1249. HRESULT hr = E_FAIL;
  1250. V_INAME(DirectMusicSynthPort::IKsContol::KsProperty);
  1251. V_BUFPTR_WRITE(pPropertyIn, ulPropertyLength);
  1252. V_BUFPTR_WRITE_OPT(pvPropertyData, ulDataLength);
  1253. V_PTR_WRITE(pulBytesReturned, ULONG);
  1254. DWORD dwFlags = pPropertyIn->Flags & KS_VALID_FLAGS;
  1255. SINKPROPERTY *pProperty = FindPropertyItem(pPropertyIn->Set, pPropertyIn->Id);
  1256. if (pProperty == NULL)
  1257. {
  1258. Trace(2, "Warning: KsProperty call requested unknown property.\n");
  1259. return DMUS_E_UNKNOWN_PROPERTY;
  1260. }
  1261. if (pvPropertyData == NULL )
  1262. {
  1263. return E_INVALIDARG;
  1264. }
  1265. switch (dwFlags)
  1266. {
  1267. case KSPROPERTY_TYPE_GET:
  1268. if (!(pProperty->ulSupported & KSPROPERTY_SUPPORT_GET))
  1269. {
  1270. Trace(1, "Error: SynthSink does not support Get for the requested property.\n");
  1271. hr = DMUS_E_GET_UNSUPPORTED;
  1272. break;
  1273. }
  1274. if (pProperty->ulFlags & SINKPROP_F_FNHANDLER)
  1275. {
  1276. SINKPROPHANDLER pfn = pProperty->pfnHandler;
  1277. *pulBytesReturned = ulDataLength;
  1278. return (this->*pfn)(pPropertyIn->Id, FALSE, pvPropertyData, pulBytesReturned);
  1279. }
  1280. if (ulDataLength > pProperty->cbPropertyData)
  1281. {
  1282. ulDataLength = pProperty->cbPropertyData;
  1283. }
  1284. CopyMemory(pvPropertyData, pProperty->pPropertyData, ulDataLength);
  1285. *pulBytesReturned = ulDataLength;
  1286. hr = S_OK;
  1287. break;
  1288. case KSPROPERTY_TYPE_SET:
  1289. if (!(pProperty->ulSupported & KSPROPERTY_SUPPORT_SET))
  1290. {
  1291. Trace(1, "Error: SynthSink does not support Set for the requested property.\n");
  1292. hr = DMUS_E_SET_UNSUPPORTED;
  1293. break;
  1294. }
  1295. if (pProperty->ulFlags & SINKPROP_F_FNHANDLER)
  1296. {
  1297. SINKPROPHANDLER pfn = pProperty->pfnHandler;
  1298. hr = (this->*pfn)(pPropertyIn->Id, TRUE, pvPropertyData, &ulDataLength);
  1299. }
  1300. else
  1301. {
  1302. if (ulDataLength > pProperty->cbPropertyData)
  1303. {
  1304. ulDataLength = pProperty->cbPropertyData;
  1305. }
  1306. CopyMemory(pProperty->pPropertyData, pvPropertyData, ulDataLength);
  1307. hr = S_OK;
  1308. }
  1309. break;
  1310. case KSPROPERTY_TYPE_BASICSUPPORT:
  1311. // XXX Find out what convention is for this!!
  1312. //
  1313. if (ulDataLength < sizeof(DWORD) || pvPropertyData == NULL )
  1314. {
  1315. hr = E_INVALIDARG;
  1316. break;
  1317. }
  1318. *(LPDWORD)pvPropertyData = pProperty->ulSupported;
  1319. *pulBytesReturned = sizeof(DWORD);
  1320. hr = S_OK;
  1321. break;
  1322. default:
  1323. Trace(1, "Error: KSProperty failed, Flags must contain one of %s\n"
  1324. "\tKSPROPERTY_TYPE_SET, KSPROPERTY_TYPE_GET, or KSPROPERTY_TYPE_BASICSUPPORT\n");
  1325. hr = E_INVALIDARG;
  1326. break;
  1327. }
  1328. return hr;
  1329. }
  1330. STDMETHODIMP CDSLink::KsMethod(
  1331. PKSMETHOD pMethod, ULONG ulMethodLength,
  1332. LPVOID pvMethodData, ULONG ulDataLength,
  1333. PULONG pulBytesReturned)
  1334. {
  1335. V_INAME(DirectMusicSynth::IKsContol::KsMethod);
  1336. V_BUFPTR_WRITE(pMethod, ulMethodLength);
  1337. V_BUFPTR_WRITE_OPT(pvMethodData, ulDataLength);
  1338. V_PTR_WRITE(pulBytesReturned, ULONG);
  1339. return DMUS_E_UNKNOWN_PROPERTY;
  1340. }
  1341. STDMETHODIMP CDSLink::KsEvent(
  1342. PKSEVENT pEvent, ULONG ulEventLength,
  1343. LPVOID pvEventData, ULONG ulDataLength,
  1344. PULONG pulBytesReturned)
  1345. {
  1346. V_INAME(DirectMusicSynthPort::IKsContol::KsEvent);
  1347. V_BUFPTR_WRITE(pEvent, ulEventLength);
  1348. V_BUFPTR_WRITE_OPT(pvEventData, ulDataLength);
  1349. V_PTR_WRITE(pulBytesReturned, ULONG);
  1350. return DMUS_E_UNKNOWN_PROPERTY;
  1351. }