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.

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