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.

1247 lines
29 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. H323call.cpp
  5. Abstract:
  6. This module contains implementation of CH323MSPCall.
  7. Author:
  8. Mu Han (muhan) 5-September-1998
  9. --*/
  10. #include "stdafx.h"
  11. #include "common.h"
  12. #include <H323pdu.h>
  13. STDMETHODIMP CH323MSPCall::CreateStream(
  14. IN long lMediaType,
  15. IN TERMINAL_DIRECTION Direction,
  16. IN OUT ITStream ** ppStream
  17. )
  18. /*++
  19. Routine Description:
  20. This method is called by the app to create a new stream. If this happens
  21. before the TSP's new call notification, we just create the object. If the
  22. call is already connected, we will send the TSP an open channel request
  23. when the first terminal is selected.
  24. Arguments:
  25. lMediaType - The media type of this stream.
  26. Direction - The direction of this stream.
  27. ppStream - The memory address to store the returned pointer.
  28. Return Value:
  29. HRESULT.
  30. --*/
  31. {
  32. LOG((MSP_TRACE,
  33. "CH323MSPCall.CreateStream--dwMediaType:%x, Direction:%x, ppStream %x",
  34. lMediaType, Direction, ppStream
  35. ));
  36. // first call the base class's implementation to create the stream object.
  37. HRESULT hr = CMSPCallBase::CreateStream(
  38. lMediaType,
  39. Direction,
  40. ppStream
  41. );
  42. return hr;
  43. }
  44. STDMETHODIMP CH323MSPCall::RemoveStream(
  45. IN ITStream * pStream
  46. )
  47. /*++
  48. Routine Description:
  49. This method is called by the app to remove a stream. If the channel is
  50. already connected, we need to send the TSP an close channel request.
  51. Arguments:
  52. pStream - The stream to be removed.
  53. Return Value:
  54. HRESULT.
  55. --*/
  56. {
  57. LOG((MSP_TRACE, "CH323MSPCall::RemoveStream - pStream %x", pStream));
  58. // acquire the lock before accessing the stream object list.
  59. CLock lock(m_lock);
  60. if (m_Streams.Find(pStream) < 0)
  61. {
  62. LOG((MSP_ERROR, "CH323MSPCall::RemoveStream - Stream %x is not found.", pStream));
  63. return E_INVALIDARG;
  64. }
  65. // Close the TSP channel if it is active.
  66. HANDLE htChannel;
  67. if ((htChannel = ((CH323MSPStream *)pStream)->TSPChannel()) != NULL)
  68. {
  69. SendTSPMessage(
  70. H323MSP_CLOSE_CHANNEL_COMMAND,
  71. NULL,
  72. htChannel
  73. );
  74. }
  75. return CMSPCallMultiGraph::RemoveStream(pStream);
  76. }
  77. HRESULT CH323MSPCall::Init(
  78. IN CMSPAddress * pMSPAddress,
  79. IN MSP_HANDLE htCall,
  80. IN DWORD dwReserved,
  81. IN DWORD dwMediaType
  82. )
  83. /*++
  84. Routine Description:
  85. This method is called when the call is first created. It sets
  86. up the streams based on the mediatype specified.
  87. Arguments:
  88. pMSPAddress - The pointer to the address object.
  89. htCall - The handle to the Call in TAPI's space.
  90. Used in sending events.
  91. dwReserved - Reserved.
  92. dwMediaType - The media type of this call.
  93. Return Value:
  94. HRESULT.
  95. --*/
  96. {
  97. LOG((MSP_TRACE,
  98. "H323MSP call %x initialize entered,"
  99. " pMSPAddress:%x, htCall %x, dwMediaType %x",
  100. this, pMSPAddress, htCall, dwMediaType
  101. ));
  102. #ifdef DEBUG_REFCOUNT
  103. LOG((MSP_TRACE, "Number of Streams alive: %d", g_lStreamObjects));
  104. if (g_lStreamObjects != 0)
  105. {
  106. DebugBreak();
  107. }
  108. #endif
  109. // Call the base class's init.
  110. HRESULT hr= CMSPCallMultiGraph::Init(
  111. pMSPAddress,
  112. htCall,
  113. dwReserved,
  114. dwMediaType
  115. );
  116. if (FAILED(hr))
  117. {
  118. LOG((MSP_ERROR, "MSPCallMultiGraph init failed:%x", hr));
  119. return hr;
  120. }
  121. // create streams based on the media types.
  122. if (dwMediaType & TAPIMEDIATYPE_AUDIO)
  123. {
  124. ITStream * pStream;
  125. // create a stream object.
  126. hr = InternalCreateStream(TAPIMEDIATYPE_AUDIO, TD_RENDER, &pStream);
  127. if (FAILED(hr))
  128. {
  129. LOG((MSP_ERROR, "create audio render stream failed:%x", hr));
  130. return hr;
  131. }
  132. // The stream is already in our array, we don't need this pointer.
  133. pStream->Release();
  134. // create a stream object.
  135. hr = InternalCreateStream(TAPIMEDIATYPE_AUDIO, TD_CAPTURE, &pStream);
  136. if (FAILED(hr))
  137. {
  138. LOG((MSP_ERROR, "create audio capture stream failed:%x", hr));
  139. return hr;
  140. }
  141. // The stream is already in our array, we don't need this pointer.
  142. pStream->Release();
  143. }
  144. if (dwMediaType & TAPIMEDIATYPE_VIDEO)
  145. {
  146. ITStream * pStream;
  147. // create a stream object.
  148. hr = InternalCreateStream(TAPIMEDIATYPE_VIDEO, TD_RENDER, &pStream);
  149. if (FAILED(hr))
  150. {
  151. LOG((MSP_ERROR, "create video render stream failed:%x", hr));
  152. return hr;
  153. }
  154. // The stream is already in our array, we don't need this pointer.
  155. pStream->Release();
  156. // create a stream object.
  157. hr = InternalCreateStream(TAPIMEDIATYPE_VIDEO, TD_CAPTURE, &pStream);
  158. if (FAILED(hr))
  159. {
  160. LOG((MSP_ERROR, "create video capture stream failed:%x", hr));
  161. return hr;
  162. }
  163. // The stream is already in our array, we don't need this pointer.
  164. pStream->Release();
  165. }
  166. m_fCallConnected = FALSE;
  167. m_fShutDown = FALSE;
  168. return S_OK;
  169. }
  170. HRESULT CH323MSPCall::ShutDown()
  171. /*++
  172. Routine Description:
  173. Just call the internal shut down method.
  174. Arguments:
  175. Return Value:
  176. HRESULT.
  177. --*/
  178. {
  179. InternalShutDown();
  180. // acquire the lock on the call.
  181. CLock lock(m_lock);
  182. // release all the streams
  183. for (int i = m_Streams.GetSize() - 1; i >= 0; i --)
  184. {
  185. m_Streams[i]->Release();
  186. }
  187. m_Streams.RemoveAll();
  188. return S_OK;
  189. }
  190. HRESULT CH323MSPCall::InternalShutDown()
  191. /*++
  192. Routine Description:
  193. First call the base class's shutdown and then release all the participant
  194. objects.
  195. Arguments:
  196. Return Value:
  197. HRESULT.
  198. --*/
  199. {
  200. // acquire the lock on the call.
  201. CLock lock(m_lock);
  202. if (m_fShutDown)
  203. {
  204. return S_OK;
  205. }
  206. // Shutdown all the streams
  207. for (int i = m_Streams.GetSize() - 1; i >= 0; i --)
  208. {
  209. UnregisterWaitEvent(i);
  210. ((CMSPStream*)m_Streams[i])->ShutDown();
  211. }
  212. m_ThreadPoolWaitBlocks.RemoveAll();
  213. m_fShutDown = TRUE;
  214. return S_OK;
  215. }
  216. template <class T>
  217. HRESULT CreateStreamHelper(
  218. IN T * pT,
  219. IN HANDLE hAddress,
  220. IN CH323MSPCall* pMSPCall,
  221. IN IMediaEvent * pGraph,
  222. IN DWORD dwMediaType,
  223. IN TERMINAL_DIRECTION Direction,
  224. OUT ITStream ** ppITStream
  225. )
  226. /*++
  227. Routine Description:
  228. Create a stream object and initialize it. This method is called internally
  229. to create a stream object of different class.
  230. Arguments:
  231. hAddress - the handle to the address object.
  232. pCall - the call object.
  233. pGraph - the filter graph for this stream.
  234. dwMediaType - the media type of the stream.
  235. Direction - the direction of the steam.
  236. ppITStream - the interface on this stream object.
  237. Return Value:
  238. HRESULT.
  239. --*/
  240. {
  241. CComObject<T> * pCOMMSPStream;
  242. HRESULT hr = CComObject<T>::CreateInstance(&pCOMMSPStream);
  243. if (NULL == pCOMMSPStream)
  244. {
  245. LOG((MSP_ERROR, "CreateMSPStream:could not create stream:%x", hr));
  246. return hr;
  247. }
  248. // get the interface pointer.
  249. hr = pCOMMSPStream->_InternalQueryInterface(
  250. IID_ITStream,
  251. (void **)ppITStream
  252. );
  253. if (FAILED(hr))
  254. {
  255. LOG((MSP_ERROR, "CreateMSPStream:QueryInterface failed: %x", hr));
  256. delete pCOMMSPStream;
  257. return hr;
  258. }
  259. // Initialize the object.
  260. hr = pCOMMSPStream->Init(
  261. hAddress,
  262. pMSPCall,
  263. pGraph,
  264. dwMediaType,
  265. Direction
  266. );
  267. if (FAILED(hr))
  268. {
  269. LOG((MSP_ERROR, "CreateMSPStream:call init failed: %x", hr));
  270. (*ppITStream)->Release();
  271. return hr;
  272. }
  273. return S_OK;
  274. }
  275. HRESULT CH323MSPCall::CreateStreamObject(
  276. IN DWORD dwMediaType,
  277. IN TERMINAL_DIRECTION Direction,
  278. IN IMediaEvent * pGraph,
  279. IN ITStream ** ppStream
  280. )
  281. /*++
  282. Routine Description:
  283. Create a media stream object based on the mediatype and direction.
  284. Arguments:
  285. pMediaType - TAPI3 media type.
  286. Direction - direction of this stream.
  287. IMediaEvent - The filter graph used in this stream.
  288. ppStream - the return pointer of the stream interface
  289. Return Value:
  290. HRESULT.
  291. --*/
  292. {
  293. LOG((MSP_TRACE, "CreateStreamObject, entered"));
  294. HRESULT hr;
  295. ITStream * pIMSPStream = NULL;
  296. // Create a stream object based on the media type.
  297. if (dwMediaType == TAPIMEDIATYPE_AUDIO)
  298. {
  299. if (Direction == TD_RENDER)
  300. {
  301. CStreamAudioRecv *pAudioRecv = NULL;
  302. hr = ::CreateStreamHelper(
  303. pAudioRecv,
  304. m_pMSPAddress,
  305. this,
  306. pGraph,
  307. TAPIMEDIATYPE_AUDIO,
  308. TD_RENDER,
  309. &pIMSPStream
  310. );
  311. LOG((MSP_TRACE, "create audio receive:%x, hr:%x", pIMSPStream,hr));
  312. }
  313. else if (Direction == TD_CAPTURE)
  314. {
  315. CStreamAudioSend *pAudioSend = NULL;
  316. hr = ::CreateStreamHelper(
  317. pAudioSend,
  318. m_pMSPAddress,
  319. this,
  320. pGraph,
  321. TAPIMEDIATYPE_AUDIO,
  322. TD_CAPTURE,
  323. &pIMSPStream
  324. );
  325. LOG((MSP_TRACE, "create audio send:%x, hr:%x", pIMSPStream,hr));
  326. }
  327. }
  328. else if (dwMediaType == TAPIMEDIATYPE_VIDEO)
  329. {
  330. if (Direction == TD_RENDER)
  331. {
  332. CStreamVideoRecv *pVideoRecv = NULL;
  333. hr = ::CreateStreamHelper(
  334. pVideoRecv,
  335. m_pMSPAddress,
  336. this,
  337. pGraph,
  338. TAPIMEDIATYPE_VIDEO,
  339. TD_RENDER,
  340. &pIMSPStream
  341. );
  342. LOG((MSP_TRACE, "create video Recv:%x, hr:%x", pIMSPStream,hr));
  343. }
  344. else if (Direction == TD_CAPTURE)
  345. {
  346. CStreamVideoSend *pVideoSend = NULL;
  347. hr = ::CreateStreamHelper(
  348. pVideoSend,
  349. m_pMSPAddress,
  350. this,
  351. pGraph,
  352. TAPIMEDIATYPE_VIDEO,
  353. TD_CAPTURE,
  354. &pIMSPStream
  355. );
  356. LOG((MSP_TRACE, "create video send:%x, hr:%x", pIMSPStream,hr));
  357. }
  358. }
  359. if (FAILED(hr))
  360. {
  361. LOG((MSP_ERROR, "create stream failed. %x", hr));
  362. return hr;
  363. }
  364. *ppStream = pIMSPStream;
  365. return S_OK;
  366. }
  367. HRESULT CH323MSPCall::SendTSPMessage(
  368. IN H323MSP_MESSAGE_TYPE Type,
  369. IN ITStream * hmChannel,
  370. IN HANDLE htChannel,
  371. IN MEDIATYPE MediaType,
  372. IN DWORD dwReason,
  373. IN DWORD dwBitRate
  374. ) const
  375. /*++
  376. Routine Description:
  377. Send the TSP a message from the MSP.
  378. Arguments:
  379. command - the command to be sent.
  380. hmChannel - the handle of the stream.
  381. htChannel - the handle of the channel in the TSP.
  382. Mediatype - the media type of the channel.
  383. dwReason - the reason for the command.
  384. Return Value:
  385. HRESULT.
  386. --*/
  387. {
  388. LOG((MSP_TRACE, "SendTSPMessage, type %d, hmChannel %p, htChannel %d",
  389. Type, hmChannel, htChannel));
  390. // first allocate the memory.
  391. DWORD dwSize = sizeof(H323MSP_MESSAGE);
  392. MSPEVENTITEM* pEventItem = AllocateEventItem(dwSize);
  393. if (pEventItem == NULL)
  394. {
  395. LOG((MSP_ERROR, "No memory for the TSPMSP data, size: %d", dwSize));
  396. return E_OUTOFMEMORY;
  397. }
  398. // Fill in the necessary fields for the event structure.
  399. pEventItem->MSPEventInfo.dwSize =
  400. sizeof(MSP_EVENT_INFO) + sizeof(H323MSP_MESSAGE);
  401. pEventItem->MSPEventInfo.Event = ME_TSP_DATA;
  402. pEventItem->MSPEventInfo.hCall = m_htCall;
  403. pEventItem->MSPEventInfo.MSP_TSP_DATA.dwBufferSize = sizeof(H323MSP_MESSAGE);
  404. H323MSP_MESSAGE *pData = (H323MSP_MESSAGE *)
  405. pEventItem->MSPEventInfo.MSP_TSP_DATA.pBuffer;
  406. // Fill in the data for the TSP.
  407. pData->Type = Type;
  408. switch (Type)
  409. {
  410. case H323MSP_OPEN_CHANNEL_REQUEST:
  411. pData->OpenChannelRequest.hmChannel = hmChannel;
  412. pData->OpenChannelRequest.Settings.MediaType = MediaType;
  413. break;
  414. case H323MSP_ACCEPT_CHANNEL_RESPONSE:
  415. pData->AcceptChannelResponse.hmChannel = hmChannel;
  416. pData->AcceptChannelResponse.htChannel = htChannel;
  417. break;
  418. case H323MSP_CLOSE_CHANNEL_COMMAND:
  419. pData->CloseChannelCommand.hChannel = htChannel;
  420. pData->CloseChannelCommand.dwReason = dwReason;
  421. break;
  422. case H323MSP_QOS_Evnet:
  423. pData->QOSEvent.dwEvent = dwReason;
  424. pData->QOSEvent.htChannel = htChannel;
  425. break;
  426. case H323MSP_VIDEO_FAST_UPDATE_PICTURE_COMMAND:
  427. pData->VideoFastUpdatePictureCommand.hChannel = htChannel;
  428. break;
  429. case H323MSP_FLOW_CONTROL_COMMAND:
  430. pData->FlowControlCommand.hChannel = htChannel;
  431. pData->FlowControlCommand.dwBitRate = dwBitRate;
  432. break;
  433. }
  434. HRESULT hr = m_pMSPAddress->PostEvent(pEventItem);
  435. if (FAILED(hr))
  436. {
  437. LOG((MSP_ERROR, "Post event failed %x", hr));
  438. FreeEventItem(pEventItem);
  439. return hr;
  440. }
  441. return S_OK;
  442. }
  443. void CH323MSPCall::ProcessNewCallIndication(void)
  444. /*++
  445. Routine Description:
  446. This function handles the new call indication pdu. It walk through the
  447. list of streams and send open channel requests to the TSP for each
  448. outgoing stream.
  449. Arguments:
  450. none.
  451. Return Value:
  452. none.
  453. --*/
  454. {
  455. LOG((MSP_TRACE, "NewCallIndication entered."));
  456. CLock lock(m_lock);
  457. if (m_fCallConnected)
  458. {
  459. LOG((MSP_ERROR, "New Call indication Twice!!!"));
  460. return;
  461. }
  462. for (int i = 0; i < m_Streams.GetSize(); i ++)
  463. {
  464. CH323MSPStream* pH323MSPStream = (CH323MSPStream*)m_Streams[i];
  465. // Notify the stream that the call is connected.
  466. pH323MSPStream->CallConnect();
  467. if ((pH323MSPStream->Direction() == TD_CAPTURE)
  468. && (pH323MSPStream->IsTerminalSelected()))
  469. {
  470. // Send an open Channel request for outgoing channels.
  471. SendTSPMessage(
  472. H323MSP_OPEN_CHANNEL_REQUEST,
  473. m_Streams[i],
  474. NULL,
  475. (pH323MSPStream->MediaType() == TAPIMEDIATYPE_AUDIO)
  476. ? MEDIA_AUDIO : MEDIA_VIDEO
  477. );
  478. }
  479. }
  480. m_fCallConnected = TRUE;
  481. return;
  482. }
  483. void CH323MSPCall::ProcessOpenChannelResponse(
  484. IN H323MSG_OPEN_CHANNEL_RESPONSE * pOpenChannelResponse
  485. )
  486. /*++
  487. Routine Description:
  488. This function handles the open channel response pdu. It finds the stream
  489. based on the handle and configures the stream.
  490. Arguments:
  491. pOpenChannelResponse - the PDU that has the detailed info.
  492. Return Value:
  493. none.
  494. --*/
  495. {
  496. LOG((MSP_TRACE,
  497. "OpenChannelResponse entered, hmChannel %x, htChannel %x, media %d",
  498. pOpenChannelResponse->hmChannel,
  499. pOpenChannelResponse->htChannel,
  500. pOpenChannelResponse->Settings.MediaType
  501. ));
  502. ITStream *pITStream = (ITStream *)(pOpenChannelResponse->hmChannel);
  503. m_lock.Lock();
  504. if (m_Streams.Find(pITStream) < 0)
  505. {
  506. LOG((MSP_ERROR, "Stream %x does not exit", pITStream));
  507. m_lock.Unlock();
  508. return;
  509. }
  510. // it is a valid stream, addref it so that it won't go away.
  511. pITStream->AddRef();
  512. // release the lock on the call.
  513. m_lock.Unlock();
  514. HRESULT hr = ((CH323MSPStream *)pITStream)->Configure(
  515. pOpenChannelResponse->htChannel,
  516. pOpenChannelResponse->Settings
  517. );
  518. if (FAILED(hr))
  519. {
  520. SendTSPMessage(
  521. H323MSP_CLOSE_CHANNEL_COMMAND,
  522. NULL,
  523. pOpenChannelResponse->htChannel
  524. );
  525. }
  526. // release the refcount we just added.
  527. pITStream->Release();
  528. return;
  529. }
  530. HRESULT CH323MSPCall::SendTAPIStreamEvent(
  531. IN ITStream * pITStream,
  532. IN MSP_CALL_EVENT Type,
  533. IN MSP_CALL_EVENT_CAUSE Cause
  534. )
  535. {
  536. MSPEVENTITEM* pEventItem = AllocateEventItem();
  537. if (pEventItem == NULL)
  538. {
  539. LOG((MSP_ERROR, "No memory for the TSPMSP data, size: %d", sizeof(MSPEVENTITEM)));
  540. return E_OUTOFMEMORY;
  541. }
  542. // Fill in the necessary fields for the event structure.
  543. pEventItem->MSPEventInfo.dwSize = sizeof(MSP_EVENT_INFO);;
  544. pEventItem->MSPEventInfo.Event = ME_CALL_EVENT;
  545. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.Type = Type;
  546. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.Cause = Cause;
  547. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pStream = pITStream;
  548. // Addref to prevent it from going away.
  549. pITStream->AddRef();
  550. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.pTerminal = NULL;
  551. pEventItem->MSPEventInfo.MSP_CALL_EVENT_INFO.hrError= 0;
  552. // send the event to tapi.
  553. HRESULT hr = HandleStreamEvent(pEventItem);
  554. if (FAILED(hr))
  555. {
  556. LOG((MSP_ERROR, "Post event failed %x", hr));
  557. FreeEventItem(pEventItem);
  558. return hr;
  559. }
  560. return S_OK;
  561. }
  562. void CH323MSPCall::ProcessAcceptChannelRequest(
  563. IN H323MSG_ACCEPT_CHANNEL_REQUEST * pAcceptChannelRequest
  564. )
  565. /*++
  566. Routine Description:
  567. This function handles the accept channel request pdu. It finds a free
  568. stream that can be used for this channel. If no one can be found, it will
  569. create a new stream and notify the app. The channel is always accepted
  570. automatically. If the app choose to remove the stream, the channel will
  571. be closed.
  572. Arguments:
  573. pAcceptChannelRequest - the PDU that has the detailed info.
  574. Return Value:
  575. none.
  576. --*/
  577. {
  578. LOG((MSP_TRACE,
  579. "AcceptChannelRequest entered, htChannel %x, media %d",
  580. pAcceptChannelRequest->htChannel,
  581. pAcceptChannelRequest->Settings.MediaType
  582. ));
  583. DWORD dwMediaType;
  584. if (pAcceptChannelRequest->Settings.MediaType == MEDIA_AUDIO)
  585. {
  586. dwMediaType = TAPIMEDIATYPE_AUDIO;
  587. }
  588. else
  589. {
  590. dwMediaType = TAPIMEDIATYPE_VIDEO;
  591. }
  592. // if the media type of the channel is not one of the media types of the
  593. // call, reject the channel.
  594. if (!(dwMediaType & m_dwMediaType))
  595. {
  596. LOG((MSP_WARN,
  597. "Unwanted media type %x, call media type %x",
  598. dwMediaType, m_dwMediaType
  599. ));
  600. SendTSPMessage(
  601. H323MSP_CLOSE_CHANNEL_COMMAND,
  602. NULL,
  603. pAcceptChannelRequest->htChannel
  604. );
  605. return;
  606. }
  607. CH323MSPStream* pStream = NULL;
  608. BOOL fFoundUnused = FALSE;
  609. BOOL fExistButInUse = FALSE;
  610. CLock lock(m_lock);
  611. // find an unused incoming stream of that media type.
  612. for (int i = 0; i < m_Streams.GetSize(); i++)
  613. {
  614. pStream = (CH323MSPStream*)m_Streams[i];
  615. if ((pStream->Direction() == TD_RENDER)
  616. && (pStream->MediaType() == dwMediaType))
  617. {
  618. if (pStream->IsConfigured())
  619. {
  620. fExistButInUse = TRUE;
  621. }
  622. else
  623. {
  624. fFoundUnused = TRUE;
  625. break;
  626. }
  627. }
  628. }
  629. HRESULT hr;
  630. if (!fFoundUnused)
  631. {
  632. if (!fExistButInUse)
  633. {
  634. // This means the app has deleted the streams of this type and
  635. // direction. We should reject this channel.
  636. SendTSPMessage(
  637. H323MSP_CLOSE_CHANNEL_COMMAND,
  638. NULL,
  639. pAcceptChannelRequest->htChannel
  640. );
  641. return;
  642. }
  643. //
  644. // This channel might be wanted by the APP, create a stream for it.
  645. //
  646. ITStream * pITStream;
  647. // create a stream object.
  648. hr = InternalCreateStream(dwMediaType, TD_RENDER, &pITStream);
  649. if (FAILED(hr))
  650. {
  651. LOG((MSP_ERROR, "create stream failed:%x", hr));
  652. SendTSPMessage(
  653. H323MSP_CLOSE_CHANNEL_COMMAND,
  654. NULL,
  655. pAcceptChannelRequest->htChannel
  656. );
  657. return;
  658. }
  659. // notify the app about the new stream.
  660. hr = SendTAPIStreamEvent(pITStream, CALL_NEW_STREAM, CALL_CAUSE_REMOTE_REQUEST);
  661. if (FAILED(hr))
  662. {
  663. LOG((MSP_ERROR, "Send new stream event failed:%x", hr));
  664. RemoveStream(pITStream);
  665. SendTSPMessage(
  666. H323MSP_CLOSE_CHANNEL_COMMAND,
  667. NULL,
  668. pAcceptChannelRequest->htChannel
  669. );
  670. return;
  671. }
  672. // The stream is already in our array, we don't need this pointer.
  673. pITStream->Release();
  674. pStream = (CH323MSPStream*)pITStream;
  675. }
  676. if (SUCCEEDED(pStream->Configure(
  677. pAcceptChannelRequest->htChannel,
  678. pAcceptChannelRequest->Settings
  679. )))
  680. {
  681. SendTSPMessage(
  682. H323MSP_ACCEPT_CHANNEL_RESPONSE,
  683. (ITStream*)pStream,
  684. pAcceptChannelRequest->htChannel
  685. );
  686. }
  687. return;
  688. }
  689. void CH323MSPCall::ProcessCloseChannelCommand(
  690. IN H323MSG_CLOSE_CHANNEL_COMMAND * pCloseChannelCommand
  691. )
  692. /*++
  693. Routine Description:
  694. This function handles the close channel pdu. It finds the stream
  695. based on the handle and remove the stream and also notify the app.
  696. Arguments:
  697. pCloseChannelCommand - the PDU that has the detailed info.
  698. Return Value:
  699. none.
  700. --*/
  701. {
  702. LOG((MSP_TRACE,
  703. "CloseChannelCommand entered, hChannel %x, reason: %x",
  704. pCloseChannelCommand->hChannel,
  705. pCloseChannelCommand->dwReason
  706. ));
  707. ITStream *pITStream = (ITStream *)(pCloseChannelCommand->hChannel);
  708. m_lock.Lock();
  709. if (m_Streams.Find(pITStream) < 0)
  710. {
  711. LOG((MSP_ERROR, "Stream %x does not exit", pITStream));
  712. m_lock.Unlock();
  713. return;
  714. }
  715. // it is a valid stream, addref it so that it won't go away.
  716. pITStream->AddRef();
  717. // release the lock on the call.
  718. m_lock.Unlock();
  719. ((CH323MSPStream *)pITStream)->ShutDown();
  720. // notify the app about the stream being closed.
  721. SendTAPIStreamEvent(pITStream, CALL_STREAM_NOT_USED, CALL_CAUSE_REMOTE_REQUEST);
  722. // release the refcount we just added.
  723. pITStream->Release();
  724. return;
  725. }
  726. void CH323MSPCall::ProcessIFrameRequest(
  727. IN H323MSG_VIDEO_FAST_UPDATE_PICTURE_COMMAND * pIFrameRequest
  728. )
  729. /*++
  730. Routine Description:
  731. Arguments:
  732. Return Value:
  733. none.
  734. --*/
  735. {
  736. LOG((MSP_TRACE,
  737. "ProcessIFrameRequest entered, hChannel %x",
  738. pIFrameRequest->hChannel
  739. ));
  740. ITStream *pITStream = (ITStream *)(pIFrameRequest->hChannel);
  741. m_lock.Lock();
  742. if (m_Streams.Find(pITStream) < 0)
  743. {
  744. LOG((MSP_ERROR, "Stream %x does not exit", pITStream));
  745. m_lock.Unlock();
  746. return;
  747. }
  748. // it is a valid stream, addref it so that it won't go away.
  749. pITStream->AddRef();
  750. // release the lock on the call.
  751. m_lock.Unlock();
  752. ((CH323MSPStream *)pITStream)->SendIFrame();
  753. // release the refcount we just added.
  754. pITStream->Release();
  755. return;
  756. }
  757. void CH323MSPCall::ProcessFlowControlCommand(
  758. IN H323MSG_FLOW_CONTROL_COMMAND * pFlowControlCommand
  759. )
  760. /*++
  761. Routine Description:
  762. Arguments:
  763. Return Value:
  764. none.
  765. --*/
  766. {
  767. LOG((MSP_TRACE,
  768. "FlowControlCommand entered, hChannel %x, dataRate: %d",
  769. pFlowControlCommand->hChannel,
  770. pFlowControlCommand->dwBitRate
  771. ));
  772. ITStream *pITStream = (ITStream *)(pFlowControlCommand->hChannel);
  773. m_lock.Lock();
  774. if (m_Streams.Find(pITStream) < 0)
  775. {
  776. LOG((MSP_ERROR, "Stream %x does not exit", pITStream));
  777. m_lock.Unlock();
  778. return;
  779. }
  780. // it is a valid stream, addref it so that it won't go away.
  781. pITStream->AddRef();
  782. // release the lock on the call.
  783. m_lock.Unlock();
  784. ((CH323MSPStream *)pITStream)->ChangeMaxBitRate(
  785. pFlowControlCommand->dwBitRate
  786. );
  787. // release the refcount we just added.
  788. pITStream->Release();
  789. return;
  790. }
  791. DWORD CH323MSPCall::ProcessWorkerCallBack(
  792. IN PBYTE pBuffer,
  793. IN DWORD dwSize
  794. )
  795. /*++
  796. Routine Description:
  797. This function handles the work item given by the TSP.
  798. Arguments:
  799. pBuffer - a buffer that contains a TSP_MSP command block.
  800. dwSize - the size of the buffer.
  801. Return Value:
  802. NOERROR.
  803. --*/
  804. {
  805. LOG((MSP_TRACE, "ProcessWorkerCallBAck"));
  806. _ASSERTE(!IsBadReadPtr(pBuffer, dwSize));
  807. H323TSP_MESSAGE * pData = (H323TSP_MESSAGE *)pBuffer;
  808. switch (pData->Type)
  809. {
  810. //
  811. // H323TSP_NEW_CALL_INDICATION - sent only from the TSP
  812. // to the MSP in order to initiate communication once
  813. // a call has been created.
  814. //
  815. case H323TSP_NEW_CALL_INDICATION:
  816. ProcessNewCallIndication();
  817. break;
  818. //
  819. // H323TSP_OPEN_CHANNEL_RESPONSE - sent only from the TSP
  820. // to the MSP in response to H323MSP_OPEN_CHANNEL_REQUEST.
  821. //
  822. case H323TSP_OPEN_CHANNEL_RESPONSE:
  823. ProcessOpenChannelResponse(&(pData->OpenChannelResponse));
  824. break;
  825. //
  826. // H323TSP_ACCEPT_CHANNEL_REQUEST - sent only from the TSP
  827. // to the MSP in order to request the acceptance of an
  828. // incoming logical channel.
  829. //
  830. case H323TSP_ACCEPT_CHANNEL_REQUEST:
  831. ProcessAcceptChannelRequest(&(pData->AcceptChannelRequest));
  832. break;
  833. //
  834. // H323TSP_CLOSE_CHANNEL_COMMAND - sent only from the TSP
  835. // to the MSP in order to demand the immediate closure of
  836. // an incoming or outgoing logical channel.
  837. //
  838. case H323TSP_CLOSE_CHANNEL_COMMAND:
  839. ProcessCloseChannelCommand(&(pData->CloseChannelCommand));
  840. break;
  841. //
  842. // H323TSP_CLOSE_CALL_CAMMAND - sent only from the TSP
  843. // to the MSP in order to stop all the streaming for a call.
  844. //
  845. case H323TSP_CLOSE_CALL_COMMAND:
  846. InternalShutDown();
  847. break;
  848. // I Frame Request.
  849. //
  850. case H323TSP_VIDEO_FAST_UPDATE_PICTURE_COMMAND:
  851. ProcessIFrameRequest(&(pData->VideoFastUpdatePictureCommand));
  852. break;
  853. // Flow control command Request.
  854. //
  855. case H323TSP_FLOW_CONTROL_COMMAND:
  856. ProcessFlowControlCommand(&(pData->FlowControlCommand));
  857. break;
  858. }
  859. return NOERROR;
  860. }
  861. DWORD WINAPI CH323MSPCall::WorkerCallbackDispatcher(VOID *pContext)
  862. /*++
  863. Routine Description:
  864. Because configure the streams uses a lot of COM
  865. stuff, we can't rely on the RPC thread the calls into the MSP to
  866. receive the TSP data. So, we let our own working thread do the work.
  867. This method is the callback function for the queued work item. It
  868. just gets the call object from the context structure and calls a method
  869. on the call object to handle the work item.
  870. Arguments:
  871. pContext - A pointer to a CALLWORKITEM structure.
  872. Return Value:
  873. HRESULT.
  874. --*/
  875. {
  876. CALLWORKITEM *pItem = (CALLWORKITEM *)pContext;
  877. pItem->pCall->ProcessWorkerCallBack(pItem->Buffer, pItem->dwLen);
  878. pItem->pCall->MSPCallRelease();
  879. free(pItem);
  880. return NOERROR;
  881. }
  882. HRESULT CH323MSPCall::ReceiveTSPCallData(
  883. IN PBYTE pBuffer,
  884. IN DWORD dwSize
  885. )
  886. /*++
  887. Routine Description:
  888. This function handles the work item given by the TSP.
  889. Arguments:
  890. pBuffer - a buffer that contains a TSP_MSP command block.
  891. dwSize - the size of the buffer.
  892. Return Value:
  893. E_POINTER.
  894. S_OK.
  895. --*/
  896. {
  897. LOG((MSP_TRACE,
  898. "ReceiveTSPCallData, pBuffer %x, dwSize %d", pBuffer, dwSize));
  899. // make sure the data is valid.
  900. if (IsBadReadPtr(pBuffer, dwSize))
  901. {
  902. LOG((MSP_ERROR, "the TSP data is invalid."));
  903. return E_POINTER;
  904. }
  905. // allocate a work item structure for our worker thread.
  906. CALLWORKITEM *pItem = (CALLWORKITEM *)malloc(sizeof(CALLWORKITEM) + dwSize);
  907. if (pItem == NULL)
  908. {
  909. LOG((MSP_ERROR, "out of memory for work item."));
  910. return E_OUTOFMEMORY;
  911. }
  912. this->MSPCallAddRef();
  913. pItem->pCall = this;
  914. pItem->dwLen = dwSize;
  915. CopyMemory(pItem->Buffer, pBuffer, dwSize);
  916. // post a work item to our worker thread.
  917. HRESULT hr = g_Thread.QueueWorkItem(
  918. WorkerCallbackDispatcher, // the callback
  919. pItem, // the context.
  920. FALSE // sync (FALSE means asyn)
  921. );
  922. if (FAILED(hr))
  923. {
  924. this->MSPCallRelease();
  925. free(pItem);
  926. LOG((MSP_ERROR, "queue work item failed."));
  927. return E_UNEXPECTED;
  928. }
  929. return S_OK;
  930. }