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.

941 lines
22 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1996 - 1999
  3. Module Name:
  4. source.cpp
  5. Abstract:
  6. Implementation of CRtpSourceFilter class.
  7. Environment:
  8. User Mode - Win32
  9. Revision History:
  10. 10-Nov-1996 DonRyan
  11. Created.
  12. --*/
  13. ///////////////////////////////////////////////////////////////////////////////
  14. // //
  15. // Include files //
  16. // //
  17. ///////////////////////////////////////////////////////////////////////////////
  18. #include "globals.h"
  19. ///////////////////////////////////////////////////////////////////////////////
  20. // //
  21. // CRtpSourceFilter Implementation //
  22. // //
  23. ///////////////////////////////////////////////////////////////////////////////
  24. CRtpSourceFilter::CRtpSourceFilter(
  25. LPUNKNOWN pUnk,
  26. HRESULT * phr
  27. )
  28. /*++
  29. Routine Description:
  30. Constructor for CRtpSourceFilter class.
  31. Arguments:
  32. pUnk - IUnknown interface of the delegating object.
  33. phr - pointer to the general OLE return value.
  34. Return Values:
  35. Returns an HRESULT value.
  36. --*/
  37. : CSource(
  38. NAME("CRtpSourceFilter"),
  39. pUnk,
  40. CLSID_RTPSourceFilter,
  41. phr
  42. ),
  43. CPersistStream(pUnk, phr)
  44. {
  45. TraceDebug((
  46. TRACE_TRACE,
  47. TRACE_DEVELOP,
  48. TEXT("[%x:0x%X]CRtpSourceFilter::CRtpSourceFilter"),
  49. GetCurrentThreadId(), this));
  50. WSADATA WSAData;
  51. WORD VersionRequested = MAKEWORD(1,1);
  52. // initialize winsock first
  53. if (WSAStartup(VersionRequested, &WSAData)) {
  54. TraceDebug((
  55. TRACE_ERROR,
  56. TRACE_DEVELOP,
  57. TEXT("WSAStartup returned %d"),
  58. WSAGetLastError()
  59. ));
  60. // default
  61. *phr = E_FAIL;
  62. return; // bail...
  63. }
  64. // allocate new rtp output pin to use as default
  65. CRtpOutputPin * pRtpOutputPin = new CRtpOutputPin(this, GetOwner(), phr);
  66. if (FAILED(*phr)) {
  67. TraceDebug((
  68. TRACE_ERROR,
  69. TRACE_DEVELOP,
  70. TEXT("CRtpSourceFilter::CRtpSourceFilter: "
  71. "new CRtpOutputPin() failed: 0x%X"),
  72. *phr
  73. ));
  74. return;
  75. }
  76. // validate pointer
  77. if (pRtpOutputPin == NULL) {
  78. TraceDebug((
  79. TRACE_ERROR,
  80. TRACE_DEVELOP,
  81. TEXT("Could not create CRtpOutputPin")
  82. ));
  83. // return default
  84. *phr = E_OUTOFMEMORY;
  85. return; // bail...
  86. }
  87. *phr = NO_ERROR;
  88. //
  89. // pins add themselves to filters's array...
  90. //
  91. }
  92. CRtpSourceFilter::~CRtpSourceFilter(
  93. )
  94. /*++
  95. Routine Description:
  96. Destructor for CRtpSourceFilter class.
  97. Arguments:
  98. None.
  99. Return Values:
  100. None.
  101. --*/
  102. {
  103. TraceDebug((
  104. TRACE_TRACE,
  105. TRACE_DEVELOP,
  106. TEXT("[%x:0x%X]CRtpSourceFilter::~CRtpSourceFilter"),
  107. GetCurrentThreadId(), this));
  108. // shutdown now
  109. if (WSACleanup()) {
  110. TraceDebug((
  111. TRACE_ERROR,
  112. TRACE_DEVELOP,
  113. TEXT("WSACleanup returned %d"),
  114. WSAGetLastError()
  115. ));
  116. }
  117. //
  118. // pins delete themselves from filter's array
  119. //
  120. }
  121. CUnknown *
  122. CRtpSourceFilter::CreateInstance(
  123. LPUNKNOWN punk,
  124. HRESULT * phr
  125. )
  126. /*++
  127. Routine Description:
  128. Called by COM to create a CRtpSourceFilter object.
  129. Arguments:
  130. pUnk - pointer to the owner of this object.
  131. phr - pointer to an HRESULT value for resulting information.
  132. Return Values:
  133. None.
  134. --*/
  135. {
  136. TraceDebug((
  137. TRACE_TRACE,
  138. TRACE_ALWAYS,
  139. TEXT("CRtpSourceFilter::CreateInstance")
  140. ));
  141. // attempt to create rtp sender object
  142. CRtpSourceFilter * pNewObject = new CRtpSourceFilter(punk, phr);
  143. // validate pointer
  144. if (pNewObject == NULL) {
  145. TraceDebug((
  146. TRACE_ERROR,
  147. TRACE_DEVELOP,
  148. TEXT("Could not create CRtpSourceFilter")
  149. ));
  150. // return default
  151. *phr = E_OUTOFMEMORY;
  152. }
  153. // return object
  154. return pNewObject;
  155. }
  156. ///////////////////////////////////////////////////////////////////////////////
  157. // //
  158. // CBaseFilter overrided methods //
  159. // //
  160. ///////////////////////////////////////////////////////////////////////////////
  161. LPAMOVIESETUP_FILTER
  162. CRtpSourceFilter::GetSetupData(
  163. )
  164. /*++
  165. Routine Description:
  166. Called by ActiveMovie to retrieve filter setup information.
  167. Arguments:
  168. None.
  169. Return Values:
  170. Returns pointer to filter info structure.
  171. --*/
  172. {
  173. TraceDebug((
  174. TRACE_TRACE,
  175. TRACE_ALWAYS,
  176. TEXT("CRtpSourceFilter::GetSetupData")
  177. ));
  178. // get sink filter info
  179. return &g_RtpSourceFilter;
  180. }
  181. STDMETHODIMP
  182. CRtpSourceFilter::Pause(
  183. )
  184. /*++
  185. Routine Description:
  186. Transitions filter to State_Paused state if it is not in state already.
  187. Arguments:
  188. None.
  189. Return Values:
  190. Returns an HRESULT value.
  191. --*/
  192. {
  193. TraceDebug((
  194. TRACE_TRACE,
  195. TRACE_ALWAYS,
  196. TEXT("CRtpSourceFilter::Pause")
  197. ));
  198. // obtain lock to this object
  199. CAutoLock LockThis(pStateLock());
  200. // check current filter state
  201. if (m_State != State_Paused) {
  202. // obtain number of pins
  203. int cPins = GetPinCount();
  204. // process each pin in filter
  205. for (int c = 0; c < cPins; c++) {
  206. // obtain interface pointer to output pins
  207. CRtpOutputPin * pPin = (CRtpOutputPin *)GetPin(c);
  208. // ignore unconnected pins
  209. if (pPin->IsConnected()) {
  210. // activate pin if stopped else pause
  211. HRESULT hr;
  212. if (m_State == State_Stopped) {
  213. hr = pPin->Active();
  214. } else {
  215. //
  216. // Note: we no longer process pause in the stream thread because
  217. // renderers may block. The stream thread pause actually
  218. // does nothing anyway as our current implementation simply
  219. // stops delivering when in paused state.
  220. //
  221. hr = S_OK;
  222. }
  223. // validate
  224. if (FAILED(hr)) {
  225. TraceDebug((
  226. TRACE_ERROR,
  227. TRACE_DEVELOP,
  228. (m_State == State_Stopped)
  229. ? TEXT("CRtpOutputPin::Active returned 0x%08lx")
  230. : TEXT("CRtpOutputPin::Pause returned 0x%08lx"),
  231. hr
  232. ));
  233. return hr; // bail...
  234. }
  235. }
  236. }
  237. }
  238. // change state now
  239. m_State = State_Paused;
  240. return NOERROR;
  241. }
  242. // ZCS bugfix 6-20-97 as per mail from amovie guys
  243. // Here we overload the CBaseMediaFilter::GetState() method. The only
  244. // difference is that we return VFW_S_CANT_CUE, which keeps the filter graph
  245. // from hanging when we stop the graph before receiving any packets.
  246. // (The video or audio renderer keeps waiting for a packet to "cue" on -- it
  247. // is in an "inconsistent state" until it gets one -- unless we return
  248. // VFW_S_CANT_CUE here!)
  249. STDMETHODIMP
  250. CRtpSourceFilter::GetState(DWORD dwMSecs, FILTER_STATE *State)
  251. {
  252. UNREFERENCED_PARAMETER(dwMSecs);
  253. CheckPointer(State,E_POINTER);
  254. ValidateReadWritePtr(State,sizeof(FILTER_STATE));
  255. *State = m_State;
  256. if (m_State == State_Paused)
  257. {
  258. return VFW_S_CANT_CUE;
  259. }
  260. return S_OK;
  261. }
  262. ///////////////////////////////////////////////////////////////////////////////
  263. // //
  264. // IBaseFilter implemented methods //
  265. // //
  266. ///////////////////////////////////////////////////////////////////////////////
  267. STDMETHODIMP
  268. CRtpSourceFilter::QueryVendorInfo(
  269. LPWSTR * ppVendorInfo
  270. )
  271. /*++
  272. Routine Description:
  273. Returns a vendor information string.
  274. Arguments:
  275. ppVendorInfo - Pointer to a string containing vendor information.
  276. Return Values:
  277. Returns an HRESULT value.
  278. --*/
  279. {
  280. TraceDebug((
  281. TRACE_TRACE,
  282. TRACE_ALWAYS,
  283. TEXT("CRtpSourceFilter::QueryVendorInfo")
  284. ));
  285. // validate pointer
  286. CheckPointer(ppVendorInfo,E_POINTER);
  287. // allocate the description string
  288. *ppVendorInfo = (LPWSTR)CoTaskMemAlloc(
  289. (lstrlenW(g_VendorInfo)+1) * sizeof(WCHAR)
  290. );
  291. // validate pointer
  292. if (*ppVendorInfo == NULL) {
  293. TraceDebug((
  294. TRACE_ERROR,
  295. TRACE_ALWAYS,
  296. TEXT("Could not allocate vendor info")
  297. ));
  298. return E_OUTOFMEMORY; // bail...
  299. }
  300. // copy vendor description string
  301. lstrcpyW(*ppVendorInfo,g_VendorInfo);
  302. return S_OK;
  303. }
  304. ///////////////////////////////////////////////////////////////////////////////
  305. // //
  306. // IPersistStream implemented methods //
  307. // //
  308. ///////////////////////////////////////////////////////////////////////////////
  309. STDMETHODIMP
  310. CRtpSourceFilter::GetClassID(
  311. CLSID *pClsid
  312. )
  313. /*++
  314. Routine Description:
  315. Retrieves the class identifier for this filter.
  316. Arguments:
  317. pClsid - Pointer to a CLSID structure.
  318. Return Values:
  319. Returns an HRESULT value.
  320. --*/
  321. {
  322. TraceDebug((
  323. TRACE_TRACE,
  324. TRACE_ALWAYS,
  325. TEXT("CRtpSourceFilter::GetClassID")
  326. ));
  327. // transfer filter class id
  328. *pClsid = CLSID_RTPSourceFilter;
  329. return S_OK;
  330. }
  331. // ZCS: 6-22-97: copied this from the Demux filter code and modified it...
  332. //
  333. // Name : WriteEntry
  334. // Purpose : A macro that implements the stuff we do to write
  335. // a property of this filter to its persistent stream.
  336. // Context : Used in WriteToStream() to improve readability.
  337. // Returns : Will only return if an error is detected.
  338. // Params :
  339. // Entry Pointer to a buffer containing the value to write.
  340. // InSize Integer indicating the length of the buffer
  341. // OutSize Integer to store the written length.
  342. // Description Char string used to describe the entry.
  343. // Notes :
  344. #define WriteEntry(Entry, InSize, OutSize, Description) \
  345. { TraceDebug((TRACE_TRACE, 4, TEXT("CRtpSourceFilter::WriteToStream: Writing %s"), Description)); \
  346. hr = pStream->Write(Entry, InSize, &OutSize); \
  347. if (FAILED(hr)) { \
  348. TraceDebug((TRACE_ERROR, 2, TEXT("CRtpSourceFilter::WriteToStream: Error 0x%08x writing %s"), hr, Description)); \
  349. return hr; \
  350. } else if (OutSize != InSize) { \
  351. TraceDebug((TRACE_ERROR, 2, \
  352. TEXT("CRtpSourceFilter::WriteToStream: Too few (%d/%d) bytes written for %s"), \
  353. uBytesWritten, sizeof(int), Description)); \
  354. return E_INVALIDARG; \
  355. } /* if */ }
  356. HRESULT
  357. CRtpSourceFilter::WriteToStream(
  358. IStream *pStream
  359. )
  360. /*++
  361. Routine Description:
  362. Writes the filter's data to the given stream.
  363. Arguments:
  364. pStream - Pointer to an IStream to write the filter's data to.
  365. Return Values:
  366. Returns an HRESULT value.
  367. --*/
  368. {
  369. TraceDebug((
  370. TRACE_TRACE,
  371. TRACE_ALWAYS,
  372. TEXT("CRtpSourceFilter::WriteToStream")
  373. ));
  374. // validate pointer
  375. CheckPointer(pStream,E_POINTER);
  376. // obtain lock to this object
  377. CAutoLock LockThis(pStateLock());
  378. //
  379. // Rest of this function added 6-22-97 by ZCS
  380. //
  381. HRESULT hr; // used in the WriteEntry macro
  382. ULONG uBytesWritten = 0;
  383. DWORD dwRtpAddr;
  384. WORD wRtpPort;
  385. DWORD dwMulticastScope;
  386. DWORD dwQOSstate;
  387. DWORD dwMCLoopBack;
  388. // get the RTP session object so we can see the address, port, scope
  389. CRtpSession *pCRtpSession;
  390. ASSERT(m_iPins == 1);
  391. EXECUTE_ASSERT(SUCCEEDED(((CRtpOutputPin *) *m_paStreams)->GetSession(&pCRtpSession)));
  392. // retrieve the address of the rtp stream object
  393. // for a receiver, local port matters
  394. EXECUTE_ASSERT(SUCCEEDED(pCRtpSession->GetAddress(&wRtpPort,
  395. NULL,
  396. &dwRtpAddr)));
  397. // retrieve multicast scope of rtp stream object
  398. EXECUTE_ASSERT(SUCCEEDED(pCRtpSession->GetMulticastScope(&dwMulticastScope)));
  399. // retrieve QOS state of rtp stream object
  400. EXECUTE_ASSERT(SUCCEEDED(pCRtpSession->GetQOSstate(&dwQOSstate)));
  401. // retrieve Multicast Loopback state of rtp stream object
  402. EXECUTE_ASSERT(SUCCEEDED(pCRtpSession->GetMulticastLoopBack(&dwMCLoopBack)));
  403. // write RTP address/port and multicast to the PersistStream
  404. WriteEntry(&dwRtpAddr, sizeof(dwRtpAddr), uBytesWritten,
  405. "RTP address");
  406. WriteEntry(&wRtpPort, sizeof(wRtpPort), uBytesWritten,
  407. "RTP port");
  408. WriteEntry(&dwMulticastScope, sizeof(dwMulticastScope), uBytesWritten, "multicast scope");
  409. WriteEntry(&dwQOSstate, sizeof(dwQOSstate), uBytesWritten, "QOS state");
  410. WriteEntry(&dwMCLoopBack, sizeof(dwMCLoopBack), uBytesWritten, "Multicast Loopback state");
  411. return S_OK;
  412. }
  413. // ZCS: 6-22-97: copied this from the Demux filter code and modified it...
  414. //
  415. // Name : ReadEntry
  416. // Purpose : A macro that implements the stuff we do to read
  417. // a property of this filter from its persistent stream.
  418. // Context : Used in ReadFromStream() to improve readability.
  419. // Returns : Will only return if an error is detected.
  420. // Params :
  421. // Entry Pointer to a buffer containing the value to read.
  422. // InSize Integer indicating the length of the buffer
  423. // OutSize Integer to store the written length.
  424. // Description Char string used to describe the entry.
  425. // Notes :
  426. HRESULT ReadEntry(IStream *pStream, void *Entry,
  427. DWORD InSize, DWORD *pOutSize, char *Description)
  428. {
  429. HRESULT hr;
  430. TraceDebug((TRACE_TRACE, 4,
  431. TEXT("CRtpSourceFilter::ReadFromStream: Reading %s"),
  432. Description));
  433. hr = pStream->Read(Entry, InSize, pOutSize);
  434. if (FAILED(hr)) {
  435. TraceDebug((TRACE_ERROR, 2,
  436. TEXT("CRtpSourceFilter::ReadFromStream: "
  437. "Error 0x%08x reading %s"),
  438. hr, Description));
  439. return hr;
  440. } else if (*pOutSize != InSize) {
  441. TraceDebug((TRACE_ERROR, 2,
  442. TEXT("CRtpSourceFilter::ReadFromStream: "
  443. "Too few (%d/%d) bytes read for %s"),
  444. *pOutSize, InSize, Description));
  445. return E_INVALIDARG;
  446. }
  447. return(S_OK);
  448. }
  449. HRESULT ReadEntry(IStream *pStream, void *Entry,
  450. DWORD InSize, DWORD *pOutSize, char *Description);
  451. HRESULT
  452. CRtpSourceFilter::ReadFromStream(
  453. IStream *pStream
  454. )
  455. /*++
  456. Routine Description:
  457. Reads the filter's data from the given stream.
  458. Arguments:
  459. pStream - Pointer to an IStream to read the filter's data from.
  460. Return Values:
  461. Returns an HRESULT value.
  462. --*/
  463. {
  464. TraceDebug((
  465. TRACE_TRACE,
  466. TRACE_ALWAYS,
  467. TEXT("CRtpSourceFilter::ReadFromStream")
  468. ));
  469. // validate pointer
  470. CheckPointer(pStream,E_POINTER);
  471. // obtain lock to this object
  472. CAutoLock LockThis(pStateLock());
  473. //
  474. // Rest of this function added 6-22-97 by ZCS based mostly on
  475. // Don Ryan's property page code...
  476. //
  477. HRESULT hr;
  478. DWORD uBytesWritten = 0;
  479. DWORD dwRtpAddr;
  480. WORD wRtpPort;
  481. DWORD RtpScope;
  482. DWORD QOSstate;
  483. DWORD MCLoopBack;
  484. // get the RTP session object so we can see the address, port, scope
  485. CRtpSession *pCRtpSession = NULL;
  486. ASSERT(m_iPins == 1);
  487. // hr = ((CRtpOutputPin *) *m_paStreams)->GetSession(&pCRtpSession);
  488. // if (FAILED(hr)) {
  489. // pCRtpSession = NULL;
  490. // }
  491. // ASSERT(SUCCEEDED(hr));
  492. EXECUTE_ASSERT(SUCCEEDED(((CRtpOutputPin *) *m_paStreams)->
  493. GetSession(&pCRtpSession)));
  494. ASSERT(!IsBadReadPtr(pCRtpSession, sizeof(pCRtpSession)));
  495. // retrieve RTP address and port from stream
  496. hr = ReadEntry(pStream, &dwRtpAddr, sizeof(dwRtpAddr), &uBytesWritten,
  497. "RTP address");
  498. if (FAILED(hr)) return(hr);
  499. hr = ReadEntry(pStream, &wRtpPort, sizeof(wRtpPort), &uBytesWritten,
  500. "RTP address");
  501. if (FAILED(hr)) return(hr);
  502. // attempt to modify the rtp address
  503. // in unicast, the remote port is what matters for a sender
  504. // in multicast, they have to be the same, SetAddress takes care
  505. hr = pCRtpSession->SetAddress(wRtpPort, wRtpPort, dwRtpAddr);
  506. // validate
  507. if (FAILED(hr)) {
  508. TraceDebug((
  509. TRACE_ERROR,
  510. TRACE_ALWAYS,
  511. TEXT("IRTPStream::SetAddress returns 0x%08lx"), hr
  512. ));
  513. return hr; // bail...
  514. }
  515. // retrieve multicast scope from stream
  516. ReadEntry(pStream, &RtpScope, sizeof(RtpScope), &uBytesWritten,
  517. "multicast scope");
  518. // attempt to modify the scope
  519. hr = pCRtpSession->SetMulticastScope(RtpScope);
  520. // validate
  521. if (FAILED(hr)) {
  522. TraceDebug((
  523. TRACE_ERROR,
  524. TRACE_ALWAYS,
  525. TEXT("IRTPStream::SetScope returns 0x%08lx"), hr
  526. ));
  527. return hr; // bail...
  528. }
  529. // retrieve QOS state from stream
  530. ReadEntry(pStream, &QOSstate, sizeof(QOSstate), &uBytesWritten,
  531. "QOS state");
  532. // attempt to modify the QOS state
  533. hr = pCRtpSession->SetQOSstate(QOSstate);
  534. // validate
  535. if (FAILED(hr)) {
  536. TraceDebug((
  537. TRACE_ERROR,
  538. TRACE_ALWAYS,
  539. TEXT("IRTPStream::SetQOSstate returns 0x%08lx"), hr
  540. ));
  541. return hr; // bail...
  542. }
  543. // retrieve Multicast Loopback state from stream
  544. ReadEntry(pStream, &MCLoopBack, sizeof(MCLoopBack), &uBytesWritten,
  545. "Multicast Loopback state");
  546. // attempt to modify the QOS state
  547. MCLoopBack = (MCLoopBack)? TRUE:FALSE;
  548. hr = pCRtpSession->SetMulticastLoopBack(MCLoopBack);
  549. // validate
  550. if (FAILED(hr)) {
  551. TraceDebug((
  552. TRACE_ERROR,
  553. TRACE_ALWAYS,
  554. TEXT("IRTPStream::SetMulticastLoopBack returns 0x%08lx"), hr
  555. ));
  556. return hr; // bail...
  557. }
  558. return S_OK;
  559. }
  560. int
  561. CRtpSourceFilter::SizeMax(
  562. )
  563. /*++
  564. Routine Description:
  565. Returns an interface and increments the reference count.
  566. Arguments:
  567. riid - reference identifier.
  568. ppv - pointer to the interface.
  569. Return Values:
  570. Returns a pointer to the interface.
  571. --*/
  572. {
  573. TraceDebug((
  574. TRACE_TRACE,
  575. TRACE_ALWAYS,
  576. TEXT("CRtpSourceFilter::SizeMax")
  577. ));
  578. // obtain lock to this object
  579. CAutoLock LockThis(pStateLock());
  580. //
  581. // CODEWORK...
  582. //
  583. return S_OK;
  584. }
  585. ///////////////////////////////////////////////////////////////////////////////
  586. // //
  587. // ISpecifyPropertyPages implemented methods //
  588. // //
  589. ///////////////////////////////////////////////////////////////////////////////
  590. STDMETHODIMP
  591. CRtpSourceFilter::GetPages(
  592. CAUUID * pPages
  593. )
  594. /*++
  595. Routine Description:
  596. Returns property class id associated with filter.
  597. Arguments:
  598. pPages - pointer to received property page class id.
  599. Return Values:
  600. Returns an HRESULT value.
  601. --*/
  602. {
  603. TraceDebug((
  604. TRACE_TRACE,
  605. TRACE_ALWAYS,
  606. TEXT("CRtpSourceFilter::GetPages")
  607. ));
  608. // number of pages
  609. pPages->cElems = 1;
  610. // allocate space to place property page guid
  611. pPages->pElems = (GUID *)CoTaskMemAlloc(sizeof(GUID));
  612. // validate pointer
  613. if (pPages->pElems == NULL) {
  614. TraceDebug((
  615. TRACE_ERROR,
  616. TRACE_ALWAYS,
  617. TEXT("Could not allocate property page guid")
  618. ));
  619. return E_OUTOFMEMORY;
  620. }
  621. // transfer property page guid to caller
  622. *(pPages->pElems) = CLSID_RTPRenderFilterProperties;
  623. return S_OK;
  624. }
  625. ///////////////////////////////////////////////////////////////////////////////
  626. // //
  627. // INonDelegatingUnknown implemented methods //
  628. // //
  629. ///////////////////////////////////////////////////////////////////////////////
  630. STDMETHODIMP
  631. CRtpSourceFilter::NonDelegatingQueryInterface(
  632. REFIID riid,
  633. void ** ppv
  634. )
  635. /*++
  636. Routine Description:
  637. Returns an interface and increments the reference count.
  638. Arguments:
  639. riid - reference identifier.
  640. ppv - pointer to the interface.
  641. Return Values:
  642. Returns a pointer to the interface.
  643. --*/
  644. {
  645. #ifdef DEBUG_CRITICAL_PATH
  646. TraceDebug((
  647. TRACE_TRACE,
  648. TRACE_CRITICAL,
  649. TEXT("CRtpSourceFilter::NonDelegatingQueryInterface")
  650. ));
  651. #endif // DEBUG_CRITICAL_PATH
  652. // validate pointer
  653. CheckPointer(ppv,E_POINTER);
  654. // obtain proper interface
  655. if (riid == IID_IPersistStream) {
  656. // return pointer to this object
  657. return GetInterface((IPersistStream *)this, ppv);
  658. } else if (riid == IID_ISpecifyPropertyPages) {
  659. // return pointer to this object
  660. return GetInterface((ISpecifyPropertyPages *)this, ppv);
  661. } else if (riid == IID_IRTPStream ||
  662. riid == IID_IRTCPStream ||
  663. riid == IID_IRTPParticipant) {
  664. // obtain pointer to default output pin object
  665. CRtpOutputPin * pRtpOutputPin = (CRtpOutputPin *)GetPin(0);
  666. // forward request to default pin object
  667. return pRtpOutputPin->NonDelegatingQueryInterface(riid, ppv);
  668. } else {
  669. // forward this request to the base object
  670. return CSource::NonDelegatingQueryInterface(riid, ppv);
  671. }
  672. }