Source code of Windows XP (NT5)
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.

681 lines
17 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: loopback.cpp
  6. * Content: Implements the loopback portion of the full duplex test
  7. *
  8. * History:
  9. * Date By Reason
  10. * ==== == ======
  11. * 09/10/99 pnewson Created
  12. * 10/25/99 rodtoll Removed lpszVoicePassword member from sessiondesc
  13. * 10/27/99 pnewson Fix: Bug #113936 - Wizard should reset the AGC level before loopback test
  14. * Note: this fix adds the DVCLIENTCONFIG_AUTOVOLUMERESET flag
  15. * 10/28/99 pnewson Bug #114176 updated DVSOUNDDEVICECONFIG struct
  16. * 11/04/99 pnewson Bug #115279 changed SendMessage to PostMessage to resolve some deadlocks
  17. * 11/30/99 pnewson use default codec
  18. * use devices passed to CheckAudioSetup, instead of default devices
  19. * 12/01/99 rodtoll Added flag to cause wizard to auto-select the microphone
  20. * 01/14/2000 rodtoll Updated with API changes
  21. * 01/21/2000 pnewson Updated for UI revisions
  22. * Updated to support use of loopback tests for full duplex testing
  23. * 01/27/2000 rodtoll Updated with API changes
  24. * 02/08/2000 rodtoll Bug #131496 - Selecting DVTHRESHOLD_DEFAULT results in voice
  25. * never being detected
  26. * 03/03/2000 rodtoll Updated to handle alternative gamevoice build.
  27. * 04/19/2000 pnewson Error handling cleanup
  28. * 04/21/2000 rodtoll Bug #32952 Does not run on Win95 GOLD w/o IE4 installed
  29. * 06/21/2000 rodtoll Updated to use new parameters
  30. * 06/28/2000 rodtoll Prefix Bug #38022
  31. * 07/31/2000 rodtoll Bug #39590 - SB16 class soundcards are passing when they should fail
  32. * Half duplex code was being ignored in mic test portion.
  33. * 08/28/2000 masonb Voice Merge: Changed ccomutil.h to ccomutil.h
  34. * 08/31/2000 rodtoll Bug #43804 - DVOICE: dwSensitivity structure member is confusing - should be dwThreshold
  35. * 11/29/2000 rodtoll Bug #48348 - DPVOICE: Modify wizard to make use of DirectPlay8 as the transport.
  36. * NOTE: Now requires a TCP/IP adapter to be present (or at least loopback)
  37. * 02/04/2001 simonpow Bug #354859 PREfast spotted errors (PostMessage return codes incorrectly
  38. * treated as HRESULTs)
  39. * 04/12/2001 kareemc WINBUG #360971 - Wizard Memory Leaks
  40. *
  41. ***************************************************************************/
  42. #include "dxvtlibpch.h"
  43. #undef DPF_SUBCOMP
  44. #define DPF_SUBCOMP DN_SUBCOMP_VOICE
  45. // application defined message ids
  46. //#define WMAPP_LOOPBACKRUNNING WM_USER + 1
  47. //#define WMAPP_INPUTVOLUME WM_USER + 2
  48. // {53CA3FB7-4FD5-4a67-99E4-6F2496E6FEC2}
  49. static const GUID GUID_LOOPBACKTEST =
  50. { 0x53ca3fb7, 0x4fd5, 0x4a67, { 0x99, 0xe4, 0x6f, 0x24, 0x96, 0xe6, 0xfe, 0xc2 } };
  51. HRESULT StartDirectPlay( PDIRECTPLAY8SERVER* lplpdp8 );
  52. HRESULT StopDirectPlay( PDIRECTPLAY8SERVER lpdp8 );
  53. #undef DPF_MODNAME
  54. #define DPF_MODNAME "DVMessageHandlerServer"
  55. HRESULT PASCAL DVMessageHandlerServer(
  56. LPVOID lpvUserContext,
  57. DWORD dwMessageType,
  58. LPVOID lpMessage
  59. )
  60. {
  61. DPF_ENTER();
  62. switch( dwMessageType )
  63. {
  64. case DVMSGID_CREATEVOICEPLAYER:
  65. break;
  66. case DVMSGID_DELETEVOICEPLAYER:
  67. break;
  68. case DVMSGID_SESSIONLOST:
  69. break;
  70. case DVMSGID_PLAYERVOICESTART:
  71. break;
  72. case DVMSGID_PLAYERVOICESTOP:
  73. break;
  74. case DVMSGID_RECORDSTART:
  75. break;
  76. case DVMSGID_RECORDSTOP:
  77. break;
  78. case DVMSGID_CONNECTRESULT:
  79. break;
  80. case DVMSGID_DISCONNECTRESULT:
  81. break;
  82. case DVMSGID_INPUTLEVEL:
  83. break;
  84. case DVMSGID_OUTPUTLEVEL:
  85. break;
  86. default:
  87. break;
  88. }
  89. DPF_EXIT();
  90. return DV_OK;
  91. }
  92. #undef DPF_MODNAME
  93. #define DPF_MODNAME "DVMessageHandlerClient"
  94. HRESULT PASCAL DVMessageHandlerClient(
  95. LPVOID lpvUserContext,
  96. DWORD dwMessageType,
  97. LPVOID lpMessage
  98. )
  99. {
  100. DPF_EXIT();
  101. HWND hwndDialog;
  102. HWND hwndPeakMeter;
  103. HWND hwndSlider;
  104. LONG lRet;
  105. HRESULT hr;
  106. CSupervisorInfo* lpsinfo;
  107. PDVMSG_INPUTLEVEL pdvInputLevel;
  108. PDVMSG_OUTPUTLEVEL pdvOutputLevel;
  109. lpsinfo = (CSupervisorInfo*)lpvUserContext;
  110. if( lpsinfo )
  111. {
  112. if( !lpsinfo->GetLoopbackRunning() )
  113. return DV_OK;
  114. }
  115. switch( dwMessageType )
  116. {
  117. case DVMSGID_CREATEVOICEPLAYER:
  118. break;
  119. case DVMSGID_DELETEVOICEPLAYER:
  120. break;
  121. case DVMSGID_SESSIONLOST:
  122. break;
  123. case DVMSGID_PLAYERVOICESTART:
  124. break;
  125. case DVMSGID_PLAYERVOICESTOP:
  126. break;
  127. case DVMSGID_RECORDSTART:
  128. if (lpsinfo == NULL)
  129. {
  130. break;
  131. }
  132. // forward the message along to the appropriate window
  133. lpsinfo->GetHWNDDialog(&hwndDialog);
  134. if (!PostMessage(hwndDialog, WM_APP_RECORDSTART, 0, 0))
  135. {
  136. DPFX(DPFPREP, DVF_ERRORLEVEL, "PostMessage failed, code: %i", GetLastError());
  137. break; // no error return, just continue
  138. }
  139. break;
  140. case DVMSGID_RECORDSTOP:
  141. if (lpsinfo == NULL)
  142. {
  143. break;
  144. }
  145. // forward the message along to the appropriate window
  146. lpsinfo->GetHWNDDialog(&hwndDialog);
  147. if (!PostMessage(hwndDialog, WM_APP_RECORDSTOP, 0, 0))
  148. {
  149. DPFX(DPFPREP, DVF_ERRORLEVEL, "PostMessage failed, code: %i", GetLastError());
  150. break; // no error return, just continue
  151. }
  152. break;
  153. case DVMSGID_CONNECTRESULT:
  154. break;
  155. case DVMSGID_DISCONNECTRESULT:
  156. break;
  157. case DVMSGID_INPUTLEVEL:
  158. if (lpsinfo == NULL)
  159. {
  160. break;
  161. }
  162. // update the peak meter
  163. lpsinfo->GetHWNDInputPeak(&hwndPeakMeter);
  164. if (IsWindow(hwndPeakMeter))
  165. {
  166. pdvInputLevel = (PDVMSG_INPUTLEVEL) lpMessage;
  167. if (!PostMessage(hwndPeakMeter, PM_SETCUR, 0, pdvInputLevel->dwPeakLevel ))
  168. {
  169. DPFX(DPFPREP, DVF_ERRORLEVEL, "PostMessage failed, code: %i", GetLastError());
  170. break; // no error return, just continue
  171. }
  172. }
  173. // update the volume slider
  174. lpsinfo->GetHWNDInputVolumeSlider(&hwndSlider);
  175. if (IsWindow(hwndSlider))
  176. {
  177. pdvInputLevel = (PDVMSG_INPUTLEVEL) lpMessage;
  178. if (!PostMessage(hwndSlider, TBM_SETPOS, 1, DBToAmpFactor(DSBVOLUME_MAX)-DBToAmpFactor(pdvInputLevel->lRecordVolume)))
  179. {
  180. DPFX(DPFPREP, DVF_ERRORLEVEL, "PostMessage failed, code: %i", GetLastError());
  181. break; // no error return, just continue
  182. }
  183. }
  184. break;
  185. case DVMSGID_OUTPUTLEVEL:
  186. if (lpsinfo == NULL)
  187. {
  188. break;
  189. }
  190. // update the peak meter
  191. lpsinfo->GetHWNDOutputPeak(&hwndPeakMeter);
  192. if (IsWindow(hwndPeakMeter))
  193. {
  194. pdvOutputLevel = (PDVMSG_OUTPUTLEVEL) lpMessage;
  195. if (!PostMessage(hwndPeakMeter, PM_SETCUR, 0, pdvOutputLevel->dwPeakLevel ))
  196. {
  197. DPFX(DPFPREP, DVF_ERRORLEVEL, "PostMessage failed, code: %i", GetLastError());
  198. break; // no error return, just continue
  199. }
  200. }
  201. // update the volume slider
  202. lpsinfo->GetHWNDOutputVolumeSlider(&hwndSlider);
  203. if (IsWindow(hwndSlider))
  204. {
  205. DWORD dwVolume = 0; // Set to 0 to avoid PREFIX bug
  206. // Get the current waveOut volume and set the slider to that position
  207. hr = lpsinfo->GetWaveOutVolume(&dwVolume);
  208. if (FAILED(hr))
  209. {
  210. // couldn't get the volume - set the slider to top
  211. PostMessage(hwndSlider, TBM_SETPOS, 1, DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MAX));
  212. // disable the slider
  213. PostMessage(hwndSlider, WM_CANCELMODE, 0, 0 );
  214. }
  215. else
  216. {
  217. PostMessage(hwndSlider, TBM_SETPOS, 1, (DBToAmpFactor(DSBVOLUME_MAX) - DBToAmpFactor(DSBVOLUME_MIN)) - dwVolume);
  218. }
  219. }
  220. break;
  221. default:
  222. break;
  223. }
  224. DPF_EXIT();
  225. return DV_OK;
  226. }
  227. #undef DPF_MODNAME
  228. #define DPF_MODNAME "StartDirectPlay"
  229. HRESULT StartDirectPlay( PDIRECTPLAY8SERVER* lplpdp8 )
  230. {
  231. HRESULT hr = DPN_OK;
  232. LONG lRet = S_OK;
  233. PDIRECTPLAY8ADDRESS pDeviceAddress = NULL;
  234. PDIRECTPLAY8SERVER pdp8Server = NULL;
  235. DPN_APPLICATION_DESC dpnApplicationDesc;
  236. DPF_ENTER();
  237. *lplpdp8 = NULL;
  238. hr = COM_CoCreateInstance(
  239. CLSID_DirectPlay8Server,
  240. NULL,
  241. CLSCTX_INPROC_SERVER,
  242. IID_IDirectPlay8Server,
  243. (void **)lplpdp8);
  244. if (FAILED(hr))
  245. {
  246. *lplpdp8 = NULL;
  247. DPFX(DPFPREP, DVF_ERRORLEVEL, "CoCreateInstance for DirectPlay failed, code: %i", hr);
  248. goto error_cleanup;
  249. }
  250. pdp8Server = *lplpdp8;
  251. hr = COM_CoCreateInstance(
  252. CLSID_DirectPlay8Address,
  253. NULL,
  254. CLSCTX_INPROC_SERVER,
  255. IID_IDirectPlay8Address,
  256. (void **)&pDeviceAddress );
  257. if( FAILED( hr ) )
  258. {
  259. pDeviceAddress = NULL;
  260. DPFX(DPFPREP, DVF_ERRORLEVEL, "CoCreateInstance for DirectPlay8Address failed, code: 0x%x", hr );
  261. goto error_cleanup;
  262. }
  263. //
  264. // NOTE: This now causes the wizard to require TCP/IP to be installed.
  265. // (doesn't have to be dialed up -- as long as local loopback is available)
  266. //
  267. // Eventually build a loopback SP for directplay8.
  268. //
  269. // TODO: Allow this to fall back to other SPs or use loopback SP
  270. //
  271. hr = pDeviceAddress->SetSP( &CLSID_DP8SP_TCPIP );
  272. if( FAILED( hr ) )
  273. {
  274. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed setting SP for address, code: 0x%x", hr );
  275. goto error_cleanup;
  276. }
  277. hr = pdp8Server->Initialize( NULL, DVMessageHandlerServer, 0 );
  278. if( FAILED( hr ) )
  279. {
  280. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed initializing directplay layer, code: 0x%x", hr );
  281. goto error_cleanup;
  282. }
  283. ZeroMemory( &dpnApplicationDesc, sizeof( DPN_APPLICATION_DESC ) );
  284. dpnApplicationDesc.dwSize = sizeof( DPN_APPLICATION_DESC );
  285. dpnApplicationDesc.guidApplication = GUID_LOOPBACKTEST;
  286. dpnApplicationDesc.dwFlags = DPNSESSION_NODPNSVR | DPNSESSION_CLIENT_SERVER;
  287. hr = pdp8Server->Host(
  288. &dpnApplicationDesc,
  289. &pDeviceAddress,
  290. 1,
  291. NULL,
  292. NULL,
  293. NULL,
  294. 0 );
  295. if( FAILED( hr ) )
  296. {
  297. DPFX(DPFPREP, DVF_ERRORLEVEL, "Failed to host on directplay layer, code: 0x%x", hr );
  298. goto error_cleanup;
  299. }
  300. pDeviceAddress->Release();
  301. DPF_EXIT();
  302. return S_OK;
  303. error_cleanup:
  304. if (*lplpdp8 != NULL)
  305. {
  306. pdp8Server->Close(0);
  307. pdp8Server->Release();
  308. *lplpdp8 = NULL;
  309. }
  310. if( pDeviceAddress )
  311. {
  312. pDeviceAddress->Release();
  313. }
  314. DPF_EXIT();
  315. return hr;
  316. }
  317. #undef DPF_MODNAME
  318. #define DPF_MODNAME "StopDirectPlay"
  319. HRESULT StopDirectPlay(PDIRECTPLAY8SERVER lpdp8)
  320. {
  321. DPF_ENTER();
  322. // Kill the session
  323. if (lpdp8 != NULL)
  324. {
  325. lpdp8->Close(0);
  326. lpdp8->Release();
  327. }
  328. DPF_EXIT();
  329. return S_OK;
  330. }
  331. #undef DPF_MODNAME
  332. #define DPF_MODNAME "StartLoopback"
  333. HRESULT StartLoopback(
  334. LPDIRECTPLAYVOICESERVER* lplpdvs,
  335. LPDIRECTPLAYVOICECLIENT* lplpdvc,
  336. PDIRECTPLAY8SERVER* lplpdp8,
  337. LPVOID lpvCallbackContext,
  338. HWND hwndAppWindow,
  339. GUID guidCaptureDevice,
  340. GUID guidRenderDevice,
  341. DWORD dwFlags)
  342. {
  343. HRESULT hr;
  344. DWORD dwSize = 0;
  345. DVCLIENTCONFIG dvcc;
  346. DVSOUNDDEVICECONFIG dvsdc;
  347. DVID dvidAllPlayers = DVID_ALLPLAYERS;
  348. PBYTE pDeviceConfigBuffer = NULL;
  349. PDVSOUNDDEVICECONFIG pdvsdc = NULL;
  350. BOOL fVoiceSessionStarted = FALSE;
  351. BOOL fClientConnected = FALSE;
  352. DPF_ENTER();
  353. *lplpdvs = NULL;
  354. *lplpdvc = NULL;
  355. hr = COM_CoCreateInstance(
  356. DPVOICE_CLSID_DPVOICE,
  357. NULL,
  358. CLSCTX_INPROC_SERVER,
  359. IID_IDirectPlayVoiceServer,
  360. (void **)lplpdvs);
  361. if (FAILED(hr))
  362. {
  363. *lplpdvs = NULL;
  364. DPFX(DPFPREP, DVF_ERRORLEVEL, "CoCreateInstance failed, code: %i", hr);
  365. goto error_cleanup;
  366. }
  367. hr = (*lplpdvs)->Initialize(*lplpdp8, DVMessageHandlerServer, lpvCallbackContext, NULL, 0);
  368. if (FAILED(hr))
  369. {
  370. DPFX(DPFPREP, DVF_ERRORLEVEL, "IDirectPlayVoiceServer::Initialize failed, code: %i", hr);
  371. goto error_cleanup;
  372. }
  373. DVSESSIONDESC dvSessionDesc;
  374. dvSessionDesc.dwSize = sizeof( DVSESSIONDESC );
  375. dvSessionDesc.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
  376. dvSessionDesc.dwBufferQuality = DVBUFFERQUALITY_DEFAULT;
  377. dvSessionDesc.dwFlags = 0;
  378. dvSessionDesc.dwSessionType = DVSESSIONTYPE_ECHO;
  379. // Note this compression type is used for its short frame size so
  380. // we can quickly detect lockups.
  381. dvSessionDesc.guidCT = DPVCTGUID_NONE;
  382. hr = (*lplpdvs)->StartSession( &dvSessionDesc, 0 );
  383. if (FAILED(hr))
  384. {
  385. DPFX(DPFPREP, DVF_ERRORLEVEL, "IDirectPlayVoiceServer::StartSession failed, code: %i", hr);
  386. goto error_cleanup;
  387. }
  388. fVoiceSessionStarted = TRUE;
  389. hr = COM_CoCreateInstance(
  390. DPVOICE_CLSID_DPVOICE,
  391. NULL,
  392. CLSCTX_INPROC_SERVER,
  393. IID_IDirectPlayVoiceClient,
  394. (void **)lplpdvc);
  395. if (FAILED(hr))
  396. {
  397. *lplpdvc = NULL;
  398. DPFX(DPFPREP, DVF_ERRORLEVEL, "CoCreateInstance failed, code: %i", hr);
  399. goto error_cleanup;
  400. }
  401. hr = (*lplpdvc)->Initialize(*lplpdp8, DVMessageHandlerClient, lpvCallbackContext, NULL, 0);
  402. if (FAILED(hr))
  403. {
  404. DPFX(DPFPREP, DVF_ERRORLEVEL, "IDirectPlayVoiceClient::Initialize failed, code: %i", hr);
  405. goto error_cleanup;
  406. }
  407. dvsdc.dwSize = sizeof( DVSOUNDDEVICECONFIG );
  408. dvsdc.hwndAppWindow = hwndAppWindow;
  409. dvsdc.dwFlags = DVSOUNDCONFIG_AUTOSELECT;
  410. if (dwFlags & DVSOUNDCONFIG_HALFDUPLEX)
  411. {
  412. // The caller wants a half duplex session.
  413. dvsdc.dwFlags |= DVSOUNDCONFIG_HALFDUPLEX;
  414. }
  415. if (dwFlags & DVSOUNDCONFIG_TESTMODE)
  416. {
  417. // The caller wants a test mode session.
  418. dvsdc.dwFlags |= DVSOUNDCONFIG_TESTMODE;
  419. }
  420. dvsdc.guidCaptureDevice = guidCaptureDevice;
  421. dvsdc.guidPlaybackDevice = guidRenderDevice;
  422. dvsdc.lpdsPlaybackDevice = NULL;
  423. dvsdc.lpdsCaptureDevice = NULL;
  424. dvsdc.dwMainBufferFlags = 0;
  425. dvsdc.dwMainBufferPriority = 0;
  426. dvsdc.lpdsMainBuffer = NULL;
  427. dvcc.dwSize = sizeof( DVCLIENTCONFIG );
  428. dvcc.dwFlags =
  429. DVCLIENTCONFIG_AUTOVOICEACTIVATED |
  430. DVCLIENTCONFIG_AUTORECORDVOLUME | DVCLIENTCONFIG_AUTOVOLUMERESET |
  431. DVCLIENTCONFIG_PLAYBACKMUTE; // we don't want the user to hear his/her voice right away
  432. dvcc.dwThreshold = DVTHRESHOLD_UNUSED;
  433. dvcc.lPlaybackVolume = DSBVOLUME_MAX;
  434. dvcc.lRecordVolume = DSBVOLUME_MAX;
  435. dvcc.dwNotifyPeriod = 50;
  436. dvcc.dwBufferQuality = DVBUFFERQUALITY_DEFAULT;
  437. dvcc.dwBufferAggressiveness = DVBUFFERAGGRESSIVENESS_DEFAULT;
  438. hr = (*lplpdvc)->Connect( &dvsdc, &dvcc, DVFLAGS_SYNC|DVFLAGS_NOQUERY );
  439. if (FAILED(hr))
  440. {
  441. DPFX(DPFPREP, DVF_ERRORLEVEL, "IDirectPlayVoiceClient::Connect failed, code: %i", hr);
  442. goto error_cleanup;
  443. }
  444. fClientConnected = TRUE;
  445. hr = (*lplpdvc)->SetTransmitTargets(&dvidAllPlayers, 1 , 0);
  446. if (FAILED(hr))
  447. {
  448. DPFX(DPFPREP, DVF_ERRORLEVEL, "IDirectPlayVoiceClient::SetTransmitTargets failed, code: %i", hr);
  449. goto error_cleanup;
  450. }
  451. dwSize = 0;
  452. hr = (*lplpdvc)->GetSoundDeviceConfig(pdvsdc, &dwSize);
  453. if( hr != DVERR_BUFFERTOOSMALL )
  454. {
  455. DPFX(DPFPREP, DVF_ERRORLEVEL, "IDirectPlayVoiceClient::GetSoundDeviceConfig failed, hr: %i", hr);
  456. goto error_cleanup;
  457. }
  458. pDeviceConfigBuffer = new BYTE[dwSize];
  459. if( pDeviceConfigBuffer == NULL )
  460. {
  461. DPFX(DPFPREP, DVF_ERRORLEVEL, "Memory alloc failure" );
  462. hr = DVERR_OUTOFMEMORY;
  463. goto error_cleanup;
  464. }
  465. pdvsdc = (PDVSOUNDDEVICECONFIG) pDeviceConfigBuffer;
  466. pdvsdc->dwSize = sizeof( DVSOUNDDEVICECONFIG );
  467. hr = (*lplpdvc)->GetSoundDeviceConfig(pdvsdc, &dwSize );
  468. if (FAILED(hr))
  469. {
  470. DPFX(DPFPREP, DVF_ERRORLEVEL, "IDirectPlayVoiceClient::GetSoundDeviceConfig failed, hr: %i", hr);
  471. goto error_cleanup;
  472. }
  473. // If we're looking for full duplex fail and notify caller if we get half duplex
  474. if( !(dwFlags & DVSOUNDCONFIG_HALFDUPLEX) )
  475. {
  476. if (pdvsdc->dwFlags & DVSOUNDCONFIG_HALFDUPLEX)
  477. {
  478. DPFX(DPFPREP, DVF_ERRORLEVEL, "We received a half duplex when we expected full duplex" );
  479. // It only started up in half duplex. Notify the caller.
  480. hr = DV_HALFDUPLEX;
  481. goto error_cleanup;
  482. }
  483. }
  484. if( pdvsdc->dwFlags & DVSOUNDCONFIG_HALFDUPLEX )
  485. {
  486. DPFX(DPFPREP, DVF_INFOLEVEL, "StartLoopBack() returning DV_HALFDUPLEX flags=0x%x dwFlags = 0x%x", pdvsdc->dwFlags, dwFlags );
  487. // it started in fullduplex, notify the caller
  488. delete [] pDeviceConfigBuffer;
  489. DPF_EXIT();
  490. return DV_HALFDUPLEX;
  491. }
  492. else
  493. {
  494. DPFX(DPFPREP, DVF_INFOLEVEL, "StartLoopBack() returning DV_FULLDUPLEX flags=0x%x dwFlags = 0x%x", pdvsdc->dwFlags, dwFlags );
  495. // it started in fullduplex, notify the caller
  496. delete [] pDeviceConfigBuffer;
  497. DPF_EXIT();
  498. return DV_FULLDUPLEX;
  499. }
  500. error_cleanup:
  501. if (pDeviceConfigBuffer != NULL)
  502. {
  503. delete [] pDeviceConfigBuffer;
  504. pDeviceConfigBuffer = NULL;
  505. }
  506. if (*lplpdvc != NULL)
  507. {
  508. if (fClientConnected)
  509. {
  510. (*lplpdvc)->Disconnect(DVFLAGS_SYNC);
  511. fClientConnected = FALSE;
  512. }
  513. (*lplpdvc)->Release();
  514. *lplpdvc = NULL;
  515. }
  516. if (*lplpdvs != NULL)
  517. {
  518. if (fVoiceSessionStarted)
  519. {
  520. (*lplpdvs)->StopSession(0);
  521. fVoiceSessionStarted = FALSE;
  522. }
  523. (*lplpdvs)->Release();
  524. *lplpdvs = NULL;
  525. }
  526. DPFX(DPFPREP, DVF_ERRORLEVEL, "StartLoopback() returning hr=0x%x", hr );
  527. DPF_EXIT();
  528. return hr;
  529. }
  530. #undef DPF_MODNAME
  531. #define DPF_MODNAME "StopLoopback"
  532. HRESULT StopLoopback(
  533. LPDIRECTPLAYVOICESERVER lpdvs,
  534. LPDIRECTPLAYVOICECLIENT lpdvc,
  535. PDIRECTPLAY8SERVER lpdp8 )
  536. {
  537. HRESULT hr;
  538. LONG lRet;
  539. BOOL fRet;
  540. BOOL fClientConnected = TRUE;
  541. BOOL fVoiceSessionRunning = TRUE;
  542. DPF_ENTER();
  543. if (lpdvc != NULL)
  544. {
  545. hr = lpdvc->Disconnect(DVFLAGS_SYNC);
  546. fClientConnected = FALSE;
  547. if (FAILED(hr))
  548. {
  549. DPFX(DPFPREP, DVF_ERRORLEVEL, "IDirectPlayVoiceClient::Disconnect failed, hr: %i", hr);
  550. goto error_cleanup;
  551. }
  552. lpdvc->Release();
  553. lpdvc = NULL;
  554. }
  555. if (lpdvs != NULL)
  556. {
  557. hr = lpdvs->StopSession(0);
  558. fVoiceSessionRunning = FALSE;
  559. if (FAILED(hr))
  560. {
  561. DPFX(DPFPREP, DVF_ERRORLEVEL, "IDirectPlayVoiceServer::StopSession failed, hr: %i", hr);
  562. goto error_cleanup;
  563. }
  564. lpdvs->Release();
  565. lpdvs = NULL;
  566. }
  567. DPF_EXIT();
  568. return S_OK;
  569. error_cleanup:
  570. if (lpdvc != NULL)
  571. {
  572. if (fClientConnected)
  573. {
  574. lpdvc->Disconnect(DVFLAGS_SYNC);
  575. fClientConnected = FALSE;
  576. }
  577. lpdvc->Release();
  578. lpdvc = NULL;
  579. }
  580. if (lpdvs != NULL)
  581. {
  582. if (fVoiceSessionRunning)
  583. {
  584. lpdvs->StopSession(0);
  585. fVoiceSessionRunning = FALSE;
  586. }
  587. lpdvs->Release();
  588. lpdvs = NULL;
  589. }
  590. DPF_EXIT();
  591. return hr;
  592. }