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.

939 lines
22 KiB

  1. // MultiTrackTerminal.cpp: implementation of the CMultiTrackTerminal class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "MultiTrackTerminal.h"
  6. //////////////////////////////////////////////////////////////////////
  7. // Construction/Destruction
  8. //////////////////////////////////////////////////////////////////////
  9. CMultiTrackTerminal::CMultiTrackTerminal()
  10. :m_nNumberOfTracks(0)
  11. {
  12. LOG((MSP_TRACE,
  13. "CMultiTrackTerminal::CMultiTrackTerminal[%p] - enter", this));
  14. LOG((MSP_TRACE,
  15. "CMultiTrackTerminal::CMultiTrackTerminal - finish"));
  16. }
  17. CMultiTrackTerminal::~CMultiTrackTerminal()
  18. {
  19. LOG((MSP_TRACE,
  20. "CMultiTrackTerminal::~CMultiTrackTerminal - enter"));
  21. ReleaseAllTracks();
  22. //
  23. // we should have no tracks at this point, and counter should be in sync
  24. //
  25. TM_ASSERT(m_nNumberOfTracks == 0);
  26. LOG((MSP_TRACE,
  27. "CMultiTrackTerminal::~CMultiTrackTerminal - finish"));
  28. }
  29. HRESULT CMultiTrackTerminal::get_TrackTerminals(OUT VARIANT *pVariant)
  30. {
  31. LOG((MSP_TRACE, "CMultiTrackTerminal::get_TrackTerminals[%p] - enter. pVariant [%p]", this, pVariant));
  32. //
  33. // Check parameters
  34. //
  35. if ( IsBadWritePtr(pVariant, sizeof(VARIANT) ) )
  36. {
  37. LOG((MSP_ERROR, "CMultiTrackTerminal::get_TrackTerminals - "
  38. "bad pointer argument - exit E_POINTER"));
  39. return E_POINTER;
  40. }
  41. //
  42. // the caller needs to provide us with an empty variant
  43. //
  44. if (pVariant->vt != VT_EMPTY)
  45. {
  46. LOG((MSP_ERROR, "CMultiTrackTerminal::get_TrackTerminals - "
  47. "variant argument is not empty"));
  48. return E_UNEXPECTED;
  49. }
  50. //
  51. // create the collection object - see mspbase\mspcoll.h
  52. //
  53. HRESULT hr = S_OK;
  54. typedef CTapiIfCollection<ITTerminal*> TerminalCollection;
  55. CComObject<TerminalCollection> *pCollection = NULL;
  56. hr = CComObject<TerminalCollection>::CreateInstance(&pCollection);
  57. if ( FAILED(hr) )
  58. {
  59. LOG((MSP_ERROR, "CMultiTrackTerminal::get_TrackTerminals - "
  60. "can't create collection - exit %lx", hr));
  61. return hr;
  62. }
  63. //
  64. // get the Collection's IDispatch interface
  65. //
  66. IDispatch *pDispatch = NULL;
  67. hr = pCollection->QueryInterface(IID_IDispatch,
  68. (void **) &pDispatch );
  69. if ( FAILED(hr) )
  70. {
  71. LOG((MSP_ERROR, "CMultiTrackTerminal::get_TrackTerminals - "
  72. "QI for IDispatch on collection failed - exit %lx", hr));
  73. delete pCollection;
  74. return hr;
  75. }
  76. {
  77. //
  78. // access data member array in a lock
  79. //
  80. CLock lock(m_lock);
  81. //
  82. // Init the collection using an iterator -- pointers to the beginning and
  83. // the ending element plus one.
  84. //
  85. hr = pCollection->Initialize( m_TrackTerminals.GetSize(),
  86. m_TrackTerminals.GetData(),
  87. m_TrackTerminals.GetData() + m_TrackTerminals.GetSize() );
  88. }
  89. if (FAILED(hr))
  90. {
  91. LOG((MSP_ERROR, "CMultiTrackTerminal::get_TrackTerminals - "
  92. "Initialize on collection failed - exit %lx", hr));
  93. pDispatch->Release();
  94. delete pCollection;
  95. return hr;
  96. }
  97. //
  98. // put the IDispatch interface pointer into the variant
  99. //
  100. LOG((MSP_ERROR, "CMultiTrackTerminal::get_TrackTerminals - "
  101. "placing IDispatch value %p in variant", pDispatch));
  102. VariantInit(pVariant);
  103. pVariant->vt = VT_DISPATCH;
  104. pVariant->pdispVal = pDispatch;
  105. LOG((MSP_TRACE, "CMultiTrackTerminal::get_TrackTerminals - exit S_OK"));
  106. return S_OK;
  107. }
  108. HRESULT CMultiTrackTerminal::EnumerateTrackTerminals(
  109. IEnumTerminal **ppEnumTerminal
  110. )
  111. {
  112. LOG((MSP_TRACE,
  113. "CMultiTrackTerminal::EnumerateTrackTerminals entered. ppEnumTerminal[%p]", ppEnumTerminal));
  114. //
  115. // check arguments
  116. //
  117. if (IsBadWritePtr(ppEnumTerminal, sizeof(IEnumTerminal*)))
  118. {
  119. LOG((MSP_ERROR, "CMultiTrackTerminal::EnumerateTrackTerminals ppEnumTerminal is a bad pointer"));
  120. return E_POINTER;
  121. }
  122. //
  123. // don't return garbage
  124. //
  125. *ppEnumTerminal = NULL;
  126. typedef _CopyInterface<ITTerminal> CCopy;
  127. typedef CSafeComEnum<IEnumTerminal, &IID_IEnumTerminal,
  128. ITTerminal *, CCopy> CEnumerator;
  129. HRESULT hr = S_OK;
  130. //
  131. // create enumeration object
  132. //
  133. CMSPComObject<CEnumerator> *pEnum = NULL;
  134. hr = CMSPComObject<CEnumerator>::CreateInstance(&pEnum);
  135. if (FAILED(hr))
  136. {
  137. LOG((MSP_ERROR, "CMultiTrackTerminal::EnumerateTrackTerminals Could not create enumerator object, %x", hr));
  138. return hr;
  139. }
  140. //
  141. // get pEnum's IID_IEnumTerminal interface
  142. //
  143. hr = pEnum->QueryInterface(IID_IEnumTerminal, (void**)ppEnumTerminal);
  144. if (FAILED(hr))
  145. {
  146. LOG((MSP_ERROR, "CMultiTrackTerminal::EnumerateTrackTerminals query enum interface failed, %x", hr));
  147. *ppEnumTerminal = NULL;
  148. //
  149. // don't yet have outstanding reference count on pEnum, so delete it.
  150. //
  151. // note: this can lead to a problem if FinalRelease of pEnum is
  152. // supposed to deallocate resources that have been allocated in its
  153. // constructor
  154. //
  155. delete pEnum;
  156. return hr;
  157. }
  158. //
  159. // access data member track terminal list from a lock
  160. //
  161. {
  162. CLock lock(m_lock);
  163. // The CSafeComEnum can handle zero-sized array.
  164. hr = pEnum->Init(
  165. m_TrackTerminals.GetData(), // the begin itor
  166. m_TrackTerminals.GetData() + m_TrackTerminals.GetSize(), // the end itor,
  167. NULL, // IUnknown
  168. AtlFlagCopy // copy the data.
  169. );
  170. }
  171. if (FAILED(hr))
  172. {
  173. LOG((MSP_ERROR, "CMultiTrackTerminal::EnumerateTrackTerminals init enumerator object failed, %x", hr));
  174. (*ppEnumTerminal)->Release();
  175. *ppEnumTerminal= NULL;
  176. return hr;
  177. }
  178. LOG((MSP_TRACE, "CMultiTrackTerminal::EnumerateTrackTerminals - exit S_OK"));
  179. return hr;
  180. }
  181. HRESULT CMultiTrackTerminal::get_MediaTypesInUse(
  182. OUT long *plMediaTypesInUse
  183. )
  184. {
  185. LOG((MSP_TRACE, "CMultiTrackTerminal::get_MediaTypesInUse - enter. "
  186. "plMediaTypesInUse [%p]", plMediaTypesInUse));
  187. if (IsBadWritePtr(plMediaTypesInUse, sizeof(long)))
  188. {
  189. LOG((MSP_ERROR,
  190. "CMultiTrackTerminal::get_MediaTypesInUse plMediaTypesInUse "
  191. "does not point to a valid long"));
  192. return E_POINTER;
  193. }
  194. //
  195. // enumerate all the terminal and OR their media types and media types in use
  196. //
  197. long lMediaTypesInUse = 0;
  198. //
  199. // access data member array in a lock
  200. //
  201. CLock lock(m_lock);
  202. for ( int i = 0; i < m_TrackTerminals.GetSize(); i++ )
  203. {
  204. long lMT = 0;
  205. //
  206. // is the track terminal a multitrack terminal itself?
  207. //
  208. ITMultiTrackTerminal *pMTT = NULL;
  209. HRESULT hr = m_TrackTerminals[i]->QueryInterface(IID_ITMultiTrackTerminal,
  210. (void**)&pMTT);
  211. if (SUCCEEDED(hr))
  212. {
  213. //
  214. // this is a multitrack terminal. get its mediatypes in use
  215. //
  216. hr = pMTT->get_MediaTypesInUse(&lMT);
  217. pMTT->Release();
  218. pMTT = NULL;
  219. if (FAILED(hr))
  220. {
  221. //
  222. // failed to get track's media types in use.
  223. // continue to the next track
  224. //
  225. LOG((MSP_ERROR,
  226. "CMultiTrackTerminal::get_MediaTypesInUse "
  227. "get_MediaTypesInUse on terminal (%d) failed.", i));
  228. continue;
  229. }
  230. }
  231. else
  232. {
  233. //
  234. // the track is not a multitrack terminal, so use its ITTerminal
  235. // interface to get its media type
  236. //
  237. hr = m_TrackTerminals[i]->get_MediaType(&lMT);
  238. if (FAILED(hr))
  239. {
  240. //
  241. // failed to get track's media types in use.
  242. // continue to the next track
  243. //
  244. LOG((MSP_ERROR,
  245. "CMultiTrackTerminal::get_MediaTypesInUse "
  246. "get_MediaType on terminal (%d) failed.", i));
  247. continue;
  248. }
  249. }
  250. LOG((MSP_TRACE,
  251. "CMultiTrackTerminal::get_MediaTypesInUse "
  252. "track terminal (%d) has media type of %lx.", i, lMT));
  253. lMediaTypesInUse |= lMT;
  254. }
  255. *plMediaTypesInUse = lMediaTypesInUse;
  256. LOG((MSP_TRACE, "CMultiTrackTerminal::get_EnumerateTrackTerminals - "
  257. "exit S_OK. MediaTypeInUse %lx", lMediaTypesInUse));
  258. return S_OK;
  259. }
  260. HRESULT CMultiTrackTerminal::get_DirectionsInUse(
  261. OUT TERMINAL_DIRECTION *ptdDirectionsInUse
  262. )
  263. {
  264. LOG((MSP_TRACE, "CMultiTrackTerminal::get_DirectionsInUse - enter. plDirectionsInUsed[%p]", ptdDirectionsInUse));
  265. if (IsBadWritePtr(ptdDirectionsInUse, sizeof(TERMINAL_DIRECTION)))
  266. {
  267. LOG((MSP_ERROR,
  268. "CMultiTrackTerminal::get_DirectionsInUse plDirectionsInUsed"
  269. "does not point to a valid long"));
  270. return E_POINTER;
  271. }
  272. //
  273. // don't return gardbage
  274. //
  275. *ptdDirectionsInUse = TD_NONE;
  276. //
  277. // enumerate all the terminal and OR their media types and media types in use
  278. //
  279. TERMINAL_DIRECTION tdDirInUse = TD_NONE;
  280. //
  281. // access data member array in a lock
  282. //
  283. CLock lock(m_lock);
  284. for ( int i = 0; i < m_TrackTerminals.GetSize(); i++ )
  285. {
  286. TERMINAL_DIRECTION td = TD_NONE;
  287. //
  288. // is the track terminal a multitrack terminal itself?
  289. //
  290. ITMultiTrackTerminal *pMTT = NULL;
  291. HRESULT hr = m_TrackTerminals[i]->QueryInterface(IID_ITMultiTrackTerminal,
  292. (void**)&pMTT);
  293. if (SUCCEEDED(hr))
  294. {
  295. //
  296. // this is a multitrack terminal. get its mediatypes in use
  297. //
  298. hr = pMTT->get_DirectionsInUse(&td);
  299. pMTT->Release();
  300. pMTT = NULL;
  301. if (FAILED(hr))
  302. {
  303. //
  304. // failed to get track's media types in use.
  305. // continue to the next track
  306. //
  307. LOG((MSP_ERROR,
  308. "CMultiTrackTerminal::get_DirectionsInUse "
  309. "get_MediaTypesInUse on terminal (%d) failed.", i));
  310. continue;
  311. }
  312. }
  313. else
  314. {
  315. //
  316. // the track is not a multitrack terminal, so use its ITTerminal
  317. // interface to get its direction
  318. //
  319. hr = m_TrackTerminals[i]->get_Direction(&td);
  320. if (FAILED(hr))
  321. {
  322. //
  323. // failed to get track's media types in use.
  324. // continue to the next track
  325. //
  326. LOG((MSP_ERROR,
  327. "CMultiTrackTerminal::get_DirectionsInUse "
  328. "get_MediaType on terminal (%d) failed.", i));
  329. continue;
  330. }
  331. }
  332. LOG((MSP_TRACE,
  333. "CMultiTrackTerminal::get_DirectionsInUse "
  334. "track terminal (%d) has media type of %lx.", i, td));
  335. //
  336. // based on directions we have collected so far, and on the direction that we just got, calculate total direction
  337. //
  338. switch (tdDirInUse)
  339. {
  340. case TD_NONE:
  341. tdDirInUse = td;
  342. break;
  343. case TD_RENDER:
  344. if ( (td != TD_RENDER) && (td != TD_NONE) )
  345. {
  346. tdDirInUse = TD_MULTITRACK_MIXED;
  347. }
  348. break;
  349. case TD_CAPTURE:
  350. if ( (td != TD_CAPTURE) && (td != TD_NONE) )
  351. {
  352. tdDirInUse = TD_MULTITRACK_MIXED;
  353. }
  354. break;
  355. } // switch
  356. if ( TD_MULTITRACK_MIXED == tdDirInUse )
  357. {
  358. //
  359. // if the current direction is mixed, then break -- there is no point in looking further
  360. //
  361. break;
  362. }
  363. } // for (track terminals)
  364. *ptdDirectionsInUse = tdDirInUse;
  365. LOG((MSP_TRACE, "CMultiTrackTerminal::get_DirectionsInUse - exit S_OK. "
  366. "plDirectionsInUsed = %lx", *ptdDirectionsInUse));
  367. return S_OK;
  368. }
  369. ///////////////////////////////////////////////////////
  370. //
  371. // CMultiTrackTerminal::AddTrackTerminal
  372. //
  373. // adds the terminal that is passed in as the argument to the
  374. // list of track terminals managed by this multitrack terminal
  375. //
  376. // Note: this function increments refcount of the terminal that is being added to the list
  377. //
  378. HRESULT CMultiTrackTerminal::AddTrackTerminal(ITTerminal *pTrackTerminalToAdd)
  379. {
  380. LOG((MSP_TRACE, "CMultiTrackTerminal::AddTrackTerminal[%p] - enter. "
  381. "pTrackTerminalToAdd = %p", this, pTrackTerminalToAdd));
  382. if (IsBadReadPtr(pTrackTerminalToAdd, sizeof(ITTerminal*)))
  383. {
  384. LOG((MSP_TRACE, "CMultiTrackTerminal::AddTrackTerminal - invalid ptr"));
  385. return E_POINTER;
  386. }
  387. {
  388. //
  389. // access data member array in a lock
  390. //
  391. CLock lock(m_lock);
  392. //
  393. // we use a special lock to increment track counter, to avoid deadlocks
  394. // on reference counting
  395. //
  396. Lock();
  397. //
  398. // add track terminal to the array
  399. //
  400. if (!m_TrackTerminals.Add(pTrackTerminalToAdd))
  401. {
  402. LOG((MSP_ERROR, "CMultiTrackTerminal::AddTrackTerminal - "
  403. "failed to add track to the array of terminals"));
  404. return E_OUTOFMEMORY;
  405. }
  406. m_nNumberOfTracks++;
  407. //
  408. // the counter should never ever go out of sync
  409. //
  410. TM_ASSERT(m_nNumberOfTracks == m_TrackTerminals.GetSize());
  411. Unlock();
  412. }
  413. //
  414. // we are keeping a reference to the terminal, so increment refcount
  415. //
  416. pTrackTerminalToAdd->AddRef();
  417. LOG((MSP_TRACE, "CMultiTrackTerminal::AddTrackTerminal - finished"));
  418. return S_OK;
  419. }
  420. ///////////////////////////////////////////////////////
  421. //
  422. // CMultiTrackTerminal::RemoveTrackTerminal
  423. //
  424. // removes the terminal from the list of track terminals
  425. // managed by this multitrack terminal
  426. //
  427. // if success, decrementing refcount on the track terminal
  428. //
  429. HRESULT CMultiTrackTerminal::RemoveTrackTerminal(ITTerminal *pTrackTerminalToRemove)
  430. {
  431. LOG((MSP_TRACE, "CMultiTrackTerminal::RemoveTrackTerminal[%p] - enter"
  432. "pTrackTerminalToRemove = %p", this, pTrackTerminalToRemove));
  433. {
  434. //
  435. // access data member array in a lock
  436. //
  437. CLock lock(m_lock);
  438. //
  439. // decrement track counter in a special lock to prevent deadlocks
  440. // with reference counting
  441. //
  442. Lock();
  443. //
  444. // remove track from the array
  445. //
  446. if (!m_TrackTerminals.Remove(pTrackTerminalToRemove))
  447. {
  448. LOG((MSP_ERROR, "CMultiTrackTerminal::RemoveTrackTerminal - "
  449. "failed to remove from the array of terminals"));
  450. return E_INVALIDARG;
  451. }
  452. m_nNumberOfTracks--;
  453. //
  454. // the counter should never ever go out of sync
  455. //
  456. TM_ASSERT(m_nNumberOfTracks == m_TrackTerminals.GetSize());
  457. Unlock();
  458. }
  459. //
  460. // we are releasing a reference to the terminal, so decrement refcount
  461. //
  462. pTrackTerminalToRemove->Release();
  463. LOG((MSP_TRACE, "CMultiTrackTerminal::RemoveTrackTerminal- finished"));
  464. return S_OK;
  465. }
  466. ///////////////////////////////////////////////////////
  467. //
  468. // CMultiTrackTerminal::ReleaseAllTracks
  469. //
  470. // removes all tracks from the list of managed track terminals
  471. // and Release's them
  472. //
  473. //
  474. HRESULT CMultiTrackTerminal::ReleaseAllTracks()
  475. {
  476. LOG((MSP_TRACE, "CMultiTrackTerminal::ReleaseAllTracks[%p] - enter", this));
  477. {
  478. //
  479. // access data member array in a lock
  480. //
  481. CLock lock(m_lock);
  482. int nNumberOfTerminalsInArray = m_TrackTerminals.GetSize();
  483. for (int i = 0; i < nNumberOfTerminalsInArray; i++)
  484. {
  485. //
  486. // release and remove the first terminal in the array
  487. //
  488. LOG((MSP_TRACE, "CMultiTrackTerminal::ReleaseAllTracks - releasing track [%p]", m_TrackTerminals[0]));
  489. m_TrackTerminals[0]->Release();
  490. //
  491. // remove element from the array and decrement track counter in a
  492. // special lock to prevent deadlocks with reference counting
  493. //
  494. Lock();
  495. m_TrackTerminals.RemoveAt(0);
  496. m_nNumberOfTracks--;
  497. //
  498. // the counter should never ever go out of sync
  499. //
  500. TM_ASSERT(m_nNumberOfTracks == m_TrackTerminals.GetSize());
  501. Unlock();
  502. }
  503. //
  504. // we should have cleared the array
  505. //
  506. TM_ASSERT(0 == m_TrackTerminals.GetSize());
  507. }
  508. LOG((MSP_TRACE, "CMultiTrackTerminal::ReleaseAllTracks - finished"));
  509. return S_OK;
  510. }
  511. /////////////////////////////////////////////////////////////////////////////
  512. //
  513. // CMultiTrackTerminal::InternalAddRef
  514. //
  515. // keep track of refcount.
  516. //
  517. // we need to adjust refcount with the information on the number of tracks
  518. // that we are managing.
  519. //
  520. ULONG CMultiTrackTerminal::InternalAddRef()
  521. {
  522. // LOG((MSP_TRACE, "CMultiTrackTerminal::InternalAddRef[%p] - enter.", this));
  523. LONG lReturnValue = InterlockedIncrement(&m_dwRef);
  524. lReturnValue -= CountTracks();
  525. // LOG((MSP_TRACE, "CMultiTrackTerminal::InternalAddRef - finish. returning %ld", lReturnValue));
  526. return lReturnValue;
  527. }
  528. /////////////////////////////////////////////////////////////////////////////
  529. //
  530. // CMultiTrackTerminal::InternalRelease
  531. //
  532. // keep track of refcount.
  533. // return 0 when there are no outstanding references to me or my children
  534. //
  535. ULONG CMultiTrackTerminal::InternalRelease()
  536. {
  537. // LOG((MSP_TRACE, "CMultiTrackTerminal::InternalRelease[%p] - enter", this));
  538. LONG lReturnValue = InterlockedDecrement(&m_dwRef);
  539. lReturnValue -= CountTracks();
  540. // LOG((MSP_TRACE, "CMultiTrackTerminal::InternalRelease - finish. returning %ld", lReturnValue));
  541. return lReturnValue;
  542. }
  543. //////////////////////////////////////////////////////////////////////
  544. //
  545. // CMultiTrackTerminal::ChildAddRef
  546. //
  547. // this method is called by a track terminal when it is AddRef'd,
  548. // so the File Rec terminal can keep track of its children's refcounts
  549. //
  550. void CMultiTrackTerminal::ChildAddRef()
  551. {
  552. // LOG((MSP_TRACE, "CMultiTrackTerminal::ChildAddRef[%p] - enter.", this));
  553. AddRef();
  554. // LOG((MSP_TRACE, "CMultiTrackTerminal::ChildAddRef - finish."));
  555. }
  556. //////////////////////////////////////////////////////////////////////
  557. //
  558. // CMultiTrackTerminal::ChildRelease
  559. //
  560. // this method is called by a track terminal when it is released,
  561. // so the File Rec terminal can keep track of its children's refcounts
  562. //
  563. void CMultiTrackTerminal::ChildRelease()
  564. {
  565. // LOG((MSP_TRACE, "CMultiTrackTerminal::ChildRelease[%p] - enter.", this));
  566. Release();
  567. // LOG((MSP_TRACE, "CMultiTrackTerminal::ChildRelease - finish."));
  568. }
  569. //////////////////////////////////////////////////////////////////////
  570. //
  571. // CMultiTrackTerminal::CountTracks
  572. //
  573. // this method returns the number of tracks managed by this parent
  574. //
  575. int CMultiTrackTerminal::CountTracks()
  576. {
  577. // LOG((MSP_TRACE, "CMultiTrackTerminal::CountTracks[%p] - enter", this));
  578. //
  579. // this lock is only used to protect accesses to this var. this is
  580. // needed to prevent deadlocks when
  581. //
  582. // one thread locks the parent
  583. // terminal and enumerates the tracks (thus getting their locks)
  584. //
  585. // and
  586. //
  587. // another thread addrefs or releases a track. this locks the
  588. // track and attempts to notify the parent of the child's refcount
  589. // change. if this thread tries to lock the parent, we would have a
  590. // deadlock
  591. //
  592. // so instead of locking the parent on addref and release, we only use
  593. // this "addref/release" lock
  594. //
  595. Lock();
  596. int nNumberOfTracks = m_nNumberOfTracks;
  597. Unlock();
  598. // LOG((MSP_TRACE, "CMultiTrackTerminal::CountTracks - finished. NumberOfTracks = %d", nNumberOfTracks));
  599. return nNumberOfTracks;
  600. }