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.

1392 lines
37 KiB

  1. /////////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1997 Active Voice Corporation. All Rights Reserved.
  4. //
  5. // Active Agent(r) and Unified Communications(tm) are trademarks of Active Voice Corporation.
  6. //
  7. // Other brand and product names used herein are trademarks of their respective owners.
  8. //
  9. // The entire program and user interface including the structure, sequence, selection,
  10. // and arrangement of the dialog, the exclusively "yes" and "no" choices represented
  11. // by "1" and "2," and each dialog message are protected by copyrights registered in
  12. // the United States and by international treaties.
  13. //
  14. // Protected by one or more of the following United States patents: 5,070,526, 5,488,650,
  15. // 5,434,906, 5,581,604, 5,533,102, 5,568,540, 5,625,676, 5,651,054.
  16. //
  17. // Active Voice Corporation
  18. // Seattle, Washington
  19. // USA
  20. //
  21. /////////////////////////////////////////////////////////////////////////////////////////
  22. // ConfRoom.cpp : Implementation of CConfRoom
  23. #include "stdafx.h"
  24. #include "TapiDialer.h"
  25. #include "AVTapi.h"
  26. #include "ConfRoom.h"
  27. #include "CRTreeView.h"
  28. /////////////////////////////////////////////////////////////////////////////
  29. // CConfRoom
  30. CConfRoom::CConfRoom()
  31. {
  32. m_pAVCall = NULL;
  33. m_pTreeView = NULL;
  34. m_wndRoom.m_pConfRoom = this;
  35. m_bShowNames = true;
  36. m_nShowNamesNumLines = 1;
  37. m_nMaxTerms = DEFAULT_VIDEO;
  38. m_nNumTerms = m_nMaxTerms;
  39. m_lNumParticipants = 0;
  40. m_szMembers.cx = VID_SX;
  41. m_szMembers.cy = VID_SY;
  42. m_szTalker.cx = VID_X;
  43. m_szTalker.cy = VID_Y;
  44. m_bConfirmDisconnect = false;
  45. m_pVideoPreview = NULL;
  46. m_pITTalkerParticipant = NULL;
  47. m_pITalkerVideo = NULL;
  48. m_bPreviewStreaming = FALSE;
  49. m_bExiting = false;
  50. m_nScale = 100;
  51. }
  52. void CConfRoom::FinalRelease()
  53. {
  54. ATLTRACE(_T(".enter.CConfRoom::FinalRelease().\n") );
  55. // Clean out the call object
  56. IAVTapiCall *pAVCall = m_pAVCall;
  57. m_pAVCall = NULL;
  58. ReleaseAVCall( pAVCall, true );
  59. RELEASE( m_pTreeView );
  60. // Is the window still visible?
  61. if ( m_wndRoom.m_hWnd && IsWindow(m_wndRoom.m_hWnd) )
  62. m_wndRoom.DestroyWindow();
  63. CComObjectRootEx<CComMultiThreadModel>::FinalRelease();
  64. ATLTRACE(_T(".exit.CConfRoom::FinalRelease().\n") );
  65. }
  66. void CConfRoom::ReleaseAVCall( IAVTapiCall *pAVCall, bool bDisconnect )
  67. {
  68. ATLTRACE(_T(".enter.CConfRoom::ReleaseAVCall().\n"));
  69. if ( pAVCall )
  70. {
  71. ITBasicCallControl *pControl;
  72. if ( SUCCEEDED(pAVCall->get_ITBasicCallControl(&pControl)) )
  73. {
  74. // Only attempt disconnect if requested
  75. if ( bDisconnect )
  76. pControl->Disconnect( DC_NORMAL );
  77. // Release ref to call and remove from call list
  78. CAVTapi *pAVTapi;
  79. if ( SUCCEEDED(_Module.GetAVTapi(&pAVTapi)) )
  80. {
  81. pAVTapi->RemoveAVTapiCall( pControl );
  82. (dynamic_cast<IUnknown *> (pAVTapi))->Release();
  83. }
  84. pControl->Release();
  85. }
  86. pAVCall->Release();
  87. pAVCall = NULL;
  88. }
  89. // Release the call, and disconnect if active
  90. set_TalkerVideo( NULL, !IsExiting(), false );
  91. set_ITTalkerParticipant( NULL );
  92. ATLTRACE(_T(".exit.CConfRoom::ReleaseAVCall().\n"));
  93. }
  94. STDMETHODIMP CConfRoom::UnShow()
  95. {
  96. ATLTRACE(_T(".enter.CConfRoom::UnShow().\n") );
  97. UpdateData( true );
  98. IConfRoomTreeView *pTreeView;
  99. if ( SUCCEEDED(get_TreeView(&pTreeView)) )
  100. {
  101. pTreeView->put_hWnd( NULL );
  102. pTreeView->put_ConfRoom( NULL );
  103. pTreeView->Release();
  104. }
  105. if ( IsWindow(m_wndRoom.m_hWnd) )
  106. {
  107. Lock();
  108. m_bExiting = true;
  109. Unlock();
  110. InternalDisconnect();
  111. }
  112. return S_OK;
  113. }
  114. bool CConfRoom::IsExiting()
  115. {
  116. bool bRet;
  117. Lock();
  118. bRet = m_bExiting;
  119. Unlock();
  120. return bRet;
  121. }
  122. void CConfRoom::UpdateData( bool bSaveAndValidate )
  123. {
  124. CRegKey regKey;
  125. TCHAR szReg[255];
  126. DWORD dwTemp;
  127. LoadString( _Module.GetResourceInstance(), IDN_REG_CONFROOM_VIEW_KEY, szReg, ARRAYSIZE(szReg) );
  128. if ( bSaveAndValidate )
  129. {
  130. // Save data to registry
  131. if ( regKey.Create(HKEY_CURRENT_USER, szReg) == ERROR_SUCCESS )
  132. {
  133. // Full size video
  134. short nSize;
  135. get_MemberVideoSize( &nSize );
  136. LoadString( _Module.GetResourceInstance(), IDN_REG_CONFROOM_VIDEOSIZE, szReg, ARRAYSIZE(szReg) );
  137. regKey.SetValue( (DWORD) nSize, szReg );
  138. // $CRIT - enter
  139. Lock();
  140. // Show Names
  141. LoadString( _Module.GetResourceInstance(), IDN_REG_CONFROOM_SHOWNAMES, szReg, ARRAYSIZE(szReg) );
  142. dwTemp = m_bShowNames;
  143. regKey.SetValue( dwTemp, szReg );
  144. // Number of lines in name text
  145. LoadString( _Module.GetResourceInstance(), IDN_REG_CONFROOM_SHOWNAMES_NUMLINES, szReg, ARRAYSIZE(szReg) );
  146. dwTemp = m_nShowNamesNumLines;
  147. regKey.SetValue( dwTemp, szReg );
  148. // Size of talker window
  149. LoadString( _Module.GetResourceInstance(), IDN_REG_CONFROOM_TALKER_SCALE, szReg, ARRAYSIZE(szReg) );
  150. dwTemp = m_nScale;
  151. regKey.SetValue( dwTemp, szReg );
  152. Unlock();
  153. // $CRIT - exit
  154. }
  155. }
  156. else if ( regKey.Open(HKEY_CURRENT_USER, szReg, KEY_READ) == ERROR_SUCCESS )
  157. {
  158. // Load data from registry
  159. // Full size video?
  160. dwTemp = 50; // default is 50 percent
  161. LoadString( _Module.GetResourceInstance(), IDN_REG_CONFROOM_VIDEOSIZE, szReg, ARRAYSIZE(szReg) );
  162. regKey.QueryValue( dwTemp, szReg );
  163. put_MemberVideoSize( (short) max(10, min(dwTemp, 100)) ); // arbitrary limits
  164. // $CRIT - enter
  165. Lock();
  166. // Show names
  167. LoadString( _Module.GetResourceInstance(), IDN_REG_CONFROOM_SHOWNAMES, szReg, ARRAYSIZE(szReg) );
  168. dwTemp = 1;
  169. regKey.QueryValue( dwTemp, szReg );
  170. m_bShowNames = (bool) (dwTemp != 0 );
  171. // Number of lines in name text
  172. LoadString( _Module.GetResourceInstance(), IDN_REG_CONFROOM_SHOWNAMES_NUMLINES, szReg, ARRAYSIZE(szReg) );
  173. regKey.QueryValue( dwTemp, szReg );
  174. m_nShowNamesNumLines = (short) max(1, min(dwTemp, 3));
  175. // Size of talker window
  176. LoadString( _Module.GetResourceInstance(), IDN_REG_CONFROOM_TALKER_SCALE, szReg, ARRAYSIZE(szReg) );
  177. regKey.QueryValue( dwTemp, szReg );
  178. m_nScale = (short) max(100, min(dwTemp, 200));
  179. m_szTalker.cx = VID_X * m_nScale / 100;
  180. m_szTalker.cy = VID_Y * m_nScale / 100;
  181. Unlock();
  182. // $CRIT - exit
  183. }
  184. regKey.Close();
  185. }
  186. STDMETHODIMP CConfRoom::get_TalkerVideo(IDispatch **ppVideo)
  187. {
  188. HRESULT hr = E_FAIL;
  189. m_atomTalkerVideo.Lock( CAtomicList::LIST_READ );
  190. if ( m_pITalkerVideo )
  191. hr = m_pITalkerVideo->QueryInterface( IID_IVideoWindow, (void **) ppVideo );
  192. m_atomTalkerVideo.Unlock( CAtomicList::LIST_READ );
  193. return hr;
  194. }
  195. HRESULT CConfRoom::get_ITTalkerParticipant(ITParticipant **ppVal)
  196. {
  197. HRESULT hr = E_FAIL;
  198. m_atomTalkerParticipant.Lock( CAtomicList::LIST_READ );
  199. if ( m_pITTalkerParticipant )
  200. hr = m_pITTalkerParticipant->QueryInterface( IID_ITParticipant, (void **) ppVal );
  201. m_atomTalkerParticipant.Unlock( CAtomicList::LIST_READ );
  202. return hr;
  203. }
  204. HRESULT CConfRoom::set_ITTalkerParticipant(ITParticipant *pVal)
  205. {
  206. HRESULT hr = E_FAIL;
  207. m_atomTalkerParticipant.Lock( CAtomicList::LIST_WRITE );
  208. RELEASE( m_pITTalkerParticipant );
  209. if ( pVal )
  210. hr = pVal->QueryInterface( IID_ITParticipant, (void **) &m_pITTalkerParticipant );
  211. m_atomTalkerParticipant.Unlock( CAtomicList::LIST_WRITE );
  212. return hr;
  213. }
  214. HRESULT CConfRoom::set_TalkerVideo( IVideoWindow *pVideo, bool bUpdate, bool bUpdateTree )
  215. {
  216. if ( pVideo && !m_pAVCall ) return S_OK;
  217. HRESULT hr = S_OK;
  218. // Set the talker video if it's different from the current one
  219. m_atomTalkerVideo.Lock( CAtomicList::LIST_WRITE );
  220. if ( !pVideo || (pVideo != m_pITalkerVideo) )
  221. {
  222. // Save old video window
  223. IVideoWindow *pVideoOld = m_pITalkerVideo;
  224. m_pITalkerVideo = pVideo;
  225. if ( m_pITalkerVideo )
  226. m_pITalkerVideo->AddRef();
  227. m_atomTalkerVideo.Unlock( CAtomicList::LIST_WRITE );
  228. // Clean out old talker window
  229. if ( pVideoOld )
  230. {
  231. pVideoOld->put_Visible( OAFALSE );
  232. m_wndRoom.m_wndMembers.ClearFeed( pVideoOld );
  233. pVideoOld->Release();
  234. }
  235. // Show new talker
  236. if ( bUpdate )
  237. {
  238. // Layout the talker dialog
  239. m_wndRoom.LayoutRoom( CConfRoomWnd::LAYOUT_TALKER, true );
  240. // Only update the talker if there is video to show
  241. if ( pVideo )
  242. m_wndRoom.m_wndMembers.UpdateTalkerFeed( true, false );
  243. }
  244. }
  245. else
  246. {
  247. m_atomTalkerVideo.Unlock( CAtomicList::LIST_WRITE );
  248. }
  249. // Select the appropriate talker from the treeview
  250. if ( bUpdateTree )
  251. {
  252. VARIANT_BOOL bPreview = TRUE;
  253. ITParticipant *pParticipant = NULL;
  254. IVideoFeed *pFeed;
  255. if ( SUCCEEDED(m_wndRoom.m_wndMembers.FindVideoFeed(pVideo, &pFeed)) )
  256. {
  257. if ( FAILED(pFeed->get_bPreview(&bPreview)) || !bPreview )
  258. pFeed->get_ITParticipant( &pParticipant );
  259. pFeed->Release();
  260. }
  261. // Select the appropriate participant
  262. IConfRoomTreeView *pTreeView;
  263. if ( SUCCEEDED(get_TreeView(&pTreeView)) )
  264. {
  265. pTreeView->SelectParticipant( pParticipant, bPreview );
  266. pTreeView->Release();
  267. }
  268. RELEASE( pParticipant );
  269. }
  270. return hr;
  271. }
  272. STDMETHODIMP CConfRoom::SelectTalker(ITParticipant *pParticipant, VARIANT_BOOL bUpdateTree )
  273. {
  274. HRESULT hr = S_OK;
  275. IVideoFeed *pFeed = NULL;
  276. set_ITTalkerParticipant( NULL );
  277. // Select 'Me' from the list if possible (don't select me if the conference room is minimized)
  278. if ( !pParticipant )
  279. m_wndRoom.m_wndMembers.FindVideoPreviewFeed( &pFeed );
  280. // Bail if necessary
  281. if ( FAILED(hr) ) return hr;
  282. if ( pFeed || (pParticipant && SUCCEEDED(hr = FindVideoFeedFromParticipant(pParticipant, &pFeed))) )
  283. {
  284. IVideoWindow *pVideo;
  285. if ( SUCCEEDED(hr = pFeed->get_IVideoWindow((IUnknown **) &pVideo)) )
  286. {
  287. hr = set_TalkerVideo( pVideo, true, (bool) (bUpdateTree != 0));
  288. pVideo->Release();
  289. }
  290. pFeed->Release();
  291. }
  292. else if ( pParticipant )
  293. {
  294. // Must re-map to valid stream
  295. bool bSucceed = false;
  296. IAVTapiCall *pAVCall;
  297. if ( SUCCEEDED(get_IAVTapiCall(&pAVCall)) )
  298. {
  299. IParticipant *pIParticipant;
  300. if ( SUCCEEDED(pAVCall->FindParticipant(pParticipant, &pIParticipant)) )
  301. {
  302. VARIANT_BOOL bStreamingVideo = false;
  303. pIParticipant->get_bStreamingVideo( &bStreamingVideo );
  304. if ( bStreamingVideo )
  305. {
  306. IVideoFeed *pFeed;
  307. bSucceed = MapStreamingParticipant( pIParticipant, &pFeed );
  308. if ( bSucceed )
  309. {
  310. IVideoWindow *pVideo;
  311. if ( SUCCEEDED(pFeed->get_IVideoWindow((IUnknown **) &pVideo)) )
  312. {
  313. hr = set_TalkerVideo( pVideo, true, (bool) (bUpdateTree != 0) );
  314. pVideo->Release();
  315. }
  316. pFeed->Release();
  317. }
  318. }
  319. pIParticipant->Release();
  320. }
  321. pAVCall->Release();
  322. }
  323. // Participant only, no video
  324. if ( !bSucceed )
  325. {
  326. set_ITTalkerParticipant( pParticipant );
  327. hr = set_TalkerVideo( NULL, false, (bool) (bUpdateTree != 0) );
  328. }
  329. m_wndRoom.m_wndTalker.UpdateNames( pParticipant );
  330. m_wndRoom.m_wndTalker.Invalidate( FALSE );
  331. // Make sure to update the member's as well
  332. if ( bSucceed )
  333. m_wndRoom.m_wndMembers.UpdateNames( NULL );
  334. }
  335. else
  336. {
  337. // Select nothing
  338. hr = set_TalkerVideo( NULL, true, (bool) (bUpdateTree != 0) );
  339. }
  340. return hr;
  341. }
  342. STDMETHODIMP CConfRoom::put_CallState(CALL_STATE callState)
  343. {
  344. bool bUpdateTree = false;
  345. // Update call state information
  346. Lock();
  347. if ( (m_wndRoom.m_wndTalker.m_dlgTalker.m_callState != AV_CS_ABORT) ||
  348. (callState == CS_DISCONNECTED) || (callState == CS_IDLE) )
  349. {
  350. m_wndRoom.m_wndTalker.m_dlgTalker.m_callState = callState;
  351. }
  352. Unlock();
  353. switch ( callState )
  354. {
  355. case AV_CS_DIALING:
  356. Lock();
  357. // Setup conference name information
  358. SysFreeString( m_wndRoom.m_wndTalker.m_dlgTalker.m_bstrConfName );
  359. m_wndRoom.m_wndTalker.m_dlgTalker.m_bstrConfName = NULL;
  360. get_bstrConfName( &m_wndRoom.m_wndTalker.m_dlgTalker.m_bstrConfName );
  361. Unlock();
  362. m_wndRoom.LayoutRoom( CConfRoomWnd::LAYOUT_TALKER, false );
  363. break;
  364. /////////////////////////////
  365. case CS_CONNECTED:
  366. bUpdateTree = true;
  367. OnConnected();
  368. break;
  369. ///////////////////////////////
  370. case AV_CS_ABORT:
  371. bUpdateTree = true;
  372. OnAbort();
  373. break;
  374. ///////////////////////////////
  375. case CS_DISCONNECTED:
  376. bUpdateTree = true;
  377. OnDisconnected();
  378. break;
  379. /////////////////////////////
  380. default:
  381. m_wndRoom.LayoutRoom( CConfRoomWnd::LAYOUT_TALKER, false );
  382. break;
  383. }
  384. // Store conference server setup
  385. if ( bUpdateTree )
  386. {
  387. IConfRoomTreeView *pTreeView;
  388. if ( SUCCEEDED(get_TreeView(&pTreeView)) )
  389. {
  390. pTreeView->UpdateData( false );
  391. pTreeView->Release();
  392. }
  393. }
  394. return S_OK;
  395. }
  396. void CConfRoom::OnConnected()
  397. {
  398. IAVTapiCall *pAVCall;
  399. if ( SUCCEEDED(get_IAVTapiCall(&pAVCall)) )
  400. {
  401. // Preview Streaming?
  402. IVideoWindow *pVideoPreview = NULL;;
  403. pAVCall->get_IVideoWindowPreview( (IDispatch **) &pVideoPreview );
  404. Lock();
  405. m_bPreviewStreaming = (BOOL) (pVideoPreview != NULL);
  406. Unlock();
  407. // Basic status information for conference room
  408. UpdateNumParticipants( pAVCall );
  409. m_wndRoom.LayoutRoom( CConfRoomWnd::LAYOUT_CREATE, true );
  410. // Force window to re-paint itself
  411. m_wndRoom.PostMessage( WM_SIZE );
  412. // Clean up
  413. RELEASE(pVideoPreview);
  414. pAVCall->Release();
  415. }
  416. }
  417. void CConfRoom::OnAbort()
  418. {
  419. OnDisconnected();
  420. Lock();
  421. m_wndRoom.m_wndTalker.m_dlgTalker.m_callState = CS_DISCONNECTED;
  422. Unlock();
  423. m_wndRoom.LayoutRoom( CConfRoomWnd::LAYOUT_CREATE, true );
  424. }
  425. void CConfRoom::OnDisconnected()
  426. {
  427. IAVTapiCall *pAVCall = NULL;
  428. get_IAVTapiCall( &pAVCall );
  429. Lock();
  430. // Clean out conference name
  431. SysFreeString( m_wndRoom.m_wndTalker.m_dlgTalker.m_bstrConfName );
  432. m_wndRoom.m_wndTalker.m_dlgTalker.m_bstrConfName = NULL;
  433. SysFreeString( m_wndRoom.m_wndTalker.m_dlgTalker.m_bstrCallerID );
  434. m_wndRoom.m_wndTalker.m_dlgTalker.m_bstrCallerID = NULL;
  435. SysFreeString( m_wndRoom.m_wndTalker.m_dlgTalker.m_bstrCallerInfo );
  436. m_wndRoom.m_wndTalker.m_dlgTalker.m_bstrCallerInfo = NULL;
  437. // Reset number of video terminals
  438. m_nNumTerms = m_nMaxTerms;
  439. Unlock();
  440. m_critAVCall.Lock();
  441. RELEASE(m_pAVCall);
  442. m_critAVCall.Unlock();
  443. if ( !IsExiting() )
  444. m_wndRoom.LayoutRoom( CConfRoomWnd::LAYOUT_CREATE, true );
  445. // Log the call after it's released
  446. if ( pAVCall )
  447. pAVCall->Log( CL_CALL_CONFERENCE );
  448. ReleaseAVCall( pAVCall, false );
  449. // Notify that the conference room is no longer in use
  450. if ( !IsExiting() )
  451. {
  452. CAVTapi *pAVTapi;
  453. if ( SUCCEEDED(_Module.GetAVTapi(&pAVTapi)) )
  454. pAVTapi->fire_ActionSelected( CC_ACTIONS_LEAVE_CONFERENCE );
  455. }
  456. }
  457. void CConfRoom::InternalDisconnect()
  458. {
  459. IAVTapiCall *pAVCall;
  460. if ( SUCCEEDED(get_IAVTapiCall(&pAVCall)) )
  461. {
  462. if ( IsConfRoomConnected() == S_OK )
  463. {
  464. // Hide video feeds, prior to disconnecting
  465. m_wndRoom.m_wndMembers.HideVideoFeeds();
  466. if ( IsWindow(m_wndRoom.m_wndTalker.m_dlgTalker.m_hWnd) )
  467. {
  468. m_wndRoom.m_wndTalker.m_dlgTalker.m_callState = (CALL_STATE) AV_CS_DISCONNECTING;
  469. m_wndRoom.m_wndTalker.m_dlgTalker.UpdateData( false );
  470. }
  471. pAVCall->PostMessage( 0, CAVTapiCall::TI_DISCONNECT );
  472. }
  473. else
  474. {
  475. // Disconnect the call
  476. pAVCall->Disconnect( TRUE );
  477. }
  478. // Release the call
  479. pAVCall->Release();
  480. }
  481. }
  482. //////////////////////////////////////////////////////////////////////////////////////
  483. // COM interface methods
  484. //
  485. STDMETHODIMP CConfRoom::IsConfRoomInUse()
  486. {
  487. HRESULT hr = S_FALSE;
  488. m_critAVCall.Lock();
  489. if ( m_pAVCall ) hr = S_OK;
  490. m_critAVCall.Unlock();
  491. return hr;
  492. }
  493. STDMETHODIMP CConfRoom::IsConfRoomConnected()
  494. {
  495. HRESULT hr = S_FALSE;
  496. IAVTapiCall *pAVCall;
  497. if ( SUCCEEDED(get_IAVTapiCall(&pAVCall)) )
  498. {
  499. CALL_STATE nState;
  500. pAVCall->get_callState(&nState);
  501. if ( nState == CS_CONNECTED )
  502. hr = S_OK;
  503. pAVCall->Release();
  504. }
  505. return hr;
  506. }
  507. ////////////////////////////////////////////////////////////////////////////////////////
  508. // CConfRoom::EnterConfRoom( pAVCall )
  509. //
  510. // This method is invoked by the AVTapiCall object to request that it be represtented by
  511. // the conference room.
  512. //
  513. STDMETHODIMP CConfRoom::EnterConfRoom(IAVTapiCall * pAVCall )
  514. {
  515. // Upfront verifications...
  516. _ASSERT( pAVCall );
  517. CErrorInfo er ( IDS_ER_CALL_ENTERCONFROOM, 0 );
  518. if ( !IsWindow(m_wndRoom.m_hWnd) ) er.set_hr( E_PENDING ); // Must have window alread set up via Show()
  519. else if ( !pAVCall ) er.set_hr( E_POINTER ); // Must have valid pAVCall pointer
  520. // Is conference room already in use?
  521. m_critAVCall.Lock();
  522. if ( m_pAVCall )
  523. {
  524. er.set_Details( IDS_ER_CONFERENCE_ROOM_LIMIT_EXCEEDED );
  525. er.set_hr( E_ACCESSDENIED );
  526. }
  527. else
  528. {
  529. er.set_Details( IDS_ER_QUERY_AVCALL);
  530. er.set_hr( pAVCall->QueryInterface(IID_IAVTapiCall, (void **) &m_pAVCall) );
  531. }
  532. m_critAVCall.Unlock();
  533. if ( SUCCEEDED(er.m_hr) )
  534. {
  535. put_CallState( (CALL_STATE) AV_CS_DIALING );
  536. // General notification of conference room in use
  537. CAVTapi *pAVTapi;
  538. if ( SUCCEEDED(_Module.GetAVTapi(&pAVTapi)) )
  539. pAVTapi->fire_ActionSelected( CC_ACTIONS_JOIN_CONFERENCE );
  540. }
  541. return er.m_hr;
  542. }
  543. void CConfRoom::UpdateNumParticipants( IAVTapiCall *pAVCall )
  544. {
  545. _ASSERT( pAVCall );
  546. ITParticipantControl *pITParticipantControl;
  547. if ( SUCCEEDED(pAVCall->get_ITParticipantControl(&pITParticipantControl)) )
  548. {
  549. long lNum = 0;
  550. IEnumParticipant *pEnum;
  551. if ( SUCCEEDED(pITParticipantControl->EnumerateParticipants(&pEnum)) )
  552. {
  553. lNum++; // add one for ourself
  554. ITParticipant *pParticipant = NULL;
  555. while ( (pEnum->Next(1, &pParticipant, NULL) == S_OK) && pParticipant )
  556. {
  557. pParticipant->Release();
  558. pParticipant = NULL;
  559. lNum++;
  560. }
  561. pEnum->Release();
  562. }
  563. // Clean up
  564. pITParticipantControl->Release();
  565. // Store participant count
  566. Lock();
  567. m_lNumParticipants = lNum;
  568. Unlock();
  569. }
  570. }
  571. STDMETHODIMP CConfRoom::Show(HWND hWndTree, HWND hWndClient)
  572. {
  573. _ASSERT( IsWindow(hWndTree) && IsWindow(hWndClient) );
  574. if ( !IsWindow(hWndTree) || !IsWindow(hWndClient) ) return E_INVALIDARG;
  575. HRESULT hr = E_FAIL;
  576. // Retrieve conf room settings
  577. UpdateData( false );
  578. IConfRoomTreeView *pTreeView;
  579. if ( SUCCEEDED(hr = get_TreeView(&pTreeView)) )
  580. {
  581. // Create the tree view
  582. pTreeView->put_hWnd( hWndTree );
  583. pTreeView->Release();
  584. // Create the conferenc room window
  585. ::SetClassLongPtr( hWndClient, GCLP_HBRBACKGROUND, (LONG_PTR) GetSysColorBrush(COLOR_BTNFACE) );
  586. if ( IsWindow(m_wndRoom.m_hWnd) )
  587. {
  588. // Are we just changing parents?
  589. m_wndRoom.SetParent( hWndClient );
  590. }
  591. else
  592. {
  593. // Are we creating a new conference room window?
  594. RECT rc;
  595. GetClientRect( hWndClient, &rc );
  596. m_wndRoom.Create( hWndClient, rc, NULL, WS_CHILD | WS_VISIBLE, 0, IDW_CONFROOM );
  597. }
  598. // Before continuing, make sure we have a valid window
  599. if ( IsWindow(m_wndRoom.m_hWnd) )
  600. {
  601. hr = m_wndRoom.LayoutRoom( CConfRoomWnd::LAYOUT_CREATE, true );
  602. m_wndRoom.PostMessage( WM_SIZE );
  603. }
  604. else
  605. {
  606. hr = E_FAIL;
  607. }
  608. }
  609. return hr;
  610. }
  611. STDMETHODIMP CConfRoom::get_TreeView(IConfRoomTreeView **ppVal)
  612. {
  613. HRESULT hr = S_OK;
  614. Lock();
  615. if ( !m_pTreeView )
  616. {
  617. m_pTreeView = new CComObject<CConfRoomTreeView>;
  618. if ( m_pTreeView )
  619. {
  620. m_pTreeView->AddRef();
  621. m_pTreeView->put_ConfRoom( this );
  622. }
  623. else
  624. {
  625. hr = E_OUTOFMEMORY;
  626. }
  627. }
  628. if ( SUCCEEDED(hr) )
  629. {
  630. *ppVal = m_pTreeView;
  631. (*ppVal)->AddRef();
  632. }
  633. Unlock();
  634. return hr;
  635. }
  636. STDMETHODIMP CConfRoom::Disconnect()
  637. {
  638. HRESULT hr = E_FAIL;
  639. if ( IsConfRoomConnected() == S_OK )
  640. {
  641. Lock();
  642. VARIANT_BOOL bConfirm = m_bConfirmDisconnect;
  643. Unlock();
  644. if ( !bConfirm || (_Module.DoMessageBox(IDS_CONFIRM_CONFROOM_DISCONNECT, MB_YESNO | MB_ICONQUESTION, false) == IDYES) )
  645. {
  646. m_wndRoom.RedrawWindow();
  647. InternalDisconnect();
  648. }
  649. }
  650. else
  651. {
  652. Cancel();
  653. }
  654. return hr;
  655. }
  656. STDMETHODIMP CConfRoom::CanDisconnect()
  657. {
  658. HRESULT hr = S_FALSE;
  659. m_critAVCall.Lock();
  660. if ( m_pAVCall )
  661. {
  662. CALL_STATE callState;
  663. if ( SUCCEEDED(m_pAVCall->get_callState(&callState)) )
  664. {
  665. if ( (callState != CS_IDLE) && (callState != CS_DISCONNECTED) )
  666. hr = S_OK;
  667. }
  668. }
  669. m_critAVCall.Unlock();
  670. return hr;
  671. }
  672. STDMETHODIMP CConfRoom::NotifyStateChange( IAVTapiCall *pAVCall )
  673. {
  674. HRESULT hr = E_FAIL;
  675. bool bMatch = false;
  676. m_critAVCall.Lock();
  677. if ( m_pAVCall == pAVCall )
  678. bMatch = true;
  679. m_critAVCall.Unlock();
  680. if ( bMatch )
  681. {
  682. CALL_STATE callState;
  683. pAVCall->get_callState( &callState );
  684. put_CallState( callState );
  685. }
  686. return hr;
  687. }
  688. STDMETHODIMP CConfRoom::NotifyParticipantChange(IAVTapiCall * pAVCall, ITParticipant * pParticipant, AV_PARTICIPANT_EVENT nEvent )
  689. {
  690. ATLTRACE(_T(".enter.CConfRoom::NotifyParticipantChange(%d, %p).\n"), nEvent, pParticipant);
  691. HRESULT hr = E_FAIL;
  692. m_critAVCall.Lock();
  693. if ( m_pAVCall && (m_pAVCall == pAVCall) || !pAVCall )
  694. hr = S_OK;
  695. m_critAVCall.Unlock();
  696. CConfRoomWnd::LayoutStyles_t nStyle = CConfRoomWnd::LAYOUT_NONE;
  697. // If we have a match, re-load the treeview
  698. if ( SUCCEEDED(hr) )
  699. {
  700. IConfRoomTreeView *pTreeView;
  701. if ( SUCCEEDED(get_TreeView(&pTreeView)) )
  702. {
  703. switch ( nEvent )
  704. {
  705. case AV_PARTICIPANT_UPDATE:
  706. m_wndRoom.UpdateNames( pParticipant );
  707. break;
  708. // Joined the conference
  709. case AV_PARTICIPANT_JOIN:
  710. UpdateNumParticipants( pAVCall );
  711. pTreeView->UpdateRootItem();
  712. break;
  713. // Showing video
  714. case AV_PARTICIPANT_STREAMING_START:
  715. pTreeView->UpdateRootItem();
  716. m_wndRoom.UpdateNames( NULL );
  717. nStyle = CConfRoomWnd::LAYOUT_MEMBERS;
  718. // Any video to start streaming gets automatically selected
  719. if ( !IsTalkerStreaming() )
  720. SelectTalker( pParticipant, true );
  721. break;
  722. // Not Showing video
  723. case AV_PARTICIPANT_STREAMING_STOP:
  724. pTreeView->UpdateRootItem();
  725. nStyle = (IsTalkerParticipant(pParticipant)) ? CConfRoomWnd::LAYOUT_ALL : CConfRoomWnd::LAYOUT_MEMBERS;
  726. break;
  727. // Participant leaving
  728. case AV_PARTICIPANT_LEAVE:
  729. UpdateNumParticipants( pAVCall );
  730. pTreeView->UpdateRootItem();
  731. m_wndRoom.UpdateNames( NULL );
  732. // Select new talker in the case where the talker leaves
  733. nStyle = CConfRoomWnd::LAYOUT_MEMBERS;
  734. {
  735. ITParticipant *pTemp = NULL;
  736. // bool bNewTalker = (bool) (FAILED(get_TalkerParticipant(&pTemp)) || IsTalkerParticipant(pParticipant));
  737. bool bNewTalker = (bool) IsTalkerParticipant(pParticipant);
  738. RELEASE( pTemp );
  739. if ( bNewTalker )
  740. {
  741. nStyle = CConfRoomWnd::LAYOUT_ALL;
  742. // Find a video feed that's streaming!
  743. IVideoWindow *pVideo = NULL;
  744. if ( SUCCEEDED(GetFirstVideoWindowThatsStreaming((IDispatch **) &pVideo)) )
  745. {
  746. set_TalkerVideo( pVideo, true, true );
  747. pVideo->Release();
  748. }
  749. else
  750. {
  751. // Select anything!
  752. SelectTalker( NULL, true );
  753. }
  754. }
  755. }
  756. break;
  757. }
  758. pTreeView->Release();
  759. // Layout room if requested
  760. if ( nStyle != CConfRoomWnd::LAYOUT_NONE )
  761. m_wndRoom.LayoutRoom( nStyle, true );
  762. }
  763. }
  764. return hr;
  765. }
  766. STDMETHODIMP CConfRoom::get_MemberVideoSize(short * pVal)
  767. {
  768. Lock();
  769. *pVal = (m_szMembers.cx * 100) / VID_X;
  770. Unlock();
  771. return S_OK;
  772. }
  773. STDMETHODIMP CConfRoom::put_MemberVideoSize(short newVal)
  774. {
  775. Lock();
  776. m_szMembers.cx = (newVal * VID_X) / 100;
  777. m_szMembers.cy = (newVal * VID_Y) / 100;
  778. Unlock();
  779. return m_wndRoom.LayoutRoom( CConfRoomWnd::LAYOUT_MEMBERS, true );
  780. }
  781. STDMETHODIMP CConfRoom::get_nNumTerms(short *pVal)
  782. {
  783. Lock();
  784. *pVal = m_nNumTerms;
  785. Unlock();
  786. return S_OK;
  787. }
  788. STDMETHODIMP CConfRoom::get_bstrConfName(BSTR * pVal)
  789. {
  790. HRESULT hr = E_FAIL;
  791. // Name of conference is stored as originally dialed address
  792. m_critAVCall.Lock();
  793. if ( m_pAVCall )
  794. hr = m_pAVCall->get_bstrOriginalAddress( pVal );
  795. m_critAVCall.Unlock();
  796. return hr;
  797. }
  798. STDMETHODIMP CConfRoom::get_hWndConfRoom(HWND * pVal)
  799. {
  800. Lock();
  801. *pVal = m_wndRoom.m_hWnd;
  802. Unlock();
  803. return S_OK;
  804. }
  805. STDMETHODIMP CConfRoom::get_bShowNames(VARIANT_BOOL * pVal)
  806. {
  807. Lock();
  808. *pVal = m_bShowNames;
  809. Unlock();
  810. return S_OK;
  811. }
  812. STDMETHODIMP CConfRoom::put_bShowNames(VARIANT_BOOL newVal)
  813. {
  814. // Only update if different
  815. bool bChanged = false;
  816. Lock();
  817. if ( newVal != m_bShowNames )
  818. {
  819. m_bShowNames = newVal;
  820. bChanged = true;
  821. }
  822. Unlock();
  823. if ( bChanged )
  824. m_wndRoom.LayoutRoom( CConfRoomWnd::LAYOUT_MEMBERS, true );
  825. return S_OK;
  826. }
  827. STDMETHODIMP CConfRoom::get_nShowNamesNumLines(short * pVal)
  828. {
  829. Lock();
  830. *pVal = m_nShowNamesNumLines;
  831. Unlock();
  832. return S_OK;
  833. }
  834. STDMETHODIMP CConfRoom::put_nShowNamesNumLines(short newVal)
  835. {
  836. bool bChanged = false;
  837. Lock();
  838. if ( m_nShowNamesNumLines != newVal )
  839. {
  840. m_nShowNamesNumLines = newVal;
  841. bChanged = true;
  842. }
  843. Unlock();
  844. if ( bChanged )
  845. m_wndRoom.LayoutRoom( CConfRoomWnd::LAYOUT_MEMBERS, true );
  846. return S_OK;
  847. }
  848. STDMETHODIMP CConfRoom::get_IAVTapiCall(IAVTapiCall **ppVal)
  849. {
  850. HRESULT hr = E_POINTER;
  851. if ( ppVal )
  852. {
  853. m_critAVCall.Lock();
  854. if ( m_pAVCall )
  855. hr = m_pAVCall->QueryInterface( IID_IAVTapiCall, (void **) ppVal );
  856. m_critAVCall.Unlock();
  857. }
  858. return hr;
  859. }
  860. STDMETHODIMP CConfRoom::get_bConfirmDisconnect(VARIANT_BOOL * pVal)
  861. {
  862. Lock();
  863. *pVal = m_bConfirmDisconnect;
  864. Unlock();
  865. return S_OK;
  866. }
  867. STDMETHODIMP CConfRoom::put_bConfirmDisconnect(VARIANT_BOOL newVal)
  868. {
  869. Lock();
  870. m_bConfirmDisconnect;
  871. Unlock();
  872. return S_OK;
  873. }
  874. HRESULT CConfRoom::get_szMembers( SIZE *pSize )
  875. {
  876. Lock();
  877. *pSize = m_szMembers;
  878. Unlock();
  879. return S_OK;
  880. }
  881. STDMETHODIMP CConfRoom::get_TalkerParticipant(ITParticipant **ppVal)
  882. {
  883. HRESULT hr = E_FAIL;
  884. *ppVal = NULL;
  885. // Set the talker video if it's different from the current one
  886. m_atomTalkerVideo.Lock( CAtomicList::LIST_READ );
  887. if ( m_pITalkerVideo )
  888. {
  889. IVideoFeed *pFeed;
  890. if ( SUCCEEDED(hr = m_wndRoom.m_wndMembers.FindVideoFeed(m_pITalkerVideo, &pFeed)) )
  891. {
  892. hr = pFeed->get_ITParticipant( ppVal );
  893. pFeed->Release();
  894. }
  895. }
  896. else
  897. {
  898. hr = get_ITTalkerParticipant( ppVal );
  899. }
  900. m_atomTalkerVideo.Unlock( CAtomicList::LIST_READ );
  901. return hr;
  902. }
  903. STDMETHODIMP CConfRoom::get_nMaxTerms(short * pVal)
  904. {
  905. Lock();
  906. *pVal = m_nMaxTerms;
  907. Unlock();
  908. return S_OK;
  909. }
  910. STDMETHODIMP CConfRoom::put_nMaxTerms(short newVal)
  911. {
  912. HRESULT hrInUse = IsConfRoomInUse();
  913. Lock();
  914. m_nMaxTerms = max(0, min(MAX_VIDEO, newVal));
  915. if ( hrInUse == S_FALSE )
  916. m_nNumTerms = m_nMaxTerms;
  917. Unlock();
  918. // Redraw room with new number of terminals (note that this won't change for an active call)
  919. if ( hrInUse == S_FALSE )
  920. m_wndRoom.LayoutRoom( CConfRoomWnd::LAYOUT_CREATE, true );
  921. return S_OK;
  922. }
  923. STDMETHODIMP CConfRoom::get_lNumParticipants(long * pVal)
  924. {
  925. Lock();
  926. *pVal = m_lNumParticipants;
  927. Unlock();
  928. return S_OK;
  929. }
  930. STDMETHODIMP CConfRoom::get_ConfDetails(long **ppVal)
  931. {
  932. Lock();
  933. *((CConfDetails *) *ppVal) = m_confDetails;
  934. Unlock();
  935. return S_OK;
  936. }
  937. STDMETHODIMP CConfRoom::put_ConfDetails(long * newVal)
  938. {
  939. Lock();
  940. m_confDetails = *((CConfDetails *) newVal);
  941. Unlock();
  942. return S_OK;
  943. }
  944. STDMETHODIMP CConfRoom::get_bstrConfDetails(BSTR * pVal)
  945. {
  946. _ASSERT( pVal );
  947. if ( IsConfRoomInUse() == S_OK )
  948. {
  949. // Retrieve information from details data structuren
  950. Lock();
  951. m_confDetails.MakeDetailsCaption( *pVal );
  952. Unlock();
  953. }
  954. else
  955. {
  956. // Conference room not presently in use
  957. USES_CONVERSION;
  958. TCHAR szText[255];
  959. //
  960. // We have to initialize szText
  961. //
  962. _tcscpy( szText, _T(""));
  963. LoadString( _Module.GetResourceInstance(), IDS_CONFROOM_NODETAILS, szText, ARRAYSIZE(szText) );
  964. *pVal = SysAllocString( T2COLE(szText) );
  965. }
  966. return S_OK;
  967. }
  968. STDMETHODIMP CConfRoom::Layout(VARIANT_BOOL bTalker, VARIANT_BOOL bMembers )
  969. {
  970. CConfRoomWnd::LayoutStyles_t nStyle = CConfRoomWnd::LAYOUT_NONE;
  971. if ( bTalker ) nStyle = (CConfRoomWnd::LayoutStyles_t) (nStyle | CConfRoomWnd::LAYOUT_TALKER);
  972. if ( bMembers ) nStyle = (CConfRoomWnd::LayoutStyles_t) (nStyle | CConfRoomWnd::LAYOUT_MEMBERS);
  973. return m_wndRoom.LayoutRoom( nStyle, true );
  974. }
  975. void CConfRoom::set_PreviewVideo( IVideoWindow *pVideo )
  976. {
  977. Lock();
  978. m_pVideoPreview = pVideo;
  979. Unlock();
  980. }
  981. bool CConfRoom::IsPreviewVideo( IVideoWindow *pVideo )
  982. {
  983. bool bRet;
  984. Lock();
  985. bRet = (bool) (m_pVideoPreview && (m_pVideoPreview == pVideo));
  986. Unlock();
  987. return bRet;
  988. }
  989. bool CConfRoom::IsTalkerParticipant( ITParticipant *pParticipant )
  990. {
  991. bool bRet = false;
  992. ITParticipant *pTalkerParticipant;
  993. if ( SUCCEEDED(get_TalkerParticipant(&pTalkerParticipant)) )
  994. {
  995. if ( pTalkerParticipant == pParticipant )
  996. bRet = true;
  997. pTalkerParticipant->Release();
  998. }
  999. return bRet;
  1000. }
  1001. STDMETHODIMP CConfRoom::SelectTalkerVideo(IDispatch * pDisp, VARIANT_BOOL bUpdate)
  1002. {
  1003. return set_TalkerVideo( (IVideoWindow *) pDisp, (bool) (bUpdate != 0), true);
  1004. }
  1005. STDMETHODIMP CConfRoom::get_hWndTalker(HWND * pVal)
  1006. {
  1007. *pVal = m_wndRoom.m_wndTalker;
  1008. return S_OK;
  1009. }
  1010. STDMETHODIMP CConfRoom::get_hWndMembers(HWND * pVal)
  1011. {
  1012. *pVal = m_wndRoom.m_wndMembers;
  1013. return S_OK;
  1014. }
  1015. STDMETHODIMP CConfRoom::get_bPreviewStreaming(VARIANT_BOOL * pVal)
  1016. {
  1017. Lock();
  1018. *pVal = m_bPreviewStreaming;
  1019. Unlock();
  1020. return S_OK;
  1021. }
  1022. STDMETHODIMP CConfRoom::FindVideoFeedFromParticipant(ITParticipant * pParticipant, IVideoFeed **ppFeed)
  1023. {
  1024. return m_wndRoom.m_wndMembers.FindVideoFeedFromParticipant( pParticipant, ppFeed );
  1025. }
  1026. STDMETHODIMP CConfRoom::SetQOSOnParticipants()
  1027. {
  1028. // TODO: Add your implementation code here
  1029. return S_OK;
  1030. }
  1031. STDMETHODIMP CConfRoom::FindVideoFeedFromSubStream(ITSubStream * pSubStream, IVideoFeed * * ppFeed)
  1032. {
  1033. HRESULT hr;
  1034. _ASSERT( pSubStream );
  1035. IEnumTerminal *pEnum;
  1036. if ( SUCCEEDED(hr = pSubStream->EnumerateTerminals(&pEnum)) )
  1037. {
  1038. hr = E_FAIL;
  1039. ITTerminal *pITTerminal = NULL;
  1040. if ( (pEnum->Next(1, &pITTerminal, NULL) == S_OK) && pITTerminal )
  1041. {
  1042. IVideoWindow *pVideo;
  1043. if ( SUCCEEDED(pITTerminal->QueryInterface(IID_IVideoWindow, (void **) &pVideo)) )
  1044. {
  1045. hr = m_wndRoom.m_wndMembers.FindVideoFeed( pVideo, ppFeed );
  1046. pVideo->Release();
  1047. }
  1048. RELEASE( pITTerminal );
  1049. }
  1050. pEnum->Release();
  1051. }
  1052. return hr;
  1053. }
  1054. STDMETHODIMP CConfRoom::GetFirstVideoWindowThatsStreaming(IDispatch **ppVideo)
  1055. {
  1056. return m_wndRoom.m_wndMembers.GetFirstVideoWindowThatsStreaming( (IVideoWindow **) ppVideo );
  1057. }
  1058. STDMETHODIMP CConfRoom::Cancel()
  1059. {
  1060. Lock();
  1061. CALL_STATE nState = m_wndRoom.m_wndTalker.m_dlgTalker.m_callState;
  1062. Unlock();
  1063. if ( (nState != AV_CS_DISCONNECTING) && (IsConfRoomInUse() == S_OK) )
  1064. put_CallState( (CALL_STATE) AV_CS_ABORT );
  1065. return S_OK;
  1066. }
  1067. bool CConfRoom::IsTalkerStreaming()
  1068. {
  1069. IVideoWindow *pVideo = NULL;
  1070. HRESULT hr = get_TalkerVideo( (IDispatch **) &pVideo );
  1071. // For preview make sure we're streaming!
  1072. if ( SUCCEEDED(hr) && IsPreviewVideo(pVideo) )
  1073. {
  1074. IAVTapiCall *pAVCall;
  1075. if ( SUCCEEDED(get_IAVTapiCall(&pAVCall)) )
  1076. {
  1077. // If we are failing to stream video for some reason, flag as error.
  1078. if ( pAVCall->IsPreviewStreaming() != S_OK )
  1079. hr = E_FAIL;
  1080. pAVCall->Release();
  1081. }
  1082. }
  1083. RELEASE( pVideo );
  1084. return (bool) (hr == S_OK);
  1085. }
  1086. STDMETHODIMP CConfRoom::get_szTalker(SIZE * pVal)
  1087. {
  1088. Lock();
  1089. *pVal = m_szTalker;
  1090. Unlock();
  1091. return S_OK;
  1092. }
  1093. STDMETHODIMP CConfRoom::get_TalkerScale(short * pVal)
  1094. {
  1095. Lock();
  1096. *pVal = m_nScale;
  1097. Unlock();
  1098. return S_OK;
  1099. }
  1100. STDMETHODIMP CConfRoom::put_TalkerScale(short newVal)
  1101. {
  1102. Lock();
  1103. if ( newVal != m_nScale )
  1104. {
  1105. m_nScale = newVal;
  1106. m_szTalker.cx = (VID_X * m_nScale) / 100;
  1107. m_szTalker.cy = (VID_Y * m_nScale) / 100;
  1108. }
  1109. Unlock();
  1110. m_wndRoom.PostMessage( WM_SIZE, 0, 0 );
  1111. return S_OK;
  1112. }
  1113. bool CConfRoom::MapStreamingParticipant( IParticipant *pIParticipant, IVideoFeed **ppFeed )
  1114. {
  1115. _ASSERT( pIParticipant && ppFeed );
  1116. bool bRet = false;
  1117. if ( SUCCEEDED(m_wndRoom.m_wndMembers.GetAndMoveVideoFeedThatStreamingForParticipantReMap((IVideoFeed **) ppFeed)) )
  1118. {
  1119. ITParticipant *p;
  1120. if ( SUCCEEDED(pIParticipant->get_ITParticipant(&p)) )
  1121. {
  1122. if ( SUCCEEDED((*ppFeed)->MapToParticipant(p)) )
  1123. bRet = true;
  1124. p->Release();
  1125. }
  1126. // Make sure we clean up feed ref count accordingly...
  1127. if ( !bRet )
  1128. (*ppFeed)->Release();
  1129. }
  1130. return bRet;
  1131. }