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.

1627 lines
41 KiB

  1. //////////////////////////////////////////////////////////
  2. // T3OUT.EXE
  3. //
  4. // Example of making an outgoing call with TAPI 3.0
  5. //
  6. // This application will allow a user to make a call
  7. // by using TAPI 3.0. The application will simply look
  8. // for the first TAPI line that support Audio, and can
  9. // dial a phone number. It will then use that line to
  10. // make calls.
  11. //
  12. // This application does not handle incoming calls, and
  13. // does not process incoming messages.
  14. //
  15. //////////////////////////////////////////////////////////
  16. #include "Precomp.h"
  17. //////////////////////////////////////////////////////////
  18. // Constants
  19. //////////////////////////////////////////////////////////
  20. const DWORD ADDRESSLENGTH = 128;
  21. const DWORD MAXTERMINALS = 5;
  22. const WCHAR * const gszTapi30 = L"TAPI 3.0 Outgoing Call Sample";
  23. const WCHAR * const SDP = L"\
  24. v=0\n\
  25. o=muhan 0 0 IN IP4 172.31.76.157\n\
  26. s=TestConf_01\n\
  27. c=IN IP4 239.9.20.11/15\n\
  28. t=0 0\n\
  29. m=video 20050 RTP/AVP 34\n\
  30. a=fmtp:34 CIF=4\n\
  31. ";
  32. /*
  33. k=clear:testkey\n\
  34. m=video 20000 RTP/AVP 34\n\
  35. m=audio 20040 RTP/AVP 0 4\n\
  36. */
  37. const WCHAR * const gszConferenceName = L"Conference Name";
  38. const WCHAR * const gszEmailName = L"Email Name";
  39. const WCHAR * const gszMachineName = L"Machine Name";
  40. const WCHAR * const gszPhoneNumber = L"Phone Number";
  41. const WCHAR * const gszIPAddress = L"IP Address";
  42. //////////////////////////////////////////////////////////
  43. // GLOBALS
  44. //////////////////////////////////////////////////////////
  45. HINSTANCE ghInst;
  46. HWND ghDlg = NULL;
  47. ITTAPI * gpTapi;
  48. ITAddress * gpAddress = NULL;
  49. ITBasicCallControl * gpCall;
  50. ITStream * gpVideoRenderStream;
  51. ITTerminal * gpLastVideoWindow;
  52. //////////////////////////////////////////////////////////
  53. // PROTOTYPES
  54. //////////////////////////////////////////////////////////
  55. BOOL
  56. CALLBACK
  57. MainDialogProc(
  58. HWND hDlg,
  59. UINT uMsg,
  60. WPARAM wParam,
  61. LPARAM lParam
  62. );
  63. HRESULT
  64. FindAnAddress(
  65. DWORD dwAddressType,
  66. BSTR * ppName
  67. );
  68. HRESULT
  69. GetTerminal(
  70. ITStream * pStream,
  71. ITTerminal ** ppTerminal
  72. );
  73. HRESULT
  74. FindCaptureTerminal(
  75. ITStream * pStream,
  76. ITTerminal ** ppTerminal
  77. );
  78. HRESULT
  79. GetVideoRenderTerminal(
  80. ITTerminal ** ppTerminal
  81. );
  82. HRESULT
  83. MakeTheCall(
  84. DWORD dwAddressType,
  85. PWCHAR szAddressToCall
  86. );
  87. HRESULT
  88. DisconnectTheCall();
  89. void
  90. DoMessage(
  91. LPWSTR pszMessage
  92. );
  93. HRESULT
  94. InitializeTapi();
  95. void
  96. ShutdownTapi();
  97. void
  98. EnableButton(
  99. HWND hDlg,
  100. int ID
  101. );
  102. void
  103. DisableButton(
  104. HWND hDlg,
  105. int ID
  106. );
  107. BOOL
  108. AddressSupportsMediaType(
  109. ITAddress * pAddress,
  110. long lMediaType
  111. );
  112. void ShowDialogs(ITBasicCallControl *pCall);
  113. //////////////////////////////////////////////////////////
  114. // WinMain
  115. //////////////////////////////////////////////////////////
  116. int
  117. WINAPI
  118. WinMain(
  119. HINSTANCE hInst,
  120. HINSTANCE hPrevInst,
  121. LPSTR lpCmdLine,
  122. int nCmdShow
  123. )
  124. {
  125. ghInst = hInst;
  126. // need to coinit
  127. if ( FAILED( CoInitializeEx(NULL, COINIT_MULTITHREADED) ) )
  128. {
  129. return 0;
  130. }
  131. if ( FAILED( InitializeTapi() ) )
  132. {
  133. return 0;
  134. }
  135. // everything is initialized, so
  136. // start the main dialog box
  137. DialogBox(
  138. ghInst,
  139. MAKEINTRESOURCE(IDD_MAINDLG),
  140. NULL,
  141. MainDialogProc
  142. );
  143. ShutdownTapi();
  144. CoUninitialize();
  145. return 1;
  146. }
  147. //////////////////////////////////////////////////////////////
  148. // InitializeTapi
  149. //
  150. // Various initializations
  151. ///////////////////////////////////////////////////////////////
  152. HRESULT
  153. InitializeTapi()
  154. {
  155. HRESULT hr;
  156. // cocreate the TAPI object
  157. hr = CoCreateInstance(
  158. CLSID_TAPI,
  159. NULL,
  160. CLSCTX_INPROC_SERVER,
  161. IID_ITTAPI,
  162. (LPVOID *)&gpTapi
  163. );
  164. if ( FAILED(hr) )
  165. {
  166. DoMessage(L"CoCreateInstance on TAPI failed");
  167. return hr;
  168. }
  169. // call initialize. this must be called before
  170. // any other tapi functions are called.
  171. hr = gpTapi->Initialize();
  172. if (S_OK != hr)
  173. {
  174. DoMessage(L"TAPI failed to initialize");
  175. gpTapi->Release();
  176. gpTapi = NULL;
  177. return hr;
  178. }
  179. return S_OK;
  180. }
  181. ///////////////////////////////////////////////////////////////
  182. // ShutdownTapi
  183. ///////////////////////////////////////////////////////////////
  184. void
  185. ShutdownTapi()
  186. {
  187. // if there is still a call,
  188. // release it
  189. if (NULL != gpCall)
  190. {
  191. gpCall->Release();
  192. gpCall = NULL;
  193. }
  194. // if we have an address object
  195. // release it
  196. if (NULL != gpAddress)
  197. {
  198. gpAddress->Release();
  199. gpAddress = NULL;
  200. }
  201. // release main object.
  202. if (NULL != gpTapi)
  203. {
  204. gpTapi->Shutdown();
  205. gpTapi->Release();
  206. gpTapi = NULL;
  207. }
  208. }
  209. ///////////////////////////////////////////////////////////////////////////
  210. // InitAddressTypeComboBox
  211. //
  212. // Put address type string in the combo box
  213. // and save the addresstype with the string
  214. //
  215. ///////////////////////////////////////////////////////////////////////////
  216. void
  217. InitAddressTypeComboBox(
  218. HWND hComboBox
  219. )
  220. {
  221. int i;
  222. i = SendMessage( hComboBox, CB_ADDSTRING, 0, (long)gszConferenceName );
  223. SendMessage(
  224. hComboBox,
  225. CB_SETITEMDATA ,
  226. i,
  227. (long)LINEADDRESSTYPE_SDP
  228. );
  229. SendMessage( hComboBox, CB_SETCURSEL, i, 0 );
  230. i = SendMessage( hComboBox, CB_ADDSTRING, 0, (long)gszEmailName );
  231. SendMessage(
  232. hComboBox,
  233. CB_SETITEMDATA ,
  234. i,
  235. (long)LINEADDRESSTYPE_EMAILNAME
  236. );
  237. i = SendMessage( hComboBox, CB_ADDSTRING, 0, (long)gszMachineName );
  238. SendMessage(
  239. hComboBox,
  240. CB_SETITEMDATA ,
  241. i,
  242. (long)LINEADDRESSTYPE_DOMAINNAME
  243. );
  244. i = SendMessage( hComboBox, CB_ADDSTRING, 0, (long)gszPhoneNumber );
  245. SendMessage(
  246. hComboBox,
  247. CB_SETITEMDATA ,
  248. i,
  249. (long)LINEADDRESSTYPE_PHONENUMBER
  250. );
  251. i = SendMessage( hComboBox, CB_ADDSTRING, 0, (long)gszIPAddress );
  252. SendMessage(
  253. hComboBox,
  254. CB_SETITEMDATA ,
  255. i,
  256. (long)LINEADDRESSTYPE_IPADDRESS
  257. );
  258. }
  259. ///////////////////////////////////////////////////////////////////////////
  260. // MainDlgProc
  261. ///////////////////////////////////////////////////////////////////////////
  262. BOOL
  263. CALLBACK
  264. MainDialogProc(
  265. HWND hDlg,
  266. UINT uMsg,
  267. WPARAM wParam,
  268. LPARAM lParam
  269. )
  270. {
  271. switch (uMsg)
  272. {
  273. case WM_INITDIALOG:
  274. {
  275. HWND hComboBox;
  276. // set up dialog
  277. ghDlg = hDlg;
  278. EnableButton( hDlg, IDOK );
  279. DisableButton( hDlg, IDC_DISCONNECT );
  280. DisableButton( hDlg, IDC_SETTINGS );
  281. hComboBox = GetDlgItem( hDlg, IDC_ADDRESSTYPE );
  282. InitAddressTypeComboBox(hComboBox);
  283. SetFocus( hComboBox );
  284. return 0;
  285. }
  286. case WM_COMMAND:
  287. {
  288. switch(LOWORD(wParam))
  289. {
  290. case IDCANCEL:
  291. {
  292. // quit
  293. EndDialog( hDlg, 0 );
  294. break;
  295. }
  296. case IDOK:
  297. {
  298. // dial request
  299. HWND hComboBox;
  300. DWORD dwIndex;
  301. DWORD dwAddressType;
  302. WCHAR szAddressToCall[ADDRESSLENGTH];
  303. // get the address type the user selected.
  304. hComboBox = GetDlgItem( hDlg, IDC_ADDRESSTYPE );
  305. dwIndex = SendMessage( hComboBox, CB_GETCURSEL, 0, 0 );
  306. dwAddressType = SendMessage(
  307. hComboBox,
  308. CB_GETITEMDATA,
  309. dwIndex,
  310. 0
  311. );
  312. // get the address the user wants to call
  313. GetDlgItemText(
  314. hDlg,
  315. IDC_ADDRESS,
  316. szAddressToCall,
  317. ADDRESSLENGTH
  318. );
  319. // make the call
  320. if ( S_OK == MakeTheCall(dwAddressType, szAddressToCall) )
  321. {
  322. EnableButton( hDlg, IDC_DISCONNECT );
  323. EnableButton( hDlg, IDC_SETTINGS );
  324. DisableButton( hDlg, IDOK );
  325. }
  326. else
  327. {
  328. DoMessage(L"The call failed to connect");
  329. }
  330. break;
  331. }
  332. case IDC_DISCONNECT:
  333. {
  334. // disconnect request
  335. if (S_OK == DisconnectTheCall())
  336. {
  337. EnableButton( hDlg, IDOK );
  338. DisableButton( hDlg, IDC_DISCONNECT );
  339. DisableButton( hDlg, IDC_SETTINGS );
  340. }
  341. else
  342. {
  343. DoMessage(L"The call failed to disconnect");
  344. }
  345. break;
  346. }
  347. case IDC_SETTINGS:
  348. {
  349. // Show TAPI 3.1 configuration dialogs
  350. ShowDialogs(gpCall);
  351. break;
  352. }
  353. case IDC_ADDWINDOW:
  354. {
  355. if (gpVideoRenderStream)
  356. {
  357. ITTerminal * pTerminal;
  358. HRESULT hr = GetVideoRenderTerminal(&pTerminal);
  359. if ( SUCCEEDED(hr) )
  360. {
  361. hr = gpVideoRenderStream->SelectTerminal(pTerminal);
  362. if (SUCCEEDED(hr))
  363. {
  364. if (gpLastVideoWindow) gpLastVideoWindow->Release();
  365. gpLastVideoWindow = pTerminal;
  366. }
  367. else
  368. {
  369. pTerminal->Release();
  370. }
  371. }
  372. }
  373. break;
  374. }
  375. case IDC_DELWINDOW:
  376. {
  377. if (gpVideoRenderStream && gpLastVideoWindow)
  378. {
  379. HRESULT hr = gpVideoRenderStream->UnselectTerminal(gpLastVideoWindow);
  380. gpLastVideoWindow->Release();
  381. gpLastVideoWindow = NULL;
  382. }
  383. break;
  384. }
  385. default:
  386. return 0;
  387. }
  388. return 1;
  389. }
  390. default:
  391. return 0;
  392. }
  393. }
  394. ////////////////////////////////////////////////////////////////////////
  395. // FindAnAddress
  396. //
  397. // Finds an address object that this application will use to make calls on.
  398. //
  399. // This function finds an address that supports the addresstype passed
  400. // in, as well as the audioin and audioout media types.
  401. //
  402. // Return Value
  403. // S_OK if it finds an address
  404. // E_FAIL if it does not find an address
  405. ////////////////////////////////////////////////////////////////////////
  406. HRESULT
  407. FindAnAddress(
  408. DWORD dwAddressType,
  409. BSTR * ppName
  410. )
  411. {
  412. HRESULT hr = S_OK;
  413. BOOL bFoundAddress = FALSE;
  414. IEnumAddress * pEnumAddress;
  415. ITAddress * pAddress;
  416. ITAddressCapabilities * pAddressCaps;
  417. long lType = 0;
  418. // if we have an address object
  419. // release it
  420. if (NULL != gpAddress)
  421. {
  422. gpAddress->Release();
  423. gpAddress = NULL;
  424. }
  425. // enumerate the addresses
  426. hr = gpTapi->EnumerateAddresses( &pEnumAddress );
  427. if ( FAILED(hr) )
  428. {
  429. return hr;
  430. }
  431. while ( !bFoundAddress )
  432. {
  433. // get the next address
  434. hr = pEnumAddress->Next( 1, &pAddress, NULL );
  435. if (S_OK != hr)
  436. {
  437. break;
  438. }
  439. hr = pAddress->QueryInterface(IID_ITAddressCapabilities, (void**)&pAddressCaps);
  440. if ( SUCCEEDED(hr) )
  441. {
  442. hr = pAddressCaps->get_AddressCapability( AC_ADDRESSTYPES, &lType );
  443. pAddressCaps->Release();
  444. if ( SUCCEEDED(hr) )
  445. {
  446. // is the type we are looking for?
  447. if ( dwAddressType & lType )
  448. {
  449. // does it support audio?
  450. if ( AddressSupportsMediaType(pAddress, TAPIMEDIATYPE_AUDIO) )
  451. {
  452. // does it have a name?
  453. if ( SUCCEEDED( pAddress->get_AddressName(ppName) ) )
  454. {
  455. // save it in the global variable
  456. // since we break out of the loop, this one won't
  457. // get released
  458. gpAddress = pAddress;
  459. bFoundAddress = TRUE;
  460. break;
  461. }
  462. }
  463. }
  464. }
  465. }
  466. pAddress->Release();
  467. } // end while loop
  468. pEnumAddress->Release();
  469. if (!bFoundAddress)
  470. {
  471. return E_FAIL;
  472. }
  473. return S_OK;
  474. }
  475. /////////////////////////////////////////////////////////////////
  476. // IsVideoCaptureStream
  477. //
  478. // Returns true if the stream is for video capture
  479. /////////////////////////////////////////////////////////////////
  480. BOOL
  481. IsVideoCaptureStream(
  482. ITStream * pStream
  483. )
  484. {
  485. TERMINAL_DIRECTION tdStreamDirection;
  486. long lStreamMediaType;
  487. if ( FAILED( pStream ->get_Direction(&tdStreamDirection) ) ) { return FALSE; }
  488. if ( FAILED( pStream ->get_MediaType(&lStreamMediaType) ) ) { return FALSE; }
  489. return (tdStreamDirection == TD_CAPTURE) &&
  490. (lStreamMediaType == TAPIMEDIATYPE_VIDEO);
  491. }
  492. /////////////////////////////////////////////////////////////////
  493. // IsVideoRenderStream
  494. //
  495. // Returns true if the stream is for video render
  496. /////////////////////////////////////////////////////////////////
  497. BOOL
  498. IsVideoRenderStream(
  499. ITStream * pStream
  500. )
  501. {
  502. TERMINAL_DIRECTION tdStreamDirection;
  503. long lStreamMediaType;
  504. if ( FAILED( pStream ->get_Direction(&tdStreamDirection) ) ) { return FALSE; }
  505. if ( FAILED( pStream ->get_MediaType(&lStreamMediaType) ) ) { return FALSE; }
  506. return (tdStreamDirection == TD_RENDER) &&
  507. (lStreamMediaType == TAPIMEDIATYPE_VIDEO);
  508. }
  509. /////////////////////////////////////////////////////////////////
  510. // IsAudioCaptureStream
  511. //
  512. // Returns true if the stream is for audio capture
  513. /////////////////////////////////////////////////////////////////
  514. BOOL
  515. IsAudioCaptureStream(
  516. ITStream * pStream
  517. )
  518. {
  519. TERMINAL_DIRECTION tdStreamDirection;
  520. long lStreamMediaType;
  521. if ( FAILED( pStream ->get_Direction(&tdStreamDirection) ) ) { return FALSE; }
  522. if ( FAILED( pStream ->get_MediaType(&lStreamMediaType) ) ) { return FALSE; }
  523. return (tdStreamDirection == TD_CAPTURE) &&
  524. (lStreamMediaType == TAPIMEDIATYPE_AUDIO);
  525. }
  526. /////////////////////////////////////////////////////////////////
  527. // EnablePreview
  528. //
  529. // Selects a video render terminal on a video capture stream,
  530. // thereby enabling video preview.
  531. /////////////////////////////////////////////////////////////////
  532. HRESULT
  533. EnablePreview(
  534. ITStream * pStream
  535. )
  536. {
  537. ITTerminal * pTerminal;
  538. HRESULT hr = GetVideoRenderTerminal(&pTerminal);
  539. if ( SUCCEEDED(hr) )
  540. {
  541. hr = pStream->SelectTerminal(pTerminal);
  542. pTerminal->Release();
  543. }
  544. return hr;
  545. }
  546. HRESULT
  547. EnableAEC(
  548. ITStream * pStream
  549. )
  550. {
  551. ITAudioDeviceControl *pITAudioDeviceControl;
  552. HRESULT hr = pStream->QueryInterface(&pITAudioDeviceControl);
  553. if ( SUCCEEDED(hr) )
  554. {
  555. hr = pITAudioDeviceControl->Set(AudioDevice_AcousticEchoCancellation, 1, TAPIControl_Flags_None);
  556. pITAudioDeviceControl->Release();
  557. }
  558. return hr;
  559. }
  560. void WINAPI DeleteMediaType(AM_MEDIA_TYPE* pmt)
  561. {
  562. if (pmt->cbFormat != 0) {
  563. CoTaskMemFree((PVOID)pmt->pbFormat);
  564. }
  565. if (pmt->pUnk != NULL) {
  566. pmt->pUnk->Release();
  567. pmt->pUnk = NULL;
  568. }
  569. CoTaskMemFree((PVOID)pmt);;
  570. }
  571. HRESULT
  572. CheckFormats(
  573. ITStream *pStream
  574. )
  575. {
  576. HRESULT hr;
  577. DWORD dw;
  578. BYTE * buf;
  579. ITFormatControl *pITFormatControl;
  580. hr = pStream->QueryInterface(&pITFormatControl);
  581. if (FAILED(hr))
  582. {
  583. return hr;
  584. }
  585. // get the number of capabilities of the stream.
  586. DWORD dwCount;
  587. hr = pITFormatControl->GetNumberOfCapabilities(&dwCount);
  588. if (FAILED(hr))
  589. {
  590. goto cleanup;
  591. }
  592. TAPI_STREAM_CONFIG_CAPS caps;
  593. AM_MEDIA_TYPE *pMediaType;
  594. // Walk through each capability.
  595. for (dw = 0; dw < dwCount; dw ++)
  596. {
  597. BOOL fEnabled;
  598. hr = pITFormatControl->GetStreamCaps(dw, &pMediaType, &caps, &fEnabled);
  599. if (FAILED(hr))
  600. {
  601. break;
  602. }
  603. DeleteMediaType(pMediaType);
  604. }
  605. // get the current format.
  606. hr = pITFormatControl->GetCurrentFormat(&pMediaType);
  607. if (FAILED(hr))
  608. {
  609. goto cleanup;
  610. }
  611. // set it back just for fun.
  612. // hr = pITFormatControl->SetPreferredFormat(pMediaType);
  613. DeleteMediaType(pMediaType);
  614. cleanup:
  615. pITFormatControl->Release();
  616. return hr;
  617. }
  618. #if USE_VFW
  619. HRESULT
  620. CheckVfwDialog(
  621. ITTerminal *pTerminal
  622. )
  623. {
  624. ITVfwCaptureDialogs *pVfwCaptureDialogs;
  625. HRESULT hr = pTerminal->QueryInterface(&pVfwCaptureDialogs);
  626. if (FAILED(hr))
  627. {
  628. return hr;
  629. }
  630. hr = pVfwCaptureDialogs->HasDialog(VfwCaptureDialog_Source);
  631. pVfwCaptureDialogs->Release();
  632. return hr;
  633. }
  634. #endif
  635. /////////////////////////////////////////////////////////////////
  636. // SelectTerminalsOnCall
  637. //
  638. // Creates and selects terminals for all streams on the given
  639. // call.
  640. /////////////////////////////////////////////////////////////////
  641. HRESULT
  642. SelectTerminalsOnCall(
  643. ITBasicCallControl * pCall
  644. )
  645. {
  646. HRESULT hr;
  647. //
  648. // get the ITStreamControl interface for this call
  649. //
  650. ITStreamControl * pStreamControl;
  651. hr = pCall->QueryInterface(IID_ITStreamControl,
  652. (void **) &pStreamControl);
  653. if ( SUCCEEDED(hr) )
  654. {
  655. //
  656. // enumerate the streams
  657. //
  658. IEnumStream * pEnumStreams;
  659. hr = pStreamControl->EnumerateStreams(&pEnumStreams);
  660. pStreamControl->Release();
  661. if ( SUCCEEDED(hr) )
  662. {
  663. //
  664. // for each stream
  665. //
  666. ITStream * pStream;
  667. while ( S_OK == pEnumStreams->Next(1, &pStream, NULL) )
  668. {
  669. ITTerminal * pTerminal;
  670. //
  671. // Find out the media type and direction of this stream,
  672. // and create the default terminal for this media type and
  673. // direction.
  674. //
  675. hr = GetTerminal(pStream,
  676. &pTerminal);
  677. if ( SUCCEEDED(hr) )
  678. {
  679. //
  680. // Select the terminal on the stream.
  681. //
  682. if ( IsAudioCaptureStream( pStream ) )
  683. {
  684. //EnableAEC( pStream );
  685. }
  686. hr = pStream->SelectTerminal(pTerminal);
  687. if ( SUCCEEDED(hr) )
  688. {
  689. //
  690. // Also enable preview on the video capture stream.
  691. //
  692. if ( IsVideoCaptureStream( pStream ) )
  693. {
  694. EnablePreview( pStream );
  695. }
  696. if ( IsVideoRenderStream( pStream ) )
  697. {
  698. pStream->AddRef();
  699. gpVideoRenderStream = pStream;
  700. if (gpLastVideoWindow) gpLastVideoWindow->Release();
  701. gpLastVideoWindow = pTerminal;
  702. gpLastVideoWindow->AddRef();
  703. }
  704. }
  705. CheckFormats(pStream);
  706. pTerminal->Release();
  707. }
  708. pStream->Release();
  709. }
  710. pEnumStreams->Release();
  711. }
  712. }
  713. return hr;
  714. }
  715. HRESULT SetLocalInfo()
  716. {
  717. const WCHAR * const LocalInfo[] = {
  718. L"My CName",
  719. L"Mu Han",
  720. L"[email protected]",
  721. L"703-5484",
  722. L"Redmond",
  723. L"Test app",
  724. L"New interface test",
  725. L"Some randmon info"
  726. };
  727. ITLocalParticipant *pLocalParticipant;
  728. HRESULT hr = gpCall->QueryInterface(
  729. IID_ITLocalParticipant,
  730. (void **)&pLocalParticipant
  731. );
  732. if (SUCCEEDED(hr))
  733. {
  734. for (int i = 0; i < PTI_PRIVATE; i ++)
  735. {
  736. BSTR info;
  737. hr = pLocalParticipant->get_LocalParticipantTypedInfo(
  738. (PARTICIPANT_TYPED_INFO)i, &info
  739. );
  740. if (SUCCEEDED(hr))
  741. {
  742. SysFreeString(info);
  743. }
  744. info = SysAllocString(LocalInfo[i]);
  745. hr = pLocalParticipant->put_LocalParticipantTypedInfo(
  746. (PARTICIPANT_TYPED_INFO)i, info
  747. );
  748. SysFreeString(info);
  749. }
  750. pLocalParticipant->Release();
  751. }
  752. return hr;
  753. }
  754. /////////////////////////////////////////////////////////////////
  755. // MakeTheCall
  756. //
  757. // Sets up and makes a call
  758. /////////////////////////////////////////////////////////////////
  759. HRESULT
  760. MakeTheCall(
  761. DWORD dwAddressType,
  762. PWCHAR szAddressToCall
  763. )
  764. {
  765. HRESULT hr = S_OK;
  766. BSTR bstrAddressToCall;
  767. BSTR pAddressName;
  768. // find an address object that
  769. // we will use to make calls on
  770. hr = FindAnAddress(dwAddressType, &pAddressName);
  771. if ( FAILED(hr) )
  772. {
  773. DoMessage(L"Could not find a TAPI address for making calls.");
  774. return hr;
  775. }
  776. SysFreeString(pAddressName);
  777. //
  778. // find out which media types this address supports
  779. //
  780. long lMediaTypes = 0;
  781. if ( AddressSupportsMediaType(gpAddress, TAPIMEDIATYPE_AUDIO) )
  782. {
  783. lMediaTypes |= TAPIMEDIATYPE_AUDIO; // we will use audio
  784. }
  785. if ( AddressSupportsMediaType(gpAddress, TAPIMEDIATYPE_VIDEO) )
  786. {
  787. lMediaTypes |= TAPIMEDIATYPE_VIDEO; // we will use video
  788. }
  789. //
  790. // Create the call.
  791. //
  792. if (dwAddressType == LINEADDRESSTYPE_SDP)
  793. {
  794. bstrAddressToCall = SysAllocString( SDP );
  795. }
  796. else
  797. {
  798. bstrAddressToCall = SysAllocString( szAddressToCall );
  799. }
  800. hr = gpAddress->CreateCall( bstrAddressToCall,
  801. dwAddressType,
  802. lMediaTypes,
  803. &gpCall);
  804. SysFreeString ( bstrAddressToCall );
  805. if ( FAILED(hr) )
  806. {
  807. DoMessage(L"Could not create a call.");
  808. return hr;
  809. }
  810. //
  811. // Select our terminals on the call; if any of the selections fail we
  812. // proceed without that terminal.
  813. //
  814. hr = SelectTerminalsOnCall( gpCall );
  815. //
  816. // We're now ready to call connect.
  817. //
  818. // the VARIANT_TRUE parameter indicates that this
  819. // call is sychronous - that is, it won't
  820. // return until the call is in the connected
  821. // state (or fails to connect)
  822. // Since this is called in the UI thread,
  823. // this means that the app will appear
  824. // to hang until this function returns.
  825. // Some TAPI service providers may take a long
  826. // time for a call to reach the connected state.
  827. //
  828. // SetLocalInfo();
  829. hr = gpCall->Connect( VARIANT_TRUE );
  830. if ( FAILED(hr) )
  831. {
  832. gpCall->Release();
  833. gpCall = NULL;
  834. DoMessage(L"Could not connect the call.");
  835. return hr;
  836. }
  837. return S_OK;
  838. }
  839. HRESULT CheckBasicAudio(
  840. ITTerminal * pTerminal
  841. )
  842. {
  843. HRESULT hr;
  844. ITBasicAudioTerminal *pITBasicAudioTerminal;
  845. hr = pTerminal->QueryInterface(&pITBasicAudioTerminal);
  846. if ( FAILED(hr) ) return hr;
  847. long lVolume;
  848. hr = pITBasicAudioTerminal->get_Volume(&lVolume);
  849. if ( SUCCEEDED(hr) )
  850. {
  851. hr = pITBasicAudioTerminal->put_Volume(lVolume * 2);
  852. }
  853. pITBasicAudioTerminal->Release();
  854. return hr;
  855. }
  856. /////////////////////////////////////////////////////////
  857. // GetTerminal
  858. //
  859. // Creates the default terminal for the passed-in stream.
  860. //
  861. /////////////////////////////////////////////////////////
  862. HRESULT
  863. GetTerminal(
  864. ITStream * pStream,
  865. ITTerminal ** ppTerminal
  866. )
  867. {
  868. //
  869. // Determine the media type and direction of this stream.
  870. //
  871. HRESULT hr;
  872. long lMediaType;
  873. TERMINAL_DIRECTION dir;
  874. hr = pStream->get_MediaType( &lMediaType );
  875. if ( FAILED(hr) ) return hr;
  876. hr = pStream->get_Direction( &dir );
  877. if ( FAILED(hr) ) return hr;
  878. //
  879. // Since video render is a dynamic terminal, the procedure for creating
  880. // it is different.
  881. //
  882. if ( ( lMediaType == TAPIMEDIATYPE_VIDEO ) &&
  883. ( dir == TD_RENDER ) )
  884. {
  885. return GetVideoRenderTerminal(ppTerminal);
  886. }
  887. //
  888. // For all other terminals we use GetDefaultStaticTerminal.
  889. // First, get the terminal support interface.
  890. //
  891. ITTerminalSupport * pTerminalSupport;
  892. hr = gpAddress->QueryInterface( IID_ITTerminalSupport,
  893. (void **)&pTerminalSupport);
  894. if ( SUCCEEDED(hr) )
  895. {
  896. //
  897. // get the default terminal for this MediaType and direction
  898. //
  899. hr = pTerminalSupport->GetDefaultStaticTerminal(lMediaType,
  900. dir,
  901. ppTerminal);
  902. pTerminalSupport->Release();
  903. if (TAPIMEDIATYPE_AUDIO)
  904. {
  905. CheckBasicAudio(*ppTerminal);
  906. }
  907. }
  908. return hr;
  909. }
  910. /////////////////////////////////////////////////////////
  911. // FindCaptureTerminal
  912. //
  913. // Find the capture terminal on a stream.
  914. //
  915. /////////////////////////////////////////////////////////
  916. HRESULT
  917. FindCaptureTerminal(
  918. ITStream * pStream,
  919. ITTerminal ** ppTerminal
  920. )
  921. {
  922. HRESULT hr;
  923. TERMINAL_DIRECTION dir;
  924. // enumerate all the terminals.
  925. IEnumTerminal *pEnumTerminals;
  926. hr = pStream->EnumerateTerminals(&pEnumTerminals);
  927. if (FAILED(hr))
  928. {
  929. return hr;
  930. }
  931. BOOL fFound = FALSE;
  932. ITTerminal *pTerminal;
  933. // find the capture terminal.
  934. while (S_OK == pEnumTerminals->Next(1, &pTerminal, NULL))
  935. {
  936. hr = pTerminal->get_Direction( &dir );
  937. if ( FAILED(hr) ) continue;
  938. if ( ( dir == TD_CAPTURE ) )
  939. {
  940. fFound = TRUE;
  941. break;
  942. }
  943. pTerminal->Release();
  944. }
  945. pEnumTerminals->Release();
  946. if (fFound)
  947. {
  948. *ppTerminal = pTerminal;
  949. return S_OK;
  950. }
  951. return E_FAIL;
  952. }
  953. /////////////////////////////////////////////////////////
  954. // GetVideoRenderTerminal
  955. //
  956. // Creates a dynamic terminal for the Video Render mediatype / direction
  957. //
  958. /////////////////////////////////////////////////////////
  959. HRESULT
  960. GetVideoRenderTerminal(
  961. ITTerminal ** ppTerminal
  962. )
  963. {
  964. //
  965. // Construct a BSTR for the correct IID.
  966. //
  967. LPOLESTR lpTerminalClass;
  968. HRESULT hr;
  969. hr = StringFromIID(CLSID_VideoWindowTerm,
  970. &lpTerminalClass);
  971. if ( SUCCEEDED(hr) )
  972. {
  973. BSTR bstrTerminalClass;
  974. bstrTerminalClass = SysAllocString ( lpTerminalClass );
  975. CoTaskMemFree( lpTerminalClass );
  976. if ( bstrTerminalClass == NULL )
  977. {
  978. hr = E_OUTOFMEMORY;
  979. }
  980. else
  981. {
  982. //
  983. // Get the terminal support interface
  984. //
  985. ITTerminalSupport * pTerminalSupport;
  986. hr = gpAddress->QueryInterface(IID_ITTerminalSupport,
  987. (void **)&pTerminalSupport);
  988. if ( SUCCEEDED(hr) )
  989. {
  990. //
  991. // Create the video render terminal.
  992. //
  993. hr = pTerminalSupport->CreateTerminal(bstrTerminalClass,
  994. TAPIMEDIATYPE_VIDEO,
  995. TD_RENDER,
  996. ppTerminal);
  997. pTerminalSupport->Release();
  998. if ( SUCCEEDED(hr) )
  999. {
  1000. // Get the video window interface for the terminal
  1001. IVideoWindow *pVideoWindow = NULL;
  1002. hr = (*ppTerminal)->QueryInterface(IID_IVideoWindow,
  1003. (void**)&pVideoWindow);
  1004. if ( SUCCEEDED(hr) )
  1005. {
  1006. //
  1007. // Set the visible member to true
  1008. //
  1009. // Note that the visibility property is the only one
  1010. // we can use on this terminal's IVideoWindow and
  1011. // IBasicVideo interfaces before the CME_STREAM_ACTIVE
  1012. // event is received for the stream. All other methods
  1013. // will fail until CME_STREAM_ACTIVE has been sent.
  1014. // Applications that need to control more about a video
  1015. // window than just its visibility must listen for the
  1016. // CME_STREAM_ACTIVE event. See the "t3in.exe" sample
  1017. // for how to do this.
  1018. //
  1019. hr = pVideoWindow->put_AutoShow( VARIANT_TRUE );
  1020. pVideoWindow->Release();
  1021. }
  1022. }
  1023. }
  1024. SysFreeString( bstrTerminalClass );
  1025. }
  1026. }
  1027. return hr;
  1028. }
  1029. //////////////////////////////////////////////////////////////////////
  1030. // DisconnectTheCall
  1031. //
  1032. // Disconnects the call
  1033. //////////////////////////////////////////////////////////////////////
  1034. HRESULT
  1035. DisconnectTheCall()
  1036. {
  1037. HRESULT hr = S_OK;
  1038. if (gpVideoRenderStream)
  1039. {
  1040. gpVideoRenderStream->Release();
  1041. gpVideoRenderStream = NULL;
  1042. }
  1043. if (gpLastVideoWindow)
  1044. {
  1045. gpLastVideoWindow->Release();
  1046. gpLastVideoWindow = NULL;
  1047. }
  1048. if (NULL != gpCall)
  1049. {
  1050. hr = gpCall->Disconnect( DC_NORMAL );
  1051. gpCall->Release();
  1052. gpCall = NULL;
  1053. return hr;
  1054. }
  1055. return S_FALSE;
  1056. }
  1057. ///////////////////////////////////////////////////////////////////
  1058. //
  1059. // HELPER FUNCTIONS
  1060. //
  1061. ///////////////////////////////////////////////////////////////////
  1062. ///////////////////////////////////////////////////////////////////
  1063. // DoMessage
  1064. ///////////////////////////////////////////////////////////////////
  1065. void
  1066. DoMessage(
  1067. LPWSTR pszMessage
  1068. )
  1069. {
  1070. MessageBox(
  1071. ghDlg,
  1072. pszMessage,
  1073. gszTapi30,
  1074. MB_OK
  1075. );
  1076. }
  1077. ///////////////////////////////////////////////////////////////
  1078. // EnableButton
  1079. //
  1080. // Enable, make default, and setfocus to a button
  1081. ///////////////////////////////////////////////////////////////
  1082. void
  1083. EnableButton(
  1084. HWND hDlg,
  1085. int ID
  1086. )
  1087. {
  1088. SendDlgItemMessage(
  1089. hDlg,
  1090. ID,
  1091. BM_SETSTYLE,
  1092. BS_DEFPUSHBUTTON,
  1093. 0
  1094. );
  1095. EnableWindow(
  1096. GetDlgItem( hDlg, ID ),
  1097. TRUE
  1098. );
  1099. SetFocus(
  1100. GetDlgItem( hDlg, ID )
  1101. );
  1102. }
  1103. //////////////////////////////////////////////////////////////
  1104. // DisableButton
  1105. //
  1106. // Disable a button
  1107. //////////////////////////////////////////////////////////////
  1108. void
  1109. DisableButton(
  1110. HWND hDlg,
  1111. int ID
  1112. )
  1113. {
  1114. SendDlgItemMessage(
  1115. hDlg,
  1116. ID,
  1117. BM_SETSTYLE,
  1118. BS_PUSHBUTTON,
  1119. 0
  1120. );
  1121. EnableWindow(
  1122. GetDlgItem( hDlg, ID ),
  1123. FALSE
  1124. );
  1125. }
  1126. //////////////////////////////////////////////////////////////
  1127. // AddressSupportsMediaType
  1128. //
  1129. // Finds out if the given address supports the given media
  1130. // type, and returns TRUE if it does.
  1131. //////////////////////////////////////////////////////////////
  1132. BOOL
  1133. AddressSupportsMediaType(
  1134. ITAddress * pAddress,
  1135. long lMediaType
  1136. )
  1137. {
  1138. VARIANT_BOOL bSupport = VARIANT_FALSE;
  1139. ITMediaSupport * pMediaSupport;
  1140. if ( SUCCEEDED( pAddress->QueryInterface( IID_ITMediaSupport,
  1141. (void **)&pMediaSupport ) ) )
  1142. {
  1143. // does it support this media type?
  1144. pMediaSupport->QueryMediaType(
  1145. lMediaType,
  1146. &bSupport
  1147. );
  1148. pMediaSupport->Release();
  1149. }
  1150. return (bSupport == VARIANT_TRUE);
  1151. }
  1152. //////////////////////////////////////////////////////////////
  1153. // ShowDialogs
  1154. //
  1155. // Puts up TAPI 3.1 configuration dialogs:
  1156. // Camera Control page
  1157. // Video Settings page
  1158. // Format Control page
  1159. // Bitrate and Frame Rate Control page
  1160. //////////////////////////////////////////////////////////////
  1161. void
  1162. ShowDialogs(ITBasicCallControl *pCall)
  1163. {
  1164. #define MAX_PAGES 9
  1165. HRESULT Hr;
  1166. PROPSHEETHEADER Psh;
  1167. HPROPSHEETPAGE Pages[MAX_PAGES];
  1168. ITStreamControl *pITStreamControl = NULL;
  1169. IEnumStream *pEnumStreams = NULL;
  1170. ITTerminal *pVideoCaptureTerminal = NULL;
  1171. ITStream *pVideoCaptureStream = NULL;
  1172. ITStream *pVideoRenderStream = NULL;
  1173. ITStream *pAudioCaptureStream = NULL;
  1174. BOOL bfMatch = FALSE;
  1175. // Only show settings in a call
  1176. if (!pCall)
  1177. return;
  1178. // Get the ITStreamControl interface for this call
  1179. if (FAILED(Hr = pCall->QueryInterface(IID_ITStreamControl, (void **) &pITStreamControl)))
  1180. return;
  1181. // Look for the video capture stream and terminal
  1182. Hr = pITStreamControl->EnumerateStreams(&pEnumStreams);
  1183. pITStreamControl->Release();
  1184. if (FAILED(Hr))
  1185. return;
  1186. // For each stream
  1187. ITStream *pStream;
  1188. while (S_OK == pEnumStreams->Next(1, &pStream, NULL))
  1189. {
  1190. // Find out the media type and direction of this stream,
  1191. if (IsVideoCaptureStream(pStream))
  1192. {
  1193. pVideoCaptureStream = pStream;
  1194. // find the capture terminal selected on this stream.
  1195. FindCaptureTerminal(pVideoCaptureStream, &pVideoCaptureTerminal);
  1196. }
  1197. else if (IsAudioCaptureStream(pStream))
  1198. {
  1199. pAudioCaptureStream = pStream;
  1200. }
  1201. else if (IsVideoRenderStream(pStream))
  1202. {
  1203. pVideoRenderStream = pStream;
  1204. }
  1205. else
  1206. {
  1207. pStream->Release();
  1208. }
  1209. }
  1210. pEnumStreams->Release();
  1211. CCameraControlProperties CamControlOut;
  1212. CCameraControlProperties CamControlIn;
  1213. CProcAmpProperties VideoSettingsIn;
  1214. CProcAmpProperties VideoSettingsOut;
  1215. CCaptureProperties CaptureSettings;
  1216. CVDeviceProperties VideoDevice;
  1217. CNetworkProperties NetworkSettings;
  1218. CSystemProperties SystemSettings;
  1219. CAudRecProperties AudRecSettings;
  1220. // Initialize property sheet header and common controls
  1221. Psh.dwSize = sizeof(Psh);
  1222. Psh.dwFlags = PSH_DEFAULT;
  1223. Psh.hInstance = ghInst;
  1224. Psh.hwndParent = ghDlg;
  1225. Psh.pszCaption = L"Settings";
  1226. Psh.nPages = 0;
  1227. Psh.nStartPage = 0;
  1228. Psh.pfnCallback = NULL;
  1229. Psh.phpage = Pages;
  1230. if (pVideoCaptureStream)
  1231. {
  1232. // Create the outgoing video settings property page
  1233. if (Pages[Psh.nPages] = VideoSettingsOut.OnCreate(L"Image Settings Out"))
  1234. Psh.nPages++;
  1235. // Connect page to the stream
  1236. VideoSettingsOut.OnConnect(pVideoCaptureStream);
  1237. // Create the outgoing camera control property page
  1238. if (Pages[Psh.nPages] = CamControlOut.OnCreate(L"Camera Control Out"))
  1239. Psh.nPages++;
  1240. // Connect page to the stream
  1241. CamControlOut.OnConnect(pVideoCaptureStream);
  1242. // Create the incoming video settings property page
  1243. if (Pages[Psh.nPages] = VideoSettingsIn.OnCreate(L"Image Settings In"))
  1244. Psh.nPages++;
  1245. // Connect page to the stream
  1246. VideoSettingsIn.OnConnect(pVideoRenderStream);
  1247. // Create the incoming camera control property page
  1248. if (Pages[Psh.nPages] = CamControlIn.OnCreate(L"Camera Control In"))
  1249. Psh.nPages++;
  1250. // Connect page to the stream
  1251. CamControlIn.OnConnect(pVideoRenderStream);
  1252. // Create the video stream control property page
  1253. if (Pages[Psh.nPages] = CaptureSettings.OnCreate())
  1254. Psh.nPages++;
  1255. // Connect page to the stream
  1256. CaptureSettings.OnConnect(pVideoCaptureStream);
  1257. // Create the video device control property page
  1258. if (Pages[Psh.nPages] = VideoDevice.OnCreate())
  1259. Psh.nPages++;
  1260. // Connect page to the stream
  1261. NetworkSettings.OnConnect(NULL, pVideoCaptureStream, NULL, NULL);
  1262. // Create the system settings property page
  1263. if (Pages[Psh.nPages] = SystemSettings.OnCreate())
  1264. Psh.nPages++;
  1265. // Connect page to the address object
  1266. SystemSettings.OnConnect(gpAddress);
  1267. }
  1268. if (pVideoCaptureTerminal)
  1269. {
  1270. // Connect page to the stream
  1271. VideoDevice.OnConnect(pVideoCaptureTerminal);
  1272. // Create the network control property page
  1273. if (Pages[Psh.nPages] = NetworkSettings.OnCreate())
  1274. Psh.nPages++;
  1275. }
  1276. if (pAudioCaptureStream)
  1277. {
  1278. // Connect page to the stream
  1279. AudRecSettings.OnConnect(pAudioCaptureStream);
  1280. // Create the network control property page
  1281. if (Pages[Psh.nPages] = AudRecSettings.OnCreate())
  1282. Psh.nPages++;
  1283. }
  1284. // Put up the property sheet
  1285. if (Psh.nPages)
  1286. PropertySheet(&Psh);
  1287. // Disconnect pages from the stream
  1288. VideoSettingsOut.OnDisconnect();
  1289. CamControlOut.OnDisconnect();
  1290. VideoSettingsIn.OnDisconnect();
  1291. CamControlIn.OnDisconnect();
  1292. CaptureSettings.OnDisconnect();
  1293. VideoDevice.OnDisconnect();
  1294. NetworkSettings.OnDisconnect();
  1295. SystemSettings.OnDisconnect();
  1296. AudRecSettings.OnDisconnect();
  1297. if (pVideoCaptureTerminal) pVideoCaptureTerminal->Release();
  1298. if (pVideoCaptureStream) pVideoCaptureStream->Release();
  1299. if (pVideoRenderStream) pVideoRenderStream->Release();
  1300. if (pAudioCaptureStream) pAudioCaptureStream->Release();
  1301. return;
  1302. }