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.

3027 lines
68 KiB

  1. //
  2. // FPTerm.cpp
  3. //
  4. #include "stdafx.h"
  5. #include "FPTerm.h"
  6. #include "FPTrack.h" // FilePlayback Track Terminal
  7. #include "FPPriv.h"
  8. #include "tm.h"
  9. #define PLAYBACK_NOPLAYITEM (0xFF)
  10. // {4C8D0AF0-7BF0-4f33-9117-981A33DBD4E6}
  11. const CLSID CLSID_FilePlaybackTerminalCOMClass =
  12. {0x4C8D0AF0,0x7BF0,0x4f33,0x91,0x17,0x98,0x1A,0x33,0xDB,0xD4,0xE6};
  13. //////////////////////////////////////////////////////////////////////
  14. //
  15. // Constructor / Destructor - Methods implementation
  16. //
  17. //////////////////////////////////////////////////////////////////////
  18. CFPTerminal::CFPTerminal()
  19. :m_State(TMS_IDLE),
  20. m_htAddress(NULL),
  21. m_TerminalState( TS_NOTINUSE),
  22. m_pEventSink(NULL),
  23. m_nPlayIndex( PLAYBACK_NOPLAYITEM ),
  24. m_pFTM(NULL),
  25. m_bKnownSafeContext(FALSE),
  26. m_pPlaybackUnit(NULL)
  27. {
  28. LOG((MSP_TRACE, "CFPTerminal::CFPTerminal[%p] - enter", this));
  29. m_szName[0] = (TCHAR)0;
  30. VariantInit( &m_varPlayList );
  31. LOG((MSP_TRACE, "CFPTerminal::CFPTerminal - exit"));
  32. }
  33. CFPTerminal::~CFPTerminal()
  34. {
  35. LOG((MSP_TRACE, "CFPTerminal::~CFPTerminal[%p] - enter", this));
  36. //
  37. // get rid of all the tracks
  38. //
  39. ShutdownTracks();
  40. // Clean-up the event sink
  41. if( NULL != m_pEventSink )
  42. {
  43. m_pEventSink->Release();
  44. m_pEventSink = NULL;
  45. }
  46. // Release free thread marshaler
  47. if( m_pFTM )
  48. {
  49. m_pFTM->Release();
  50. m_pFTM = NULL;
  51. }
  52. // Clean-up the playback unit
  53. if( m_pPlaybackUnit )
  54. {
  55. m_pPlaybackUnit->Shutdown();
  56. delete m_pPlaybackUnit;
  57. m_pPlaybackUnit = NULL;
  58. }
  59. //
  60. // Clean the play list
  61. //
  62. VariantClear(&m_varPlayList);
  63. LOG((MSP_TRACE, "CFPTerminal::~CFPTerminal - exit"));
  64. }
  65. HRESULT CFPTerminal::FinalConstruct(void)
  66. {
  67. LOG((MSP_TRACE, "CFPTerminal::FinalConstruct[%p] - enter", this));
  68. HRESULT hr = CoCreateFreeThreadedMarshaler( GetControllingUnknown(),
  69. & m_pFTM );
  70. if ( FAILED(hr) )
  71. {
  72. LOG((MSP_ERROR, "CFPTerminal::FinalConstruct - "
  73. "create FTM returned 0x%08x; exit", hr));
  74. return hr;
  75. }
  76. LOG((MSP_TRACE, "CFPTerminal::FinalConstruct - exit S_OK"));
  77. return S_OK;
  78. }
  79. //////////////////////////////////////////////////////////////////////
  80. //
  81. // ITTerminal - Methods implementation
  82. //
  83. //////////////////////////////////////////////////////////////////////
  84. HRESULT CFPTerminal::get_TerminalClass(
  85. OUT BSTR *pVal)
  86. {
  87. //
  88. // Critical section
  89. //
  90. CLock lock(m_Lock);
  91. LOG((MSP_TRACE, "CFPTerminal::get_TerminalClass - enter [%p]", this));
  92. //
  93. // Validates argument
  94. //
  95. if( IsBadWritePtr( pVal, sizeof(BSTR)) )
  96. {
  97. LOG((MSP_ERROR, "CFPTerminal::get_TerminalClass - exit "
  98. "bad BSTR pointer. Returns E_POINTER"));
  99. return E_POINTER;
  100. }
  101. //
  102. // Get the LPOLESTR from IID
  103. //
  104. LPOLESTR lpszIID = NULL;
  105. HRESULT hr = StringFromIID( m_TerminalClassID, &lpszIID);
  106. if( FAILED(hr) )
  107. {
  108. LOG((MSP_ERROR, "CFPTerminal::get_TerminalClass - exit "
  109. "StringFromIID failed. Returns 0x%08x", hr));
  110. return hr;
  111. }
  112. //
  113. // Get BSTR from LPOLESTR
  114. //
  115. *pVal = SysAllocString( lpszIID );
  116. //
  117. // Clean up
  118. //
  119. CoTaskMemFree( lpszIID );
  120. hr = (*pVal) ? S_OK : E_OUTOFMEMORY;
  121. LOG((MSP_TRACE, "CFPTerminal::get_TerminalClass - exit 0x%08x", hr));
  122. return hr;
  123. }
  124. HRESULT CFPTerminal::get_TerminalType(
  125. OUT TERMINAL_TYPE *pVal)
  126. {
  127. //
  128. // Critical section
  129. //
  130. CLock lock(m_Lock);
  131. LOG((MSP_TRACE, "CFPTerminal::get_TerminalType - enter [%p]", this));
  132. //
  133. // Validates argument
  134. //
  135. if( IsBadWritePtr( pVal, sizeof(TERMINAL_TYPE)) )
  136. {
  137. LOG((MSP_ERROR, "CFPTerminal::get_TerminalType - exit "
  138. "bad TERMINAL_TYPE pointer. Returns E_POINTER"));
  139. return E_POINTER;
  140. }
  141. //
  142. // Return value
  143. //
  144. *pVal = TT_DYNAMIC;
  145. LOG((MSP_TRACE, "CFPTerminal::get_TerminalType - exit S_OK"));
  146. return S_OK;
  147. }
  148. HRESULT CFPTerminal::get_State(
  149. OUT TERMINAL_STATE *pVal)
  150. {
  151. //
  152. // Critical section
  153. //
  154. CLock lock(m_Lock);
  155. LOG((MSP_TRACE, "CFPTerminal::get_State - enter [%p]", this));
  156. //
  157. // Validates argument
  158. //
  159. if( IsBadWritePtr( pVal, sizeof(TERMINAL_STATE)) )
  160. {
  161. LOG((MSP_ERROR, "CFPTerminal::get_State - exit "
  162. "bad TERMINAL_TYPE pointer. Returns E_POINTER"));
  163. return E_POINTER;
  164. }
  165. //
  166. // Enumerate tracks
  167. //
  168. IEnumTerminal* pTracks = NULL;
  169. HRESULT hr = EnumerateTrackTerminals( &pTracks );
  170. if( FAILED(hr) )
  171. {
  172. LOG((MSP_ERROR, "CFPTerminal::get_State - exit "
  173. "EnumerateTrackTerminals failed. Returns 0x%08x", hr));
  174. return hr;
  175. }
  176. //
  177. // Read the state for each track
  178. // If one of them is in use then the parent
  179. // terminal is in use
  180. //
  181. TERMINAL_STATE TerminalState = TS_NOTINUSE;
  182. ITTerminal* pTerminal = NULL;
  183. ULONG cFetched = 0;
  184. while( S_OK == pTracks->Next(1, &pTerminal, &cFetched) )
  185. {
  186. //
  187. // Get the state for the track
  188. //
  189. hr = pTerminal->get_State( &TerminalState );
  190. //
  191. // Clean-up
  192. //
  193. pTerminal->Release();
  194. pTerminal = NULL;
  195. if( FAILED(hr) )
  196. {
  197. // Clean-up
  198. pTracks->Release();
  199. LOG((MSP_ERROR, "CFPTerminal::get_State - exit "
  200. "get_State failed. Returns 0x%08x", hr));
  201. return hr;
  202. }
  203. if( TerminalState == TS_INUSE )
  204. {
  205. // OK, we have a terminal in use
  206. break;
  207. }
  208. }
  209. //
  210. // Clean-up
  211. //
  212. pTracks->Release();
  213. //
  214. // Return value
  215. //
  216. *pVal = TerminalState;
  217. LOG((MSP_TRACE, "CFPTerminal::get_State - exit S_OK"));
  218. return S_OK;
  219. }
  220. HRESULT CFPTerminal::get_Name(
  221. OUT BSTR *pVal)
  222. {
  223. //
  224. // Critical section
  225. //
  226. CLock lock(m_Lock);
  227. LOG((MSP_TRACE, "CFPTerminal::get_Name - enter [%p]", this));
  228. //
  229. // Validates argument
  230. //
  231. if( IsBadWritePtr( pVal, sizeof(BSTR)) )
  232. {
  233. LOG((MSP_ERROR, "CFPTerminal::get_TerminalClass - exit "
  234. "bad BSTR pointer. Returns E_POINTER"));
  235. return E_POINTER;
  236. }
  237. //
  238. // Get the name from the resource file
  239. // if wasn't already read
  240. //
  241. if( m_szName[0] == (TCHAR)0)
  242. {
  243. //
  244. // Read the name
  245. //
  246. TCHAR szName[ MAX_PATH ];
  247. if(::LoadString(_Module.GetResourceInstance(), IDS_FPTERMINAL, szName, MAX_PATH))
  248. {
  249. lstrcpyn( m_szName, szName, MAX_PATH);
  250. }
  251. else
  252. {
  253. LOG((MSP_ERROR, "CFPTerminal::get_TerminalClass - exit "
  254. "LoadString failed. Returns E_OUTOFMEMORY"));
  255. return E_OUTOFMEMORY;
  256. }
  257. }
  258. //
  259. // Return value
  260. //
  261. *pVal = SysAllocString( m_szName );
  262. HRESULT hr = (*pVal) ? S_OK : E_OUTOFMEMORY;
  263. if( FAILED(hr) )
  264. {
  265. LOG((MSP_ERROR, "CFPTerminal::get_Name - exit 0x%08x", hr));
  266. }
  267. else
  268. {
  269. LOG((MSP_TRACE, "CFPTerminal::get_Name - exit 0x%08x", hr));
  270. }
  271. return hr;
  272. }
  273. HRESULT CFPTerminal::get_MediaType(
  274. OUT long * plMediaType)
  275. {
  276. //
  277. // Critical section
  278. //
  279. CLock lock(m_Lock);
  280. LOG((MSP_TRACE, "CFPTerminal::get_MediaType - enter [%p]", this));
  281. //
  282. // Validates argument
  283. //
  284. if( IsBadWritePtr( plMediaType, sizeof(long)) )
  285. {
  286. LOG((MSP_ERROR, "CFPTerminal::get_MediaType - exit "
  287. "bad long pointer. Returns E_POINTER"));
  288. return E_POINTER;
  289. }
  290. //
  291. //
  292. *plMediaType = TAPIMEDIATYPE_AUDIO | TAPIMEDIATYPE_MULTITRACK;
  293. LOG((MSP_TRACE, "CFPTerminal::get_MediaType - exit S_OK"));
  294. return S_OK;
  295. }
  296. HRESULT CFPTerminal::get_Direction(
  297. OUT TERMINAL_DIRECTION *pDirection)
  298. {
  299. //
  300. // Critical section
  301. //
  302. CLock lock(m_Lock);
  303. LOG((MSP_TRACE, "CFPTerminal::get_Direction - enter [%p]", this));
  304. //
  305. // Validates argument
  306. //
  307. if( IsBadWritePtr( pDirection, sizeof(TERMINAL_DIRECTION)) )
  308. {
  309. LOG((MSP_ERROR, "CFPTerminal::get_Direction - exit "
  310. "bad TERMINAL_DIRECTION pointer. Returns E_POINTER"));
  311. return E_POINTER;
  312. }
  313. //
  314. // Return value, this multi track temrinal supoports just
  315. // CAPTURE tracks!
  316. //
  317. *pDirection = TD_CAPTURE;
  318. LOG((MSP_TRACE, "CFPTerminal::get_Direction - exit S_OK"));
  319. return S_OK;
  320. }
  321. //////////////////////////////////////////////////////////////////////
  322. //
  323. // ITMultiTrackTerminal - Methods implementation
  324. //
  325. // neither CreateTrackTerminal nor RemoveTrackTerminal make sense on
  326. // a playback terminal
  327. //
  328. //////////////////////////////////////////////////////////////////////
  329. HRESULT STDMETHODCALLTYPE CFPTerminal::CreateTrackTerminal(
  330. IN long lMediaType,
  331. IN TERMINAL_DIRECTION Direction,
  332. OUT ITTerminal **ppTerminal
  333. )
  334. {
  335. LOG((MSP_TRACE, "CFPTerminal::CreateTrackTerminal[%p] - enter", this));
  336. LOG((MSP_TRACE,
  337. "CFPTerminal::CreateTrackTerminal - not supported on the playback terminal. return TAPI_E_NOTSUPPORTED"));
  338. return TAPI_E_NOTSUPPORTED;
  339. }
  340. HRESULT STDMETHODCALLTYPE CFPTerminal::RemoveTrackTerminal(
  341. IN ITTerminal *pTrackTerminalToRemove
  342. )
  343. {
  344. LOG((MSP_TRACE, "CFPTerminal::RemoveTrackTerminal[%p] - enter. pTrackTerminalToRemove = [%p]",
  345. this, pTrackTerminalToRemove));
  346. LOG((MSP_WARN,
  347. "CFPTerminal::RemoveTrackTerminal - not supported on a playback terminal. returning TAPI_E_NOTSUPPORTED"));
  348. return TAPI_E_NOTSUPPORTED;
  349. }
  350. //////////////////////////////////////////////////////////////////////
  351. //
  352. // ITMediaPlayback - Methods implementation
  353. //
  354. //////////////////////////////////////////////////////////////////////
  355. HRESULT CFPTerminal::put_PlayList(
  356. IN VARIANTARG PlayListVariant
  357. )
  358. {
  359. //
  360. // Critical section
  361. //
  362. CLock lock(m_Lock);
  363. LOG((MSP_TRACE, "CFPTerminal::put_PlayList[%p] - enter", this));
  364. long nLeftBound = 0;
  365. long nRightBound = 0;
  366. //
  367. // Validates the playlist
  368. //
  369. HRESULT hr = ValidatePlayList(
  370. PlayListVariant,
  371. &nLeftBound,
  372. &nRightBound
  373. );
  374. if( FAILED(hr) )
  375. {
  376. LOG((MSP_ERROR, "CFPTerminal::put_PlayList - "
  377. " ValidatePlayList failed. Returns 0x%08x", hr));
  378. return hr;
  379. }
  380. //
  381. // Validates the playlist
  382. //
  383. long nLeftBoundOld = 0;
  384. long nRightBoundOld = 0;
  385. HRESULT hrOld = ValidatePlayList(
  386. m_varPlayList,
  387. &nLeftBoundOld,
  388. &nRightBoundOld
  389. );
  390. if( SUCCEEDED(hrOld) )
  391. {
  392. HRESULT hr = DoStateTransition(TMS_IDLE);
  393. if(FAILED(hr) )
  394. {
  395. LOG((MSP_TRACE, "CFPTerminal::put_PlayList - "
  396. "DoStateTransition failed 0x%08x", hr));
  397. }
  398. //
  399. // attempt to stop all tracks
  400. //
  401. hr = StopAllTracks();
  402. if (FAILED(hr))
  403. {
  404. LOG((MSP_TRACE, "CFPTerminal::put_PlayList - "
  405. "StopAllTrack failed 0x%08x", hr));
  406. }
  407. //
  408. // the terminal is now stoped. update state.
  409. //
  410. m_State = TMS_IDLE;
  411. //
  412. // Store internal the playlist
  413. //
  414. VariantClear(&m_varPlayList);
  415. VariantCopy( &m_varPlayList, &PlayListVariant);
  416. //
  417. // Play the first item
  418. //
  419. m_nPlayIndex = nLeftBound;
  420. //
  421. // Play the first element
  422. //
  423. hr = PlayItem( m_nPlayIndex );
  424. LOG((MSP_TRACE, "CFPTerminal::put_PlayList - exit 0x%08x", hr));
  425. return hr;
  426. }
  427. //
  428. // Clean-up the existing play list
  429. //
  430. RollbackTrackInfo();
  431. //
  432. // Store internal the playlist
  433. //
  434. VariantClear(&m_varPlayList);
  435. hr = VariantCopy( &m_varPlayList, &PlayListVariant);
  436. if( FAILED(hr) )
  437. {
  438. // Clean-up
  439. RollbackTrackInfo();
  440. LOG((MSP_ERROR, "CFPTerminal::put_PlayList - "
  441. " VariantCopy failed. Returns 0x%08x", hr));
  442. return hr;
  443. }
  444. //
  445. // Get the first file name from the list
  446. //
  447. m_nPlayIndex = nLeftBound;
  448. BSTR bstrFileName = GetFileNameFromPlayList(
  449. m_varPlayList,
  450. m_nPlayIndex
  451. );
  452. if( bstrFileName == NULL )
  453. {
  454. // Clean-up
  455. RollbackTrackInfo();
  456. LOG((MSP_ERROR, "CFPTerminal::put_PlayList - "
  457. " GetFileNameFromPlayList failed. Returns E_INVAlIDARG"));
  458. return E_INVALIDARG;
  459. }
  460. //
  461. // Play the file from the list
  462. //
  463. hr = ConfigurePlaybackUnit( bstrFileName );
  464. //
  465. // Clan-up the file name
  466. //
  467. SysFreeString( bstrFileName );
  468. if( FAILED(hr) )
  469. {
  470. //
  471. // Something was wrong
  472. //
  473. FireEvent( TMS_IDLE, FTEC_READ_ERROR, hr);
  474. LOG((MSP_ERROR, "CFPTerminal::put_PlayList - "
  475. " ConfigurePlaybackUnit failed. Returns 0x%08x", hr));
  476. return hr;
  477. }
  478. LOG((MSP_TRACE, "CFPTerminal::put_PlayList - exit S_OK"));
  479. return S_OK;
  480. }
  481. HRESULT CFPTerminal::get_PlayList(
  482. IN VARIANTARG* pPlayListVariant
  483. )
  484. {
  485. //
  486. // Critical section
  487. //
  488. CLock lock(m_Lock);
  489. LOG((MSP_TRACE, "CFPTerminal::get_PlayList[%p] - enter", this));
  490. //
  491. // Validates argument
  492. //
  493. if( IsBadWritePtr( pPlayListVariant, sizeof(VARIANTARG)) )
  494. {
  495. LOG((MSP_ERROR, "CFPTerminal::put_PlayList - exit "
  496. "the argument is invalid pointer; returning E_POINTER"));
  497. return E_POINTER;
  498. }
  499. //
  500. // Pass the playlist
  501. //
  502. HRESULT hr = VariantCopy( pPlayListVariant, &m_varPlayList);
  503. LOG((MSP_TRACE, "CFPTerminal::get_PlayList - exit 0x%08x", hr));
  504. return hr;
  505. }
  506. //////////////////////////////////////////////////////////////////////
  507. //
  508. // ITMediaControl - Methods implementation
  509. //
  510. //////////////////////////////////////////////////////////////////////
  511. HRESULT CFPTerminal::Start( void)
  512. {
  513. //
  514. // Critical section
  515. //
  516. CLock lock(m_Lock);
  517. LOG((MSP_TRACE, "CFPTerminal::Start[%p] - enter.", this));
  518. //
  519. // Check the current state
  520. //
  521. if (TMS_ACTIVE == m_State)
  522. {
  523. LOG((MSP_TRACE, "CFPTerminal::Start - "
  524. "terminal already running. Returns S_FALSE"));
  525. return S_FALSE;
  526. }
  527. //
  528. // Get the number of tracks to see
  529. // there are tracks
  530. if(m_TrackTerminals.GetSize()==0)
  531. {
  532. LOG((MSP_TRACE, "CFPTerminal::Start - "
  533. "no tracks. Returns TAPI_E_WRONG_STATE"));
  534. return TAPI_E_WRONG_STATE;
  535. }
  536. HRESULT hr = DoStateTransition(TMS_ACTIVE);
  537. if(FAILED(hr) )
  538. {
  539. LOG((MSP_TRACE, "CFPTerminal::Start - exit "
  540. "DoStateTransition failed. Returns 0x%08x", hr));
  541. return hr;
  542. }
  543. if (TMS_IDLE == m_State)
  544. {
  545. LOG((MSP_TRACE, "CFPTerminal::Start - from IDLE to START"));
  546. }
  547. if (TMS_PAUSED == m_State)
  548. {
  549. LOG((MSP_TRACE, "CFPTerminal::Start - from PAUSED to START"));
  550. }
  551. //
  552. // Start every child temrinals
  553. // Enumerate all child terminals
  554. //
  555. IEnumTerminal *pEnumTerminal = NULL;
  556. hr = EnumerateTrackTerminals(&pEnumTerminal);
  557. if (FAILED(hr))
  558. {
  559. LOG((MSP_ERROR, "CFPTerminal::Start - failed to enumerate track terminals. hr = 0x%08x", hr));
  560. return hr;
  561. }
  562. //
  563. // bTrackStarted will be set to true if at least one track is successfully started
  564. // bTrackFailed will be set if at least one track fails
  565. BOOL bTracksStarted = FALSE;
  566. BOOL bStartFailed = FALSE;
  567. //
  568. // Iterate through the list of terminals
  569. //
  570. ITTerminal *pTrackTerminal = NULL;
  571. ULONG ulFetched = 0;
  572. while ( pEnumTerminal->Next(1, &pTrackTerminal, &ulFetched) == S_OK)
  573. {
  574. hr = E_FAIL;
  575. //
  576. // Block for ITMEdiaControl
  577. // Attempt to start the track terminal
  578. //
  579. {
  580. //CComQIPtr<ITMediaControl, &IID_ITMediaControl> pMediaControl(pTrackTerminal);
  581. CFPTrack *pTrack = static_cast<CFPTrack*>(pTrackTerminal);
  582. hr = pTrack->Start();
  583. }
  584. // Clean-up
  585. pTrackTerminal->Release();
  586. pTrackTerminal = NULL;
  587. if (FAILED(hr))
  588. {
  589. //
  590. // A track failed to start. set a flag so we know to stop all the tracks that succeeded.
  591. //
  592. LOG((MSP_ERROR, "CFPTerminal::Start - track failed to start hr = 0x%08x",hr));
  593. bStartFailed = TRUE;
  594. break;
  595. }
  596. else
  597. {
  598. //
  599. // The track succeded
  600. //
  601. LOG((MSP_TRACE, "CFPTerminal::Start - track started "));
  602. bTracksStarted = TRUE;
  603. }
  604. } // while walking through tracks
  605. //
  606. // if some tracks failed and some started, stop all the tracks
  607. //
  608. if (bStartFailed && bTracksStarted)
  609. {
  610. //
  611. // iterate through tracks again and attempt to stop each track in the iteration
  612. //
  613. pEnumTerminal->Reset();
  614. while((pEnumTerminal->Next(1, &pTrackTerminal, &ulFetched) == S_OK))
  615. {
  616. //
  617. // Attempt to stop the track. best effort -- not much to do if we fail
  618. //
  619. {
  620. //CComQIPtr<ITMediaControl, &IID_ITMediaControl> pMediaControl(pTrackTerminal);
  621. CFPTrack* pTrack = static_cast<CFPTrack*>(pTrackTerminal);
  622. pTrack->Stop();
  623. }
  624. // Clean-up
  625. pTrackTerminal->Release();
  626. pTrackTerminal = NULL;
  627. } // stopping each track in the enum
  628. m_State = TMS_IDLE;
  629. } // at least some tracks need to be stopped
  630. //
  631. // Clean-up
  632. //
  633. pEnumTerminal->Release();
  634. pEnumTerminal = NULL;
  635. //
  636. // if something failed, or no tracks were started, reset stream time
  637. //
  638. if (bStartFailed || !bTracksStarted)
  639. {
  640. LOG((MSP_TRACE, "CFPTerminal::Start - exit "
  641. "tracks have not been started. Returns E_FAIL"));
  642. return E_FAIL;
  643. }
  644. //
  645. // the terminal is now running. update state.
  646. //
  647. m_State = TMS_ACTIVE;
  648. //
  649. // attempt to fire an event notifying the app of the state change
  650. //
  651. FireEvent(TMS_ACTIVE, FTEC_NORMAL, S_OK);
  652. LOG((MSP_TRACE, "CFPTerminal::Start - exit S_OK"));
  653. return S_OK;
  654. }
  655. HRESULT CFPTerminal::Stop( void)
  656. {
  657. //
  658. // Critical section
  659. //
  660. CLock lock(m_Lock);
  661. LOG((MSP_TRACE, "CFPTerminal::Stop[%p] - enter", this));
  662. //
  663. // Is terminal already stopped?
  664. //
  665. if( TMS_IDLE == m_State )
  666. {
  667. LOG((MSP_TRACE, "CFPTerminal::Stop - "
  668. "the terminals is already IDLE. Returns S_OK"));
  669. return S_FALSE;
  670. }
  671. HRESULT hr = DoStateTransition(TMS_IDLE);
  672. if(FAILED(hr) )
  673. {
  674. LOG((MSP_TRACE, "CFPTerminal::Stop - exit "
  675. "DoStateTransition failed. Returns 0x%08x", hr));
  676. return hr;
  677. }
  678. //
  679. // attempt to stop all tracks
  680. //
  681. hr = StopAllTracks();
  682. if (FAILED(hr))
  683. {
  684. LOG((MSP_TRACE, "CFPTerminal::Stop - StopAllTrack failed hr = %lx", hr));
  685. return hr;
  686. }
  687. //
  688. // the terminal is now stoped. update state.
  689. //
  690. m_State = TMS_IDLE;
  691. //
  692. // attempt to fire an event notifying the app of the state change
  693. //
  694. FireEvent(TMS_IDLE, FTEC_NORMAL, S_OK);
  695. LOG((MSP_TRACE, "CFPTerminal::Stop - exit S_OK"));
  696. return S_OK;
  697. }
  698. HRESULT CFPTerminal::StopAllTracks()
  699. {
  700. LOG((MSP_TRACE, "CFPTerminal::StopAllTracks[%p] - enter", this));
  701. //
  702. // Enumerate child temrinals
  703. //
  704. IEnumTerminal *pEnumTerminal = NULL;
  705. HRESULT hr = EnumerateTrackTerminals(&pEnumTerminal);
  706. if (FAILED(hr))
  707. {
  708. LOG((MSP_ERROR, "CFPTerminal::StopAllTracks - exit "
  709. "failed to enumerate track terminals. hr = %lx", hr));
  710. return hr;
  711. }
  712. //
  713. // bSomeTracksFailedToStop will be set if at least one track fails
  714. //
  715. BOOL bSomeTracksFailedToStop = FALSE;
  716. ITTerminal *pTrackTerminal = NULL;
  717. ULONG ulFetched = 0;
  718. //
  719. // Iterate through the list of terminals
  720. //
  721. while( (pEnumTerminal->Next(1, &pTrackTerminal, &ulFetched) == S_OK) )
  722. {
  723. hr = E_FAIL;
  724. //
  725. // Attempt to stop the track terminal
  726. //
  727. CFPTrack *pFilePlaybackTrack = static_cast<CFPTrack *>(pTrackTerminal);
  728. hr = pFilePlaybackTrack->Stop();
  729. // Clean-up
  730. pTrackTerminal->Release();
  731. pTrackTerminal = NULL;
  732. if (FAILED(hr))
  733. {
  734. //
  735. // A track failed to stop.
  736. // Log a message and continue to the next track. there is not much else we can do.
  737. //
  738. LOG((MSP_ERROR, "CFPTerminal::StopAllTracks - track failed to stop hr = 0x%08x", hr));
  739. bSomeTracksFailedToStop = TRUE;
  740. }
  741. else
  742. {
  743. LOG((MSP_TRACE, "CFPTerminal::StopAllTracks - track stopped"));
  744. }
  745. } // while walking through tracks
  746. //
  747. // remember to release enumeration
  748. //
  749. pEnumTerminal->Release();
  750. pEnumTerminal = NULL;
  751. //
  752. // If some tracks failed, log and return S_FALSE
  753. //
  754. if (bSomeTracksFailedToStop)
  755. {
  756. LOG((MSP_TRACE, "CFPTerminal::StopAllTracks - exit "
  757. "some tracks failed. Returns S_FALSE"));
  758. return S_FALSE;
  759. }
  760. LOG((MSP_TRACE, "CFPTerminal::StopAllTracks - exit S_OK"));
  761. return S_OK;
  762. }
  763. HRESULT CFPTerminal::Pause( void)
  764. {
  765. //
  766. // Critical section
  767. //
  768. CLock lock(m_Lock);
  769. LOG((MSP_TRACE, "CFPTerminal::Pause[%p] - enter.", this));
  770. //
  771. // Check the current state
  772. //
  773. if (TMS_PAUSED == m_State)
  774. {
  775. LOG((MSP_TRACE, "CFPTerminal::Pause - "
  776. "terminal already paused. Returns S_OK"));
  777. return S_FALSE;
  778. }
  779. if (TMS_IDLE == m_State)
  780. {
  781. LOG((MSP_TRACE, "CFPTerminal::Pause - "
  782. "terminal already Idle. Returns TAPI_E_WRONG_STATE"));
  783. return TAPI_E_WRONG_STATE;
  784. }
  785. if (TMS_ACTIVE == m_State)
  786. {
  787. LOG((MSP_TRACE, "CFPTerminal::Pause - from ACTIVE to PAUSED"));
  788. }
  789. HRESULT hr = DoStateTransition(TMS_PAUSED);
  790. if(FAILED(hr) )
  791. {
  792. LOG((MSP_TRACE, "CFPTerminal::Pause - exit "
  793. "DoStateTransition failed. Returns 0x%08x", hr));
  794. return hr;
  795. }
  796. //
  797. // Start every child terminals
  798. // Enumerate all child terminals
  799. //
  800. IEnumTerminal *pEnumTerminal = NULL;
  801. hr = EnumerateTrackTerminals(&pEnumTerminal);
  802. if (FAILED(hr))
  803. {
  804. LOG((MSP_ERROR, "CFPTerminal::Pause - failed to enumerate track terminals. hr = 0x%08x", hr));
  805. return hr;
  806. }
  807. //
  808. // bTrackPaused will be set to true if at least one track is successfully paused
  809. // bTrackFailed will be set if at least one track fails
  810. BOOL bTracksPaused = FALSE;
  811. BOOL bPauseFailed = FALSE;
  812. //
  813. // Iterate through the list of terminals
  814. //
  815. ITTerminal *pTrackTerminal = NULL;
  816. ULONG ulFetched = 0;
  817. while ( pEnumTerminal->Next(1, &pTrackTerminal, &ulFetched) == S_OK)
  818. {
  819. hr = E_FAIL;
  820. //
  821. // Block for ITMEdiaControl
  822. // Attempt to start the track terminal
  823. //
  824. {
  825. //CComQIPtr<ITMediaControl, &IID_ITMediaControl> pMediaControl(pTrackTerminal);
  826. CFPTrack* pTrack = static_cast<CFPTrack*>(pTrackTerminal);
  827. hr = pTrack->Pause();
  828. }
  829. // Clean-up
  830. pTrackTerminal->Release();
  831. pTrackTerminal = NULL;
  832. if (FAILED(hr))
  833. {
  834. //
  835. // A track failed to pause. Set a flag so we know to stop all the tracks that succeeded.
  836. //
  837. LOG((MSP_ERROR, "CFPTerminal::Pause - track failed to pause hr = 0x%08x",hr));
  838. bPauseFailed = TRUE;
  839. break;
  840. }
  841. else
  842. {
  843. //
  844. // The track succeded
  845. //
  846. LOG((MSP_TRACE, "CFPTerminal::Pause - track paused "));
  847. bTracksPaused = TRUE;
  848. }
  849. } // while walking through tracks
  850. //
  851. // if some tracks failed and some paused, stop all the tracks
  852. //
  853. if (bPauseFailed && bTracksPaused)
  854. {
  855. //
  856. // iterate through tracks again and attempt to stop each track in the iteration
  857. //
  858. pEnumTerminal->Reset();
  859. while((pEnumTerminal->Next(1, &pTrackTerminal, &ulFetched) == S_OK))
  860. {
  861. //
  862. // Attempt to stop the track. best effort -- not much to do if we fail
  863. //
  864. {
  865. //CComQIPtr<ITMediaControl, &IID_ITMediaControl> pMediaControl(pTrackTerminal);
  866. CFPTrack* pTrack = static_cast<CFPTrack*>(pTrackTerminal);
  867. pTrack->Stop();
  868. }
  869. // Clean-up
  870. pTrackTerminal->Release();
  871. pTrackTerminal = NULL;
  872. } // stopping each track in the enum
  873. m_State = TMS_IDLE;
  874. } // at least some tracks need to be stopped
  875. //
  876. // Clean-up
  877. //
  878. pEnumTerminal->Release();
  879. pEnumTerminal = NULL;
  880. //
  881. // if something failed, or no tracks were started, reset stream time
  882. //
  883. if (bPauseFailed || !bTracksPaused)
  884. {
  885. LOG((MSP_TRACE, "CFPTerminal::Pause - exit "
  886. "tracks have not been started. Returns E_FAIL"));
  887. return E_FAIL;
  888. }
  889. //
  890. // the terminal is now paused. update state.
  891. //
  892. m_State = TMS_PAUSED;
  893. //
  894. // attempt to fire an event notifying the app of the state change
  895. //
  896. FireEvent(TMS_PAUSED, FTEC_NORMAL, S_OK);
  897. LOG((MSP_TRACE, "CFPTerminal::Pause - exit S_OK"));
  898. return S_OK;
  899. }
  900. HRESULT CFPTerminal::get_MediaState(
  901. OUT TERMINAL_MEDIA_STATE *pMediaState)
  902. {
  903. //
  904. // Critical section
  905. //
  906. CLock lock(m_Lock);
  907. LOG((MSP_TRACE, "CFPTerminal::get_MediaState[%p] - enter.", this));
  908. //
  909. // Validates argument
  910. //
  911. if( IsBadWritePtr( pMediaState, sizeof(TERMINAL_MEDIA_STATE)) )
  912. {
  913. LOG((MSP_ERROR, "CFPTerminal::get_MediaState - exit "
  914. "invalid TERMINAL_MEDIA_STATE. Returns E_POINTER"));
  915. return E_POINTER;
  916. }
  917. //
  918. // Return state
  919. //
  920. *pMediaState = m_State;
  921. LOG((MSP_TRACE, "CFPTerminal::get_MediaState - exit S_OK"));
  922. return S_OK;
  923. }
  924. //////////////////////////////////////////////////////////////////////
  925. //
  926. // ITPluggableTerminalInitialization - Methods implementation
  927. //
  928. //////////////////////////////////////////////////////////////////////
  929. HRESULT CFPTerminal::InitializeDynamic (
  930. IN IID iidTerminalClass,
  931. IN DWORD dwMediaType,
  932. IN TERMINAL_DIRECTION Direction,
  933. IN MSP_HANDLE htAddress)
  934. {
  935. //
  936. // Critical section
  937. //
  938. CLock lock(m_Lock);
  939. LOG((MSP_TRACE, "CFPTerminal::InitializeDynamic - enter [%p]", this));
  940. //
  941. // Check the direction
  942. //
  943. if (TD_CAPTURE != Direction)
  944. {
  945. LOG((MSP_ERROR, "CFPTerminal::InitializeDynamic - exit "
  946. "bad direction [%d] requested. Returns E_INVALIDARG", Direction));
  947. return E_INVALIDARG;
  948. }
  949. //
  950. // Check mediatypes
  951. //
  952. DWORD dwMediaTypesOtherThanVideoAndAudio = dwMediaType & ~(TAPIMEDIATYPE_AUDIO | TAPIMEDIATYPE_VIDEO);
  953. if ( (TAPIMEDIATYPE_MULTITRACK != dwMediaType) && (0 != dwMediaTypesOtherThanVideoAndAudio) )
  954. {
  955. LOG((MSP_ERROR, "CFPTerminal::InitializeDynamic - exit "
  956. "bad media type [%d] requested. Returns E_INVALIDARG", dwMediaType));
  957. return E_INVALIDARG;
  958. }
  959. //
  960. // Sets the terminal attributes
  961. //
  962. m_TerminalClassID = iidTerminalClass;
  963. m_dwMediaTypes = dwMediaType;
  964. m_Direction = Direction;
  965. m_htAddress = htAddress;
  966. //
  967. // since InitializeDynamic was called, we will assume that we are
  968. // running in safe context. so we can can now start telling people
  969. // we are safe for scripting (if anyone asks).
  970. //
  971. m_bKnownSafeContext = TRUE;
  972. LOG((MSP_TRACE, "CFPTerminal::InitializeDynamic - exit S_OK"));
  973. return S_OK;
  974. }
  975. //////////////////////////////////////////////////////////////////////////////
  976. //
  977. // SetInterfaceSafetyOptions
  978. //
  979. // this is a safeguard to prevent using this terminal in scripting outside
  980. // terminal manager context.
  981. //
  982. // if we detect that InitializeDynamic has not been called, this method will
  983. // fail thus marking the object as unsafe for scripting
  984. //
  985. //////////////////////////////////////////////////////////////////////////////
  986. STDMETHODIMP CFPTerminal::SetInterfaceSafetyOptions(REFIID riid,
  987. DWORD dwOptionSetMask,
  988. DWORD dwEnabledOptions)
  989. {
  990. CLock lock(m_lock);
  991. //
  992. // check if we are running in safe context
  993. //
  994. if (!m_bKnownSafeContext)
  995. {
  996. //
  997. // we have not been initialized properly... someone evil is trying to
  998. // use this terminal. NO!
  999. //
  1000. return E_FAIL;
  1001. }
  1002. //
  1003. // we are known to safe, so simply delegate request to the base class
  1004. //
  1005. return CMSPObjectSafetyImpl::SetInterfaceSafetyOptions(riid,
  1006. dwOptionSetMask,
  1007. dwEnabledOptions);
  1008. }
  1009. //////////////////////////////////////////////////////////////////////////////
  1010. //
  1011. // GetInterfaceSafetyOptions
  1012. //
  1013. // this is a safeguard to prevent using this terminal in scripting outside
  1014. // terminal manager context.
  1015. //
  1016. // if we detect that InitializeDynamic has not been called, this method will
  1017. // fail thus marking the object as unsafe for scripting
  1018. //
  1019. //////////////////////////////////////////////////////////////////////////////
  1020. STDMETHODIMP CFPTerminal::GetInterfaceSafetyOptions(REFIID riid,
  1021. DWORD *pdwSupportedOptions,
  1022. DWORD *pdwEnabledOptions)
  1023. {
  1024. CLock lock(m_lock);
  1025. //
  1026. // check if we are running in safe context
  1027. //
  1028. if (!m_bKnownSafeContext)
  1029. {
  1030. //
  1031. // we have not been initialized properly... someone evil is trying to
  1032. // use this terminal. NO!
  1033. //
  1034. return E_FAIL;
  1035. }
  1036. //
  1037. // we are known to safe, so simply delegate request to the base class
  1038. //
  1039. return CMSPObjectSafetyImpl::GetInterfaceSafetyOptions(riid,
  1040. pdwSupportedOptions,
  1041. pdwEnabledOptions);
  1042. }
  1043. //////////////////////////////////////////////////////////////////////
  1044. //
  1045. // ITPluggableTerminalEventSinkRegistration - Methods implementation
  1046. //
  1047. //////////////////////////////////////////////////////////////////////
  1048. HRESULT CFPTerminal::RegisterSink(
  1049. IN ITPluggableTerminalEventSink *pSink
  1050. )
  1051. {
  1052. //
  1053. // Critical section
  1054. //
  1055. CLock lock(m_Lock);
  1056. LOG((MSP_TRACE, "CFPTerminal::RegisterSink - enter [%p]", this));
  1057. //
  1058. // Validates argument
  1059. //
  1060. if( IsBadReadPtr( pSink, sizeof(ITPluggableTerminalEventSink)) )
  1061. {
  1062. LOG((MSP_ERROR, "CFPTerminal::RegisterSink - exit "
  1063. "ITPluggableTerminalEventSink invalid pointer. Returns E_POINTER"));
  1064. return E_POINTER;
  1065. }
  1066. //
  1067. // Release the old event sink
  1068. //
  1069. if( m_pEventSink )
  1070. {
  1071. m_pEventSink->Release();
  1072. m_pEventSink = NULL;
  1073. }
  1074. //
  1075. // Set the new event sink
  1076. //
  1077. m_pEventSink = pSink;
  1078. m_pEventSink->AddRef();
  1079. LOG((MSP_TRACE, "CFPTerminal::RegisterSink - exit S_OK"));
  1080. return S_OK;
  1081. }
  1082. HRESULT CFPTerminal::UnregisterSink()
  1083. {
  1084. //
  1085. // Critical section
  1086. //
  1087. CLock lock(m_Lock);
  1088. LOG((MSP_TRACE, "CFPTerminal::UnregisterSink - enter [%p]", this));
  1089. //
  1090. // Release the old event sink
  1091. //
  1092. if( m_pEventSink )
  1093. {
  1094. m_pEventSink->Release();
  1095. m_pEventSink = NULL;
  1096. }
  1097. LOG((MSP_TRACE, "CFPTerminal::UnregisterSink - exit S_OK"));
  1098. return S_OK;
  1099. }
  1100. /*++
  1101. IsTrackCreated
  1102. Verify if is already a specific track created
  1103. Is called by CreateMediaTrack method
  1104. --*/
  1105. int CFPTerminal::TracksCreated(
  1106. IN long lMediaType
  1107. )
  1108. {
  1109. LOG((MSP_TRACE, "CFPTerminal::IsTrackCreated[%p] - enter", this));
  1110. int nCreated = 0;
  1111. IEnumTerminal* pTerminals = NULL;
  1112. HRESULT hr = E_FAIL;
  1113. hr = EnumerateTrackTerminals(&pTerminals);
  1114. if( FAILED(hr) )
  1115. {
  1116. LOG((MSP_ERROR, "CFPTerminal::IsTrackCreated - exit "
  1117. "EnumerateTrackTerminals failed %d", nCreated));
  1118. return nCreated;
  1119. }
  1120. //
  1121. // Parse the tracks
  1122. //
  1123. ITTerminal* pTerminal = NULL;
  1124. ULONG ulFetched = 0;
  1125. while ( pTerminals->Next(1, &pTerminal, &ulFetched) == S_OK)
  1126. {
  1127. //
  1128. // Get the mediatype supported by the terminal
  1129. //
  1130. long nTerminalMediaType =0;
  1131. hr = pTerminal->get_MediaType( &nTerminalMediaType);
  1132. if (SUCCEEDED(hr) )
  1133. {
  1134. if( nTerminalMediaType == lMediaType)
  1135. {
  1136. nCreated++;
  1137. }
  1138. }
  1139. //
  1140. // Clean-up
  1141. //
  1142. pTerminal->Release();
  1143. pTerminal = NULL;
  1144. }
  1145. //
  1146. // Clean-up
  1147. //
  1148. pTerminals->Release();
  1149. LOG((MSP_TRACE, "CFPTerminal::IsTrackCreated - exit %d", nCreated));
  1150. return nCreated;
  1151. }
  1152. typedef IDispatchImpl<ITMediaPlaybackVtbl<CFPTerminal>, &IID_ITMediaPlayback, &LIBID_TAPI3Lib> CTMediaPlayBack;
  1153. typedef IDispatchImpl<ITTerminalVtbl<CFPTerminal>, &IID_ITTerminal, &LIBID_TAPI3Lib> CTTerminal;
  1154. typedef IDispatchImpl<ITMediaControlVtbl<CFPTerminal>, &IID_ITMediaControl, &LIBID_TAPI3Lib> CTMediaControl;
  1155. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  1156. //
  1157. // CFPTerminal::GetIDsOfNames
  1158. //
  1159. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  1160. STDMETHODIMP CFPTerminal::GetIDsOfNames(REFIID riid,
  1161. LPOLESTR* rgszNames,
  1162. UINT cNames,
  1163. LCID lcid,
  1164. DISPID* rgdispid
  1165. )
  1166. {
  1167. LOG((MSP_TRACE, "CFPTerminal::GetIDsOfNames[%p] - enter. Name [%S]",this, *rgszNames));
  1168. HRESULT hr = DISP_E_UNKNOWNNAME;
  1169. //
  1170. // See if the requsted method belongs to the default interface
  1171. //
  1172. hr = CTTerminal::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  1173. if (SUCCEEDED(hr))
  1174. {
  1175. LOG((MSP_TRACE, "CFPTerminal::GetIDsOfNames - found %S on CTTerminal", *rgszNames));
  1176. rgdispid[0] |= 0;
  1177. return hr;
  1178. }
  1179. //
  1180. // If not, then try the ITMediaControl interface
  1181. //
  1182. hr = CTMediaControl::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  1183. if (SUCCEEDED(hr))
  1184. {
  1185. LOG((MSP_TRACE, "CFPTerminal::GetIDsOfNames - found %S on ITMediaControl", *rgszNames));
  1186. rgdispid[0] |= IDISPMEDIACONTROL;
  1187. return hr;
  1188. }
  1189. //
  1190. // If not, then try the CTMediaPlayBack interface
  1191. //
  1192. hr = CTMediaPlayBack::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  1193. if (SUCCEEDED(hr))
  1194. {
  1195. LOG((MSP_TRACE, "CFPTerminal::GetIDsOfNames - found %S on CTMediaPlayBack", *rgszNames));
  1196. rgdispid[0] |= IDISPMEDIAPLAYBACK;
  1197. return hr;
  1198. }
  1199. //
  1200. // If not, then try CTMultiTrack
  1201. //
  1202. hr = CTMultiTrack::GetIDsOfNames(riid, rgszNames, cNames, lcid, rgdispid);
  1203. if (SUCCEEDED(hr))
  1204. {
  1205. LOG((MSP_TRACE, "CFPTerminal::GetIDsOfNames - found %S on CTMultiTrack", *rgszNames));
  1206. rgdispid[0] |= IDISPMULTITRACK;
  1207. return hr;
  1208. }
  1209. LOG((MSP_ERROR, "CFPTerminal::GetIDsOfNames[%p] - finish. didn't find %S on our iterfaces",*rgszNames));
  1210. return hr;
  1211. }
  1212. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  1213. //
  1214. // CFPTerminal::Invoke
  1215. //
  1216. //+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
  1217. STDMETHODIMP CFPTerminal::Invoke(DISPID dispidMember,
  1218. REFIID riid,
  1219. LCID lcid,
  1220. WORD wFlags,
  1221. DISPPARAMS* pdispparams,
  1222. VARIANT* pvarResult,
  1223. EXCEPINFO* pexcepinfo,
  1224. UINT* puArgErr
  1225. )
  1226. {
  1227. LOG((MSP_TRACE, "CFPTerminal::Invoke[%p] - enter. dispidMember %lx",this, dispidMember));
  1228. HRESULT hr = DISP_E_MEMBERNOTFOUND;
  1229. DWORD dwInterface = (dispidMember & INTERFACEMASK);
  1230. //
  1231. // Call invoke for the required interface
  1232. //
  1233. switch (dwInterface)
  1234. {
  1235. case 0:
  1236. {
  1237. hr = CTTerminal::Invoke(dispidMember,
  1238. riid,
  1239. lcid,
  1240. wFlags,
  1241. pdispparams,
  1242. pvarResult,
  1243. pexcepinfo,
  1244. puArgErr
  1245. );
  1246. LOG((MSP_TRACE, "CFPTerminal::Invoke - ITTerminal"));
  1247. break;
  1248. }
  1249. case IDISPMEDIACONTROL:
  1250. {
  1251. hr = CTMediaControl::Invoke(dispidMember,
  1252. riid,
  1253. lcid,
  1254. wFlags,
  1255. pdispparams,
  1256. pvarResult,
  1257. pexcepinfo,
  1258. puArgErr
  1259. );
  1260. LOG((MSP_TRACE, "CFPTerminal::Invoke - ITMediaControl"));
  1261. break;
  1262. }
  1263. case IDISPMEDIAPLAYBACK:
  1264. {
  1265. hr = CTMediaPlayBack::Invoke( dispidMember,
  1266. riid,
  1267. lcid,
  1268. wFlags,
  1269. pdispparams,
  1270. pvarResult,
  1271. pexcepinfo,
  1272. puArgErr
  1273. );
  1274. LOG((MSP_TRACE, "CFPTerminal::Invoke - ITMediaPlayBack"));
  1275. break;
  1276. }
  1277. case IDISPMULTITRACK:
  1278. {
  1279. hr = CTMultiTrack::Invoke(dispidMember,
  1280. riid,
  1281. lcid,
  1282. wFlags,
  1283. pdispparams,
  1284. pvarResult,
  1285. pexcepinfo,
  1286. puArgErr
  1287. );
  1288. LOG((MSP_TRACE, "CFPTerminal::Invoke - ITMultiTrackTerminal"));
  1289. break;
  1290. }
  1291. } // end switch (dwInterface)
  1292. LOG((MSP_TRACE, "CFPTerminal::Invoke[%p] - finish. hr = %lx", hr));
  1293. return hr;
  1294. }
  1295. //
  1296. // a helper method that fires events on one of the tracks
  1297. //
  1298. HRESULT CFPTerminal::FireEvent(
  1299. TERMINAL_MEDIA_STATE ftsState,
  1300. FT_STATE_EVENT_CAUSE ftecEventCause,
  1301. HRESULT hrErrorCode
  1302. )
  1303. {
  1304. LOG((MSP_TRACE, "CFPTerminal::FireEvent[%p] - enter.", this));
  1305. //
  1306. // try to fire the event on one of the tracks
  1307. //
  1308. IEnumTerminal *pEnumTerminal = NULL;
  1309. HRESULT hr = EnumerateTrackTerminals(&pEnumTerminal);
  1310. if (FAILED(hr))
  1311. {
  1312. LOG((MSP_ERROR, "CFPTerminal::FireEvent - failed to enumerate track terminals. hr = %lx", hr));
  1313. return hr;
  1314. }
  1315. //
  1316. // iterate through the list of terminals
  1317. //
  1318. while (TRUE)
  1319. {
  1320. //
  1321. // fetch a track terminal
  1322. //
  1323. ITTerminal *pTrackTerminal = NULL;
  1324. ULONG ulFetched = 0;
  1325. hr = pEnumTerminal->Next(1, &pTrackTerminal, &ulFetched);
  1326. if (S_OK != hr )
  1327. {
  1328. LOG((MSP_WARN, "CFPTerminal::FireEvent - enumeration ended. event was not fired. hr = %lx", hr));
  1329. hr = E_FAIL;
  1330. break;
  1331. }
  1332. //
  1333. // attempt to fire event on this track
  1334. //
  1335. //
  1336. // each track should be a CFPTrack
  1337. //
  1338. CFPTrack *pPlaybackTrackObject = static_cast<CFPTrack *>(pTrackTerminal);
  1339. //
  1340. // try to fire the event
  1341. //
  1342. hr = pPlaybackTrackObject->FireEvent(ftsState,
  1343. ftecEventCause,
  1344. hrErrorCode);
  1345. //
  1346. // release the current track
  1347. //
  1348. pPlaybackTrackObject = NULL;
  1349. pTrackTerminal->Release();
  1350. pTrackTerminal = NULL;
  1351. //
  1352. // if succeeded, we are done. otherwise try the next track
  1353. //
  1354. if (SUCCEEDED(hr))
  1355. {
  1356. LOG((MSP_TRACE, "CFPTerminal::FireEvent - event fired"));
  1357. break;
  1358. }
  1359. } // while walking through tracks
  1360. //
  1361. // no longer need the enumeration
  1362. //
  1363. pEnumTerminal->Release();
  1364. pEnumTerminal = NULL;
  1365. LOG((MSP_TRACE, "CFPTerminal::FireEvent - finish. hr = %lx", hr));
  1366. return hr;
  1367. }
  1368. //////////////////////////////////////////////////////////////////////////////
  1369. //
  1370. // CFPTerminal::TrackStateChange
  1371. //
  1372. // this method is called by tracks when they decide to make a state change. the
  1373. // reporting track tells us its new state, cause of event, and hr
  1374. //
  1375. HRESULT CFPTerminal::TrackStateChange(TERMINAL_MEDIA_STATE ftsState,
  1376. FT_STATE_EVENT_CAUSE ftecEventCause,
  1377. HRESULT hrErrorCode)
  1378. {
  1379. LOG((MSP_TRACE, "CFPTerminal::TrackStateChange[%p] - enter. state [%x] cause [%x] hresult [%lx]", this, ftsState, ftecEventCause, hrErrorCode));
  1380. HRESULT hr = S_OK;
  1381. CLock lock(m_Lock);
  1382. //
  1383. // do appropriate processing
  1384. //
  1385. switch (ftsState)
  1386. {
  1387. case TMS_IDLE:
  1388. {
  1389. //
  1390. // the track decided to stop. attempt to stop all tracks and fire an event
  1391. //
  1392. LOG((MSP_TRACE, "CFPTerminal::TrackStateChange - a track transitioned to TMS_IDLE"));
  1393. StopAllTracks();
  1394. //
  1395. // the terminal is now stoped. update state.
  1396. //
  1397. m_State = TMS_IDLE;
  1398. //
  1399. // Try to play the next file. If there is no next file
  1400. // the method will return E_INVAlIDARG and we'll not fire the
  1401. // error read event. If the next file exist but Direct Show cannot play it
  1402. // then we'll fire an extra evnt for this error
  1403. //
  1404. //
  1405. // Set the next index into the play list
  1406. //
  1407. hr = NextPlayIndex();
  1408. if( FAILED(hr) )
  1409. {
  1410. LOG((MSP_TRACE, "CFPTerminal::TrackStateChange - NextPlayIndex failed 0x%08x", hr));
  1411. goto Failure;
  1412. }
  1413. //
  1414. // Try to play the item from the new index
  1415. //
  1416. hr = PlayItem( m_nPlayIndex );
  1417. if( FAILED(hr) )
  1418. {
  1419. LOG((MSP_TRACE, "CFPTerminal::TrackStateChange - PlayItem failed 0x%08x", hr));
  1420. goto Failure;
  1421. }
  1422. //
  1423. // Play item succeeded
  1424. //
  1425. hr = Start();
  1426. if( SUCCEEDED(hr) )
  1427. {
  1428. LOG((MSP_TRACE, "CFPTerminal::TrackStateChange - finish. Returns S_OK (next file)"));
  1429. return S_OK;
  1430. }
  1431. Failure:
  1432. //
  1433. // Something was wrong with the next file. E_INVALIDARG means no next file
  1434. // so we don't have to fire the extra event. If the error was signaled by the
  1435. // Direct Show then we'll fire the extra error event
  1436. //
  1437. if( hr != E_INVALIDARG )
  1438. {
  1439. LOG((MSP_TRACE, "CFPTerminal::TrackStateChange - "
  1440. "something wrong with the next file 0x%08x", hr));
  1441. FireEvent( TMS_IDLE, FTEC_READ_ERROR, hr);
  1442. }
  1443. m_nPlayIndex = PLAYBACK_NOPLAYITEM;
  1444. }
  1445. FireEvent(ftsState, ftecEventCause, hrErrorCode);
  1446. hr = S_OK;
  1447. break;
  1448. case TMS_ACTIVE:
  1449. case TMS_PAUSED:
  1450. default:
  1451. LOG((MSP_ERROR, "CFPTerminal::TrackStateChange - unhandled state transitioned, state = %ld", ftsState));
  1452. hr = E_UNEXPECTED;
  1453. break;
  1454. }
  1455. LOG((MSP_TRACE, "CFPTerminal::TrackStateChange - finish. hr = %lx", hr));
  1456. return hr;
  1457. }
  1458. /*++
  1459. ValidatePlayList
  1460. This methos is called by put_PlayList() method and validates
  1461. the argument.
  1462. Returns the left and right bound if everything is OK
  1463. --*/
  1464. HRESULT CFPTerminal::ValidatePlayList(
  1465. IN VARIANTARG varPlayList,
  1466. OUT long* pnLeftBound,
  1467. OUT long* pnRightBound
  1468. )
  1469. {
  1470. LOG((MSP_TRACE, "CFPTerminal::ValidatePlayList[%p] - enter", this));
  1471. HRESULT hr = S_OK;
  1472. *pnLeftBound = 0;
  1473. *pnRightBound = 0;
  1474. //
  1475. // Validates argument
  1476. //
  1477. if( varPlayList.vt != (VT_ARRAY | VT_VARIANT))
  1478. {
  1479. LOG((MSP_TRACE, "CFPTerminal::ValidatePlayList - exit "
  1480. " is not a VT_VARIANT array, return E_INVALIDARG"));
  1481. return E_INVALIDARG;
  1482. }
  1483. //
  1484. // Is array of files or storages empty?
  1485. //
  1486. if( 0 == SafeArrayGetDim( V_ARRAY(&varPlayList) ) )
  1487. {
  1488. LOG((MSP_ERROR, "CFPTerminal::ValidatePlayList - exit "
  1489. "the array is empty; returning E_INVALIDARG"));
  1490. return E_INVALIDARG;
  1491. }
  1492. //
  1493. // Get the bounds of the array
  1494. //
  1495. long lLBound = 0,
  1496. lUBound = 0;
  1497. //
  1498. // Get the LBound
  1499. //
  1500. hr = SafeArrayGetLBound( V_ARRAY(&varPlayList), 1, &lLBound);
  1501. if(FAILED(hr))
  1502. {
  1503. LOG((MSP_ERROR, "CFPTerminal::ValidatePlayList - exit "
  1504. "get lbound failed; returning E_INVALIDARG"));
  1505. return E_INVALIDARG;
  1506. }
  1507. //
  1508. // Get the UBound
  1509. //
  1510. hr = SafeArrayGetUBound(V_ARRAY(&varPlayList), 1, &lUBound);
  1511. if(FAILED(hr))
  1512. {
  1513. LOG((MSP_ERROR, "CFPTerminal::ValidatePlayList - exit "
  1514. "get ubound failed; returning E_INVALIDARG"));
  1515. return E_INVALIDARG;
  1516. }
  1517. //
  1518. // Check the bounds, the testers can do anything, even this
  1519. //
  1520. if(lLBound > lUBound)
  1521. {
  1522. LOG((MSP_ERROR, "CFPTerminal::ValidatePlayList - exit "
  1523. "the bounds are switched; returning E_INVALIDARG"));
  1524. return E_INVALIDARG;
  1525. }
  1526. //
  1527. // Return bounds
  1528. //
  1529. *pnLeftBound = lLBound;
  1530. *pnRightBound = lUBound;
  1531. LOG((MSP_TRACE, "CFPTerminal::ValidatePlayList - exit 0x%08x", hr));
  1532. return hr;
  1533. }
  1534. /*++
  1535. RollbackTrackInfo
  1536. It is called by CreateTempPlayList() method and if some play item
  1537. wanted to add a track the information is rollbacked
  1538. --*/
  1539. HRESULT CFPTerminal::RollbackTrackInfo()
  1540. {
  1541. LOG((MSP_TRACE, "CFPTerminal::RollbackTrackInfo[%p] - enter", this));
  1542. LOG((MSP_TRACE, "CFPTerminal::RollbackTrackInfo - exit S_OK"));
  1543. return S_OK;
  1544. }
  1545. HRESULT CFPTerminal::ShutdownTracks()
  1546. {
  1547. LOG((MSP_TRACE, "CFPTerminal::ShutdownTracks[%p] - enter", this));
  1548. {
  1549. //
  1550. // access data member array in a lock
  1551. //
  1552. CLock lock(m_lock);
  1553. int nNumberOfTerminalsInArray = m_TrackTerminals.GetSize();
  1554. for (int i = 0; i < nNumberOfTerminalsInArray; i++)
  1555. {
  1556. //
  1557. // release and remove the first terminal in the array
  1558. //
  1559. LOG((MSP_TRACE, "CFPTerminal::ShutdownTracks - removing track [%p]", m_TrackTerminals[0]));
  1560. //
  1561. // uninitialize the track, release it, and remove from our list of managed tracks
  1562. //
  1563. HRESULT hr = InternalRemoveTrackTerminal(m_TrackTerminals[0]);
  1564. if (FAILED(hr))
  1565. {
  1566. LOG((MSP_ERROR, "CFPTerminal::ShutdownTracks - track failed to be removed"));
  1567. //
  1568. // there is no reason why this should not succeed. debug to see why it failed.
  1569. //
  1570. TM_ASSERT(FALSE);
  1571. //
  1572. // remove the track anyway. hopefully , at least
  1573. // SetParent(NULL) in RemoveTrackTerminal succeeded,
  1574. // so we'll never hear from the track again
  1575. //
  1576. CMultiTrackTerminal::RemoveTrackTerminal(m_TrackTerminals[0]);
  1577. }
  1578. }
  1579. //
  1580. // we should have cleared the array
  1581. //
  1582. TM_ASSERT(0 == m_TrackTerminals.GetSize());
  1583. }
  1584. LOG((MSP_TRACE, "CFPTerminal::ShutdownTracks - finish"));
  1585. return S_OK;
  1586. }
  1587. //////////////////////////////////////////////////////////////////////////////
  1588. //
  1589. // CFPTerminal::InternalRemoveTrackTerminal
  1590. //
  1591. // uninitializes the track and removes it from the list of tracks managed by
  1592. // this terminal, thus releasing it.
  1593. //
  1594. // at this point, i, the playback terminal, should be the only guy holding a
  1595. // reference to the track, so the track would normally be destroyed by the time
  1596. // this function returns.
  1597. //
  1598. HRESULT CFPTerminal::InternalRemoveTrackTerminal(
  1599. IN ITTerminal *pTrackTerminalToRemove
  1600. )
  1601. {
  1602. LOG((MSP_TRACE,
  1603. "CFPTerminal::InternalRemoveTrackTerminal[%p] - enter. pTrackTerminalToRemove = [%p]",
  1604. this, pTrackTerminalToRemove));
  1605. //
  1606. // get track
  1607. //
  1608. CFPTrack *pPlaybackTrackObject = static_cast<CFPTrack *>(pTrackTerminalToRemove);
  1609. if (IsBadReadPtr(pPlaybackTrackObject, sizeof(CFPTrack) ) )
  1610. {
  1611. LOG((MSP_ERROR, "CFPTerminal::InternalRemoveTrackTerminal - the track pointer is bad"));
  1612. return E_POINTER;
  1613. }
  1614. CLock lock(m_lock);
  1615. //
  1616. // see if we actually own the track
  1617. //
  1618. BOOL bIsValidTrack = DoIManageThisTrack(pTrackTerminalToRemove);
  1619. if (!bIsValidTrack)
  1620. {
  1621. LOG((MSP_ERROR, "CFPTerminal::InternalRemoveTrackTerminal - the track does not belong to me"));
  1622. return E_INVALIDARG;
  1623. }
  1624. //
  1625. // yes, this is one of my tracks. I want nothing to do with it
  1626. //
  1627. //
  1628. // orphan the track and get the number of oustanding references it has
  1629. // as far as the track is concerned, this is an atomic operation.
  1630. //
  1631. // at this point, there is at least one oustanding reference to the track
  1632. // (this terminal's array)
  1633. //
  1634. LONG lTracksRefcount = 0;
  1635. HRESULT hr = pPlaybackTrackObject->SetParent(NULL, &lTracksRefcount);
  1636. if (FAILED(hr))
  1637. {
  1638. //
  1639. // this should not really happen -- SetParent should always succeed
  1640. //
  1641. LOG((MSP_ERROR, "CFPTerminal::InternalRemoveTrackTerminal - pPlaybackTrackObject->SetParent(NULL) failed. hr = %lx", hr));
  1642. TM_ASSERT(FALSE);
  1643. return E_UNEXPECTED;
  1644. }
  1645. //
  1646. // at this point, the track terminal should have at most 2
  1647. // references -- one by us and the other one by however is in process
  1648. // of releasing the track (if anyone)
  1649. //
  1650. if (lTracksRefcount > 2)
  1651. {
  1652. LOG((MSP_ERROR,
  1653. "CFPTerminal::InternalRemoveTrackTerminal - the track that we are removing has refcount of %ld",
  1654. lTracksRefcount));
  1655. //
  1656. // debug to see why this happened.
  1657. //
  1658. TM_ASSERT(FALSE);
  1659. //
  1660. // proceed anyway
  1661. //
  1662. }
  1663. //
  1664. // the track is no longer my responsibility, so decrement my child refcount
  1665. // by the track's refcount. once again,
  1666. //
  1667. m_dwRef -= lTracksRefcount;
  1668. /*
  1669. //
  1670. // uninitialize the track
  1671. //
  1672. hr = pPlaybackTrackObject->SetUnitPin(NULL);
  1673. if (FAILED(hr))
  1674. {
  1675. //
  1676. // this should not really happen -- uninitialization should always succeed
  1677. //
  1678. LOG((MSP_ERROR,
  1679. "CFPTerminal::InternalRemoveTrackTerminal - pPlaybackTrackObject->SetStorageStream(NULL) failed. hr = %lx",
  1680. hr));
  1681. TM_ASSERT(FALSE);
  1682. return E_UNEXPECTED;
  1683. }
  1684. */
  1685. //
  1686. // remove the terminal from the list of managed terminals
  1687. //
  1688. hr = CMultiTrackTerminal::RemoveTrackTerminal(pTrackTerminalToRemove);
  1689. if (FAILED(hr))
  1690. {
  1691. LOG((MSP_ERROR, "CFPTerminal::InternalRemoveTrackTerminal - CMultiTrackTerminal::RemoveTrackTerminal failed. hr = %lx", hr));
  1692. //
  1693. // we already checked that this track is one of our tracks, so RemoveTrackTerminal must succeed.
  1694. //
  1695. TM_ASSERT(FALSE);
  1696. return E_UNEXPECTED;
  1697. }
  1698. //
  1699. // we are done. the track is on its own now.
  1700. //
  1701. LOG((MSP_TRACE, "CFPTerminal::InternalRemoveTrackTerminal - completed. "));
  1702. return S_OK;
  1703. }
  1704. //
  1705. // Create the playback graph
  1706. //
  1707. HRESULT CFPTerminal::CreatePlaybackUnit(
  1708. IN BSTR bstrFileName
  1709. )
  1710. {
  1711. LOG((MSP_TRACE, "CFPTerminal::CreatePlaybackUnit[%p] - enter", this));
  1712. //
  1713. // If we don't have already a playback unit
  1714. // let's create one
  1715. //
  1716. if( m_pPlaybackUnit == NULL)
  1717. {
  1718. m_pPlaybackUnit = new CPlaybackUnit();
  1719. //
  1720. // Validate the playback unit
  1721. //
  1722. if( m_pPlaybackUnit == NULL)
  1723. {
  1724. LOG((MSP_ERROR, "CFPTerminal::CreatePlaybackUnit - exit"
  1725. "creation of CPlaybackUnit failed. Returns E_OUTOFMEMORY"));
  1726. return E_OUTOFMEMORY;
  1727. }
  1728. //
  1729. // Initialize the playback unit
  1730. //
  1731. HRESULT hr = m_pPlaybackUnit->Initialize( );
  1732. if( FAILED(hr) )
  1733. {
  1734. // Clean-up
  1735. delete m_pPlaybackUnit;
  1736. m_pPlaybackUnit = NULL;
  1737. LOG((MSP_ERROR, "CFPTerminal::CreatePlaybackUnit - exit"
  1738. "playbackunit initialize failed. Returns 0x%08x", hr));
  1739. return hr;
  1740. }
  1741. }
  1742. //
  1743. // Setup the playback unit using a file
  1744. //
  1745. HRESULT hr = m_pPlaybackUnit->SetupFromFile( bstrFileName );
  1746. if( FAILED(hr) )
  1747. {
  1748. // Shutdown the playback if something was wrong
  1749. m_pPlaybackUnit->Shutdown();
  1750. // Clean-up
  1751. delete m_pPlaybackUnit;
  1752. m_pPlaybackUnit = NULL;
  1753. LOG((MSP_ERROR, "CFPTerminal::CreatePlaybackUnit - exit"
  1754. "playbackunit SetupFromFile failed. Returns 0x%08x", hr));
  1755. return hr;
  1756. }
  1757. LOG((MSP_TRACE, "CFPTerminal::CreatePlaybackUnit - exit. Returns S_OK"));
  1758. return S_OK;
  1759. }
  1760. //
  1761. // returns the file name from the playlist
  1762. //
  1763. BSTR CFPTerminal::GetFileNameFromPlayList(
  1764. IN VARIANTARG varPlayList,
  1765. IN long nIndex
  1766. )
  1767. {
  1768. LOG((MSP_TRACE, "CFPTerminal::GetFileNameFromPlayList[%p] - enter", this));
  1769. BSTR bstrFileName = NULL;
  1770. HRESULT hr = E_FAIL;
  1771. VARIANT varItem;
  1772. VariantInit( &varItem );
  1773. hr = SafeArrayGetElement(V_ARRAY(&varPlayList), &nIndex, &varItem);
  1774. if( FAILED(hr) )
  1775. {
  1776. LOG((MSP_ERROR, "CFPTerminal::GetFileNameFromPlayList - exit "
  1777. "SafeArrayGetElement failed. Returns NULL"));
  1778. return NULL;
  1779. }
  1780. //
  1781. // The variant should contain or a BSTR
  1782. //
  1783. if( varItem.vt != VT_BSTR)
  1784. {
  1785. // Clean-up
  1786. VariantClear( &varItem );
  1787. LOG((MSP_ERROR, "CFPTerminal::GetFileNameFromPlayList - "
  1788. "the item is neither file nor ITStrotage. Returns NULL"));
  1789. return NULL;
  1790. }
  1791. //
  1792. // Get the file name
  1793. //
  1794. bstrFileName = SysAllocString( varItem.bstrVal );
  1795. //
  1796. // Clean-up
  1797. //
  1798. VariantClear( &varItem );
  1799. LOG((MSP_TRACE, "CFPTerminal::GetFileNameFromPlayList - exit"));
  1800. return bstrFileName;
  1801. }
  1802. //
  1803. // Using a file name, try to create the playback unit
  1804. // with the input pins and then the tracks. It's called by
  1805. // put_PlayList
  1806. //
  1807. HRESULT CFPTerminal::ConfigurePlaybackUnit(
  1808. IN BSTR bstrFileName
  1809. )
  1810. {
  1811. LOG((MSP_TRACE, "CFPTerminal::ConfigurePlaybackUnit[%p] - enter", this));
  1812. //
  1813. // It's an internal method so we should have a valid
  1814. // file name here
  1815. //
  1816. TM_ASSERT( bstrFileName );
  1817. //
  1818. // Create the playback graph and render it
  1819. //
  1820. HRESULT hr = CreatePlaybackUnit( bstrFileName );
  1821. if( FAILED(hr) )
  1822. {
  1823. LOG((MSP_ERROR, "CFPTerminal::ConfigurePlaybackUnit - "
  1824. " CreatePlaybackUnit failed. Returns 0x%08x", hr));
  1825. return hr;
  1826. }
  1827. //
  1828. // Get the media types from the unit playback
  1829. //
  1830. long nMediaTypes = 0;
  1831. hr = m_pPlaybackUnit->get_MediaTypes( &nMediaTypes );
  1832. if( FAILED(hr) )
  1833. {
  1834. // Clean-up
  1835. m_pPlaybackUnit->Shutdown();
  1836. RollbackTrackInfo();
  1837. LOG((MSP_ERROR, "CFPTerminal::ConfigurePlaybackUnit - "
  1838. " get_MediaTypes failed. Returns 0x%08x", hr));
  1839. return hr;
  1840. }
  1841. if( nMediaTypes == 0 )
  1842. {
  1843. // Clean-up
  1844. RollbackTrackInfo();
  1845. LOG((MSP_ERROR, "CFPTerminal::ConfigurePlaybackUnit - "
  1846. "no media types. Returns E_INVALIDARG"));
  1847. return E_INVALIDARG;
  1848. }
  1849. if( nMediaTypes & TAPIMEDIATYPE_AUDIO )
  1850. {
  1851. hr = CreateMediaTracks( TAPIMEDIATYPE_AUDIO );
  1852. if( FAILED(hr) )
  1853. {
  1854. // Clean-up
  1855. m_pPlaybackUnit->Shutdown();
  1856. RollbackTrackInfo();
  1857. LOG((MSP_ERROR, "CFPTerminal::ConfigurePlaybackUnit - "
  1858. "CreateTrack failed. Returns 0x%08x", hr));
  1859. return hr;
  1860. }
  1861. }
  1862. if( nMediaTypes & TAPIMEDIATYPE_VIDEO )
  1863. {
  1864. hr = CreateMediaTracks( TAPIMEDIATYPE_VIDEO );
  1865. if( FAILED(hr) )
  1866. {
  1867. // Clean-up
  1868. m_pPlaybackUnit->Shutdown();
  1869. RollbackTrackInfo();
  1870. LOG((MSP_ERROR, "CFPTerminal::ConfigurePlaybackUnit - "
  1871. "CreateTrack failed. Returns 0x%08x", hr));
  1872. return hr;
  1873. }
  1874. }
  1875. LOG((MSP_TRACE, "CFPTerminal::ConfigurePlaybackUnit - exit"));
  1876. return hr;
  1877. }
  1878. HRESULT CFPTerminal::CreateMediaTracks(
  1879. IN long nMediaType
  1880. )
  1881. {
  1882. LOG((MSP_TRACE, "CFPTerminal::CreateMediaTracks[%p] - enter", this));
  1883. //
  1884. // Do we have already a track for this media?
  1885. //
  1886. int nMediaPin = TracksCreated( nMediaType );
  1887. while(TRUE)
  1888. {
  1889. //
  1890. // Get the pin that supports this media type
  1891. //
  1892. CPBPin* pPin = NULL;
  1893. HRESULT hr = m_pPlaybackUnit->GetMediaPin( nMediaType, nMediaPin, &pPin);
  1894. if( FAILED(hr) )
  1895. {
  1896. LOG((MSP_TRACE, "CFPTerminal::CreateMediaTracks - "
  1897. " get_Pin failed. Returns S_OK"));
  1898. return S_OK;
  1899. }
  1900. //
  1901. // Get media format supported by the pin
  1902. //
  1903. AM_MEDIA_TYPE* pMediaType = NULL;
  1904. hr = pPin->get_Format( &pMediaType );
  1905. if( FAILED(hr) )
  1906. {
  1907. LOG((MSP_ERROR, "CFPTerminal::CreateMediaTracks - "
  1908. " get_Format failed. Returns 0x%08x", hr));
  1909. return hr;
  1910. }
  1911. //
  1912. // Get the ALLOCATOR_PROPERTIES
  1913. //
  1914. IMemAllocator* pMemAllocator = NULL;
  1915. hr = pPin->GetAllocator( &pMemAllocator );
  1916. if( FAILED(hr) )
  1917. {
  1918. // Clean-up
  1919. DeleteMediaType( pMediaType );
  1920. LOG((MSP_ERROR, "CFPTerminal::CreateMediaTracks - "
  1921. " GetAllocator failed. Returns 0x%08x", hr));
  1922. return hr;
  1923. }
  1924. ALLOCATOR_PROPERTIES AllocProp;
  1925. pMemAllocator->GetProperties( &AllocProp );
  1926. // Clean-up IMemAllocator
  1927. pMemAllocator->Release();
  1928. //
  1929. // Get the stream from the pin
  1930. //
  1931. IStream* pStream = NULL;
  1932. hr = pPin->get_Stream(&pStream);
  1933. if( FAILED(hr) )
  1934. {
  1935. // Clean-up
  1936. DeleteMediaType( pMediaType );
  1937. LOG((MSP_ERROR, "CFPTerminal::CreateMediaTracks - "
  1938. " get_Stream failed. Returns 0x%08x", hr));
  1939. return hr;
  1940. }
  1941. //
  1942. // Instantiate track terminal object
  1943. //
  1944. CComObject<CFPTrack> *pTrack = NULL;
  1945. hr = CComObject<CFPTrack>::CreateInstance(&pTrack);
  1946. if (FAILED(hr))
  1947. {
  1948. // Clean-up
  1949. DeleteMediaType( pMediaType );
  1950. pStream->Release();
  1951. LOG((MSP_ERROR, "CFPTerminal::CreateMediaTracks - "
  1952. "failed to create playback track terminal. Returns 0x%08x", hr));
  1953. return hr;
  1954. }
  1955. //
  1956. // Initialize internal
  1957. //
  1958. ITTerminal* pFPTerminal = NULL;
  1959. _InternalQueryInterface(IID_ITTerminal, (void**)&pFPTerminal);
  1960. hr = pTrack->InitializePrivate(
  1961. nMediaType,
  1962. pMediaType,
  1963. pFPTerminal,
  1964. AllocProp,
  1965. pStream
  1966. );
  1967. //
  1968. // Clean-up
  1969. //
  1970. DeleteMediaType( pMediaType );
  1971. pStream->Release();
  1972. if( pFPTerminal )
  1973. {
  1974. pFPTerminal->Release();
  1975. pFPTerminal = NULL;
  1976. }
  1977. if( FAILED(hr) )
  1978. {
  1979. //Clean-up
  1980. delete pTrack;
  1981. LOG((MSP_ERROR, "CFPTerminal::CreateMediaTracks - "
  1982. "Initialize failed. Returns 0x%08x", hr));
  1983. return hr;
  1984. }
  1985. //
  1986. // Get to the Track's ITTerminal interface
  1987. // to be added to the array of tracks and returned to the caller
  1988. //
  1989. ITTerminal *pTerminal = NULL;
  1990. hr = pTrack->QueryInterface(IID_ITTerminal, (void **)&pTerminal);
  1991. if (FAILED(hr))
  1992. {
  1993. //Clean-up
  1994. delete pTrack;
  1995. LOG((MSP_ERROR, "CFPTerminal::CreateMediaTracks - "
  1996. "failed to QI playback track terminal for ITTerminal. Returns 0x%08x", hr));
  1997. return hr;
  1998. }
  1999. //
  2000. // Get ITPluggableTerminalInitialization
  2001. //
  2002. ITPluggableTerminalInitialization* pTerminalInitialization = NULL;
  2003. hr = pTerminal->QueryInterface(
  2004. IID_ITPluggableTerminalInitialization,
  2005. (void**)&pTerminalInitialization);
  2006. if( FAILED(hr) )
  2007. {
  2008. // Clean-up
  2009. pTerminal->Release();
  2010. LOG((MSP_ERROR, "CFPTerminal::CreateMediaTracks - "
  2011. "failed to QI for ITPluggableTerminalInitialization. Returns 0x%08x", hr));
  2012. return hr;
  2013. }
  2014. //
  2015. // Initialize Dynamic this track terminal
  2016. //
  2017. hr = pTerminalInitialization->InitializeDynamic(
  2018. m_TerminalClassID,
  2019. (DWORD)nMediaType,
  2020. TD_CAPTURE,
  2021. m_htAddress
  2022. );
  2023. //
  2024. // Clean-up
  2025. //
  2026. pTerminalInitialization->Release();
  2027. if( FAILED(hr) )
  2028. {
  2029. // Clean-up
  2030. pTerminal->Release();
  2031. LOG((MSP_ERROR, "CFPTerminal::CreateMediaTracks - exit "
  2032. "InitializeDynamic for track failed. Returns 0x%08x", hr));
  2033. return hr;
  2034. }
  2035. //
  2036. // Add the track to the array of tracks managed by this track terminal
  2037. // this will increment refcount
  2038. //
  2039. hr = AddTrackTerminal(pTerminal);
  2040. if (FAILED(hr))
  2041. {
  2042. // Clean-up
  2043. pTerminal->Release();
  2044. LOG((MSP_ERROR, "CFPTerminal::CreateMediaTracks - exit "
  2045. "failed to add track to the array of terminals. Returns 0x%08x", hr));
  2046. return hr;
  2047. }
  2048. // Clean-up
  2049. pTerminal->Release();
  2050. nMediaPin++;
  2051. } // while
  2052. LOG((MSP_TRACE, "CFPTerminal::CreateMediaTracks exit S_OK"));
  2053. return S_OK;
  2054. }
  2055. //
  2056. // Helper method that causes a state transition
  2057. //
  2058. HRESULT CFPTerminal::DoStateTransition(
  2059. IN TERMINAL_MEDIA_STATE tmsDesiredState
  2060. )
  2061. {
  2062. LOG((MSP_TRACE, "CFPTerminal::DoStateTransition[%p] - enter. tmsDesiredState[%ld], playbackunit=%p",
  2063. this, tmsDesiredState, m_pPlaybackUnit));
  2064. //
  2065. // Validate the playback unit.
  2066. // There should be a playback unit
  2067. //
  2068. if( m_pPlaybackUnit == NULL )
  2069. {
  2070. LOG((MSP_ERROR,
  2071. "CFPTerminal::DoStateTransition - no playback unit [%p]. Returns TAPI_E_WRONG_STATE", m_pPlaybackUnit));
  2072. return TAPI_E_WRONG_STATE;
  2073. }
  2074. //
  2075. // are we already in the desired state?
  2076. //
  2077. if (tmsDesiredState == m_State)
  2078. {
  2079. LOG((MSP_TRACE,
  2080. "CFPTerminal::DoStateTransition - already in this state. nothing to do"));
  2081. return S_FALSE;
  2082. }
  2083. HRESULT hr = E_FAIL;
  2084. //
  2085. // attempt to make state transition
  2086. //
  2087. switch (tmsDesiredState)
  2088. {
  2089. case TMS_ACTIVE:
  2090. LOG((MSP_TRACE,
  2091. "CFPTerminal::DoStateTransition - Starting"));
  2092. hr = m_pPlaybackUnit->Start();
  2093. break;
  2094. case TMS_IDLE:
  2095. LOG((MSP_TRACE,
  2096. "CFPTerminal::DoStateTransition - Stopped"));
  2097. hr = m_pPlaybackUnit->Stop();
  2098. break;
  2099. case TMS_PAUSED:
  2100. LOG((MSP_TRACE,
  2101. "CFPTerminal::DoStateTransition - Paused"));
  2102. hr = m_pPlaybackUnit->Pause();
  2103. break;
  2104. default :
  2105. LOG((MSP_ERROR,
  2106. "CFPTerminal::DoStateTransition - unknown state"));
  2107. hr = E_UNEXPECTED;
  2108. TM_ASSERT(FALSE);
  2109. break;
  2110. }
  2111. //
  2112. // did state transition succeed?
  2113. //
  2114. if (FAILED(hr))
  2115. {
  2116. LOG((MSP_TRACE, "CFPTerminal::DoStateTransition - failed to make the transition."));
  2117. return hr;
  2118. }
  2119. //
  2120. // the terminal has completed transition to the new state
  2121. //
  2122. m_State = tmsDesiredState;
  2123. //
  2124. // fire event to the app. best effort, no benefit in checking return code
  2125. //
  2126. //FireEvent(m_State, FTEC_NORMAL, S_OK);
  2127. LOG((MSP_TRACE, "CFPTerminal::DoStateTransition - finish."));
  2128. return S_OK;
  2129. }
  2130. // --- IFPBridge ---
  2131. HRESULT CFPTerminal::Deliver(
  2132. IN long nMediaType,
  2133. IN IMediaSample* pSample
  2134. )
  2135. {
  2136. LOG((MSP_TRACE, "CFPTerminal::Deliver[%p] - enter.", this));
  2137. /* //
  2138. // Critical section
  2139. //
  2140. CLock lock(m_Lock);
  2141. //
  2142. // Get the track for nMediatype
  2143. //
  2144. ITTerminal* pTrackTerminal = NULL;
  2145. if( !IsTrackCreated( nMediaType, &pTrackTerminal) )
  2146. {
  2147. //
  2148. // we don't have a track for this media type
  2149. //
  2150. LOG((MSP_ERROR,
  2151. "CFPTerminal::Deliver - exit "
  2152. "no track for %ld media. Returns E_UNEXPECTED", nMediaType));
  2153. TM_ASSERT(FALSE);
  2154. return E_UNEXPECTED;
  2155. }
  2156. TM_ASSERT( pTrackTerminal );
  2157. //
  2158. // Get the IFPBridge interface
  2159. //
  2160. CFPTrack* pTrack = dynamic_cast<CFPTrack*>(pTrackTerminal);
  2161. if( pTrack == NULL )
  2162. {
  2163. //
  2164. // we don't have a track for this media type
  2165. //
  2166. LOG((MSP_ERROR,
  2167. "CFPTerminal::Deliver - exit "
  2168. "wrong cast. Returns E_UNEXPECTED"));
  2169. TM_ASSERT(FALSE);
  2170. return E_UNEXPECTED;
  2171. }
  2172. //
  2173. // Deliver the sample to the track
  2174. //
  2175. HRESULT hr = pTrack->Deliver(
  2176. nMediaType,
  2177. pSample
  2178. );
  2179. if( FAILED(hr) )
  2180. {
  2181. LOG((MSP_ERROR,
  2182. "CFPTerminal::Deliver - exit "
  2183. "track Deliver failed. Returns 0x%08x", hr));
  2184. return hr;
  2185. }
  2186. */
  2187. LOG((MSP_TRACE, "CFPTerminal::Deliver - exit S_OK"));
  2188. return S_OK;
  2189. }
  2190. HRESULT CFPTerminal::PlayItem(
  2191. IN int nItem
  2192. )
  2193. {
  2194. LOG((MSP_TRACE, "CFPTerminal::PlayItem[%p] - enter.", this));
  2195. //
  2196. // Critical section
  2197. //
  2198. CLock lock(m_Lock);
  2199. BSTR bstrFileName = GetFileNameFromPlayList(
  2200. m_varPlayList,
  2201. nItem
  2202. );
  2203. if( bstrFileName == NULL )
  2204. {
  2205. LOG((MSP_ERROR, "CFPTerminal::PlayItem - "
  2206. " GetFileNameFromPlayList failed. Returns E_INVAlIDARG"));
  2207. return E_INVALIDARG;
  2208. }
  2209. //
  2210. // Play the file from the list
  2211. //
  2212. HRESULT hr = ConfigurePlaybackUnit( bstrFileName );
  2213. //
  2214. // Clan-up the file name
  2215. //
  2216. SysFreeString( bstrFileName );
  2217. if( FAILED(hr) )
  2218. {
  2219. LOG((MSP_ERROR, "CFPTerminal::PlayItem - "
  2220. " ConfigurePlaybackUnit failed. Returns 0x%08x", hr));
  2221. return hr;
  2222. }
  2223. LOG((MSP_TRACE, "CFPTerminal::Deliver - exit S_OK"));
  2224. return S_OK;
  2225. }
  2226. /*++
  2227. NextPlayIndex
  2228. This method increments the play index.
  2229. If the playindex is NOPLAYITEM then the new valu will be
  2230. set to the lBound element in the playlist. If there is an error
  2231. we return PLAYBACK_NOPLAYITEM
  2232. ++*/
  2233. HRESULT CFPTerminal::NextPlayIndex(
  2234. )
  2235. {
  2236. LOG((MSP_TRACE, "CFPTerminal::NextPlayIndex[%p] - enter.", this));
  2237. //
  2238. // It this a normal index
  2239. //
  2240. if( m_nPlayIndex != PLAYBACK_NOPLAYITEM )
  2241. {
  2242. m_nPlayIndex++;
  2243. LOG((MSP_TRACE, "CFPTerminal::NextPlayIndex - exit S_OK. Index=%d", m_nPlayIndex));
  2244. return S_OK;
  2245. }
  2246. //
  2247. // This is the first time. We have togo to the first
  2248. // item in the play list
  2249. //
  2250. long lLBound = 0;
  2251. HRESULT hr = SafeArrayGetLBound( V_ARRAY(&m_varPlayList), 1, &lLBound);
  2252. if( FAILED(hr) )
  2253. {
  2254. m_nPlayIndex = PLAYBACK_NOPLAYITEM;
  2255. LOG((MSP_TRACE, "CFPTerminal::NextPlayIndex - exit E_INVALIDARG. Index=PLAYBACK_NOPLAYITEM", hr));
  2256. return E_INVALIDARG;
  2257. }
  2258. //
  2259. // Set the index to the left inbound
  2260. //
  2261. m_nPlayIndex = lLBound;
  2262. LOG((MSP_TRACE, "CFPTerminal::NextPlayIndex - exit S_OK. Index=%d", m_nPlayIndex));
  2263. return S_OK;
  2264. }