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.

948 lines
23 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. MSPCall.cpp
  5. Abstract:
  6. This module contains implementation of CMSPCall.
  7. --*/
  8. #include "precomp.h"
  9. #pragma hdrstop
  10. /////////////////////////////////////////////////////////////////////////////
  11. // CMSPCallBase
  12. /////////////////////////////////////////////////////////////////////////////
  13. CMSPCallBase::CMSPCallBase()
  14. : m_pMSPAddress(NULL),
  15. m_htCall(NULL),
  16. m_dwMediaType(0)
  17. {
  18. LOG((MSP_TRACE, "CMSPCallBase::CMSPCallBase[%p] entered.", this));
  19. LOG((MSP_TRACE, "CMSPCallBase::CMSPCallBase exited."));
  20. }
  21. CMSPCallBase::~CMSPCallBase()
  22. {
  23. LOG((MSP_TRACE, "CMSPCallBase::~CMSPCallBase[%p] entered.", this));
  24. // We wait until destructor to release the address because
  25. // they might be used by calls from the stream. If the last stream
  26. // has released its reference, this pointer will not be used again.
  27. // If the MSPAddress had a refcount on the call, it should have been
  28. // released in the ShutdownMSPCall() method.
  29. // release the address
  30. if (m_pMSPAddress != NULL)
  31. {
  32. LOG((MSP_TRACE, "CMSPCallBase::~CMSPCallBase releasing address [%p].", m_pMSPAddress));
  33. m_pMSPAddress->MSPAddressRelease();
  34. }
  35. LOG((MSP_TRACE, "CMSPCallBase::~CMSPCallBase exited."));
  36. }
  37. // ITStreamControl methods, called by the app.
  38. STDMETHODIMP CMSPCallBase::EnumerateStreams(
  39. OUT IEnumStream ** ppEnumStream
  40. )
  41. {
  42. LOG((MSP_TRACE,
  43. "EnumerateStreams entered. ppEnumStream:%x", ppEnumStream));
  44. //
  45. // Check parameters.
  46. //
  47. if (MSPB_IsBadWritePtr(ppEnumStream, sizeof(VOID *)))
  48. {
  49. LOG((MSP_ERROR, "CMSPCallBase::EnumerateStreams - "
  50. "bad pointer argument - exit E_POINTER"));
  51. return E_POINTER;
  52. }
  53. //
  54. // First see if this call has been shut down.
  55. // acquire the lock before accessing the stream object list.
  56. //
  57. CLock lock(m_lock);
  58. if (m_Streams.GetData() == NULL)
  59. {
  60. LOG((MSP_ERROR, "CMSPCallBase::EnumerateStreams - "
  61. "call appears to have been shut down - exit E_UNEXPECTED"));
  62. // This call has been shut down.
  63. return E_UNEXPECTED;
  64. }
  65. //
  66. // Create an enumerator object.
  67. //
  68. typedef _CopyInterface<ITStream> CCopy;
  69. typedef CSafeComEnum<IEnumStream, &IID_IEnumStream,
  70. ITStream *, CCopy> CEnumerator;
  71. HRESULT hr;
  72. CComObject<CEnumerator> *pEnum = NULL;
  73. hr = CComObject<CEnumerator>::CreateInstance(&pEnum);
  74. if (pEnum == NULL)
  75. {
  76. LOG((MSP_ERROR, "CMSPCallBase::EnumerateStreams - "
  77. "Could not create enumerator object, %x", hr));
  78. return hr;
  79. }
  80. //
  81. // query for the IID_IEnumStream i/f
  82. //
  83. hr = pEnum->_InternalQueryInterface(IID_IEnumStream, (void**)ppEnumStream);
  84. if (FAILED(hr))
  85. {
  86. LOG((MSP_ERROR, "CMSPCallBase::EnumerateStreams - "
  87. "query enum interface failed, %x", hr));
  88. delete pEnum;
  89. return hr;
  90. }
  91. //
  92. // Init the enumerator object. The CSafeComEnum can handle zero-sized
  93. // array.
  94. //
  95. hr = pEnum->Init(
  96. m_Streams.GetData(), // the begin itor
  97. m_Streams.GetData() + m_Streams.GetSize(), // the end itor,
  98. NULL, // IUnknown
  99. AtlFlagCopy // copy the data.
  100. );
  101. if (FAILED(hr))
  102. {
  103. LOG((MSP_ERROR, "CMSPCallBase::EnumerateStreams - "
  104. "init enumerator object failed, %x", hr));
  105. (*ppEnumStream)->Release();
  106. return hr;
  107. }
  108. LOG((MSP_TRACE, "CMSPCallBase::EnumerateStreams - exit S_OK"));
  109. return hr;
  110. }
  111. ///////////////////////////////////////////////////////////////////////////////
  112. ///////////////////////////////////////////////////////////////////////////////
  113. //
  114. // return a VB collection of streams
  115. //
  116. STDMETHODIMP CMSPCallBase::get_Streams(
  117. OUT VARIANT * pVariant
  118. )
  119. {
  120. LOG((MSP_TRACE, "CMSPCallBase::get_Streams - enter"));
  121. //
  122. // Check parameters.
  123. //
  124. if ( MSPB_IsBadWritePtr(pVariant, sizeof(VARIANT) ) )
  125. {
  126. LOG((MSP_ERROR, "CMSPCallBase::get_Streams - "
  127. "bad pointer argument - exit E_POINTER"));
  128. return E_POINTER;
  129. }
  130. //
  131. // See if this call has been shut down. Acquire the lock before accessing
  132. // the stream object list.
  133. //
  134. CLock lock(m_lock);
  135. if (m_Streams.GetData() == NULL)
  136. {
  137. LOG((MSP_ERROR, "CMSPCallBase::get_Streams - "
  138. "call appears to have been shut down - exit E_UNEXPECTED"));
  139. // This call has been shut down.
  140. return E_UNEXPECTED;
  141. }
  142. //
  143. // create the collection object - see mspcoll.h
  144. //
  145. typedef CTapiIfCollection< ITStream * > StreamCollection;
  146. CComObject<StreamCollection> * pCollection;
  147. HRESULT hr = CComObject<StreamCollection>::CreateInstance( &pCollection );
  148. if ( FAILED(hr) )
  149. {
  150. LOG((MSP_ERROR, "CMSPCallBase::get_Streams - "
  151. "can't create collection - exit 0x%08x", hr));
  152. return hr;
  153. }
  154. //
  155. // get the Collection's IDispatch interface
  156. //
  157. IDispatch * pDispatch;
  158. hr = pCollection->_InternalQueryInterface(IID_IDispatch,
  159. (void **) &pDispatch );
  160. if ( FAILED(hr) )
  161. {
  162. LOG((MSP_ERROR, "CMSPCallBase::get_Streams - "
  163. "QI for IDispatch on collection failed - exit 0x%08x", hr));
  164. delete pCollection;
  165. return hr;
  166. }
  167. //
  168. // Init the collection using an iterator -- pointers to the beginning and
  169. // the ending element plus one.
  170. //
  171. hr = pCollection->Initialize( m_Streams.GetSize(),
  172. m_Streams.GetData(),
  173. m_Streams.GetData() + m_Streams.GetSize() );
  174. if (FAILED(hr))
  175. {
  176. LOG((MSP_ERROR, "CMSPCallBase::get_Streams - "
  177. "Initialize on collection failed - exit 0x%08x", hr));
  178. pDispatch->Release();
  179. return hr;
  180. }
  181. //
  182. // put the IDispatch interface pointer into the variant
  183. //
  184. LOG((MSP_INFO, "CMSPCallBase::get_Streams - "
  185. "placing IDispatch value %08x in variant", pDispatch));
  186. VariantInit(pVariant);
  187. pVariant->vt = VT_DISPATCH;
  188. pVariant->pdispVal = pDispatch;
  189. LOG((MSP_TRACE, "CMSPCallBase::get_Streams - exit S_OK"));
  190. return S_OK;
  191. }
  192. // methods called by the MSPstream object.
  193. HRESULT CMSPCallBase::HandleStreamEvent(
  194. IN MSPEVENTITEM * pEventItem
  195. ) const
  196. {
  197. _ASSERTE(!MSPB_IsBadWritePtr(pEventItem, sizeof(MSPEVENTITEM)));
  198. pEventItem->MSPEventInfo.hCall = m_htCall;
  199. return m_pMSPAddress->PostEvent(pEventItem);
  200. }
  201. STDMETHODIMP CMSPCallBase::CreateStream(
  202. IN long lMediaType,
  203. IN TERMINAL_DIRECTION Direction,
  204. IN OUT ITStream ** ppStream
  205. )
  206. /*++
  207. Routine Description:
  208. Arguments:
  209. Return Value:
  210. S_OK
  211. E_POINTER
  212. E_OUTOFMEMORY
  213. TAPI_E_INVALIDMEDIATYPE
  214. TAPI_E_INVALIDTERMINALDIRECTION
  215. TAPI_E_INVALIDTERMINALCLASS
  216. --*/
  217. {
  218. LOG((MSP_TRACE,
  219. "CreateStream--dwMediaType:%x, Direction:%x, ppStream %x",
  220. lMediaType, Direction, ppStream
  221. ));
  222. if ( ! IsValidSingleMediaType( (DWORD) lMediaType, m_dwMediaType) )
  223. {
  224. LOG((MSP_ERROR,
  225. "wrong media type:%x, call media type:%x",
  226. lMediaType, m_dwMediaType
  227. ));
  228. return TAPI_E_INVALIDMEDIATYPE;
  229. }
  230. if (MSPB_IsBadWritePtr(ppStream, sizeof (VOID *)))
  231. {
  232. LOG((MSP_ERROR, "Bad pointer, ppStream:%x",ppStream));
  233. return E_POINTER;
  234. }
  235. return InternalCreateStream( (DWORD) lMediaType, Direction, ppStream);
  236. }
  237. HRESULT CMSPCallBase::ReceiveTSPCallData(
  238. IN PBYTE pBuffer,
  239. IN DWORD dwSize
  240. )
  241. /*++
  242. Routine Description:
  243. Base class receive TSP call data method... does nothing in base class.
  244. Implemented so that MSP's that only communicate per-address don't have
  245. to override it.
  246. Arguments:
  247. Return Value:
  248. S_OK
  249. --*/
  250. {
  251. LOG((MSP_TRACE, "CMSPCallBase::ReceiveTSPCallData - enter"));
  252. LOG((MSP_TRACE, "CMSPCallBase::ReceiveTSPCallData - exit S_OK"));
  253. return S_OK;
  254. }
  255. /////////////////////////////////////////////////////////////////////////////
  256. // Debugging utilities
  257. /////////////////////////////////////////////////////////////////////////////
  258. #ifdef DBGGRAPH
  259. HRESULT
  260. SetGraphLogFile(
  261. IN IGraphBuilder *pIGraphBuilder
  262. )
  263. /*++
  264. Routine Description:
  265. Set the log file for the filter graph.
  266. Arguments:
  267. pIGraphBuilder - The filter graph.
  268. Return Value:
  269. HRESULT.
  270. --*/
  271. {
  272. const TCHAR GRAPHLOGPATH[] = _T("c:\\temp\\graph.log");
  273. HANDLE hFile = CreateFile(
  274. GRAPHLOGPATH,
  275. GENERIC_WRITE,
  276. FILE_SHARE_READ, // sharing
  277. NULL, // no security
  278. OPEN_ALWAYS,
  279. 0, // no attributes, no flags
  280. NULL // no template
  281. );
  282. if (hFile == INVALID_HANDLE_VALUE)
  283. {
  284. LOG((MSP_ERROR,
  285. "Can not open graph log file: %s, %x",
  286. GRAPHLOGPATH,
  287. GetLastError()
  288. ));
  289. return S_FALSE;
  290. }
  291. SetFilePointer(hFile, 0, NULL, FILE_END);
  292. HRESULT hr = pIGraphBuilder->SetLogFile(hFile);
  293. return hr;
  294. }
  295. #endif
  296. /////////////////////////////////////////////////////////////////////////////
  297. // CMSPCallMultiGraph
  298. /////////////////////////////////////////////////////////////////////////////
  299. CMSPCallMultiGraph::CMSPCallMultiGraph()
  300. : CMSPCallBase()
  301. {
  302. LOG((MSP_TRACE, "CMSPCallMultiGraph::CMSPCallMultiGraph entered."));
  303. LOG((MSP_TRACE, "CMSPCallMultiGraph::CMSPCallMultiGraph exited."));
  304. }
  305. CMSPCallMultiGraph::~CMSPCallMultiGraph()
  306. {
  307. LOG((MSP_TRACE, "CMSPCallMultiGraph::~CMSPCallMultiGraph entered."));
  308. LOG((MSP_TRACE, "CMSPCallMultiGraph::~CMSPCallMultiGraph exited."));
  309. }
  310. // methods called by the MSPAddress object.
  311. HRESULT CMSPCallMultiGraph::Init(
  312. IN CMSPAddress * pMSPAddress,
  313. IN MSP_HANDLE htCall,
  314. IN DWORD dwReserved,
  315. IN DWORD dwMediaType
  316. )
  317. /*++
  318. Routine Description:
  319. This method is called by CMSPAddress when the call is first created.
  320. It creates a filter graph for the streams. It gets the event handle from
  321. the graph and posts it to the thread pool. The derived method is supposed
  322. to create its own streams based one the mediatypes.
  323. Arguments:
  324. Return Value:
  325. HRESULT.
  326. --*/
  327. {
  328. LOG((MSP_TRACE,
  329. "MSP call %x initialize entered, pMSPAddress:%x",
  330. this, pMSPAddress));
  331. // No need to acquire locks on this call because it is called only
  332. // once when the object is created. No other calls can be made on
  333. // this object at this point.
  334. _ASSERTE(m_pMSPAddress == NULL);
  335. // initialize the stream array so that the array is not NULL.
  336. if (!m_Streams.Grow())
  337. {
  338. return E_OUTOFMEMORY;
  339. }
  340. pMSPAddress->MSPAddressAddRef();
  341. m_pMSPAddress = pMSPAddress;
  342. m_htCall = htCall;
  343. m_dwMediaType = dwMediaType;
  344. return S_OK;
  345. }
  346. HRESULT CMSPCallMultiGraph::ShutDown()
  347. /*++
  348. Routine Description:
  349. Cancel the event waiting and then call the base impelmentaion. Call the
  350. shutdown on the stream objects. Release the references on all the stream
  351. objects. Acquires the lock in the function.
  352. Arguments:
  353. pIGraphBuilder - The filter graph.
  354. Return Value:
  355. HRESULT.
  356. --*/
  357. {
  358. LOG((MSP_TRACE, "MSP call %x is shutting down", this));
  359. // acquire the lock on the terminal data because we are writing to it.
  360. m_lock.Lock();
  361. // release all the streams
  362. for (int i = m_Streams.GetSize() - 1; i >= 0; i --)
  363. {
  364. UnregisterWaitEvent(i);
  365. ((CMSPStream*)m_Streams[i])->ShutDown();
  366. m_Streams[i]->Release();
  367. }
  368. m_Streams.RemoveAll();
  369. m_ThreadPoolWaitBlocks.RemoveAll();
  370. m_lock.Unlock();
  371. return S_OK;
  372. }
  373. HRESULT CMSPCallMultiGraph::InternalCreateStream(
  374. IN DWORD dwMediaType,
  375. IN TERMINAL_DIRECTION Direction,
  376. IN OUT ITStream ** ppStream
  377. )
  378. /*++
  379. Routine Description:
  380. Arguments:
  381. Return Value:
  382. S_OK
  383. E_POINTER
  384. E_OUTOFMEMORY
  385. TAPI_E_INVALIDMEDIATYPE
  386. TAPI_E_INVALIDTERMINALDIRECTION
  387. TAPI_E_INVALIDTERMINALCLASS
  388. --*/
  389. {
  390. // Create a filter graph and get the media event interface.
  391. CComPtr <IMediaEvent> pIMediaEvent;
  392. HRESULT hr = CoCreateInstance(
  393. CLSID_FilterGraph,
  394. NULL,
  395. CLSCTX_INPROC_SERVER,
  396. IID_IMediaEvent,
  397. (void **) &pIMediaEvent
  398. );
  399. if (FAILED(hr))
  400. {
  401. LOG((MSP_ERROR, "create filter graph %x", hr));
  402. return hr;
  403. }
  404. ITStream * pITStream;
  405. hr = CreateStreamObject(
  406. dwMediaType,
  407. Direction,
  408. pIMediaEvent,
  409. &pITStream
  410. );
  411. if (FAILED(hr))
  412. {
  413. LOG((MSP_ERROR, "CreateStreamObject returned:%x",hr));
  414. return hr;
  415. }
  416. // Add the stream into our list of streams.
  417. m_lock.Lock();
  418. if (!m_Streams.Add(pITStream))
  419. {
  420. ((CMSPStream*)pITStream)->ShutDown();
  421. pITStream->Release();
  422. m_lock.Unlock();
  423. LOG((MSP_ERROR, "out of memory is adding a stream."));
  424. return E_OUTOFMEMORY;
  425. }
  426. // register the new graph and stream to the thread pool for graph events.
  427. hr = RegisterWaitEvent(pIMediaEvent, pITStream);
  428. if (FAILED(hr))
  429. {
  430. ((CMSPStream*)pITStream)->ShutDown();
  431. pITStream->Release();
  432. m_Streams.Remove(pITStream);
  433. m_lock.Unlock();
  434. LOG((MSP_ERROR, "Register wait returned %x.", hr));
  435. return hr;
  436. }
  437. m_lock.Unlock();
  438. // AddRef the interface pointer and return it.
  439. pITStream->AddRef();
  440. *ppStream = pITStream;
  441. return S_OK;
  442. }
  443. HRESULT CMSPCallMultiGraph::RegisterWaitEvent(
  444. IN IMediaEvent * pIMediaEvent,
  445. IN ITStream * pITStream
  446. )
  447. {
  448. // This function should only be called within a critical section
  449. // on the object.
  450. HANDLE hEvent;
  451. HRESULT hr = pIMediaEvent->GetEventHandle((OAEVENT*)&hEvent);
  452. if (FAILED(hr))
  453. {
  454. LOG((MSP_ERROR, "Can not get the event handle. %x", hr));
  455. return hr;
  456. }
  457. THREADPOOLWAITBLOCK WaitBlock;
  458. WaitBlock.pContext = (MSPSTREAMCONTEXT *)malloc(sizeof(MSPSTREAMCONTEXT));
  459. if (WaitBlock.pContext == NULL)
  460. {
  461. LOG((MSP_ERROR, "out of memory for the context."));
  462. return E_OUTOFMEMORY;
  463. }
  464. if (!m_ThreadPoolWaitBlocks.Add(WaitBlock))
  465. {
  466. free(WaitBlock.pContext);
  467. LOG((MSP_ERROR, "out of memory adding the waitblock."));
  468. return E_OUTOFMEMORY;
  469. }
  470. // increment the ref count before posting the callback to the thread pool.
  471. // but for the call, use our special inner object addref.
  472. this->MSPCallAddRef();
  473. pITStream->AddRef();
  474. pIMediaEvent->AddRef();
  475. WaitBlock.pContext->pMSPCall = this;
  476. WaitBlock.pContext->pITStream = pITStream;
  477. WaitBlock.pContext->pIMediaEvent = pIMediaEvent;
  478. //
  479. // post the event to the thread pool to wait on.
  480. //
  481. HANDLE hWaitHandle = NULL;
  482. BOOL fSuccess = RegisterWaitForSingleObject(
  483. & hWaitHandle, // pointer to the returned handle
  484. hEvent, // the event handle to wait for.
  485. DispatchGraphEvent, // the callback function.
  486. WaitBlock.pContext, // the context for the callback.
  487. INFINITE, // wait forever.
  488. WT_EXECUTEINWAITTHREAD // use the wait thread to call the callback.
  489. );
  490. if ( ( ! fSuccess ) || (hWaitHandle == NULL) )
  491. {
  492. LOG((MSP_ERROR,
  493. "Register wait call back failed. %x", GetLastError()));
  494. // decrement the ref count if the posting failed.
  495. this->MSPCallRelease();
  496. pITStream->Release();
  497. pIMediaEvent->Release();
  498. // Free the context block;
  499. free(WaitBlock.pContext);
  500. m_ThreadPoolWaitBlocks.Remove(WaitBlock);
  501. return E_FAIL;
  502. }
  503. // If register succeeded, save the wait handle. We know it is the last one.
  504. m_ThreadPoolWaitBlocks[m_ThreadPoolWaitBlocks.GetSize() - 1].hWaitHandle
  505. = hWaitHandle;
  506. return S_OK;
  507. }
  508. STDMETHODIMP CMSPCallMultiGraph::RemoveStream(
  509. IN ITStream * pStream
  510. )
  511. /*++
  512. Routine Description:
  513. Arguments:
  514. Return Value:
  515. S_OK
  516. E_INVALIDARG
  517. --*/
  518. {
  519. LOG((MSP_TRACE, "CMSPCallMultiGraph::RemoveStream - pStream %x", pStream));
  520. // acquire the lock before accessing the stream object list.
  521. CLock lock(m_lock);
  522. int index = m_Streams.Find(pStream);
  523. if (index < 0)
  524. {
  525. LOG((MSP_ERROR, "CMSPCallMultiGraph::RemoveStream - Stream %x is not found.", pStream));
  526. return E_INVALIDARG;
  527. }
  528. UnregisterWaitEvent(index);
  529. ((CMSPStream*)m_Streams[index])->ShutDown();
  530. m_Streams[index]->Release();
  531. m_Streams.RemoveAt(index);
  532. LOG((MSP_TRACE, "CMSPCallMultiGraph::RemoveStream - exit S_OK"));
  533. return S_OK;
  534. }
  535. HRESULT CMSPCallMultiGraph::UnregisterWaitEvent(
  536. IN int index
  537. )
  538. {
  539. if (index >= m_ThreadPoolWaitBlocks.GetSize())
  540. {
  541. // the call must have been disconnected.
  542. return E_UNEXPECTED;
  543. }
  544. THREADPOOLWAITBLOCK &WaitBlock = m_ThreadPoolWaitBlocks[index];
  545. // These pointers should never be NULL.
  546. _ASSERTE(WaitBlock.hWaitHandle != NULL);
  547. _ASSERTE(WaitBlock.pContext != NULL);
  548. // Cancel the wait posted to the thread pool.
  549. BOOL fRes = ::UnregisterWaitEx(WaitBlock.hWaitHandle, (HANDLE)-1);
  550. if (!fRes)
  551. {
  552. // we should never get here, UnregisterWaitEx will block until success
  553. LOG((MSP_ERROR,
  554. "UnregisterWait failed. %x", GetLastError()));
  555. // just remove it from the list. keep the data so that it won't AV.
  556. m_ThreadPoolWaitBlocks.RemoveAt(index);
  557. return E_FAIL;
  558. }
  559. // We need to decrement the refcount because it was incremented
  560. // before we post the wait.
  561. (WaitBlock.pContext->pMSPCall)->MSPCallRelease();
  562. (WaitBlock.pContext->pITStream)->Release();
  563. (WaitBlock.pContext->pIMediaEvent)->Release();
  564. // Free the context block;
  565. free(WaitBlock.pContext);
  566. m_ThreadPoolWaitBlocks.RemoveAt(index);
  567. return S_OK;
  568. }
  569. // methods called by the thread pool
  570. VOID NTAPI CMSPCallMultiGraph::DispatchGraphEvent(
  571. IN VOID * pContext,
  572. IN BOOLEAN bFlag
  573. )
  574. {
  575. LOG((MSP_EVENT,
  576. "DispatchGraphEvent:pContext:%x, bFlag:%u",
  577. pContext, bFlag));
  578. // the pContext is a pointer to a call, since it carries a ref count,
  579. // the call should still be alive.
  580. _ASSERTE( ! IsBadReadPtr(pContext, sizeof(VOID *) ) );
  581. MSPSTREAMCONTEXT * pEventContext = (MSPSTREAMCONTEXT *)pContext;
  582. pEventContext->pMSPCall->HandleGraphEvent(pEventContext);
  583. }
  584. VOID CMSPCallMultiGraph::HandleGraphEvent(
  585. IN MSPSTREAMCONTEXT * pContext
  586. )
  587. {
  588. long lEventCode;
  589. LONG_PTR lParam1, lParam2; // win64 fix
  590. HRESULT hr = pContext->pIMediaEvent->GetEvent(&lEventCode, &lParam1, &lParam2, 0);
  591. if (FAILED(hr))
  592. {
  593. LOG((MSP_ERROR, "Can not get the actual event. %x", hr));
  594. return;
  595. }
  596. LOG((MSP_EVENT, "ProcessGraphEvent, code:%d param1:%x param2:%x",
  597. lEventCode, lParam1, lParam2));
  598. //
  599. // Create an event data structure that we will pass to the worker thread.
  600. //
  601. MULTI_GRAPH_EVENT_DATA * pData;
  602. pData = new MULTI_GRAPH_EVENT_DATA;
  603. if (pData == NULL)
  604. {
  605. pContext->pIMediaEvent->FreeEventParams(lEventCode, lParam1, lParam2);
  606. LOG((MSP_ERROR, "Out of memory for event data."));
  607. return;
  608. }
  609. pData->pCall = this;
  610. pData->pITStream = pContext->pITStream;
  611. pData->lEventCode = lEventCode;
  612. pData->lParam1 = lParam1;
  613. pData->lParam2 = lParam2;
  614. //
  615. // also pass an addref'ed pointer to IMediaEvent, so that whoever processes
  616. // the message has the opportunity to free event parameters
  617. //
  618. pData->pIMediaEvent = pContext->pIMediaEvent;
  619. pData->pIMediaEvent->AddRef();
  620. //
  621. // Make sure the call and stream don't go away while we handle the event.
  622. // but use our special inner object addref for the call
  623. //
  624. pData->pCall->MSPCallAddRef();
  625. pData->pITStream->AddRef();
  626. //
  627. // Queue an async work item to call ProcessGraphEvent.
  628. //
  629. hr = g_Thread.QueueWorkItem(AsyncMultiGraphEvent,
  630. (void *) pData,
  631. FALSE); // asynchronous
  632. if (FAILED(hr))
  633. {
  634. LOG((MSP_ERROR, "QueueWorkItem failed, return code:%x", hr));
  635. pData->pCall->MSPCallRelease();
  636. pData->pITStream->Release();
  637. //
  638. // no one is going to free event params and release the IMediaEvent
  639. // pointer, so do it here
  640. //
  641. pContext->pIMediaEvent->FreeEventParams(lEventCode, lParam1, lParam2);
  642. pData->pIMediaEvent->Release();
  643. delete pData;
  644. }
  645. }
  646. DWORD WINAPI AsyncMultiGraphEvent(LPVOID pVoid)
  647. {
  648. MULTI_GRAPH_EVENT_DATA * pData = ( MULTI_GRAPH_EVENT_DATA * ) pVoid;
  649. //
  650. // Handle the event.
  651. //
  652. (pData->pCall)->ProcessGraphEvent(pData->pITStream,
  653. pData->lEventCode,
  654. pData->lParam1,
  655. pData->lParam2);
  656. //
  657. // These were addrefed when the event was queued.
  658. // but we used our special inner object addref for the call
  659. //
  660. pData->pCall->MSPCallRelease();
  661. pData->pITStream->Release();
  662. //
  663. // if we have IMediaEvent pointer, free event params and release the media
  664. // event interface pointer
  665. //
  666. if (NULL != pData->pIMediaEvent)
  667. {
  668. pData->pIMediaEvent->FreeEventParams(pData->lEventCode,
  669. pData->lParam1,
  670. pData->lParam2);
  671. pData->pIMediaEvent->Release();
  672. pData->pIMediaEvent = NULL;
  673. }
  674. //
  675. // Free the event data structure.
  676. //
  677. delete pData;
  678. return 0;
  679. }
  680. HRESULT CMSPCallMultiGraph::ProcessGraphEvent(
  681. IN ITStream * pITStream,
  682. IN long lEventCode,
  683. IN LONG_PTR lParam1,
  684. IN LONG_PTR lParam2
  685. )
  686. {
  687. CLock lock(m_lock);
  688. if (m_Streams.Find(pITStream) < 0)
  689. {
  690. LOG((MSP_WARN,
  691. "stream %x is already removed.",
  692. pITStream));
  693. return TAPI_E_NOITEMS;
  694. }
  695. //
  696. // No dynamic cast because this is our own pointer.
  697. //
  698. return ((CMSPStream*)pITStream)->
  699. ProcessGraphEvent(lEventCode, lParam1, lParam2);
  700. }