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.

670 lines
14 KiB

  1. // SAFIntercomClient.cpp : Implementation of CSAFIntercomClient
  2. #include "stdafx.h"
  3. // This is the PORT that we are using for the DPlayVoice connection
  4. //#define SAFINTERCOM_PORT 4000
  5. // *************************************************************
  6. // This GUID is defined for the sake of DPlay8Peer!
  7. // *************************************************************
  8. // {4FE80EF4-AD10-45bd-B6EB-0B7BFB95155F}
  9. static const GUID g_guidApplication =
  10. { 0x4fe80ef4, 0xad10, 0x45bd, { 0xb6, 0xeb, 0xb, 0x7b, 0xfb, 0x95, 0x15, 0x5f } };
  11. /////////////////////////////////////////////////////////////////////////////
  12. // CSAFIntercomClient
  13. //
  14. // Constructor
  15. //
  16. CSAFIntercomClient::CSAFIntercomClient()
  17. {
  18. m_dwSinkCookie = 0x0;
  19. m_bOnCall = FALSE;
  20. m_bAdvised = FALSE;
  21. m_bRTCInit = FALSE;
  22. m_iSamplingRate = 1; // Initalize at the low bandwidth
  23. }
  24. //
  25. // Destructor
  26. //
  27. CSAFIntercomClient::~CSAFIntercomClient()
  28. {
  29. DebugLog(L"CSAFIntercomClient Destructor!\r\n");
  30. Cleanup();
  31. }
  32. STDMETHODIMP CSAFIntercomClient::Event(RTC_EVENT RTCEvent, IDispatch * pEvent)
  33. {
  34. HRESULT hr = S_OK;
  35. CComPtr<IRTCSessionStateChangeEvent> pSessEvent;
  36. CComPtr<IRTCMediaEvent> pMedEvent;
  37. CComPtr<IRTCSession> pSession;
  38. // Session State Change Locals
  39. HRESULT ResCode;
  40. RTC_SESSION_STATE State;
  41. switch(RTCEvent)
  42. {
  43. case RTCE_SESSION_STATE_CHANGE:
  44. hr = pEvent ->QueryInterface(IID_IRTCSessionStateChangeEvent,
  45. (void **)&pSessEvent);
  46. if(FAILED(hr))
  47. {
  48. DebugLog(L"Could not get IID_IRTCSessionStateChangeEvent!\r\n");
  49. return hr;
  50. }
  51. pSessEvent->get_StatusCode(&ResCode);
  52. pSessEvent->get_State(&State);
  53. pSessEvent->get_Session(&pSession);
  54. hr = OnSessionChange(pSession, State, ResCode);
  55. pSessEvent.Release();
  56. if(pSession)
  57. {
  58. pSession.Release();
  59. }
  60. break;
  61. case RTCE_MEDIA:
  62. hr = pEvent->QueryInterface(IID_IRTCMediaEvent, (void **)&pMedEvent);
  63. if (FAILED(hr))
  64. {
  65. DebugLog(L"Could not get IID_IRTCMediaEvent!\r\n");
  66. return hr;
  67. }
  68. hr = onMediaEvent(pMedEvent);
  69. if (FAILED(hr))
  70. {
  71. pMedEvent.Release();
  72. }
  73. break;
  74. case RTCE_CLIENT:
  75. //TODO: Add code here for handling RTCCET_DEVICE_CHANGE (for wizard stuff)
  76. break;
  77. }
  78. return hr;
  79. }
  80. HRESULT CSAFIntercomClient::onMediaEvent(IRTCMediaEvent * pMedEvent)
  81. {
  82. HRESULT hr = S_OK;
  83. long lMediaType;
  84. RTC_MEDIA_EVENT_TYPE EventType;
  85. RTC_MEDIA_EVENT_REASON EventReason;
  86. // Get all the values for this Event
  87. pMedEvent->get_MediaType(&lMediaType);
  88. pMedEvent->get_EventType(&EventType);
  89. pMedEvent->get_EventReason(&EventReason);
  90. // Make sure we are talking about audio
  91. if (!(
  92. ( lMediaType & RTCMT_AUDIO_SEND ) | // Send
  93. ( lMediaType & RTCMT_AUDIO_RECEIVE )
  94. )
  95. )
  96. {
  97. // Don't handle it since it's not an audio event
  98. return S_OK;
  99. }
  100. switch (EventType)
  101. {
  102. case RTCMET_STOPPED:
  103. // Check to see if we have stopped because of a timeout
  104. // SPECIAL CASE:
  105. // This is the case where we are in front of a firewall
  106. if (EventReason == RTCMER_TIMEOUT)
  107. {
  108. // Disable Voice
  109. Fire_onVoiceDisabled(this);
  110. }
  111. break;
  112. case RTCMET_FAILED:
  113. // Disable voice, something happened to the connection
  114. // Special Case:
  115. // This COULD be the case where one person is GUEST
  116. Fire_onVoiceDisabled(this);
  117. break;
  118. }
  119. return hr;
  120. }
  121. HRESULT CSAFIntercomClient::OnSessionChange(IRTCSession *pSession,
  122. RTC_SESSION_STATE nState,
  123. HRESULT ResCode)
  124. {
  125. HRESULT hr = S_OK;
  126. int iRet;
  127. switch (nState)
  128. {
  129. case RTCSS_INCOMING:
  130. // Do nothing, a client cannot answer an incoming call
  131. return S_OK;
  132. break;
  133. case RTCSS_CONNECTED:
  134. Fire_onVoiceConnected(this);
  135. break;
  136. case RTCSS_DISCONNECTED:
  137. if (m_pRTCSession)
  138. {
  139. Fire_onVoiceDisconnected(this);
  140. }
  141. m_bOnCall = FALSE;
  142. if (m_pRTCSession)
  143. {
  144. m_pRTCSession.Release();
  145. }
  146. return S_OK;
  147. break;
  148. }
  149. return hr;
  150. }
  151. STDMETHODIMP CSAFIntercomClient::Connect(BSTR bstrIP, BSTR bstrKey)
  152. {
  153. HRESULT hr;
  154. VARIANT_BOOL vbRun;
  155. long flags;
  156. // Make sure we are not already in a call. If we are on a call fail, with E_FAIL;
  157. if (m_bOnCall)
  158. {
  159. DebugLog(L"Cannot call Connect(...) while on a call\r\n");
  160. return E_FAIL;
  161. }
  162. // Initialize the Call
  163. if (FAILED(hr = Init()))
  164. {
  165. DebugLog(L"Call to Init() failed!\r\n");
  166. Fire_onVoiceDisabled(this);
  167. return hr;
  168. }
  169. // Get media capabilities.
  170. // Question: Do we have audio send and receive capabilities on this machine?
  171. if (FAILED( hr = m_pRTCClient->get_MediaCapabilities(&flags)))
  172. {
  173. DebugLog(L"Call to get_MediaCapabilities failed!\r\n");
  174. Fire_onVoiceDisabled(this);
  175. return hr;
  176. }
  177. // Check results
  178. if ( !(flags & ( RTCMT_AUDIO_SEND | RTCMT_AUDIO_RECEIVE )) )
  179. {
  180. DebugLog(L"This machine does not have audio capabilites, Voice is Disabled!\r\n");
  181. Fire_onVoiceDisabled(this);
  182. return hr;
  183. }
  184. // If we have never run the Audio wizard, run it now
  185. if (FAILED( hr = m_pRTCClient->get_IsTuned(&vbRun)))
  186. {
  187. DebugLog(L"Call to IsTuned failed!\r\n");
  188. Fire_onVoiceDisabled(this);
  189. return hr;
  190. }
  191. if (VARIANT_FALSE == vbRun)
  192. {
  193. if (FAILED(hr = RunSetupWizard()))
  194. {
  195. DebugLog(L"Call to RunSetupWizard() failed!\r\n");
  196. return hr;
  197. }
  198. }
  199. // Since we have setup at this point, lets set the m_bOnCall variable
  200. // Reason: We have advised the RTCClient object and are listening for events.
  201. // NOTE: If we fail out at this point(or beyond), we need to set this bool back to FALSE
  202. m_bOnCall = TRUE;
  203. // Make the call
  204. if (FAILED( hr = m_pRTCClient->CreateSession( RTCST_PC_TO_PC,
  205. NULL,
  206. NULL,
  207. 0,
  208. &m_pRTCSession)))
  209. {
  210. DebugLog(L"CreateSession off of the RTCClient object failed!\r\n");
  211. m_bOnCall = FALSE;
  212. Fire_onVoiceDisabled(this);
  213. return hr;
  214. }
  215. // Set the key on the Client Side
  216. if (FAILED( hr = m_pRTCSession->put_EncryptionKey(RTCMT_AUDIO_SEND | RTCMT_AUDIO_RECEIVE,
  217. bstrKey)))
  218. {
  219. DebugLog(L"put_EncryptionKey failed!\r\n");
  220. Fire_onVoiceDisabled(this);
  221. return hr;
  222. }
  223. // Call the server
  224. if (FAILED( hr = m_pRTCSession->AddParticipant( bstrIP,
  225. L"",
  226. NULL)))
  227. {
  228. DebugLog(L"AddParticipant on RTCSession object failed!\r\n");
  229. m_bOnCall = FALSE;
  230. Fire_onVoiceDisabled(this);
  231. return hr;
  232. }
  233. return S_OK;
  234. }
  235. STDMETHODIMP CSAFIntercomClient::Disconnect()
  236. {
  237. // TODO: make sure we handle the case where we are shutting down.
  238. // Find out if we care about RTCSHUTDOWN
  239. HRESULT hr;
  240. if (!m_bOnCall)
  241. {
  242. DebugLog(L"Must be on a call to call Disconnect!\r\n");
  243. return E_FAIL;
  244. }
  245. if (m_pRTCSession)
  246. {
  247. if (FAILED( hr = m_pRTCSession->Terminate(RTCTR_NORMAL)))
  248. {
  249. DebugLog(L"Terminate off of the Session object failed!\r\n");
  250. return hr;
  251. }
  252. m_pRTCSession.Release();
  253. }
  254. return S_OK;
  255. }
  256. //
  257. // This method is used to Unadvise the RTCClient object of us (CSAFIntercomClient)
  258. //
  259. STDMETHODIMP CSAFIntercomClient::Exit()
  260. {
  261. HRESULT hr;
  262. DebugLog(L"Inside CSAFIntercomClient::Exit()\r\n");
  263. // Unadvise IRTCClient of the sink
  264. if (m_bAdvised)
  265. {
  266. AtlUnadvise((IUnknown *)m_pRTCClient, IID_IRTCEventNotification, m_dwSinkCookie);
  267. }
  268. return S_OK;
  269. }
  270. HRESULT CSAFIntercomClient::RunSetupWizard()
  271. {
  272. HRESULT hr = S_OK;
  273. long flags;
  274. // Setup
  275. if (FAILED(hr = Init()))
  276. {
  277. DebugLog(L"Call to Init() failed!\r\n");
  278. Fire_onVoiceDisabled(this);
  279. return hr;
  280. }
  281. if (FAILED(hr = m_pRTCClient->InvokeTuningWizard(NULL)))
  282. {
  283. DebugLog(L"InvokeTuningWizard FAILED!\r\n");
  284. Fire_onVoiceDisabled(this);
  285. return hr;
  286. }
  287. // Get media capabilities. If the wizard failed to detect sound we can
  288. // disable Voice
  289. if (FAILED( hr = m_pRTCClient->get_MediaCapabilities(&flags)))
  290. {
  291. DebugLog(L"Call to get_MediaCapabilities failed!\r\n");
  292. Fire_onVoiceDisabled(this);
  293. return hr;
  294. }
  295. // Check results
  296. if ( !(flags & ( RTCMT_AUDIO_SEND | RTCMT_AUDIO_RECEIVE )) )
  297. {
  298. DebugLog(L"This machine does not have audio capabilites, Voice is Disabled!\r\n");
  299. Fire_onVoiceDisabled(this);
  300. return hr;
  301. }
  302. return S_OK;
  303. }
  304. HRESULT CSAFIntercomClient::Cleanup()
  305. {
  306. HRESULT hr = S_OK;
  307. // Shutdown if needed
  308. if (m_bRTCInit)
  309. {
  310. m_pRTCClient->Shutdown();
  311. }
  312. // Now release all the interfaces we used
  313. if (m_pRTCSession)
  314. {
  315. m_pRTCSession.Release();
  316. }
  317. if (m_pRTCClient)
  318. {
  319. m_pRTCClient.Release();
  320. }
  321. return hr;
  322. }
  323. HRESULT CSAFIntercomClient::Init()
  324. {
  325. HRESULT hr = S_OK;
  326. CComPtr<IUnknown> pUnkThis;
  327. // Once we have initialized, do nothing
  328. if (!m_pRTCClient)
  329. {
  330. DWORD dwProfileFlags;
  331. // Check to see if we have a temporary profile
  332. if(GetProfileType( &dwProfileFlags ))
  333. {
  334. if (dwProfileFlags & PT_TEMPORARY)
  335. {
  336. return E_FAIL;
  337. }
  338. }
  339. // Create the RTCClient object
  340. if (FAILED(hr = m_pRTCClient.CoCreateInstance(CLSID_RTCClient)))
  341. {
  342. DebugLog(L"Could not create the RTCClient object\r\n");
  343. return hr;
  344. }
  345. if (!m_bRTCInit)
  346. {
  347. if (FAILED(hr = m_pRTCClient->Initialize()))
  348. {
  349. DebugLog(L"Call to Initialize on the RTCClient object failed!\r\n");
  350. return hr;
  351. }
  352. // Set the sampling bit rate (it may be different because of changes in the property)
  353. if (m_iSamplingRate == 1)
  354. {
  355. if (FAILED(hr = m_pRTCClient->put_MaxBitrate(6400)))
  356. {
  357. DebugLog(L"put_MaxBitrate failed!\r\n");
  358. }
  359. }
  360. else
  361. {
  362. if (FAILED(hr = m_pRTCClient->put_MaxBitrate(64000)))
  363. {
  364. DebugLog(L"put_MaxBitrate failed!\r\n");
  365. }
  366. }
  367. // Since we have Initialized the RTCClient, enable the flag
  368. m_bRTCInit = TRUE;
  369. if (FAILED(hr = m_pRTCClient->SetPreferredMediaTypes( RTCMT_AUDIO_SEND | RTCMT_AUDIO_RECEIVE,
  370. FALSE )))
  371. {
  372. DebugLog(L"Call to SetPreferredMediaType failed!\r\n");
  373. return hr;
  374. }
  375. }
  376. // Get the IUnknown of the 'this' ptr
  377. if (FAILED( hr = this->QueryInterface(IID_IUnknown, (void **)&pUnkThis)))
  378. {
  379. DebugLog(L"QueryInterface for IUnknown failed!\r\n");
  380. return hr;
  381. }
  382. if (!m_bAdvised)
  383. {
  384. // Advise IRTCClient of the sink
  385. if (FAILED( hr = m_pRTCClient.Advise( pUnkThis, IID_IRTCEventNotification, &m_dwSinkCookie)))
  386. {
  387. DebugLog(L"AtlAdvise failed!\r\n");
  388. return hr;
  389. }
  390. m_bAdvised = TRUE;
  391. // TODO: Verify about RTCLM_BOTH
  392. if (FAILED( hr = m_pRTCClient->put_ListenForIncomingSessions(RTCLM_NONE)))
  393. {
  394. DebugLog(L"Set ListenForIncomingSessions property failed!\r\n");
  395. return hr;
  396. }
  397. }
  398. }
  399. return hr;
  400. }
  401. /////////////////////////////////////////////////////////////////////////////
  402. /////////////////////////////////////////////////////////////////////////////
  403. //////////////////////////
  404. // //
  405. // Event Firing Methods //
  406. // //
  407. //////////////////////////
  408. HRESULT CSAFIntercomClient::Fire_onVoiceConnected( ISAFIntercomClient * safi)
  409. {
  410. CComVariant pvars[1];
  411. pvars[0] = safi;
  412. return FireAsync_Generic( DISPID_PCH_INCE__ONDISCONNECTED, pvars, ARRAYSIZE( pvars ), m_sink_onVoiceConnected );
  413. }
  414. HRESULT CSAFIntercomClient::Fire_onVoiceDisconnected( ISAFIntercomClient * safi)
  415. {
  416. CComVariant pvars[1];
  417. pvars[0] = safi;
  418. return FireAsync_Generic( DISPID_PCH_INCE__ONDISCONNECTED, pvars, ARRAYSIZE( pvars ), m_sink_onVoiceDisconnected );
  419. }
  420. HRESULT CSAFIntercomClient::Fire_onVoiceDisabled( ISAFIntercomClient * safi)
  421. {
  422. CComVariant pvars[1];
  423. pvars[0] = safi;
  424. return FireAsync_Generic( DISPID_PCH_INCE__ONVOICEDISABLED, pvars, ARRAYSIZE( pvars ), m_sink_onVoiceDisabled );
  425. }
  426. //////////////////////////
  427. // //
  428. // Properties //
  429. // //
  430. //////////////////////////
  431. STDMETHODIMP CSAFIntercomClient::put_onVoiceConnected( /*[in]*/ IDispatch* function )
  432. {
  433. __HCP_BEGIN_PROPERTY_PUT("CSAFIntercomClient::put_onVoiceConnected",hr);
  434. m_sink_onVoiceConnected = function;
  435. __HCP_END_PROPERTY(hr);
  436. }
  437. STDMETHODIMP CSAFIntercomClient::put_onVoiceDisconnected( /*[in]*/ IDispatch* function )
  438. {
  439. __HCP_BEGIN_PROPERTY_PUT("CSAFIntercomClient::put_onVoiceDisconnected",hr);
  440. m_sink_onVoiceDisconnected = function;
  441. __HCP_END_PROPERTY(hr);
  442. }
  443. STDMETHODIMP CSAFIntercomClient::put_onVoiceDisabled( /*[in]*/ IDispatch* function)
  444. {
  445. __HCP_BEGIN_PROPERTY_PUT("CSAFIntercomClient::put_onVoiceDisconnected",hr);
  446. m_sink_onVoiceDisabled = function;
  447. __HCP_END_PROPERTY(hr);
  448. }
  449. STDMETHODIMP CSAFIntercomClient::put_SamplingRate ( /*[in]*/ LONG newVal)
  450. {
  451. __HCP_BEGIN_PROPERTY_PUT("CSAFIntercomServer::put_SamplingRate", hr);
  452. hr = S_OK;
  453. // Make sure that the newVal is correct
  454. if ((newVal == 1) || (newVal == 2))
  455. {
  456. // If m_pRTCClient doesn't exist then persist the m_iSamplingRate for when it is created
  457. m_iSamplingRate = newVal;
  458. if (m_pRTCClient)
  459. {
  460. // Set the MaxBitRates on the client, because it exists (m_pRTCClient)
  461. if (m_iSamplingRate == 1)
  462. {
  463. if (FAILED(hr = m_pRTCClient->put_MaxBitrate(6400)))
  464. {
  465. DebugLog(L"put_MaxBitrate failed!\r\n");
  466. }
  467. }
  468. else
  469. {
  470. if (FAILED(hr = m_pRTCClient->put_MaxBitrate(64000)))
  471. {
  472. DebugLog(L"put_MaxBitrate failed!\r\n");
  473. }
  474. }
  475. }
  476. }
  477. else
  478. {
  479. hr = E_INVALIDARG;
  480. }
  481. __HCP_END_PROPERTY(hr);
  482. }
  483. STDMETHODIMP CSAFIntercomClient::get_SamplingRate (/*[out, retval]*/ LONG * pVal )
  484. {
  485. __HCP_BEGIN_PROPERTY_GET("CSAFIntercomServer::put_SamplingRate", hr, pVal);
  486. *pVal = m_iSamplingRate;
  487. hr = S_OK;
  488. __HCP_END_PROPERTY(hr);
  489. }
  490. /////////////////////////////////////////////////////////////////////////////
  491. /////////////////////////////////////////////////////////////////////////////
  492. void DebugLog(WCHAR * str, ...)
  493. {
  494. WCHAR newstr[200];
  495. va_list marker;
  496. va_start(marker, str);
  497. wsprintf(newstr, str, marker);
  498. va_end(marker);
  499. OutputDebugString(newstr);
  500. }