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.

1013 lines
27 KiB

  1. /*==========================================================================;
  2. *
  3. * Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: fulldup.cpp
  6. * Content: Implements a process that uses DirectSound and
  7. * DirectSoundCapture to test the systems full duplex
  8. * capability. Note that WinMain is in fdtest.cpp, but
  9. * the guts are here.
  10. * History:
  11. * Date By Reason
  12. * ============
  13. * 08/19/99 pnewson created
  14. * 10/28/99 pnewson Bug #113937 audible clicking during full duplex test
  15. * 11/02/99 pnewson Fix: Bug #116365 - using wrong DSBUFFERDESC
  16. * 01/21/2000 pnewson Changed over to using a dpvoice loopback session
  17. * for full duplex testing
  18. * 04/19/2000 pnewson Error handling cleanup
  19. * 07/12/2000 rodtoll Bug #31468 - Add diagnostic spew to logfile to show what is failing the HW Wizard
  20. ***************************************************************************/
  21. #include "dxvtlibpch.h"
  22. #undef DPF_SUBCOMP
  23. #define DPF_SUBCOMP DN_SUBCOMP_VOICE
  24. static HRESULT OpenIPCObjects();
  25. static HRESULT CloseIPCObjects();
  26. static HRESULT CommandLoop(CFullDuplexIPC* lpipcFullDuplex);
  27. static HRESULT DispatchCommand(CFullDuplexIPC* lpipcFullDuplex, SFDTestCommand* pfdtc);
  28. static HRESULT CommandFullDuplexStart(SFDTestCommandFullDuplexStart* pfdtcFullDuplexStart, HRESULT* phrIPC);
  29. static HRESULT CommandFullDuplexStop(SFDTestCommandFullDuplexStop* pfdtcFullDuplexStop, HRESULT* phrIPC);
  30. static HRESULT PlayAndCheckRender(LPDIRECTSOUNDBUFFER lpdsb, HANDLE hEvent);
  31. static HRESULT PlayAndCheckCapture(LPDIRECTSOUNDCAPTUREBUFFER lpdscb, HANDLE hEvent);
  32. static HRESULT AttemptCapture();
  33. // one global struct to store this process's state data.
  34. struct SFullDuplexData
  35. {
  36. LPDIRECTPLAYVOICESERVER lpdpvs;
  37. LPDIRECTPLAYVOICECLIENT lpdpvc;
  38. PDIRECTPLAY8SERVER lpdp8;
  39. };
  40. SFullDuplexData g_FullDuplexData;
  41. #undef DPF_MODNAME
  42. #define DPF_MODNAME "FullDuplexProcess"
  43. HRESULT FullDuplexProcess(HINSTANCE hResDLLInstance, HINSTANCE hPrevInstance, TCHAR *szCmdLine, int iCmdShow)
  44. {
  45. HRESULT hr;
  46. CFullDuplexIPC ipcFullDuplex;
  47. BOOL fIPCInitialized = FALSE;
  48. PDIRECTPLAYVOICECLIENT pdpvClient = NULL;
  49. g_FullDuplexData.lpdp8 = NULL;
  50. DPF_ENTER();
  51. // Create dummy voice object so that voice process state gets initialized
  52. hr = CoCreateInstance( CLSID_DirectPlayVoiceClient, NULL, CLSCTX_INPROC, IID_IDirectPlayVoiceClient, (void **) &pdpvClient );
  53. if( FAILED( hr ) )
  54. {
  55. Diagnostics_Write(DVF_ERRORLEVEL, "Unable to create dummy dp8 object hr: 0x%x", hr);
  56. goto error_cleanup;
  57. }
  58. if (!InitGlobGuard())
  59. {
  60. hr = DVERR_OUTOFMEMORY;
  61. goto error_cleanup;
  62. }
  63. hr = ipcFullDuplex.Init();
  64. if (FAILED(hr))
  65. {
  66. Diagnostics_Write(DVF_ERRORLEVEL, "CIPCFullDuplex::Init() failed, hr: 0x%x", hr);
  67. goto error_cleanup;
  68. }
  69. fIPCInitialized = TRUE;
  70. // Startup DirectPlay once so that we don't have to do it over and over
  71. // again for the test.
  72. hr = StartDirectPlay( &g_FullDuplexData.lpdp8 );
  73. if( FAILED( hr ) )
  74. {
  75. Diagnostics_Write(DVF_ERRORLEVEL, "Failed to start transport hr: 0x%x", hr);
  76. goto error_cleanup;
  77. }
  78. // start up the testing loop
  79. hr = CommandLoop(&ipcFullDuplex);
  80. if (FAILED(hr))
  81. {
  82. Diagnostics_Write(DVF_ERRORLEVEL, "CommandLoop failed, hr: 0x%x", hr);
  83. goto error_cleanup;
  84. }
  85. hr = StopDirectPlay( g_FullDuplexData.lpdp8 );
  86. g_FullDuplexData.lpdp8 = NULL;
  87. if( FAILED( hr ) )
  88. {
  89. Diagnostics_Write(DVF_ERRORLEVEL, "Failed to stop transport hr: 0x%x", hr);
  90. goto error_cleanup;
  91. }
  92. // close the mutex, events and shared memory stuff
  93. hr = ipcFullDuplex.Deinit();
  94. if (FAILED(hr))
  95. {
  96. Diagnostics_Write(DVF_ERRORLEVEL, "CIPCFullDuplex::Deinit() failed, hr: 0x%x", hr);
  97. goto error_cleanup;
  98. }
  99. // Destroy dummy client object which will shutdown dplayvoice state
  100. pdpvClient->Release();
  101. DeinitGlobGuard();
  102. DPF_EXIT();
  103. return S_OK;
  104. error_cleanup:
  105. if (fIPCInitialized == TRUE)
  106. {
  107. ipcFullDuplex.Deinit();
  108. fIPCInitialized = FALSE;
  109. }
  110. if( g_FullDuplexData.lpdp8 )
  111. {
  112. g_FullDuplexData.lpdp8->Release();
  113. g_FullDuplexData.lpdp8 = NULL;
  114. }
  115. if( pdpvClient )
  116. pdpvClient->Release();
  117. DeinitGlobGuard();
  118. DPF_EXIT();
  119. return hr;
  120. }
  121. #undef DPF_MODNAME
  122. #define DPF_MODNAME "CommandLoop"
  123. HRESULT CommandLoop(CFullDuplexIPC* lpipcFullDuplex)
  124. {
  125. BOOL fRet;
  126. LONG lRet;
  127. HRESULT hr;
  128. DWORD dwRet;
  129. SFDTestCommand fdtc;
  130. DPF_ENTER();
  131. // Kick the supervisor process to let it know
  132. // we're ready to go.
  133. hr = lpipcFullDuplex->SignalParentReady();
  134. if (FAILED(hr))
  135. {
  136. return hr;
  137. }
  138. // enter the main command loop
  139. while (1)
  140. {
  141. // wait for a command from the supervisor process
  142. fdtc.dwSize = sizeof(fdtc);
  143. hr = lpipcFullDuplex->Receive(&fdtc);
  144. if (FAILED(hr))
  145. {
  146. break;
  147. }
  148. // dispatch the command
  149. hr = DispatchCommand(lpipcFullDuplex, &fdtc);
  150. if (FAILED(hr))
  151. {
  152. break;
  153. }
  154. if (hr == DV_EXIT)
  155. {
  156. DPFX(DPFPREP, DVF_INFOLEVEL, "Exiting FullDuplex process command loop");
  157. break;
  158. }
  159. }
  160. DPF_EXIT();
  161. return hr;
  162. }
  163. #undef DPF_MODNAME
  164. #define DPF_MODNAME "DispatchCommand"
  165. HRESULT DispatchCommand(CFullDuplexIPC* lpipcFullDuplex, SFDTestCommand* pfdtc)
  166. {
  167. HRESULT hr;
  168. HRESULT hrIPC;
  169. DPF_ENTER();
  170. switch (pfdtc->fdtcc)
  171. {
  172. case fdtccExit:
  173. // ok - reply to the calling process to let them
  174. // know we are getting out.
  175. DPFX(DPFPREP, DVF_INFOLEVEL, "FullDuplex received Exit command");
  176. lpipcFullDuplex->Reply(DV_EXIT);
  177. // returning this code will break us out of
  178. // the command processing loop
  179. DPFX(DPFPREP, DVF_INFOLEVEL, "Exit");
  180. return DV_EXIT;
  181. case fdtccFullDuplexStart:
  182. hr = CommandFullDuplexStart(&(pfdtc->fdtu.fdtcFullDuplexStart), &hrIPC);
  183. if (FAILED(hr))
  184. {
  185. lpipcFullDuplex->Reply(hrIPC);
  186. DPF_EXIT();
  187. return hr;
  188. }
  189. hr = lpipcFullDuplex->Reply(hrIPC);
  190. DPF_EXIT();
  191. return hr;
  192. case fdtccFullDuplexStop:
  193. hr = CommandFullDuplexStop(&(pfdtc->fdtu.fdtcFullDuplexStop), &hrIPC);
  194. if (FAILED(hr))
  195. {
  196. lpipcFullDuplex->Reply(hrIPC);
  197. DPF_EXIT();
  198. return hr;
  199. }
  200. hr = lpipcFullDuplex->Reply(hrIPC);
  201. DPF_EXIT();
  202. return hr;
  203. default:
  204. // Don't know this command. Reply with the appropriate
  205. // code.
  206. DPFX(DPFPREP, DVF_WARNINGLEVEL, "FullDuplex received Unknown command");
  207. lpipcFullDuplex->Reply(DVERR_UNKNOWN);
  208. // While this is an error, it is one that the calling
  209. // process needs to figure out. In the meantime, this
  210. // process will happily continue on.
  211. DPF_EXIT();
  212. return S_OK;
  213. }
  214. }
  215. /*
  216. #undef DPF_MODNAME
  217. #define DPF_MODNAME "CommandFullDuplexStart"
  218. HRESULT CommandFullDuplexStart(SFDTestCommandFullDuplexStart* pfdtcFullDuplexStart, HRESULT* phrIPC)
  219. {
  220. HRESULT hr;
  221. DSBUFFERDESC1 dsbd;
  222. WAVEFORMATEX wfx;
  223. DWORD dwSizeWritten;
  224. DSBCAPS dsbc;
  225. LPVOID lpvAudio1 = NULL;
  226. DWORD dwAudio1Size = NULL;
  227. LPVOID lpvAudio2 = NULL;
  228. DWORD dwAudio2Size = NULL;
  229. HANDLE hFullDuplexRenderEvent;
  230. HANDLE hFullDuplexCaptureEvent;
  231. DSBPOSITIONNOTIFY dsbPositionNotify;
  232. DWORD dwRet;
  233. LONG lRet;
  234. LPDIRECTSOUNDBUFFER lpdsb;
  235. HANDLE hEvent;
  236. BYTE bSilence;
  237. DPF_ENTER();
  238. // create the DirectSound interface
  239. DPFX(DPFPREP, DVF_INFOLEVEL, "Creating DirectSound");
  240. GlobGuardIn();
  241. hr = DirectSoundCreate(&pfdtcFullDuplexStart->guidRenderDevice, &g_lpdsFullDuplexRender, NULL);
  242. GlobGuardOut();
  243. if (FAILED(hr))
  244. {
  245. DPFX(DPFPREP, DVF_WARNINGLEVEL, "DirectSoundCreate failed, code: %i", HRESULT_CODE(hr));
  246. *phrIPC = DVERR_SOUNDINITFAILURE;
  247. goto error_level_0;
  248. }
  249. // create the DirectSoundCapture interface
  250. DPFX(DPFPREP, DVF_INFOLEVEL, "Creating DirectSoundCapture");
  251. GlobGuardIn();
  252. hr = DirectSoundCaptureCreate(&pfdtcFullDuplexStart->guidCaptureDevice, &g_lpdscFullDuplexCapture, NULL);
  253. GlobGuardOut();
  254. if (FAILED(hr))
  255. {
  256. DPFX(DPFPREP, DVF_WARNINGLEVEL, "DirectSoundCaptureCreate failed, code: %i", HRESULT_CODE(hr));
  257. *phrIPC = DVERR_SOUNDINITFAILURE;
  258. goto error_level_1;
  259. }
  260. // set to normal mode
  261. DPFX(DPFPREP, DVF_INFOLEVEL, "Setting Cooperative Level");
  262. GlobGuardIn();
  263. hr = g_lpdsFullDuplexRender->SetCooperativeLevel(GetDesktopWindow(), DSSCL_NORMAL);
  264. GlobGuardOut();
  265. if (FAILED(hr))
  266. {
  267. DPFX(DPFPREP, DVF_WARNINGLEVEL, "SetCooperativeLevel failed, code: %i", HRESULT_CODE(hr));
  268. *phrIPC = DVERR_SOUNDINITFAILURE;
  269. goto error_level_2;
  270. }
  271. // Create a secondary buffer object.
  272. DPFX(DPFPREP, DVF_INFOLEVEL, "Creating Secondary Buffer");
  273. CopyMemory(&wfx, &gc_wfxSecondaryFormat, sizeof(wfx));
  274. ZeroMemory(&dsbd, sizeof(dsbd));
  275. dsbd.dwSize = sizeof(dsbd);
  276. dsbd.dwFlags = DSBCAPS_CTRLPOSITIONNOTIFY | DSBCAPS_CTRLVOLUME;
  277. dsbd.dwBufferBytes =
  278. (wfx.nSamplesPerSec
  279. * wfx.nBlockAlign)
  280. / (1000 / gc_dwFrameSize);
  281. dsbd.dwReserved = 0;
  282. dsbd.lpwfxFormat = &wfx;
  283. GlobGuardIn();
  284. hr = g_lpdsFullDuplexRender->CreateSoundBuffer((LPDSBUFFERDESC)&dsbd, &g_lpdsbFullDuplexSecondary, NULL);
  285. GlobGuardOut();
  286. if (FAILED(hr))
  287. {
  288. DPFX(DPFPREP, DVF_WARNINGLEVEL, "CreateSoundBuffer failed, code: %i", HRESULT_CODE(hr));
  289. *phrIPC = DVERR_SOUNDINITFAILURE;
  290. goto error_level_2;
  291. }
  292. // clear out the secondary buffer
  293. DPFX(DPFPREP, DVF_INFOLEVEL, "Clearing Secondary Buffer");
  294. GlobGuardIn();
  295. hr = g_lpdsbFullDuplexSecondary->Lock(
  296. 0,
  297. 0,
  298. &lpvAudio1,
  299. &dwAudio1Size,
  300. &lpvAudio2,
  301. &dwAudio2Size,
  302. DSBLOCK_ENTIREBUFFER);
  303. GlobGuardOut();
  304. if (FAILED(hr))
  305. {
  306. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Lock failed, code: %i", HRESULT_CODE(hr));
  307. *phrIPC = DVERR_SOUNDINITFAILURE;
  308. goto error_level_3;
  309. }
  310. if (lpvAudio1 == NULL)
  311. {
  312. *phrIPC = DVERR_SOUNDINITFAILURE;
  313. goto error_level_3;
  314. }
  315. if (pfdtcFullDuplexStart->wfxRenderFormat.wBitsPerSample == 8)
  316. {
  317. bSilence = 0x80;
  318. }
  319. else
  320. {
  321. bSilence = 0x00;
  322. }
  323. memset(lpvAudio1, bSilence, dwAudio1Size);
  324. if (lpvAudio2 != NULL)
  325. {
  326. memset(lpvAudio2, bSilence, dwAudio2Size);
  327. }
  328. GlobGuardIn();
  329. hr = g_lpdsbFullDuplexSecondary->Unlock(
  330. lpvAudio1,
  331. dwAudio1Size,
  332. lpvAudio2,
  333. dwAudio2Size);
  334. GlobGuardOut();
  335. if (FAILED(hr))
  336. {
  337. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Unlock failed, code: %i", HRESULT_CODE(hr));
  338. *phrIPC = DVERR_SOUNDINITFAILURE;
  339. goto error_level_3;
  340. }
  341. // Set up one notification position in the buffer so
  342. // we can tell if it is really playing, or lying to us.
  343. DPFX(DPFPREP, DVF_INFOLEVEL, "Querying for IDirectSoundNotify");
  344. GlobGuardIn();
  345. hr = g_lpdsbFullDuplexSecondary->QueryInterface(
  346. IID_IDirectSoundNotify,
  347. (LPVOID*)&g_lpdsnFullDuplexSecondary);
  348. GlobGuardOut();
  349. if (FAILED(hr))
  350. {
  351. DPFX(DPFPREP, DVF_WARNINGLEVEL, "QueryInterface(IID_DirectSoundNotify) failed, code: %i", HRESULT_CODE(hr));
  352. *phrIPC = DVERR_SOUNDINITFAILURE;
  353. goto error_level_3;
  354. }
  355. DPFX(DPFPREP, DVF_INFOLEVEL, "Creating Notification Event");
  356. GlobGuardIn();
  357. g_hFullDuplexRenderEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  358. hFullDuplexRenderEvent = g_hFullDuplexRenderEvent;
  359. GlobGuardOut();
  360. if (hFullDuplexRenderEvent == NULL)
  361. {
  362. DPFX(DPFPREP, DVF_WARNINGLEVEL, "CreateEvent failed, code: %i", HRESULT_CODE(hr));
  363. *phrIPC = DVERR_WIN32;
  364. goto error_level_4;
  365. }
  366. DPFX(DPFPREP, DVF_INFOLEVEL, "calling SetNotificationPositions");
  367. dsbPositionNotify.dwOffset = 0;
  368. dsbPositionNotify.hEventNotify = hFullDuplexRenderEvent;
  369. GlobGuardIn();
  370. hr = g_lpdsnFullDuplexSecondary->SetNotificationPositions(1, &dsbPositionNotify);
  371. GlobGuardOut();
  372. if (FAILED(hr))
  373. {
  374. DPFX(DPFPREP, DVF_WARNINGLEVEL, "SetNotificationPositions failed, code: %i", HRESULT_CODE(hr));
  375. *phrIPC = DVERR_SOUNDINITFAILURE;
  376. goto error_level_5;
  377. }
  378. // start the secondary buffer and confirm that it's running
  379. GlobGuardIn();
  380. lpdsb = g_lpdsbFullDuplexSecondary;
  381. hEvent = g_hFullDuplexRenderEvent;
  382. GlobGuardOut();
  383. hr = PlayAndCheckRender(lpdsb, hEvent);
  384. if (FAILED(hr))
  385. {
  386. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Render verification test failed, code: %i", HRESULT_CODE(hr));
  387. *phrIPC = DVERR_SOUNDINITFAILURE;
  388. goto error_level_5;
  389. }
  390. hr = AttemptCapture();
  391. if (FAILED(hr))
  392. {
  393. DPFX(DPFPREP, DVF_WARNINGLEVEL, "AttemptCapture() failed, code: %i", HRESULT_CODE(hr));
  394. *phrIPC = DVERR_SOUNDINITFAILURE;
  395. goto error_level_6;
  396. }
  397. DPF_EXIT();
  398. return S_OK;
  399. // error block
  400. error_level_6:
  401. GlobGuardIn();
  402. g_lpdsbFullDuplexSecondary->Stop();
  403. GlobGuardOut();
  404. error_level_5:
  405. GlobGuardIn();
  406. CloseHandle(g_hFullDuplexRenderEvent);
  407. g_hFullDuplexRenderEvent = NULL;
  408. GlobGuardOut();
  409. error_level_4:
  410. GlobGuardIn();
  411. g_lpdsnFullDuplexSecondary->Release();
  412. g_lpdsnFullDuplexSecondary = NULL;
  413. GlobGuardOut();
  414. error_level_3:
  415. GlobGuardIn();
  416. g_lpdsbFullDuplexSecondary->Release();
  417. g_lpdsbFullDuplexSecondary = NULL;
  418. GlobGuardOut();
  419. error_level_2:
  420. GlobGuardIn();
  421. g_lpdscFullDuplexCapture->Release();
  422. g_lpdscFullDuplexCapture = NULL;
  423. GlobGuardOut();
  424. error_level_1:
  425. GlobGuardIn();
  426. g_lpdsFullDuplexRender->Release();
  427. g_lpdsFullDuplexRender = NULL;
  428. GlobGuardOut();
  429. error_level_0:
  430. // error for other process, not this one.
  431. DPF_EXIT();
  432. return S_OK;
  433. }
  434. */
  435. #undef DPF_MODNAME
  436. #define DPF_MODNAME "CommandFullDuplexStart"
  437. HRESULT CommandFullDuplexStart(SFDTestCommandFullDuplexStart* pfdtcFullDuplexStart, HRESULT* phrIPC)
  438. {
  439. DPF_ENTER();
  440. HRESULT hr;
  441. Diagnostics_Write( DVF_INFOLEVEL, "-----------------------------------------------------------" );
  442. hr = Diagnostics_DeviceInfo( &pfdtcFullDuplexStart->guidRenderDevice, &pfdtcFullDuplexStart->guidCaptureDevice );
  443. if( FAILED( hr ) )
  444. {
  445. Diagnostics_Write( 0, "Error getting device information hr=0x%x", hr );
  446. }
  447. Diagnostics_Write( DVF_INFOLEVEL, "-----------------------------------------------------------" );
  448. *phrIPC = StartLoopback(
  449. &g_FullDuplexData.lpdpvs,
  450. &g_FullDuplexData.lpdpvc,
  451. &g_FullDuplexData.lpdp8,
  452. NULL,
  453. GetDesktopWindow(),
  454. pfdtcFullDuplexStart->guidCaptureDevice,
  455. pfdtcFullDuplexStart->guidRenderDevice,
  456. pfdtcFullDuplexStart->dwFlags);
  457. DPFX(DPFPREP, DVF_INFOLEVEL, "StartLoopback() return hr=0x%x", *phrIPC );
  458. DPF_EXIT();
  459. return DV_OK;
  460. }
  461. #undef DPF_MODNAME
  462. #define DPF_MODNAME "CommandFullDuplexStop"
  463. HRESULT CommandFullDuplexStop(SFDTestCommandFullDuplexStop* pfdtcFullDuplexStop, HRESULT* phrIPC)
  464. {
  465. DPF_ENTER();
  466. *phrIPC = StopLoopback(
  467. g_FullDuplexData.lpdpvs,
  468. g_FullDuplexData.lpdpvc,
  469. g_FullDuplexData.lpdp8);
  470. if( FAILED( *phrIPC ) )
  471. {
  472. Diagnostics_Write( DVF_ERRORLEVEL, "Full Duplex Result = 0x%x", *phrIPC );
  473. }
  474. else
  475. {
  476. Diagnostics_Write( DVF_INFOLEVEL, "Full Duplex Result = DV_OK" );
  477. }
  478. DPF_EXIT();
  479. return DV_OK;
  480. }
  481. /*
  482. #undef DPF_MODNAME
  483. #define DPF_MODNAME "CommandFullDuplexStop"
  484. HRESULT CommandFullDuplexStop(SFDTestCommandFullDuplexStop* pfdtcFullDuplexStop, HRESULT* phrIPC)
  485. {
  486. HRESULT hr;
  487. LONG lRet;
  488. HANDLE hFullDuplexRenderEvent;
  489. HANDLE hFullDuplexCaptureEvent;
  490. DWORD dwRet;
  491. DPF_ENTER();
  492. *phrIPC = S_OK;
  493. hr = S_OK;
  494. // wait for one more notification to ensure the buffer is
  495. // still playing - give the buffer up to 10 times
  496. // as long as it should need to actually notify us.
  497. DPFX(DPFPREP, DVF_INFOLEVEL, "Waiting for 2 notifications to confirm playback is still working");
  498. GlobGuardIn();
  499. hFullDuplexRenderEvent = g_hFullDuplexRenderEvent;
  500. GlobGuardOut();
  501. dwRet = WaitForSingleObject(hFullDuplexRenderEvent, 10 * gc_dwFrameSize);
  502. if (dwRet != WAIT_OBJECT_0)
  503. {
  504. // check for timeout
  505. if (dwRet == WAIT_TIMEOUT)
  506. {
  507. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Wait for notification timed out! Buffer is not really playing");
  508. *phrIPC = DVERR_SOUNDINITFAILURE;
  509. }
  510. else
  511. {
  512. lRet = GetLastError();
  513. DPFX(DPFPREP, DVF_WARNINGLEVEL, "WaitForSingleObject failed, code: %i", lRet);
  514. hr = DVERR_WIN32;
  515. *phrIPC = hr;
  516. }
  517. }
  518. if (SUCCEEDED(hr))
  519. {
  520. dwRet = WaitForSingleObject(hFullDuplexRenderEvent, 10 * gc_dwFrameSize);
  521. if (dwRet != WAIT_OBJECT_0)
  522. {
  523. // check for timeout
  524. if (dwRet == WAIT_TIMEOUT)
  525. {
  526. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Wait for notification timed out! Buffer is not really playing");
  527. *phrIPC = DVERR_SOUNDINITFAILURE;
  528. }
  529. else
  530. {
  531. lRet = GetLastError();
  532. DPFX(DPFPREP, DVF_WARNINGLEVEL, "WaitForSingleObject failed, code: %i", lRet);
  533. hr = DVERR_WIN32;
  534. *phrIPC = hr;
  535. }
  536. }
  537. }
  538. // also wait for the capture buffer...
  539. DPFX(DPFPREP, DVF_INFOLEVEL, "Waiting for 2 notifications to confirm capture is still working");
  540. GlobGuardIn();
  541. hFullDuplexCaptureEvent = g_hFullDuplexCaptureEvent;
  542. GlobGuardOut();
  543. dwRet = WaitForSingleObject(hFullDuplexCaptureEvent, 10 * gc_dwFrameSize);
  544. if (dwRet != WAIT_OBJECT_0)
  545. {
  546. // check for timeout
  547. if (dwRet == WAIT_TIMEOUT)
  548. {
  549. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Wait for notification timed out! Buffer is not really playing");
  550. *phrIPC = DVERR_SOUNDINITFAILURE;
  551. }
  552. else
  553. {
  554. lRet = GetLastError();
  555. DPFX(DPFPREP, DVF_WARNINGLEVEL, "WaitForSingleObject failed, code: %i", lRet);
  556. hr = DVERR_WIN32;
  557. *phrIPC = hr;
  558. }
  559. }
  560. if (SUCCEEDED(hr))
  561. {
  562. dwRet = WaitForSingleObject(hFullDuplexCaptureEvent, 10 * gc_dwFrameSize);
  563. if (dwRet != WAIT_OBJECT_0)
  564. {
  565. // check for timeout
  566. if (dwRet == WAIT_TIMEOUT)
  567. {
  568. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Wait for notification timed out! Buffer is not really playing");
  569. *phrIPC = DVERR_SOUNDINITFAILURE;
  570. }
  571. else
  572. {
  573. lRet = GetLastError();
  574. DPFX(DPFPREP, DVF_WARNINGLEVEL, "WaitForSingleObject failed, code: %i", lRet);
  575. hr = DVERR_WIN32;
  576. *phrIPC = hr;
  577. }
  578. }
  579. }
  580. DPFX(DPFPREP, DVF_INFOLEVEL, "Stopping Capture Buffer");
  581. GlobGuardIn();
  582. hr = g_lpdscbFullDuplexCapture->Stop();
  583. GlobGuardOut();
  584. if (FAILED(hr))
  585. {
  586. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Stop failed, code: %i", HRESULT_CODE(hr));
  587. *phrIPC = DVERR_SOUNDINITFAILURE;
  588. }
  589. DPFX(DPFPREP, DVF_INFOLEVEL, "Stopping Secondary Buffer");
  590. GlobGuardIn();
  591. hr = g_lpdsbFullDuplexSecondary->Stop();
  592. GlobGuardOut();
  593. if (FAILED(hr))
  594. {
  595. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Stop failed, code: %i", HRESULT_CODE(hr));
  596. *phrIPC = DVERR_SOUNDINITFAILURE;
  597. }
  598. GlobGuardIn();
  599. if (g_hFullDuplexCaptureEvent != NULL)
  600. {
  601. DPFX(DPFPREP, DVF_INFOLEVEL, "Closing Capture Buffer Notification Event Handle");
  602. CloseHandle(g_hFullDuplexCaptureEvent);
  603. g_hFullDuplexCaptureEvent = NULL;
  604. }
  605. if (g_lpdsnFullDuplexCapture != NULL)
  606. {
  607. DPFX(DPFPREP, DVF_INFOLEVEL, "Releasing DirectSoundNotifier (capture)");
  608. g_lpdsnFullDuplexCapture->Release();
  609. g_lpdsnFullDuplexCapture = NULL;
  610. }
  611. if (g_lpdscbFullDuplexCapture != NULL)
  612. {
  613. DPFX(DPFPREP, DVF_INFOLEVEL, "Releasing DirectSoundCaptureBuffer");
  614. g_lpdscbFullDuplexCapture->Release();
  615. g_lpdscbFullDuplexCapture = NULL;
  616. }
  617. if (g_lpdscFullDuplexCapture != NULL)
  618. {
  619. DPFX(DPFPREP, DVF_INFOLEVEL, "Releasing DirectSoundCapture");
  620. g_lpdscFullDuplexCapture->Release();
  621. g_lpdscFullDuplexCapture = NULL;
  622. }
  623. if (g_hFullDuplexRenderEvent != NULL)
  624. {
  625. DPFX(DPFPREP, DVF_INFOLEVEL, "Closing Secondary Buffer Notification Event Handle");
  626. if (!CloseHandle(g_hFullDuplexRenderEvent))
  627. {
  628. lRet = GetLastError();
  629. DPFX(DPFPREP, DVF_WARNINGLEVEL, "CloseHandle failed, code: %i", lRet);
  630. *phrIPC = DVERR_WIN32;
  631. hr = *phrIPC;
  632. }
  633. g_hFullDuplexRenderEvent = NULL;
  634. }
  635. if (g_lpdsnFullDuplexSecondary != NULL)
  636. {
  637. DPFX(DPFPREP, DVF_INFOLEVEL, "Releasing Secondary Notifier");
  638. g_lpdsnFullDuplexSecondary->Release();
  639. g_lpdsnFullDuplexSecondary = NULL;
  640. }
  641. if (g_lpdsbFullDuplexSecondary != NULL)
  642. {
  643. DPFX(DPFPREP, DVF_INFOLEVEL, "Releasing Secondary Buffer");
  644. g_lpdsbFullDuplexSecondary->Release();
  645. g_lpdsbFullDuplexSecondary = NULL;
  646. }
  647. if (g_lpdsFullDuplexRender != NULL)
  648. {
  649. DPFX(DPFPREP, DVF_INFOLEVEL, "Releasing DirectSound");
  650. g_lpdsFullDuplexRender->Release();
  651. g_lpdsFullDuplexRender = NULL;
  652. }
  653. GlobGuardOut();
  654. DPF_EXIT();
  655. return hr;
  656. }
  657. */
  658. /*
  659. #undef DPF_MODNAME
  660. #define DPF_MODNAME "PlayAndCheckRender"
  661. HRESULT PlayAndCheckRender(LPDIRECTSOUNDBUFFER lpdsb, HANDLE hEvent)
  662. {
  663. HRESULT hr;
  664. DWORD dwRet;
  665. LONG lRet;
  666. DPF_ENTER();
  667. // start playing the secondary buffer
  668. DPFX(DPFPREP, DVF_INFOLEVEL, "Playing Secondary Buffer");
  669. GlobGuardIn();
  670. hr = lpdsb->Play(0, 0, DSBPLAY_LOOPING);
  671. GlobGuardOut();
  672. if (FAILED(hr))
  673. {
  674. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Play failed, code: %i", HRESULT_CODE(hr));
  675. hr = DVERR_SOUNDINITFAILURE;
  676. goto error_level_0;
  677. }
  678. // wait for the first notification to ensure the buffer has
  679. // really started to play - give the buffer up to 10 times
  680. // as long as it should need to actually notify us.
  681. DPFX(DPFPREP, DVF_INFOLEVEL, "Waiting for notification to confirm playback is working");
  682. dwRet = WaitForSingleObject(hEvent, 10 * gc_dwFrameSize);
  683. if (dwRet != WAIT_OBJECT_0)
  684. {
  685. // check for timeout
  686. if (dwRet == WAIT_TIMEOUT)
  687. {
  688. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Wait for notification timed out! Buffer is not really playing");
  689. hr = DVERR_SOUNDINITFAILURE;
  690. goto error_level_1;
  691. }
  692. else
  693. {
  694. lRet = GetLastError();
  695. DPFX(DPFPREP, DVF_ERRORLEVEL, "WaitForSingleObject failed, code: %i", lRet);
  696. hr = DVERR_WIN32;
  697. goto error_level_1;
  698. }
  699. }
  700. DPFX(DPFPREP, DVF_INFOLEVEL, "First notification received, continuing");
  701. DPF_EXIT();
  702. return S_OK;
  703. // error block
  704. error_level_1:
  705. GlobGuardIn();
  706. lpdsb->Stop();
  707. GlobGuardOut();
  708. error_level_0:
  709. DPF_EXIT();
  710. return hr;
  711. }
  712. */
  713. /*
  714. #undef DPF_MODNAME
  715. #define DPF_MODNAME "PlayAndCheckCapture"
  716. HRESULT PlayAndCheckCapture(LPDIRECTSOUNDCAPTUREBUFFER lpdscb, HANDLE hEvent)
  717. {
  718. HRESULT hr;
  719. DWORD dwRet;
  720. LONG lRet;
  721. DPF_ENTER();
  722. // start playing the capture buffer
  723. DPFX(DPFPREP, DVF_INFOLEVEL, "Starting Capture Buffer");
  724. GlobGuardIn();
  725. hr = lpdscb->Start(DSCBSTART_LOOPING);
  726. GlobGuardOut();
  727. if (FAILED(hr))
  728. {
  729. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Start failed, code: %i", HRESULT_CODE(hr));
  730. hr = DVERR_SOUNDINITFAILURE;
  731. goto error_level_0;
  732. }
  733. // wait for the first notification to ensure the buffer has
  734. // really started to capture - give the buffer up to 10 times
  735. // as long as it should need to actually notify us.
  736. DPFX(DPFPREP, DVF_INFOLEVEL, "Waiting for notification to confirm capture is working");
  737. dwRet = WaitForSingleObject(hEvent, 10 * gc_dwFrameSize);
  738. if (dwRet != WAIT_OBJECT_0)
  739. {
  740. // check for timeout
  741. if (dwRet == WAIT_TIMEOUT)
  742. {
  743. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Wait for notification timed out! Buffer is not really playing");
  744. hr = DVERR_SOUNDINITFAILURE;
  745. goto error_level_1;
  746. }
  747. else
  748. {
  749. lRet = GetLastError();
  750. DPFX(DPFPREP, DVF_ERRORLEVEL, "WaitForSingleObject failed, code: %i", lRet);
  751. hr = DVERR_WIN32;
  752. goto error_level_1;
  753. }
  754. }
  755. DPFX(DPFPREP, DVF_INFOLEVEL, "First notification received, continuing");
  756. DPF_EXIT();
  757. return S_OK;
  758. // error block
  759. error_level_1:
  760. GlobGuardIn();
  761. lpdscb->Stop();
  762. GlobGuardOut();
  763. error_level_0:
  764. DPF_EXIT();
  765. return hr;
  766. }
  767. */
  768. /*
  769. #undef DPF_MODNAME
  770. #define DPF_MODNAME "AttemptCapture"
  771. HRESULT AttemptCapture()
  772. {
  773. DPF_ENTER();
  774. DWORD dwIndex;
  775. BOOL fCaptureFailed;
  776. HANDLE hFullDuplexCaptureEvent;
  777. DSBPOSITIONNOTIFY dsbPositionNotify;
  778. DSCBUFFERDESC dscbd;
  779. LPDIRECTSOUNDCAPTUREBUFFER lpdscb;
  780. HRESULT hr;
  781. HANDLE hEvent;
  782. WAVEFORMATEX wfx;
  783. fCaptureFailed = TRUE;
  784. dwIndex = 0;
  785. while (1)
  786. {
  787. CopyMemory(&wfx, &gc_rgwfxCaptureFormats[dwIndex], sizeof(wfx));
  788. if (wfx.wFormatTag == 0
  789. && wfx.nChannels == 0
  790. && wfx.nSamplesPerSec == 0
  791. && wfx.nAvgBytesPerSec == 0
  792. && wfx.nBlockAlign == 0
  793. && wfx.wBitsPerSample == 0
  794. && wfx.cbSize == 0)
  795. {
  796. // we've found the last element of the array, break out.
  797. break;
  798. }
  799. // create the capture buffer
  800. DPFX(DPFPREP, DVF_INFOLEVEL, "Creating DirectSoundCaptureBuffer");
  801. ZeroMemory(&dscbd, sizeof(dscbd));
  802. dscbd.dwSize = sizeof(dscbd);
  803. dscbd.dwFlags = 0;
  804. dscbd.dwBufferBytes =
  805. (wfx.nSamplesPerSec
  806. * wfx.nBlockAlign)
  807. / (1000 / gc_dwFrameSize);
  808. dscbd.dwReserved = 0;
  809. dscbd.lpwfxFormat = &wfx;
  810. GlobGuardIn();
  811. hr = g_lpdscFullDuplexCapture->CreateCaptureBuffer(&dscbd, &g_lpdscbFullDuplexCapture, NULL);
  812. GlobGuardOut();
  813. if (FAILED(hr))
  814. {
  815. // try the next format
  816. ++dwIndex;
  817. continue;
  818. }
  819. // setup the notifier on the capture buffer
  820. DPFX(DPFPREP, DVF_INFOLEVEL, "Querying for IDirectSoundNotify");
  821. GlobGuardIn();
  822. hr = g_lpdscbFullDuplexCapture->QueryInterface(
  823. IID_IDirectSoundNotify,
  824. (LPVOID*)&g_lpdsnFullDuplexCapture);
  825. GlobGuardOut();
  826. if (FAILED(hr))
  827. {
  828. // Once the above works, this should not fail, so treat
  829. // this as a real error
  830. DPFX(DPFPREP, DVF_ERRORLEVEL, "QueryInterface(IID_DirectSoundNotify) failed, code: %i", HRESULT_CODE(hr));
  831. GlobGuardIn();
  832. g_lpdscbFullDuplexCapture->Release();
  833. GlobGuardOut();
  834. DPF_EXIT();
  835. return hr;
  836. }
  837. DPFX(DPFPREP, DVF_INFOLEVEL, "Creating Notification Event");
  838. GlobGuardIn();
  839. g_hFullDuplexCaptureEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  840. hFullDuplexCaptureEvent = g_hFullDuplexCaptureEvent;
  841. GlobGuardOut();
  842. if (hFullDuplexCaptureEvent == NULL)
  843. {
  844. // Once the above works, this should not fail, so treat
  845. // this as a real error
  846. DPFX(DPFPREP, DVF_INFOLEVEL, "CreateEvent failed, code: %i", HRESULT_CODE(hr));
  847. GlobGuardIn();
  848. g_lpdscbFullDuplexCapture->Release();
  849. g_lpdsnFullDuplexCapture->Release();
  850. GlobGuardOut();
  851. DPF_EXIT();
  852. return DVERR_WIN32;
  853. }
  854. DPFX(DPFPREP, DVF_INFOLEVEL, "calling SetNotificationPositions");
  855. dsbPositionNotify.dwOffset = 0;
  856. dsbPositionNotify.hEventNotify = hFullDuplexCaptureEvent;
  857. GlobGuardIn();
  858. hr = g_lpdsnFullDuplexCapture->SetNotificationPositions(1, &dsbPositionNotify);
  859. GlobGuardOut();
  860. if (FAILED(hr))
  861. {
  862. // Once the above works, this should not fail, so treat
  863. // this as a real error
  864. DPFX(DPFPREP, DVF_ERRORLEVEL, "SetNotificationPositions failed, code: %i", HRESULT_CODE(hr));
  865. GlobGuardIn();
  866. g_lpdscbFullDuplexCapture->Release();
  867. g_lpdsnFullDuplexCapture->Release();
  868. CloseHandle(hFullDuplexCaptureEvent);
  869. GlobGuardOut();
  870. DPF_EXIT();
  871. return hr;
  872. }
  873. // start the capture buffer and confirm that it is actually working
  874. GlobGuardIn();
  875. lpdscb = g_lpdscbFullDuplexCapture;
  876. hEvent = g_hFullDuplexCaptureEvent;
  877. GlobGuardOut();
  878. hr = PlayAndCheckCapture(lpdscb, hEvent);
  879. if (FAILED(hr))
  880. {
  881. // This can happen, so just try the next format
  882. DPFX(DPFPREP, DVF_WARNINGLEVEL, "Capture verification test failed, code: %i", HRESULT_CODE(hr));
  883. GlobGuardIn();
  884. g_lpdscbFullDuplexCapture->Release();
  885. g_lpdsnFullDuplexCapture->Release();
  886. CloseHandle(hFullDuplexCaptureEvent);
  887. GlobGuardOut();
  888. ++dwIndex;
  889. continue;
  890. }
  891. // If we get here, capture is up and running, so return success!
  892. DPF_EXIT();
  893. return S_OK;
  894. }
  895. // if we get here, none of the formats worked, so return directsound error
  896. DPF_EXIT();
  897. return DVERR_SOUNDINITFAILURE;
  898. }
  899. */