1
0

audioswitch.cpp 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791
  1. #include <windows.h>
  2. #include <AtlBase.h>
  3. #include <streams.h>
  4. #include <strsafe.h>
  5. #include <qnetwork.h>
  6. #include <initguid.h> // declares DEFINE_GUID to declare an EXTERN_C const.
  7. #include "audioswitch.h"
  8. // Implements the CAudioSwitchRenderer class
  9. CAudioSwitchRenderer::CAudioSwitchRenderer(REFCLSID RenderClass, // CLSID for this renderer
  10. TCHAR *pName, // Debug ONLY description
  11. LPUNKNOWN pUnk, // Aggregated owner object
  12. HRESULT *phr) : // General OLE return code
  13. CBaseFilter(pName, pUnk, &m_InterfaceLock, RenderClass),
  14. m_evComplete(TRUE),
  15. m_bAbort(FALSE),
  16. m_pPosition(NULL),
  17. m_ThreadSignal(TRUE),
  18. m_bStreaming(FALSE),
  19. m_bEOS(FALSE),
  20. m_bEOSDelivered(FALSE),
  21. m_dwAdvise(0),
  22. m_pQSink(NULL),
  23. m_bRepaintStatus(TRUE),
  24. m_SignalTime(0),
  25. m_bInReceive(FALSE),
  26. m_EndOfStreamTimer(0),
  27. m_inputSelected(0)
  28. {
  29. for (int i = 0;i < 16;i++) m_pInputPin[i] = NULL;
  30. for (int i = 0;i < 16;i++) m_pMediaSample[i] = NULL;
  31. Ready();
  32. #ifdef PERF
  33. m_idBaseStamp = MSR_REGISTER("BaseRenderer: sample time stamp");
  34. m_idBaseRenderTime = MSR_REGISTER("BaseRenderer: draw time (msec)");
  35. m_idBaseAccuracy = MSR_REGISTER("BaseRenderer: Accuracy (msec)");
  36. #endif
  37. }
  38. // Delete the dynamically allocated IMediaPosition and IMediaSeeking helper
  39. // object. The object is created when somebody queries us. These are standard
  40. // control interfaces for seeking and setting start/stop positions and rates.
  41. // We will probably also have made an input pin based on CAudioSwitchRendererInputPin
  42. // that has to be deleted, it's created when an enumerator calls our GetPin
  43. CAudioSwitchRenderer::~CAudioSwitchRenderer()
  44. {
  45. ASSERT(m_bStreaming == FALSE);
  46. ASSERT(m_EndOfStreamTimer == 0);
  47. StopStreaming();
  48. ClearPendingSample();
  49. // Delete any IMediaPosition implementation
  50. if (m_pPosition)
  51. {
  52. delete m_pPosition;
  53. m_pPosition = NULL;
  54. }
  55. // Delete any input pin created
  56. for (int i = 0;i < 16;i++)
  57. {
  58. if (m_pInputPin[i])
  59. {
  60. delete m_pInputPin[i];
  61. m_pInputPin[i] = NULL;
  62. }
  63. }
  64. // Release any Quality sink
  65. ASSERT(m_pQSink == NULL);
  66. }
  67. // This returns the IMediaPosition and IMediaSeeking interfaces
  68. HRESULT CAudioSwitchRenderer::GetMediaPositionInterface(REFIID riid, void **ppv)
  69. {
  70. CAutoLock cRendererLock(&m_InterfaceLock);
  71. if (m_pPosition)
  72. {
  73. return m_pPosition->NonDelegatingQueryInterface(riid, ppv);
  74. }
  75. HRESULT hr = NOERROR;
  76. // Create implementation of this dynamically since sometimes we may
  77. // never try and do a seek. The helper object implements a position
  78. // control interface (IMediaPosition) which in fact simply takes the
  79. // calls normally from the filter graph and passes them upstream
  80. m_pPosition = new CRendererPosPassThru(NAME("Renderer CPosPassThru"),
  81. CBaseFilter::GetOwner(),
  82. (HRESULT *) & hr,
  83. GetPin(m_inputSelected));
  84. if (m_pPosition == NULL)
  85. {
  86. return E_OUTOFMEMORY;
  87. }
  88. if (FAILED(hr))
  89. {
  90. delete m_pPosition;
  91. m_pPosition = NULL;
  92. return E_NOINTERFACE;
  93. }
  94. return GetMediaPositionInterface(riid, ppv);
  95. }
  96. // Overriden to say what interfaces we support and where
  97. STDMETHODIMP CAudioSwitchRenderer::NonDelegatingQueryInterface(REFIID riid, void **ppv)
  98. {
  99. // Do we have this interface
  100. if (riid == IID_IMediaPosition || riid == IID_IMediaSeeking)
  101. {
  102. return GetMediaPositionInterface(riid, ppv);
  103. }
  104. else
  105. {
  106. return CBaseFilter::NonDelegatingQueryInterface(riid, ppv);
  107. }
  108. }
  109. // This is called whenever we change states, we have a manual reset event that
  110. // is signalled whenever we don't won't the source filter thread to wait in us
  111. // (such as in a stopped state) and likewise is not signalled whenever it can
  112. // wait (during paused and running) this function sets or resets the thread
  113. // event. The event is used to stop source filter threads waiting in Receive
  114. HRESULT CAudioSwitchRenderer::SourceThreadCanWait(BOOL bCanWait)
  115. {
  116. if (bCanWait == TRUE)
  117. {
  118. m_ThreadSignal.Reset();
  119. }
  120. else
  121. {
  122. m_ThreadSignal.Set();
  123. }
  124. return NOERROR;
  125. }
  126. #ifdef DEBUG
  127. // Dump the current renderer state to the debug terminal. The hardest part of
  128. // the renderer is the window where we unlock everything to wait for a clock
  129. // to signal it is time to draw or for the application to cancel everything
  130. // by stopping the filter. If we get things wrong we can leave the thread in
  131. // WaitForRenderTime with no way for it to ever get out and we will deadlock
  132. void CAudioSwitchRenderer::DisplayRendererState()
  133. {
  134. DbgLog((LOG_TIMING, 1, TEXT("\nTimed out in WaitForRenderTime")));
  135. // No way should this be signalled at this point
  136. BOOL bSignalled = m_ThreadSignal.Check();
  137. DbgLog((LOG_TIMING, 1, TEXT("Signal sanity check %d"), bSignalled));
  138. // Now output the current renderer state variables
  139. DbgLog((LOG_TIMING, 1, TEXT("Filter state %d"), m_State));
  140. DbgLog((LOG_TIMING, 1, TEXT("Abort flag %d"), m_bAbort));
  141. DbgLog((LOG_TIMING, 1, TEXT("Streaming flag %d"), m_bStreaming));
  142. DbgLog((LOG_TIMING, 1, TEXT("Clock advise link %d"), m_dwAdvise));
  143. DbgLog((LOG_TIMING, 1, TEXT("Current media sample %x"), m_pMediaSample[m_inputSelected]));
  144. DbgLog((LOG_TIMING, 1, TEXT("EOS signalled %d"), m_bEOS));
  145. DbgLog((LOG_TIMING, 1, TEXT("EOS delivered %d"), m_bEOSDelivered));
  146. DbgLog((LOG_TIMING, 1, TEXT("Repaint status %d"), m_bRepaintStatus));
  147. // Output the delayed end of stream timer information
  148. DbgLog((LOG_TIMING, 1, TEXT("End of stream timer %x"), m_EndOfStreamTimer));
  149. DbgLog((LOG_TIMING, 1, TEXT("Deliver time %s"), CDisp((LONGLONG)m_SignalTime)));
  150. // Should never timeout during a flushing state
  151. BOOL bFlushing = m_pInputPin[m_inputSelected]->IsFlushing();
  152. DbgLog((LOG_TIMING, 1, TEXT("Flushing sanity check %d"), bFlushing));
  153. // Display the time we were told to start at
  154. DbgLog((LOG_TIMING, 1, TEXT("Last run time %s"), CDisp((LONGLONG)m_tStart.m_time)));
  155. // Have we got a reference clock
  156. if (m_pClock == NULL) return ;
  157. // Get the current time from the wall clock
  158. CRefTime CurrentTime, StartTime, EndTime;
  159. m_pClock->GetTime((REFERENCE_TIME*) &CurrentTime);
  160. CRefTime Offset = CurrentTime - m_tStart;
  161. // Display the current time from the clock
  162. DbgLog((LOG_TIMING, 1, TEXT("Clock time %s"), CDisp((LONGLONG)CurrentTime.m_time)));
  163. DbgLog((LOG_TIMING, 1, TEXT("Time difference %dms"), Offset.Millisecs()));
  164. // Do we have a sample ready to render
  165. if (m_pMediaSample[m_inputSelected] == NULL) return ;
  166. m_pMediaSample[m_inputSelected]->GetTime((REFERENCE_TIME*)&StartTime, (REFERENCE_TIME*)&EndTime);
  167. DbgLog((LOG_TIMING, 1, TEXT("Next sample stream times (Start %d End %d ms)"),
  168. StartTime.Millisecs(), EndTime.Millisecs()));
  169. // Calculate how long it is until it is due for rendering
  170. CRefTime Wait = (m_tStart + StartTime) - CurrentTime;
  171. DbgLog((LOG_TIMING, 1, TEXT("Wait required %d ms"), Wait.Millisecs()));
  172. }
  173. #endif
  174. // Wait until the clock sets the timer event or we're otherwise signalled. We
  175. // set an arbitrary timeout for this wait and if it fires then we display the
  176. // current renderer state on the debugger. It will often fire if the filter's
  177. // left paused in an application however it may also fire during stress tests
  178. // if the synchronisation with application seeks and state changes is faulty
  179. #define RENDER_TIMEOUT 10000
  180. HRESULT CAudioSwitchRenderer::WaitForRenderTime()
  181. {
  182. HANDLE WaitObjects[] = { m_ThreadSignal, m_RenderEvent };
  183. DWORD Result = WAIT_TIMEOUT;
  184. // Wait for either the time to arrive or for us to be stopped
  185. OnWaitStart();
  186. while (Result == WAIT_TIMEOUT)
  187. {
  188. Result = WaitForMultipleObjects(2, WaitObjects, FALSE, RENDER_TIMEOUT);
  189. #ifdef DEBUG
  190. if (Result == WAIT_TIMEOUT) DisplayRendererState();
  191. #endif
  192. }
  193. OnWaitEnd();
  194. // We may have been awoken without the timer firing
  195. if (Result == WAIT_OBJECT_0)
  196. {
  197. return VFW_E_STATE_CHANGED;
  198. }
  199. SignalTimerFired();
  200. return NOERROR;
  201. }
  202. // Poll waiting for Receive to complete. This really matters when
  203. // Receive may set the palette and cause window messages
  204. // The problem is that if we don't really wait for a renderer to
  205. // stop processing we can deadlock waiting for a transform which
  206. // is calling the renderer's Receive() method because the transform's
  207. // Stop method doesn't know to process window messages to unblock
  208. // the renderer's Receive processing
  209. void CAudioSwitchRenderer::WaitForReceiveToComplete()
  210. {
  211. for (;;)
  212. {
  213. if (!m_bInReceive)
  214. {
  215. break;
  216. }
  217. MSG msg;
  218. // Receive all interthread snedmessages
  219. PeekMessage(&msg, NULL, WM_NULL, WM_NULL, PM_NOREMOVE);
  220. Sleep(1);
  221. }
  222. // If the wakebit for QS_POSTMESSAGE is set, the PeekMessage call
  223. // above just cleared the changebit which will cause some messaging
  224. // calls to block (waitMessage, MsgWaitFor...) now.
  225. // Post a dummy message to set the QS_POSTMESSAGE bit again
  226. if (HIWORD(GetQueueStatus(QS_POSTMESSAGE)) & QS_POSTMESSAGE)
  227. {
  228. // Send dummy message
  229. PostThreadMessage(GetCurrentThreadId(), WM_NULL, 0, 0);
  230. }
  231. }
  232. // A filter can have four discrete states, namely Stopped, Running, Paused,
  233. // Intermediate. We are in an intermediate state if we are currently trying
  234. // to pause but haven't yet got the first sample (or if we have been flushed
  235. // in paused state and therefore still have to wait for a sample to arrive)
  236. // This class contains an event called m_evComplete which is signalled when
  237. // the current state is completed and is not signalled when we are waiting to
  238. // complete the last state transition. As mentioned above the only time we
  239. // use this at the moment is when we wait for a media sample in paused state
  240. // If while we are waiting we receive an end of stream notification from the
  241. // source filter then we know no data is imminent so we can reset the event
  242. // This means that when we transition to paused the source filter must call
  243. // end of stream on us or send us an image otherwise we'll hang indefinately
  244. // Simple internal way of getting the real state
  245. FILTER_STATE CAudioSwitchRenderer::GetRealState()
  246. {
  247. return m_State;
  248. }
  249. // The renderer doesn't complete the full transition to paused states until
  250. // it has got one media sample to render. If you ask it for its state while
  251. // it's waiting it will return the state along with VFW_S_STATE_INTERMEDIATE
  252. STDMETHODIMP CAudioSwitchRenderer::GetState(DWORD dwMSecs, FILTER_STATE *State)
  253. {
  254. CheckPointer(State, E_POINTER);
  255. if (WaitDispatchingMessages(m_evComplete, dwMSecs) == WAIT_TIMEOUT)
  256. {
  257. *State = m_State;
  258. return VFW_S_STATE_INTERMEDIATE;
  259. }
  260. *State = m_State;
  261. return NOERROR;
  262. }
  263. // If we're pausing and we have no samples we don't complete the transition
  264. // to State_Paused and we return S_FALSE. However if the m_bAbort flag has
  265. // been set then all samples are rejected so there is no point waiting for
  266. // one. If we do have a sample then return NOERROR. We will only ever return
  267. // VFW_S_STATE_INTERMEDIATE from GetState after being paused with no sample
  268. // (calling GetState after either being stopped or Run will NOT return this)
  269. HRESULT CAudioSwitchRenderer::CompleteStateChange(FILTER_STATE OldState)
  270. {
  271. // Allow us to be paused when disconnected
  272. if (m_pInputPin[m_inputSelected]->IsConnected() == FALSE)
  273. {
  274. Ready();
  275. return S_OK;
  276. }
  277. // Have we run off the end of stream
  278. if (IsEndOfStream() == TRUE)
  279. {
  280. Ready();
  281. return S_OK;
  282. }
  283. // Make sure we get fresh data after being stopped
  284. if (HaveCurrentSample() == TRUE)
  285. {
  286. if (OldState != State_Stopped)
  287. {
  288. Ready();
  289. return S_OK;
  290. }
  291. }
  292. NotReady();
  293. return S_FALSE;
  294. }
  295. // When we stop the filter the things we do are:-
  296. // Decommit the allocator being used in the connection
  297. // Release the source filter if it's waiting in Receive
  298. // Cancel any advise link we set up with the clock
  299. // Any end of stream signalled is now obsolete so reset
  300. // Allow us to be stopped when we are not connected
  301. STDMETHODIMP CAudioSwitchRenderer::Stop()
  302. {
  303. CAutoLock cRendererLock(&m_InterfaceLock);
  304. // Make sure there really is a state change
  305. if (m_State == State_Stopped)
  306. {
  307. return NOERROR;
  308. }
  309. // Is our input pin connected
  310. if (m_pInputPin[m_inputSelected]->IsConnected() == FALSE)
  311. {
  312. NOTE("Input pin is not connected");
  313. m_State = State_Stopped;
  314. return NOERROR;
  315. }
  316. CBaseFilter::Stop();
  317. // If we are going into a stopped state then we must decommit whatever
  318. // allocator we are using it so that any source filter waiting in the
  319. // GetBuffer can be released and unlock themselves for a state change
  320. if (m_pInputPin[m_inputSelected]->Allocator())
  321. {
  322. m_pInputPin[m_inputSelected]->Allocator()->Decommit();
  323. }
  324. // Cancel any scheduled rendering
  325. SetRepaintStatus(TRUE);
  326. StopStreaming();
  327. SourceThreadCanWait(FALSE);
  328. ResetEndOfStream();
  329. CancelNotification();
  330. // There should be no outstanding clock advise
  331. ASSERT(CancelNotification() == S_FALSE);
  332. ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent, 0));
  333. ASSERT(m_EndOfStreamTimer == 0);
  334. Ready();
  335. WaitForReceiveToComplete();
  336. m_bAbort = FALSE;
  337. return NOERROR;
  338. }
  339. // When we pause the filter the things we do are:-
  340. // Commit the allocator being used in the connection
  341. // Allow a source filter thread to wait in Receive
  342. // Cancel any clock advise link (we may be running)
  343. // Possibly complete the state change if we have data
  344. // Allow us to be paused when we are not connected
  345. STDMETHODIMP CAudioSwitchRenderer::Pause()
  346. {
  347. CAutoLock cRendererLock(&m_InterfaceLock);
  348. FILTER_STATE OldState = m_State;
  349. ASSERT(m_pInputPin[m_inputSelected]->IsFlushing() == FALSE);
  350. // Make sure there really is a state change
  351. if (m_State == State_Paused)
  352. {
  353. return CompleteStateChange(State_Paused);
  354. }
  355. // Has our input pin been connected
  356. if (m_pInputPin[m_inputSelected]->IsConnected() == FALSE)
  357. {
  358. NOTE("Input pin is not connected");
  359. m_State = State_Paused;
  360. return CompleteStateChange(State_Paused);
  361. }
  362. // Pause the base filter class
  363. HRESULT hr = CBaseFilter::Pause();
  364. if (FAILED(hr))
  365. {
  366. NOTE("Pause failed");
  367. return hr;
  368. }
  369. // Enable EC_REPAINT events again
  370. SetRepaintStatus(TRUE);
  371. StopStreaming();
  372. SourceThreadCanWait(TRUE);
  373. CancelNotification();
  374. ResetEndOfStreamTimer();
  375. // If we are going into a paused state then we must commit whatever
  376. // allocator we are using it so that any source filter can call the
  377. // GetBuffer and expect to get a buffer without returning an error
  378. if (m_pInputPin[m_inputSelected]->Allocator())
  379. {
  380. m_pInputPin[m_inputSelected]->Allocator()->Commit();
  381. }
  382. // There should be no outstanding advise
  383. ASSERT(CancelNotification() == S_FALSE);
  384. ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent, 0));
  385. ASSERT(m_EndOfStreamTimer == 0);
  386. ASSERT(m_pInputPin[m_inputSelected]->IsFlushing() == FALSE);
  387. // When we come out of a stopped state we must clear any image we were
  388. // holding onto for frame refreshing. Since renderers see state changes
  389. // first we can reset ourselves ready to accept the source thread data
  390. // Paused or running after being stopped causes the current position to
  391. // be reset so we're not interested in passing end of stream signals
  392. if (OldState == State_Stopped)
  393. {
  394. m_bAbort = FALSE;
  395. ClearPendingSample();
  396. }
  397. return CompleteStateChange(OldState);
  398. }
  399. // When we run the filter the things we do are:-
  400. // Commit the allocator being used in the connection
  401. // Allow a source filter thread to wait in Receive
  402. // Signal the render event just to get us going
  403. // Start the base class by calling StartStreaming
  404. // Allow us to be run when we are not connected
  405. // Signal EC_COMPLETE if we are not connected
  406. STDMETHODIMP CAudioSwitchRenderer::Run(REFERENCE_TIME StartTime)
  407. {
  408. CAutoLock cRendererLock(&m_InterfaceLock);
  409. FILTER_STATE OldState = m_State;
  410. // Make sure there really is a state change
  411. if (m_State == State_Running)
  412. {
  413. return NOERROR;
  414. }
  415. // Send EC_COMPLETE if we're not connected
  416. if (m_pInputPin[m_inputSelected]->IsConnected() == FALSE)
  417. {
  418. NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)(IBaseFilter *)this);
  419. m_State = State_Running;
  420. return NOERROR;
  421. }
  422. Ready();
  423. // Pause the base filter class
  424. HRESULT hr = CBaseFilter::Run(StartTime);
  425. if (FAILED(hr))
  426. {
  427. NOTE("Run failed");
  428. return hr;
  429. }
  430. // Allow the source thread to wait
  431. ASSERT(m_pInputPin[m_inputSelected]->IsFlushing() == FALSE);
  432. SourceThreadCanWait(TRUE);
  433. SetRepaintStatus(FALSE);
  434. // There should be no outstanding advise
  435. ASSERT(CancelNotification() == S_FALSE);
  436. ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent, 0));
  437. ASSERT(m_EndOfStreamTimer == 0);
  438. ASSERT(m_pInputPin[m_inputSelected]->IsFlushing() == FALSE);
  439. // If we are going into a running state then we must commit whatever
  440. // allocator we are using it so that any source filter can call the
  441. // GetBuffer and expect to get a buffer without returning an error
  442. if (m_pInputPin[m_inputSelected]->Allocator())
  443. {
  444. m_pInputPin[m_inputSelected]->Allocator()->Commit();
  445. }
  446. // When we come out of a stopped state we must clear any image we were
  447. // holding onto for frame refreshing. Since renderers see state changes
  448. // first we can reset ourselves ready to accept the source thread data
  449. // Paused or running after being stopped causes the current position to
  450. // be reset so we're not interested in passing end of stream signals
  451. if (OldState == State_Stopped)
  452. {
  453. m_bAbort = FALSE;
  454. ClearPendingSample();
  455. }
  456. return StartStreaming();
  457. }
  458. // Return the number of input pins we support
  459. int CAudioSwitchRenderer::GetPinCount()
  460. {
  461. return 16;
  462. }
  463. // We only support one input pin and it is numbered zero
  464. CBasePin *CAudioSwitchRenderer::GetPin(int n)
  465. {
  466. CAutoLock cRendererLock(&m_InterfaceLock);
  467. HRESULT hr = NOERROR;
  468. ASSERT(n < 16 && n >= 0);
  469. // Should only ever be called with zero
  470. if (n > 16)
  471. {
  472. return NULL;
  473. }
  474. // Create the input pin if not already done so
  475. if (m_pInputPin[n] == NULL)
  476. {
  477. WCHAR t[256] = {0};
  478. StringCchPrintfW(t, 256, L"In%d", n);
  479. m_pInputPin[n] = new CAudioSwitchRendererInputPin(this, &hr, t);
  480. }
  481. return m_pInputPin[n];
  482. }
  483. // If "In" then return the IPin for our input pin, otherwise NULL and error
  484. STDMETHODIMP CAudioSwitchRenderer::FindPin(LPCWSTR Id, IPin **ppPin)
  485. {
  486. CheckPointer(ppPin, E_POINTER);
  487. int gotit = 0;
  488. for (int i = 0;i < 16;i++)
  489. {
  490. WCHAR t[256] = {0};
  491. StringCchPrintfW(t, 256, L"In%d", i);
  492. if (0 == lstrcmpW(Id, t))
  493. {
  494. gotit = 1;
  495. *ppPin = GetPin(i);
  496. ASSERT(*ppPin);
  497. (*ppPin)->AddRef();
  498. }
  499. }
  500. if (!gotit)
  501. {
  502. *ppPin = NULL;
  503. return VFW_E_NOT_FOUND;
  504. }
  505. return NOERROR;
  506. }
  507. // Called when the input pin receives an EndOfStream notification. If we have
  508. // not got a sample, then notify EC_COMPLETE now. If we have samples, then set
  509. // m_bEOS and check for this on completing samples. If we're waiting to pause
  510. // then complete the transition to paused state by setting the state event
  511. HRESULT CAudioSwitchRenderer::EndOfStream()
  512. {
  513. // Ignore these calls if we are stopped
  514. if (m_State == State_Stopped)
  515. {
  516. return NOERROR;
  517. }
  518. // If we have a sample then wait for it to be rendered
  519. m_bEOS = TRUE;
  520. if (m_pMediaSample[m_inputSelected])
  521. {
  522. return NOERROR;
  523. }
  524. // If we are waiting for pause then we are now ready since we cannot now
  525. // carry on waiting for a sample to arrive since we are being told there
  526. // won't be any. This sets an event that the GetState function picks up
  527. Ready();
  528. // Only signal completion now if we are running otherwise queue it until
  529. // we do run in StartStreaming. This is used when we seek because a seek
  530. // causes a pause where early notification of completion is misleading
  531. if (m_bStreaming)
  532. {
  533. SendEndOfStream();
  534. }
  535. return NOERROR;
  536. }
  537. // When we are told to flush we should release the source thread
  538. HRESULT CAudioSwitchRenderer::BeginFlush()
  539. {
  540. // If paused then report state intermediate until we get some data
  541. if (m_State == State_Paused)
  542. {
  543. NotReady();
  544. }
  545. SourceThreadCanWait(FALSE);
  546. CancelNotification();
  547. ClearPendingSample();
  548. // Wait for Receive to complete
  549. WaitForReceiveToComplete();
  550. return NOERROR;
  551. }
  552. // After flushing the source thread can wait in Receive again
  553. HRESULT CAudioSwitchRenderer::EndFlush()
  554. {
  555. // Reset the current sample media time
  556. if (m_pPosition) m_pPosition->ResetMediaTime();
  557. // There should be no outstanding advise
  558. ASSERT(CancelNotification() == S_FALSE);
  559. SourceThreadCanWait(TRUE);
  560. return NOERROR;
  561. }
  562. // We can now send EC_REPAINTs if so required
  563. HRESULT CAudioSwitchRenderer::CompleteConnect(IPin *pReceivePin)
  564. {
  565. SetRepaintStatus(TRUE);
  566. m_bAbort = FALSE;
  567. return NOERROR;
  568. }
  569. // Called when we go paused or running
  570. HRESULT CAudioSwitchRenderer::Active()
  571. {
  572. return NOERROR;
  573. }
  574. // Called when we go into a stopped state
  575. HRESULT CAudioSwitchRenderer::Inactive()
  576. {
  577. if (m_pPosition)
  578. {
  579. m_pPosition->ResetMediaTime();
  580. }
  581. // People who derive from this may want to override this behaviour
  582. // to keep hold of the sample in some circumstances
  583. ClearPendingSample();
  584. return NOERROR;
  585. }
  586. // Tell derived classes about the media type agreed
  587. HRESULT CAudioSwitchRenderer::SetMediaType(const CMediaType *pmt)
  588. {
  589. return NOERROR;
  590. }
  591. // When we break the input pin connection we should reset the EOS flags. When
  592. // we are asked for either IMediaPosition or IMediaSeeking we will create a
  593. // CPosPassThru object to handles media time pass through. When we're handed
  594. // samples we store (by calling CPosPassThru::RegisterMediaTime) their media
  595. // times so we can then return a real current position of data being rendered
  596. HRESULT CAudioSwitchRenderer::BreakConnect()
  597. {
  598. // Do we have a quality management sink
  599. if (m_pQSink)
  600. {
  601. m_pQSink->Release();
  602. m_pQSink = NULL;
  603. }
  604. // Check we have a valid connection
  605. int n = 0;
  606. for (int i = 0;i < 16;i++)
  607. {
  608. if (!m_pInputPin[i] || m_pInputPin[i]->IsConnected() == FALSE) { n++; continue; }
  609. // Check we are stopped before disconnecting
  610. if (m_State != State_Stopped && !m_pInputPin[i]->CanReconnectWhenActive())
  611. {
  612. return VFW_E_NOT_STOPPED;
  613. }
  614. }
  615. if (n == 16) return S_FALSE;
  616. SetRepaintStatus(FALSE);
  617. ResetEndOfStream();
  618. ClearPendingSample();
  619. m_bAbort = FALSE;
  620. return NOERROR;
  621. }
  622. // Retrieves the sample times for this samples (note the sample times are
  623. // passed in by reference not value). We return S_FALSE to say schedule this
  624. // sample according to the times on the sample. We also return S_OK in
  625. // which case the object should simply render the sample data immediately
  626. HRESULT CAudioSwitchRenderer::GetSampleTimes(IMediaSample *pMediaSample,
  627. REFERENCE_TIME *pStartTime,
  628. REFERENCE_TIME *pEndTime)
  629. {
  630. ASSERT(m_dwAdvise == 0);
  631. ASSERT(pMediaSample);
  632. // If the stop time for this sample is before or the same as start time,
  633. // then just ignore it (release it) and schedule the next one in line
  634. // Source filters should always fill in the start and end times properly!
  635. if (SUCCEEDED(pMediaSample->GetTime(pStartTime, pEndTime)))
  636. {
  637. if (*pEndTime < *pStartTime)
  638. {
  639. return VFW_E_START_TIME_AFTER_END;
  640. }
  641. }
  642. else
  643. {
  644. // no time set in the sample... draw it now?
  645. return S_OK;
  646. }
  647. // Can't synchronise without a clock so we return S_OK which tells the
  648. // caller that the sample should be rendered immediately without going
  649. // through the overhead of setting a timer advise link with the clock
  650. if (m_pClock == NULL)
  651. {
  652. return S_OK;
  653. }
  654. return ShouldDrawSampleNow(pMediaSample, pStartTime, pEndTime);
  655. }
  656. // By default all samples are drawn according to their time stamps so we
  657. // return S_FALSE. Returning S_OK means draw immediately, this is used
  658. // by the derived video renderer class in its quality management.
  659. HRESULT CAudioSwitchRenderer::ShouldDrawSampleNow(IMediaSample *pMediaSample,
  660. REFERENCE_TIME *ptrStart,
  661. REFERENCE_TIME *ptrEnd)
  662. {
  663. return S_FALSE;
  664. }
  665. // We must always reset the current advise time to zero after a timer fires
  666. // because there are several possible ways which lead us not to do any more
  667. // scheduling such as the pending image being cleared after state changes
  668. void CAudioSwitchRenderer::SignalTimerFired()
  669. {
  670. m_dwAdvise = 0;
  671. }
  672. // Cancel any notification currently scheduled. This is called by the owning
  673. // window object when it is told to stop streaming. If there is no timer link
  674. // outstanding then calling this is benign otherwise we go ahead and cancel
  675. // We must always reset the render event as the quality management code can
  676. // signal immediate rendering by setting the event without setting an advise
  677. // link. If we're subsequently stopped and run the first attempt to setup an
  678. // advise link with the reference clock will find the event still signalled
  679. HRESULT CAudioSwitchRenderer::CancelNotification()
  680. {
  681. ASSERT(m_dwAdvise == 0 || m_pClock);
  682. DWORD_PTR dwAdvise = m_dwAdvise;
  683. // Have we a live advise link
  684. if (m_dwAdvise)
  685. {
  686. m_pClock->Unadvise(m_dwAdvise);
  687. SignalTimerFired();
  688. ASSERT(m_dwAdvise == 0);
  689. }
  690. // Clear the event and return our status
  691. m_RenderEvent.Reset();
  692. return (dwAdvise ? S_OK : S_FALSE);
  693. }
  694. // Responsible for setting up one shot advise links with the clock
  695. // Return FALSE if the sample is to be dropped (not drawn at all)
  696. // Return TRUE if the sample is to be drawn and in this case also
  697. // arrange for m_RenderEvent to be set at the appropriate time
  698. BOOL CAudioSwitchRenderer::ScheduleSample(IMediaSample *pMediaSample)
  699. {
  700. REFERENCE_TIME StartSample, EndSample;
  701. // Is someone pulling our leg
  702. if (pMediaSample == NULL)
  703. {
  704. return FALSE;
  705. }
  706. // Get the next sample due up for rendering. If there aren't any ready
  707. // then GetNextSampleTimes returns an error. If there is one to be done
  708. // then it succeeds and yields the sample times. If it is due now then
  709. // it returns S_OK other if it's to be done when due it returns S_FALSE
  710. HRESULT hr = GetSampleTimes(pMediaSample, &StartSample, &EndSample);
  711. if (FAILED(hr))
  712. {
  713. return FALSE;
  714. }
  715. // If we don't have a reference clock then we cannot set up the advise
  716. // time so we simply set the event indicating an image to render. This
  717. // will cause us to run flat out without any timing or synchronisation
  718. if (hr == S_OK)
  719. {
  720. EXECUTE_ASSERT(SetEvent((HANDLE) m_RenderEvent));
  721. return TRUE;
  722. }
  723. ASSERT(m_dwAdvise == 0);
  724. ASSERT(m_pClock);
  725. ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent, 0));
  726. // We do have a valid reference clock interface so we can ask it to
  727. // set an event when the image comes due for rendering. We pass in
  728. // the reference time we were told to start at and also the current
  729. // stream time which is the offset from the start reference time
  730. hr = m_pClock->AdviseTime(
  731. (REFERENCE_TIME) m_tStart, // Start run time
  732. StartSample, // Stream time
  733. (HEVENT)(HANDLE) m_RenderEvent, // Render notification
  734. &m_dwAdvise); // Advise cookie
  735. if (SUCCEEDED(hr))
  736. {
  737. return TRUE;
  738. }
  739. // We could not schedule the next sample for rendering despite the fact
  740. // we have a valid sample here. This is a fair indication that either
  741. // the system clock is wrong or the time stamp for the sample is duff
  742. ASSERT(m_dwAdvise == 0);
  743. return FALSE;
  744. }
  745. // This is called when a sample comes due for rendering. We pass the sample
  746. // on to the derived class. After rendering we will initialise the timer for
  747. // the next sample, NOTE signal that the last one fired first, if we don't
  748. // do this it thinks there is still one outstanding that hasn't completed
  749. HRESULT CAudioSwitchRenderer::Render(IMediaSample *pMediaSample)
  750. {
  751. // If the media sample is NULL then we will have been notified by the
  752. // clock that another sample is ready but in the mean time someone has
  753. // stopped us streaming which causes the next sample to be released
  754. if (pMediaSample == NULL)
  755. {
  756. return S_FALSE;
  757. }
  758. // If we have stopped streaming then don't render any more samples, the
  759. // thread that got in and locked us and then reset this flag does not
  760. // clear the pending sample as we can use it to refresh any output device
  761. if (m_bStreaming == FALSE)
  762. {
  763. return S_FALSE;
  764. }
  765. // Time how long the rendering takes
  766. OnRenderStart(pMediaSample);
  767. DoRenderSample(pMediaSample);
  768. OnRenderEnd(pMediaSample);
  769. return NOERROR;
  770. }
  771. // Checks if there is a sample waiting at the renderer
  772. BOOL CAudioSwitchRenderer::HaveCurrentSample()
  773. {
  774. CAutoLock cRendererLock(&m_RendererLock);
  775. return (m_pMediaSample[m_inputSelected] == NULL ? FALSE : TRUE);
  776. }
  777. // Returns the current sample waiting at the video renderer. We AddRef the
  778. // sample before returning so that should it come due for rendering the
  779. // person who called this method will hold the remaining reference count
  780. // that will stop the sample being added back onto the allocator free list
  781. IMediaSample *CAudioSwitchRenderer::GetCurrentSample()
  782. {
  783. CAutoLock cRendererLock(&m_RendererLock);
  784. if (m_pMediaSample[m_inputSelected])
  785. {
  786. m_pMediaSample[m_inputSelected]->AddRef();
  787. }
  788. return m_pMediaSample[m_inputSelected];
  789. }
  790. // Called when the source delivers us a sample. We go through a few checks to
  791. // make sure the sample can be rendered. If we are running (streaming) then we
  792. // have the sample scheduled with the reference clock, if we are not streaming
  793. // then we have received an sample in paused mode so we can complete any state
  794. // transition. On leaving this function everything will be unlocked so an app
  795. // thread may get in and change our state to stopped (for example) in which
  796. // case it will also signal the thread event so that our wait call is stopped
  797. HRESULT CAudioSwitchRenderer::PrepareReceive(IMediaSample *pMediaSample)
  798. {
  799. CAutoLock cRendererLock(&m_InterfaceLock);
  800. m_bInReceive = TRUE;
  801. // Check our flushing and filter state
  802. HRESULT hr = m_pInputPin[m_inputSelected]->CBaseInputPin::Receive(pMediaSample);
  803. if (hr != NOERROR)
  804. {
  805. m_bInReceive = FALSE;
  806. return E_FAIL;
  807. }
  808. // Has the type changed on a media sample. We do all rendering
  809. // synchronously on the source thread, which has a side effect
  810. // that only one buffer is ever outstanding. Therefore when we
  811. // have Receive called we can go ahead and change the format
  812. // Since the format change can cause a SendMessage we just don't
  813. // lock
  814. if (m_pInputPin[m_inputSelected]->SampleProps()->pMediaType)
  815. {
  816. m_pInputPin[m_inputSelected]->SetMediaType((CMediaType *)m_pInputPin[m_inputSelected]->SampleProps()->pMediaType);
  817. }
  818. CAutoLock cSampleLock(&m_RendererLock);
  819. ASSERT(IsActive() == TRUE);
  820. ASSERT(m_pInputPin[m_inputSelected]->IsFlushing() == FALSE);
  821. ASSERT(m_pInputPin[m_inputSelected]->IsConnected() == TRUE);
  822. ASSERT(m_pMediaSample[m_inputSelected] == NULL);
  823. // Return an error if we already have a sample waiting for rendering
  824. // source pins must serialise the Receive calls - we also check that
  825. // no data is being sent after the source signalled an end of stream
  826. if (m_pMediaSample[m_inputSelected] || m_bEOS || m_bAbort)
  827. {
  828. Ready();
  829. m_bInReceive = FALSE;
  830. return E_UNEXPECTED;
  831. }
  832. // Store the media times from this sample
  833. if (m_pPosition) m_pPosition->RegisterMediaTime(pMediaSample);
  834. // Schedule the next sample if we are streaming
  835. if ((m_bStreaming == TRUE) && (ScheduleSample(pMediaSample) == FALSE))
  836. {
  837. ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent, 0));
  838. ASSERT(CancelNotification() == S_FALSE);
  839. m_bInReceive = FALSE;
  840. return VFW_E_SAMPLE_REJECTED;
  841. }
  842. // Store the sample end time for EC_COMPLETE handling
  843. m_SignalTime = m_pInputPin[m_inputSelected]->SampleProps()->tStop;
  844. // BEWARE we sometimes keep the sample even after returning the thread to
  845. // the source filter such as when we go into a stopped state (we keep it
  846. // to refresh the device with) so we must AddRef it to keep it safely. If
  847. // we start flushing the source thread is released and any sample waiting
  848. // will be released otherwise GetBuffer may never return (see BeginFlush)
  849. m_pMediaSample[m_inputSelected] = pMediaSample;
  850. m_pMediaSample[m_inputSelected]->AddRef();
  851. if (m_bStreaming == FALSE)
  852. {
  853. SetRepaintStatus(TRUE);
  854. }
  855. return NOERROR;
  856. }
  857. // Called by the source filter when we have a sample to render. Under normal
  858. // circumstances we set an advise link with the clock, wait for the time to
  859. // arrive and then render the data using the PURE virtual DoRenderSample that
  860. // the derived class will have overriden. After rendering the sample we may
  861. // also signal EOS if it was the last one sent before EndOfStream was called
  862. HRESULT CAudioSwitchRenderer::Receive(IMediaSample *pSample)
  863. {
  864. ASSERT(pSample);
  865. // It may return VFW_E_SAMPLE_REJECTED code to say don't bother
  866. HRESULT hr = PrepareReceive(pSample);
  867. ASSERT(m_bInReceive == SUCCEEDED(hr));
  868. if (FAILED(hr))
  869. {
  870. if (hr == VFW_E_SAMPLE_REJECTED)
  871. {
  872. return NOERROR;
  873. }
  874. return hr;
  875. }
  876. // We realize the palette in "PrepareRender()" so we have to give away the
  877. // filter lock here.
  878. if (m_State == State_Paused)
  879. {
  880. PrepareRender();
  881. // no need to use InterlockedExchange
  882. m_bInReceive = FALSE;
  883. {
  884. // We must hold both these locks
  885. CAutoLock cRendererLock(&m_InterfaceLock);
  886. if (m_State == State_Stopped)
  887. return NOERROR;
  888. m_bInReceive = TRUE;
  889. }
  890. Ready();
  891. }
  892. // Having set an advise link with the clock we sit and wait. We may be
  893. // awoken by the clock firing or by a state change. The rendering call
  894. // will lock the critical section and check we can still render the data
  895. hr = WaitForRenderTime();
  896. if (FAILED(hr))
  897. {
  898. m_bInReceive = FALSE;
  899. return NOERROR;
  900. }
  901. PrepareRender();
  902. // Set this here and poll it until we work out the locking correctly
  903. // It can't be right that the streaming stuff grabs the interface
  904. // lock - after all we want to be able to wait for this stuff
  905. // to complete
  906. m_bInReceive = FALSE;
  907. // We must hold both these locks
  908. CAutoLock cRendererLock(&m_InterfaceLock);
  909. // since we gave away the filter wide lock, the sate of the filter could
  910. // have chnaged to Stopped
  911. if (m_State == State_Stopped)
  912. return NOERROR;
  913. CAutoLock cSampleLock(&m_RendererLock);
  914. // Deal with this sample
  915. Render(m_pMediaSample[m_inputSelected]);
  916. ClearPendingSample();
  917. SendEndOfStream();
  918. CancelNotification();
  919. return NOERROR;
  920. }
  921. // This is called when we stop or are inactivated to clear the pending sample
  922. // We release the media sample interface so that they can be allocated to the
  923. // source filter again, unless of course we are changing state to inactive in
  924. // which case GetBuffer will return an error. We must also reset the current
  925. // media sample to NULL so that we know we do not currently have an image
  926. HRESULT CAudioSwitchRenderer::ClearPendingSample()
  927. {
  928. CAutoLock cRendererLock(&m_RendererLock);
  929. for (int i = 0;i < 16;i++)
  930. {
  931. if (m_pMediaSample[i])
  932. {
  933. m_pMediaSample[i]->Release();
  934. m_pMediaSample[i] = NULL;
  935. }
  936. }
  937. return NOERROR;
  938. }
  939. // Do the timer callback work
  940. void CAudioSwitchRenderer::TimerCallback()
  941. {
  942. // Lock for synchronization (but don't hold this lock when calling
  943. // timeKillEvent)
  944. CAutoLock cRendererLock(&m_RendererLock);
  945. // See if we should signal end of stream now
  946. if (m_EndOfStreamTimer)
  947. {
  948. m_EndOfStreamTimer = 0;
  949. SendEndOfStream();
  950. }
  951. }
  952. // If we are at the end of the stream signal the filter graph but do not set
  953. // the state flag back to FALSE. Once we drop off the end of the stream we
  954. // leave the flag set (until a subsequent ResetEndOfStream). Each sample we
  955. // get delivered will update m_SignalTime to be the last sample's end time.
  956. // We must wait this long before signalling end of stream to the filtergraph
  957. #define TIMEOUT_DELIVERYWAIT 50
  958. #define TIMEOUT_RESOLUTION 10
  959. HRESULT CAudioSwitchRenderer::SendEndOfStream()
  960. {
  961. ASSERT(CritCheckIn(&m_RendererLock));
  962. if (m_bEOS == FALSE || m_bEOSDelivered || m_EndOfStreamTimer)
  963. {
  964. return NOERROR;
  965. }
  966. // If there is no clock then signal immediately
  967. if (m_pClock == NULL)
  968. {
  969. return NotifyEndOfStream();
  970. }
  971. // How long into the future is the delivery time
  972. REFERENCE_TIME Signal = m_tStart + m_SignalTime;
  973. REFERENCE_TIME CurrentTime;
  974. m_pClock->GetTime(&CurrentTime);
  975. LONG Delay = LONG((Signal - CurrentTime) / 10000);
  976. // Dump the timing information to the debugger
  977. NOTE1("Delay until end of stream delivery %d", Delay);
  978. NOTE1("Current %s", (LPCTSTR)CDisp((LONGLONG)CurrentTime));
  979. NOTE1("Signal %s", (LPCTSTR)CDisp((LONGLONG)Signal));
  980. // Wait for the delivery time to arrive
  981. if (Delay < TIMEOUT_DELIVERYWAIT)
  982. {
  983. return NotifyEndOfStream();
  984. }
  985. // Signal a timer callback on another worker thread
  986. m_EndOfStreamTimer = timeSetEvent((UINT) Delay, // Period of timer
  987. TIMEOUT_RESOLUTION, // Timer resolution
  988. EndOfStreamTimer, // Callback function
  989. DWORD_PTR(this), // Used information
  990. TIME_ONESHOT); // Type of callback
  991. if (m_EndOfStreamTimer == 0)
  992. {
  993. return NotifyEndOfStream();
  994. }
  995. return NOERROR;
  996. }
  997. // Signals EC_COMPLETE to the filtergraph manager
  998. HRESULT CAudioSwitchRenderer::NotifyEndOfStream()
  999. {
  1000. CAutoLock cRendererLock(&m_RendererLock);
  1001. ASSERT(m_bEOS == TRUE);
  1002. ASSERT(m_bEOSDelivered == FALSE);
  1003. ASSERT(m_EndOfStreamTimer == 0);
  1004. // Has the filter changed state
  1005. if (m_bStreaming == FALSE)
  1006. {
  1007. ASSERT(m_EndOfStreamTimer == 0);
  1008. return NOERROR;
  1009. }
  1010. // Reset the end of stream timer
  1011. m_EndOfStreamTimer = 0;
  1012. // If we've been using the IMediaPosition interface, set it's start
  1013. // and end media "times" to the stop position by hand. This ensures
  1014. // that we actually get to the end, even if the MPEG guestimate has
  1015. // been bad or if the quality management dropped the last few frames
  1016. if (m_pPosition) m_pPosition->EOS();
  1017. m_bEOSDelivered = TRUE;
  1018. NOTE("Sending EC_COMPLETE...");
  1019. return NotifyEvent(EC_COMPLETE, S_OK, (LONG_PTR)(IBaseFilter *)this);
  1020. }
  1021. // Reset the end of stream flag, this is typically called when we transfer to
  1022. // stopped states since that resets the current position back to the start so
  1023. // we will receive more samples or another EndOfStream if there aren't any. We
  1024. // keep two separate flags one to say we have run off the end of the stream
  1025. // (this is the m_bEOS flag) and another to say we have delivered EC_COMPLETE
  1026. // to the filter graph. We need the latter otherwise we can end up sending an
  1027. // EC_COMPLETE every time the source changes state and calls our EndOfStream
  1028. HRESULT CAudioSwitchRenderer::ResetEndOfStream()
  1029. {
  1030. ResetEndOfStreamTimer();
  1031. CAutoLock cRendererLock(&m_RendererLock);
  1032. m_bEOS = FALSE;
  1033. m_bEOSDelivered = FALSE;
  1034. m_SignalTime = 0;
  1035. return NOERROR;
  1036. }
  1037. // Kills any outstanding end of stream timer
  1038. void CAudioSwitchRenderer::ResetEndOfStreamTimer()
  1039. {
  1040. ASSERT(CritCheckOut(&m_RendererLock));
  1041. if (m_EndOfStreamTimer)
  1042. {
  1043. timeKillEvent(m_EndOfStreamTimer);
  1044. m_EndOfStreamTimer = 0;
  1045. }
  1046. }
  1047. // This is called when we start running so that we can schedule any pending
  1048. // image we have with the clock and display any timing information. If we
  1049. // don't have any sample but we have queued an EOS flag then we send it. If
  1050. // we do have a sample then we wait until that has been rendered before we
  1051. // signal the filter graph otherwise we may change state before it's done
  1052. HRESULT CAudioSwitchRenderer::StartStreaming()
  1053. {
  1054. CAutoLock cRendererLock(&m_RendererLock);
  1055. if (m_bStreaming == TRUE)
  1056. {
  1057. return NOERROR;
  1058. }
  1059. // Reset the streaming times ready for running
  1060. m_bStreaming = TRUE;
  1061. timeBeginPeriod(1);
  1062. OnStartStreaming();
  1063. // There should be no outstanding advise
  1064. ASSERT(WAIT_TIMEOUT == WaitForSingleObject((HANDLE)m_RenderEvent, 0));
  1065. ASSERT(CancelNotification() == S_FALSE);
  1066. // If we have an EOS and no data then deliver it now
  1067. if (m_pMediaSample[m_inputSelected] == NULL)
  1068. {
  1069. return SendEndOfStream();
  1070. }
  1071. // Have the data rendered
  1072. ASSERT(m_pMediaSample[m_inputSelected]);
  1073. if (!ScheduleSample(m_pMediaSample[m_inputSelected]))
  1074. m_RenderEvent.Set();
  1075. return NOERROR;
  1076. }
  1077. // This is called when we stop streaming so that we can set our internal flag
  1078. // indicating we are not now to schedule any more samples arriving. The state
  1079. // change methods in the filter implementation take care of cancelling any
  1080. // clock advise link we have set up and clearing any pending sample we have
  1081. HRESULT CAudioSwitchRenderer::StopStreaming()
  1082. {
  1083. CAutoLock cRendererLock(&m_RendererLock);
  1084. m_bEOSDelivered = FALSE;
  1085. if (m_bStreaming == TRUE)
  1086. {
  1087. m_bStreaming = FALSE;
  1088. OnStopStreaming();
  1089. timeEndPeriod(1);
  1090. }
  1091. return NOERROR;
  1092. }
  1093. // We have a boolean flag that is reset when we have signalled EC_REPAINT to
  1094. // the filter graph. We set this when we receive an image so that should any
  1095. // conditions arise again we can send another one. By having a flag we ensure
  1096. // we don't flood the filter graph with redundant calls. We do not set the
  1097. // event when we receive an EndOfStream call since there is no point in us
  1098. // sending further EC_REPAINTs. In particular the AutoShowWindow method and
  1099. // the DirectDraw object use this method to control the window repainting
  1100. void CAudioSwitchRenderer::SetRepaintStatus(BOOL bRepaint)
  1101. {
  1102. CAutoLock cSampleLock(&m_RendererLock);
  1103. m_bRepaintStatus = bRepaint;
  1104. }
  1105. // Pass the window handle to the upstream filter
  1106. void CAudioSwitchRenderer::SendNotifyWindow(IPin *pPin, HWND hwnd)
  1107. {
  1108. IMediaEventSink *pSink;
  1109. // Does the pin support IMediaEventSink
  1110. HRESULT hr = pPin->QueryInterface(IID_IMediaEventSink, (void **) & pSink);
  1111. if (SUCCEEDED(hr))
  1112. {
  1113. pSink->Notify(EC_NOTIFY_WINDOW, LONG_PTR(hwnd), 0);
  1114. pSink->Release();
  1115. }
  1116. NotifyEvent(EC_NOTIFY_WINDOW, LONG_PTR(hwnd), 0);
  1117. }
  1118. // Signal an EC_REPAINT to the filter graph. This can be used to have data
  1119. // sent to us. For example when a video window is first displayed it may
  1120. // not have an image to display, at which point it signals EC_REPAINT. The
  1121. // filtergraph will either pause the graph if stopped or if already paused
  1122. // it will call put_CurrentPosition of the current position. Setting the
  1123. // current position to itself has the stream flushed and the image resent
  1124. #define RLOG(_x_) DbgLog((LOG_TRACE,1,TEXT(_x_)));
  1125. void CAudioSwitchRenderer::SendRepaint()
  1126. {
  1127. CAutoLock cSampleLock(&m_RendererLock);
  1128. ASSERT(m_pInputPin[m_inputSelected]);
  1129. // We should not send repaint notifications when...
  1130. // - An end of stream has been notified
  1131. // - Our input pin is being flushed
  1132. // - The input pin is not connected
  1133. // - We have aborted a video playback
  1134. // - There is a repaint already sent
  1135. if (m_bAbort == FALSE)
  1136. {
  1137. if (m_pInputPin[m_inputSelected]->IsConnected() == TRUE)
  1138. {
  1139. if (m_pInputPin[m_inputSelected]->IsFlushing() == FALSE)
  1140. {
  1141. if (IsEndOfStream() == FALSE)
  1142. {
  1143. if (m_bRepaintStatus == TRUE)
  1144. {
  1145. for (int i = 0;i < 16;i++)
  1146. {
  1147. IPin *pPin = (IPin *) m_pInputPin[i];
  1148. if (!pPin) continue;
  1149. NotifyEvent(EC_REPAINT, (LONG_PTR) pPin, 0);
  1150. SetRepaintStatus(FALSE);
  1151. RLOG("Sending repaint");
  1152. }
  1153. }
  1154. }
  1155. }
  1156. }
  1157. }
  1158. }
  1159. // When a video window detects a display change (WM_DISPLAYCHANGE message) it
  1160. // can send an EC_DISPLAY_CHANGED event code along with the renderer pin. The
  1161. // filtergraph will stop everyone and reconnect our input pin. As we're then
  1162. // reconnected we can accept the media type that matches the new display mode
  1163. // since we may no longer be able to draw the current image type efficiently
  1164. BOOL CAudioSwitchRenderer::OnDisplayChange()
  1165. {
  1166. // Ignore if we are not connected yet
  1167. CAutoLock cSampleLock(&m_RendererLock);
  1168. int n = 0;
  1169. for (int i = 0;i < 16;i++)
  1170. if (!m_pInputPin[i] || m_pInputPin[i]->IsConnected() == FALSE) n++;
  1171. if (n == 16)
  1172. return FALSE;
  1173. RLOG("Notification of EC_DISPLAY_CHANGE");
  1174. // Pass our input pin as parameter on the event
  1175. for (int i = 0;i < 16;i++)
  1176. if (m_pInputPin[i] && m_pInputPin[i]->IsConnected())
  1177. {
  1178. IPin *pPin = (IPin *) m_pInputPin[i];
  1179. m_pInputPin[i]->AddRef();
  1180. NotifyEvent(EC_DISPLAY_CHANGED, (LONG_PTR) pPin, 0);
  1181. SetAbortSignal(TRUE);
  1182. ClearPendingSample();
  1183. m_pInputPin[i]->Release();
  1184. }
  1185. return TRUE;
  1186. }
  1187. // Called just before we start drawing.
  1188. // Store the current time in m_trRenderStart to allow the rendering time to be
  1189. // logged. Log the time stamp of the sample and how late it is (neg is early)
  1190. void CAudioSwitchRenderer::OnRenderStart(IMediaSample *pMediaSample)
  1191. {
  1192. #ifdef PERF
  1193. REFERENCE_TIME trStart, trEnd;
  1194. pMediaSample->GetTime(&trStart, &trEnd);
  1195. MSR_INTEGER(m_idBaseStamp, (int)trStart); // dump low order 32 bits
  1196. m_pClock->GetTime(&m_trRenderStart);
  1197. MSR_INTEGER(0, (int)m_trRenderStart);
  1198. REFERENCE_TIME trStream;
  1199. trStream = m_trRenderStart - m_tStart; // convert reftime to stream time
  1200. MSR_INTEGER(0, (int)trStream);
  1201. const int trLate = (int)(trStream - trStart);
  1202. MSR_INTEGER(m_idBaseAccuracy, trLate / 10000); // dump in mSec
  1203. #endif
  1204. } // OnRenderStart
  1205. // Called directly after drawing an image.
  1206. // calculate the time spent drawing and log it.
  1207. void CAudioSwitchRenderer::OnRenderEnd(IMediaSample *pMediaSample)
  1208. {
  1209. #ifdef PERF
  1210. REFERENCE_TIME trNow;
  1211. m_pClock->GetTime(&trNow);
  1212. MSR_INTEGER(0, (int)trNow);
  1213. int t = (int)((trNow - m_trRenderStart) / 10000); // convert UNITS->msec
  1214. MSR_INTEGER(m_idBaseRenderTime, t);
  1215. #endif
  1216. } // OnRenderEnd
  1217. void CAudioSwitchRenderer::SetSelectedInput(int n)
  1218. {
  1219. if (m_inputSelected == n) return ;
  1220. if (n > 15 || n < 0) return ;
  1221. ClearPendingSample();
  1222. m_inputSelected = n;
  1223. GetSelectedPin()->NotifyMediaType();
  1224. }
  1225. int CAudioSwitchRenderer::GetSelectedInput()
  1226. {
  1227. return m_inputSelected;
  1228. }
  1229. int CAudioSwitchRenderer::GetConnectedInputsCount()
  1230. {
  1231. int n = 0;
  1232. for (int i = 0;i < 16;i++)
  1233. {
  1234. if (m_pInputPin[i] && m_pInputPin[i]->IsConnected()) n++;
  1235. }
  1236. return n;
  1237. }
  1238. // Constructor must be passed the base renderer object
  1239. CAudioSwitchRendererInputPin::CAudioSwitchRendererInputPin(CAudioSwitchRenderer *pRenderer,
  1240. HRESULT *phr,
  1241. LPCWSTR pPinName) :
  1242. CBaseInputPin(NAME("Renderer pin"),
  1243. pRenderer,
  1244. &pRenderer->m_InterfaceLock,
  1245. (HRESULT *) phr,
  1246. pPinName)
  1247. {
  1248. m_pRenderer = pRenderer;
  1249. ASSERT(m_pRenderer);
  1250. }
  1251. // Signals end of data stream on the input pin
  1252. STDMETHODIMP CAudioSwitchRendererInputPin::EndOfStream()
  1253. {
  1254. HRESULT hr = NOERROR;
  1255. if (m_pRenderer->GetSelectedPin() == this)
  1256. {
  1257. CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock);
  1258. CAutoLock cSampleLock(&m_pRenderer->m_RendererLock);
  1259. // Make sure we're streaming ok
  1260. hr = CheckStreaming();
  1261. if (hr != NOERROR)
  1262. {
  1263. return hr;
  1264. }
  1265. // Pass it onto the renderer
  1266. hr = m_pRenderer->EndOfStream();
  1267. }
  1268. if (SUCCEEDED(hr))
  1269. {
  1270. hr = CBaseInputPin::EndOfStream();
  1271. }
  1272. return hr;
  1273. }
  1274. // Signals start of flushing on the input pin - we do the final reset end of
  1275. // stream with the renderer lock unlocked but with the interface lock locked
  1276. // We must do this because we call timeKillEvent, our timer callback method
  1277. // has to take the renderer lock to serialise our state. Therefore holding a
  1278. // renderer lock when calling timeKillEvent could cause a deadlock condition
  1279. STDMETHODIMP CAudioSwitchRendererInputPin::BeginFlush()
  1280. {
  1281. if (m_pRenderer->GetSelectedPin() == this)
  1282. {
  1283. CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock);
  1284. {
  1285. CAutoLock cSampleLock(&m_pRenderer->m_RendererLock);
  1286. CBaseInputPin::BeginFlush();
  1287. m_pRenderer->BeginFlush();
  1288. }
  1289. return m_pRenderer->ResetEndOfStream();
  1290. }
  1291. else return CBaseInputPin::BeginFlush();
  1292. }
  1293. // Signals end of flushing on the input pin
  1294. STDMETHODIMP CAudioSwitchRendererInputPin::EndFlush()
  1295. {
  1296. HRESULT hr = NOERROR;
  1297. if (m_pRenderer->GetSelectedPin() == this)
  1298. {
  1299. CAutoLock cRendererLock(&m_pRenderer->m_InterfaceLock);
  1300. CAutoLock cSampleLock(&m_pRenderer->m_RendererLock);
  1301. hr = m_pRenderer->EndFlush();
  1302. }
  1303. if (SUCCEEDED(hr))
  1304. {
  1305. hr = CBaseInputPin::EndFlush();
  1306. }
  1307. return hr;
  1308. }
  1309. // Pass the sample straight through to the renderer object
  1310. STDMETHODIMP CAudioSwitchRendererInputPin::Receive(IMediaSample *pSample)
  1311. {
  1312. if (m_pRenderer->GetSelectedPin() != this)
  1313. return NOERROR;
  1314. return m_pRenderer->Receive(pSample);
  1315. }
  1316. // Called when the input pin is disconnected
  1317. HRESULT CAudioSwitchRendererInputPin::BreakConnect()
  1318. {
  1319. if (m_pRenderer->GetSelectedPin() == this)
  1320. {
  1321. HRESULT hr = m_pRenderer->BreakConnect();
  1322. if (FAILED(hr))
  1323. {
  1324. return hr;
  1325. }
  1326. }
  1327. return CBaseInputPin::BreakConnect();
  1328. }
  1329. // Called when the input pin is connected
  1330. HRESULT CAudioSwitchRendererInputPin::CompleteConnect(IPin *pReceivePin)
  1331. {
  1332. if (m_pRenderer->GetSelectedPin() == this)
  1333. {
  1334. HRESULT hr = m_pRenderer->CompleteConnect(pReceivePin);
  1335. if (FAILED(hr))
  1336. {
  1337. return hr;
  1338. }
  1339. }
  1340. return CBaseInputPin::CompleteConnect(pReceivePin);
  1341. }
  1342. // Give the pin id of our one and only pin
  1343. STDMETHODIMP CAudioSwitchRendererInputPin::QueryId(LPWSTR *Id)
  1344. {
  1345. CheckPointer(Id, E_POINTER);
  1346. *Id = (LPWSTR)CoTaskMemAlloc(8);
  1347. if (*Id == NULL)
  1348. {
  1349. return E_OUTOFMEMORY;
  1350. }
  1351. StringCbCopyW(*Id, 8, m_pName);
  1352. return NOERROR;
  1353. }
  1354. // Will the filter accept this media type
  1355. HRESULT CAudioSwitchRendererInputPin::CheckMediaType(const CMediaType *pmt)
  1356. {
  1357. return m_pRenderer->CheckMediaType(pmt);
  1358. }
  1359. // Called when we go paused or running
  1360. HRESULT CAudioSwitchRendererInputPin::Active()
  1361. {
  1362. return m_pRenderer->Active();
  1363. }
  1364. // Called when we go into a stopped state
  1365. HRESULT CAudioSwitchRendererInputPin::Inactive()
  1366. {
  1367. return m_pRenderer->Inactive();
  1368. }
  1369. // Tell derived classes about the media type agreed
  1370. HRESULT CAudioSwitchRendererInputPin::SetMediaType(const CMediaType *pmt)
  1371. {
  1372. HRESULT hr = CBaseInputPin::SetMediaType(pmt);
  1373. if (FAILED(hr))
  1374. {
  1375. return hr;
  1376. }
  1377. m_mt = *pmt;
  1378. if (m_pRenderer->GetSelectedPin() != this)
  1379. return NOERROR;
  1380. return m_pRenderer->SetMediaType(pmt);
  1381. }
  1382. HRESULT CAudioSwitchRendererInputPin::NotifyMediaType()
  1383. {
  1384. if (m_pRenderer->GetSelectedPin() != this)
  1385. return NOERROR;
  1386. return m_pRenderer->SetMediaType(&m_mt);
  1387. }