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.

493 lines
14 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (C) 1999 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dvdxtran.cpp
  6. * Content: Implementation of transport class providing DirectXVoice transport
  7. * through the IDirectXVoiceTransport interface.
  8. *
  9. * History:
  10. * Date By Reason
  11. * ==== == ======
  12. * 07/23/99 rodtoll Modified from dvdptran.cpp
  13. * 08/03/99 rodtoll Modified to conform to new base class and minor fixes
  14. * for dplay integration.
  15. * 08/04/99 rodtoll Modified to allow group targets
  16. * 08/10/99 rodtoll Removed TODO pragmas
  17. * 08/25/99 rodtoll Fixed group membership check
  18. * 08/30/99 rodtoll Modified SendToServer to send to the server player in
  19. * client/server sessions.
  20. * 08/31/99 rodtoll Updated to use new debug libs
  21. * 09/01/99 rodtoll Updated so that constructor no longer calls into dplay
  22. * rodtoll Added check for valid pointers in func calls
  23. * 09/02/99 rodtoll Added checks to handle case no local player created
  24. * 09/20/99 rodtoll Added memory alloc failure checks
  25. * 09/21/99 rodtoll Fixed memory leak
  26. * 10/05/99 rodtoll Additional comments and DPF_MODNAMEs
  27. * 11/23/99 rodtoll Split CheckForValid into Group and Player
  28. * 12/16/99 rodtoll Bug #122629 - As part of new host migration update how
  29. * sends to server before first response are sent.
  30. * 01/14/2000 rodtoll Renamed SendToID to SendToIDS and updated parameter list
  31. * to accept multiple targets.
  32. * rodtoll Added GetNumPlayers call
  33. * 01/17/2000 rodtoll Debug statement removed that limited max players to 30
  34. * 03/28/2000 rodtoll Moved nametable from here to upper level classes
  35. * rodtoll Removed uneeded functions/members
  36. * 04/07/2000 rodtoll Updated to support new DP <--> DPV interface
  37. * rodtoll Updated to support no copy sends
  38. * rodtoll Bug #32179 - Prevent multiple client/server registrations on transport
  39. * 06/21/2000 rodtoll Bug #36820 - Host migrates to wrong client when client/server are on same interface
  40. * Condition exists where host sends leave message, client attempts to start new host
  41. * which fails because old host still registered. Now deregistering is two step
  42. * process DisableReceiveHook then DestroyTransport.
  43. * 07/22/20000 rodtoll Bug #40296, 38858 - Crashes due to shutdown race condition
  44. * Now ensures that all threads from transport have left and that
  45. * all notificatinos have been processed before shutdown is complete.
  46. * 01/04/2001 rodtoll WinBug #94200 - Remove stray comments
  47. * 01/22/2001 rodtoll WINBUG #288437 - IA64 Pointer misalignment due to wire packets
  48. *
  49. ***************************************************************************/
  50. #include "dxvoicepch.h"
  51. #define DVF_SEND_DEBUG_LEVEL DVF_INFOLEVEL
  52. #undef DPF_MODNAME
  53. #define DPF_MODNAME "CDirectVoiceDirectXTransport::CDirectVoiceDirectXTransport"
  54. CDirectVoiceDirectXTransport::CDirectVoiceDirectXTransport( LPDIRECTPLAYVOICETRANSPORT lpTransport
  55. ): m_lpTransport(NULL),
  56. m_dpidServer(DPID_ALLPLAYERS),
  57. m_dpidLocalPlayer(0),
  58. m_bLocalServer(TRUE),
  59. m_bActiveSession(TRUE),
  60. m_dwTransportFlags(0),
  61. m_lpVoiceEngine(NULL),
  62. m_dwMaxPlayers(0),
  63. m_initialized(FALSE),
  64. m_dwObjectType(0),
  65. m_fAdvised(FALSE)
  66. {
  67. lpTransport->QueryInterface( IID_IDirectPlayVoiceTransport, (void **) &m_lpTransport );
  68. m_dvTransportInfo.dwSize = sizeof( DVTRANSPORTINFO );
  69. }
  70. #undef DPF_MODNAME
  71. #define DPF_MODNAME "CDirectVoiceDirectXTransport::~CDirectVoiceDirectXTransport"
  72. CDirectVoiceDirectXTransport::~CDirectVoiceDirectXTransport()
  73. {
  74. if( m_lpTransport != NULL )
  75. m_lpTransport->Release();
  76. }
  77. #undef DPF_MODNAME
  78. #define DPF_MODNAME "CDirectVoiceDirectXTransport::DestroyTransport"
  79. // DestroyTransport
  80. //
  81. // This method is used to remove last references to transport that transport
  82. // layer has. There was a memory leak where
  83. //
  84. //
  85. void CDirectVoiceDirectXTransport::DestroyTransport()
  86. {
  87. if( m_lpTransport != NULL )
  88. {
  89. m_lpTransport->Release();
  90. m_lpTransport = NULL;
  91. }
  92. }
  93. #undef DPF_MODNAME
  94. #define DPF_MODNAME "CDirectVoiceDirectXTransport::Initialize"
  95. //
  96. // Initialize
  97. //
  98. // Called from the transport when Advise is called.
  99. //
  100. // Used to initialize this object.
  101. //
  102. HRESULT CDirectVoiceDirectXTransport::Initialize( )
  103. {
  104. HRESULT hr;
  105. hr = m_lpTransport->GetSessionInfo( &m_dvTransportInfo );
  106. if( FAILED( hr ) )
  107. {
  108. DPFX(DPFPREP, 0, "DXVT::Initialize: GetSessionInfo() failed! hr=0x%x", hr );
  109. return hr;
  110. }
  111. m_dwMaxPlayers = (m_dvTransportInfo.dwMaxPlayers==0) ? 255 : m_dvTransportInfo.dwMaxPlayers;
  112. m_dpidLocalPlayer = m_dvTransportInfo.dvidLocalID;
  113. // No longer needed, the server may not bee the host of the dplay session
  114. // m_dpidServer = m_dvTransportInfo.dvidSessionHost;
  115. m_dpidServer = DPID_ALLPLAYERS;
  116. m_initialized = TRUE;
  117. return S_OK;
  118. }
  119. #undef DPF_MODNAME
  120. #define DPF_MODNAME "CDirectVoiceDirectXTransport::GetMaxPlayers"
  121. DWORD CDirectVoiceDirectXTransport::GetMaxPlayers( )
  122. {
  123. return m_dwMaxPlayers;
  124. }
  125. #undef DPF_MODNAME
  126. #define DPF_MODNAME "CDirectVoiceDirectXTransport::SendHelper"
  127. HRESULT CDirectVoiceDirectXTransport::SendHelper( UNALIGNED DVID * pdvidTargets, DWORD dwNumTargets, PDVTRANSPORT_BUFFERDESC pBufferDesc, LPVOID pvContext, DWORD dwFlags )
  128. {
  129. HRESULT hr;
  130. if( dwNumTargets > 1 )
  131. {
  132. DEBUG_ONLY( for( DWORD dwIndex = 0; dwIndex < dwNumTargets; dwIndex++ ) { )
  133. DPFX(DPFPREP, DVF_SEND_DEBUG_LEVEL, "Using multitargetted send [From=0x%x To=0x%x]", m_dpidLocalPlayer, pdvidTargets[dwIndex] );
  134. DEBUG_ONLY( } )
  135. hr = m_lpTransport->SendSpeechEx( m_dpidLocalPlayer, dwNumTargets, pdvidTargets, pBufferDesc, pvContext, dwFlags );
  136. }
  137. else
  138. {
  139. DPFX(DPFPREP, DVF_SEND_DEBUG_LEVEL, "Single target for send [From=0x%x To=0x%x]", m_dpidLocalPlayer, pdvidTargets[0] );
  140. hr = m_lpTransport->SendSpeech( m_dpidLocalPlayer, *pdvidTargets, pBufferDesc, pvContext, dwFlags );
  141. }
  142. /*
  143. DNASSERT( pdpidTargets != NULL );
  144. for( DWORD dwIndex = 0; dwIndex < dwNumTargets; dwIndex++ )
  145. {
  146. hr = m_lpTransport->SendSpeech( m_dpidLocalPlayer, pdpidTargets[dwIndex], lpBuffer, dwSize, dwFlags );
  147. } */
  148. return hr;
  149. }
  150. #undef DPF_MODNAME
  151. #define DPF_MODNAME "CDirectVoiceDirectXTransport::SendToServer"
  152. HRESULT CDirectVoiceDirectXTransport::SendToServer( PDVTRANSPORT_BUFFERDESC pBufferDesc, LPVOID pvContext, DWORD dwFlags )
  153. {
  154. if( m_dvTransportInfo.dwSessionType == DVTRANSPORT_SESSION_CLIENTSERVER )
  155. {
  156. DVID dvidTmp = DVID_SERVERPLAYER;
  157. DPFX(DPFPREP, DVF_SEND_DEBUG_LEVEL, "Sending to standard server player" );
  158. return SendHelper( &dvidTmp, 1, pBufferDesc, pvContext, dwFlags );
  159. }
  160. else
  161. {
  162. DPFX(DPFPREP, DVF_SEND_DEBUG_LEVEL, "Sending to server ID [ID=0x%x]", m_dpidServer );
  163. return SendHelper( &m_dpidServer, 1, pBufferDesc, pvContext, dwFlags );
  164. }
  165. }
  166. #undef DPF_MODNAME
  167. #define DPF_MODNAME "CDirectVoiceDirectXTransport::SendToIDS"
  168. HRESULT CDirectVoiceDirectXTransport::SendToIDS( UNALIGNED DVID * pdvidTargets, DWORD dwNumTargets, PDVTRANSPORT_BUFFERDESC pBufferDesc, LPVOID pvContext, DWORD dwFlags )
  169. {
  170. return SendHelper( pdvidTargets, dwNumTargets, pBufferDesc, pvContext, dwFlags );
  171. }
  172. #undef DPF_MODNAME
  173. #define DPF_MODNAME "CDirectVoiceDirectXTransport::SendToAll"
  174. HRESULT CDirectVoiceDirectXTransport::SendToAll( PDVTRANSPORT_BUFFERDESC pBufferDesc, LPVOID pvContext, DWORD dwFlags )
  175. {
  176. DVID dvidTmp = DPID_ALLPLAYERS;
  177. return SendHelper( &dvidTmp, 1, pBufferDesc, pvContext, dwFlags );
  178. }
  179. #undef DPF_MODNAME
  180. #define DPF_MODNAME "CDirectVoiceDirectXTransport::ConfirmValidGroup"
  181. BOOL CDirectVoiceDirectXTransport::ConfirmValidGroup( DVID dvid )
  182. {
  183. if( dvid == DVID_ALLPLAYERS )
  184. {
  185. return TRUE;
  186. }
  187. else if( m_dvTransportInfo.dwSessionType == DVTRANSPORT_SESSION_CLIENTSERVER )
  188. {
  189. return TRUE;
  190. }
  191. else
  192. {
  193. BOOL fResult;
  194. HRESULT hr;
  195. hr = m_lpTransport->IsValidGroup( dvid, &fResult );
  196. if( FAILED( hr ) )
  197. {
  198. DPFX(DPFPREP, DVF_ERRORLEVEL, "Error confirming valid group hr=0x%x", hr );
  199. return FALSE;
  200. }
  201. else
  202. {
  203. return fResult;
  204. }
  205. }
  206. return FALSE;
  207. }
  208. #undef DPF_MODNAME
  209. #define DPF_MODNAME "CDirectVoiceDirectXTransport::ConfirmValidEntity"
  210. //
  211. // ConfirmValidEntity
  212. //
  213. // Checks to ensure that the ID passed is a valid one for the session.
  214. //
  215. // Will return TRUE if the player iD is one of:
  216. // DVID_ALLPLAYERS, DVID_NOTARGET, (any value in client/server mode),
  217. // a player in the map, or a valid Transport group.
  218. //
  219. BOOL CDirectVoiceDirectXTransport::ConfirmValidEntity( DVID dvid )
  220. {
  221. if( m_dvTransportInfo.dwSessionType == DVTRANSPORT_SESSION_CLIENTSERVER )
  222. {
  223. return TRUE;
  224. }
  225. else
  226. {
  227. BOOL fResult;
  228. m_lpTransport->IsValidEntity( dvid, &fResult );
  229. return fResult;
  230. }
  231. return FALSE;
  232. }
  233. #undef DPF_MODNAME
  234. #define DPF_MODNAME "CDirectVoiceDirectXTransport::EnableReceiveHook"
  235. //
  236. // EnableReceiveHook
  237. //
  238. // This is used to activate the connection between the transport
  239. // and the transport class.
  240. //
  241. // We call advise, which will cause Initialize to be called on this
  242. // class before we return from Advise.
  243. //
  244. HRESULT CDirectVoiceDirectXTransport::EnableReceiveHook( LPDIRECTVOICEOBJECT dvObject, DWORD dwObjectType )
  245. {
  246. HRESULT hr;
  247. m_lpVoiceEngine = dvObject->lpDVEngine;
  248. m_dwObjectType = dwObjectType;
  249. // The transport will call Initialize on our notification interface
  250. // before returning from this function.
  251. //
  252. // Once we've returned from this function we should be ok.
  253. // FYI: This is safe, but using QueryInterface would be more "correct". However, we would
  254. // need to determine if this is a client or a server and call the appropriate QueryInterface.
  255. hr = m_lpTransport->Advise( (LPUNKNOWN) dvObject, m_dwObjectType );
  256. if( FAILED( hr ) )
  257. {
  258. DPFX(DPFPREP, DVF_ERRORLEVEL, "Advise failed. hr=0x%x", hr );
  259. m_fAdvised = FALSE;
  260. }
  261. else
  262. {
  263. m_fAdvised = TRUE;
  264. }
  265. return hr;
  266. }
  267. #undef DPF_MODNAME
  268. #define DPF_MODNAME "CDirectVoiceDirectXTransport::DisableReceiveHook"
  269. HRESULT CDirectVoiceDirectXTransport::WaitForDetachCompletion()
  270. {
  271. DPFX(DPFPREP, DVF_DISCONNECT_PROCEDURE_DEBUG_LEVEL, "# of threads remaining: %d", m_lRefCount );
  272. // Loop until all threads are done inside our layer
  273. while( m_lRefCount > 0 )
  274. Sleep( 5 );
  275. return DV_OK;
  276. }
  277. #undef DPF_MODNAME
  278. #define DPF_MODNAME "CDirectVoiceDirectXTransport::DisableReceiveHook"
  279. //
  280. // DisableReceiveHook
  281. //
  282. // Removes the hooks into the transport and releases the interface
  283. // reference this object holds for the transport.
  284. //
  285. // Also responsible for destroying the list of players maintained
  286. // by this object.
  287. //
  288. HRESULT CDirectVoiceDirectXTransport::DisableReceiveHook( )
  289. {
  290. if( m_fAdvised )
  291. {
  292. m_lpTransport->UnAdvise( m_dwObjectType );
  293. m_fAdvised = FALSE;
  294. m_initialized = FALSE;
  295. DPFX(DPFPREP, DVF_DISCONNECT_PROCEDURE_DEBUG_LEVEL, "Unhooking Transport" );
  296. }
  297. // When this is done no more indications will be waiting.
  298. return DV_OK;
  299. }
  300. #undef DPF_MODNAME
  301. #define DPF_MODNAME "CDirectVoiceDirectXTransport::ConfirmLocalHost"
  302. BOOL CDirectVoiceDirectXTransport::ConfirmLocalHost( )
  303. {
  304. if( !m_initialized )
  305. m_lpTransport->GetSessionInfo( &m_dvTransportInfo );
  306. if( m_dvTransportInfo.dwFlags & DVTRANSPORT_LOCALHOST )
  307. return TRUE;
  308. else
  309. return FALSE;
  310. }
  311. #undef DPF_MODNAME
  312. #define DPF_MODNAME "CDirectVoiceDirectXTransport::ConfirmSessionActive"
  313. BOOL CDirectVoiceDirectXTransport::ConfirmSessionActive( )
  314. {
  315. return TRUE;
  316. }
  317. #undef DPF_MODNAME
  318. #define DPF_MODNAME "CDirectVoiceDirectXTransport::GetTransportSettings"
  319. HRESULT CDirectVoiceDirectXTransport::GetTransportSettings( LPDWORD lpdwSessionType, LPDWORD lpdwFlags )
  320. {
  321. HRESULT hr = DV_OK;
  322. if( !m_initialized )
  323. hr = m_lpTransport->GetSessionInfo( &m_dvTransportInfo );
  324. if( FAILED( hr ) )
  325. {
  326. DPFX(DPFPREP, DVF_ERRORLEVEL, "Unable to retrieve transport settings" );
  327. return hr;
  328. }
  329. *lpdwSessionType = m_dvTransportInfo.dwSessionType;
  330. *lpdwFlags = m_dvTransportInfo.dwFlags;
  331. return DV_OK;
  332. }
  333. #undef DPF_MODNAME
  334. #define DPF_MODNAME "CDirectVoiceDirectXTransport::AddPlayerEntry"
  335. HRESULT CDirectVoiceDirectXTransport::AddPlayerEntry( DVID dvidPlayer, LPVOID lpData )
  336. {
  337. return DVERR_NOTSUPPORTED;
  338. }
  339. #undef DPF_MODNAME
  340. #define DPF_MODNAME "CDirectVoiceDirectXTransport::DeletePlayerEntry"
  341. HRESULT CDirectVoiceDirectXTransport::DeletePlayerEntry( DVID dvidPlayer )
  342. {
  343. return DVERR_NOTSUPPORTED;
  344. }
  345. #undef DPF_MODNAME
  346. #define DPF_MODNAME "CDirectVoiceDirectXTransport::GetPlayerEntry"
  347. //
  348. // GetPlayerEntry
  349. //
  350. // Retrieves the player record for the specified player (if it exists).
  351. //
  352. HRESULT CDirectVoiceDirectXTransport::GetPlayerEntry( DVID dvidPlayer, CVoicePlayer **lplpPlayer )
  353. {
  354. return DVERR_NOTSUPPORTED;
  355. }
  356. ////////////////////////////////////////////////////////////////////////
  357. //
  358. // USEFUL FOR REMOTE VOICE SESSIONS
  359. //
  360. #undef DPF_MODNAME
  361. #define DPF_MODNAME "CDirectVoiceDirectXTransport::CreateGroup"
  362. HRESULT CDirectVoiceDirectXTransport::CreateGroup( LPDVID dvidGroup )
  363. {
  364. return S_OK;
  365. }
  366. #undef DPF_MODNAME
  367. #define DPF_MODNAME "CDirectVoiceDirectXTransport::DeleteGroup"
  368. HRESULT CDirectVoiceDirectXTransport::DeleteGroup( DVID dvidGroup )
  369. {
  370. return S_OK;
  371. }
  372. #undef DPF_MODNAME
  373. #define DPF_MODNAME "CDirectVoiceDirectXTransport::AddPlayerToGroup"
  374. HRESULT CDirectVoiceDirectXTransport::AddPlayerToGroup( LPDVID dvidGroup, DVID dvidPlayer )
  375. {
  376. return S_OK;
  377. }
  378. #undef DPF_MODNAME
  379. #define DPF_MODNAME "CDirectVoiceDirectXTransport::RemovePlayerFromGroup"
  380. HRESULT CDirectVoiceDirectXTransport::RemovePlayerFromGroup( DVID dvidGroup, DVID dvidPlayer )
  381. {
  382. return S_OK;
  383. }
  384. #undef DPF_MODNAME
  385. #define DPF_MODNAME "CDirectVoiceDirectXTransport::IsPlayerInGroup"
  386. BOOL CDirectVoiceDirectXTransport::IsPlayerInGroup( DVID dvidGroup, DVID dvidPlayer )
  387. {
  388. if( dvidGroup == DVID_ALLPLAYERS )
  389. {
  390. return TRUE;
  391. }
  392. if( dvidGroup == dvidPlayer )
  393. {
  394. return TRUE;
  395. }
  396. return (m_lpTransport->IsGroupMember( dvidGroup, dvidPlayer )==DV_OK);
  397. }
  398. #undef DPF_MODNAME
  399. #define DPF_MODNAME "CDirectVoiceDirectXTransport::MigrateHost"
  400. //
  401. // MigrateHost
  402. //
  403. // Updates server DPID to match new host
  404. //
  405. HRESULT CDirectVoiceDirectXTransport::MigrateHost( DVID dvidNewHost )
  406. {
  407. DPFX(DPFPREP, DVF_HOSTMIGRATE_DEBUG_LEVEL, "HOST MIGRATION: Setting host to 0x%x", dvidNewHost );
  408. m_dpidServer = dvidNewHost;
  409. return DV_OK;
  410. }
  411. #undef DPF_MODNAME
  412. #define DPF_MODNAME "CDirectVoiceDirectXTransport::MigrateHost"
  413. DVID CDirectVoiceDirectXTransport::GetLocalID()
  414. {
  415. m_dwDuumy = m_dpidLocalPlayer;
  416. return m_dpidLocalPlayer;
  417. }