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.

1111 lines
23 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. MSPutil.cpp
  5. Abstract:
  6. This module contains implementation of msp utility functions.
  7. Author:
  8. Mu Han (muhan) 1-November-1997
  9. --*/
  10. #include "stdafx.h"
  11. HRESULT
  12. AddFilter(
  13. IN IGraphBuilder * pIGraph,
  14. IN const CLSID & Clsid,
  15. IN LPCWSTR pwstrName,
  16. OUT IBaseFilter ** ppIBaseFilter
  17. )
  18. /*++
  19. Routine Description:
  20. Create a filter and add it into the filtergraph.
  21. Arguments:
  22. pIGraph - the filter graph.
  23. Clsid - reference to the CLSID of the filter
  24. pwstrName - The name of ther filter added.
  25. ppIBaseFilter - pointer to a pointer that stores the returned IBaseFilter
  26. interface pointer to the newly created filter.
  27. Return Value:
  28. HRESULT
  29. --*/
  30. {
  31. LOG((MSP_TRACE, "AddFilter %ws", pwstrName));
  32. _ASSERTE(ppIBaseFilter != NULL);
  33. HRESULT hr;
  34. if (FAILED(hr = CoCreateInstance(
  35. Clsid,
  36. NULL,
  37. CLSCTX_INPROC_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
  38. __uuidof(IBaseFilter),
  39. (void **) ppIBaseFilter
  40. )))
  41. {
  42. LOG((MSP_ERROR, "create filter %x", hr));
  43. return hr;
  44. }
  45. if (FAILED(hr = pIGraph->AddFilter(*ppIBaseFilter, pwstrName)))
  46. {
  47. LOG((MSP_ERROR, "add filter. %x", hr));
  48. (*ppIBaseFilter)->Release();
  49. *ppIBaseFilter = NULL;
  50. return hr;
  51. }
  52. return S_OK;
  53. }
  54. HRESULT
  55. PinSupportsMediaType (
  56. IN IPin *pIPin,
  57. IN const GUID & MediaType
  58. )
  59. /*++
  60. Return Value:
  61. S_OK - media type supported
  62. S_FALSE - no
  63. other HRESULT value - error code
  64. --*/
  65. {
  66. LOG ((MSP_TRACE, "Check if the media subtype supported on pin"));
  67. HRESULT hr;
  68. // get IEnumMediaTypes on pin
  69. IEnumMediaTypes *pEnum = NULL;
  70. if (FAILED (hr = pIPin->EnumMediaTypes (&pEnum)))
  71. {
  72. LOG ((MSP_ERROR, "Failed to get IEnumMediaTypes on pin"));
  73. return hr;
  74. }
  75. // retrieve one media type each time
  76. AM_MEDIA_TYPE *pMediaType = NULL;
  77. ULONG cFetched;
  78. while (S_OK == (hr = pEnum->Next (1, &pMediaType, &cFetched)))
  79. {
  80. if (IsEqualGUID(pMediaType->majortype, MediaType))
  81. {
  82. // media subtype matched
  83. MSPDeleteMediaType (pMediaType);
  84. pEnum->Release ();
  85. return S_OK;
  86. }
  87. MSPDeleteMediaType (pMediaType);
  88. }
  89. pEnum->Release ();
  90. return hr;
  91. }
  92. HRESULT
  93. EnableRTCPEvents(
  94. IN IBaseFilter *pIBaseFilter
  95. )
  96. /*++
  97. Routine Description:
  98. Set the address of a rtp stream
  99. Arguments:
  100. pIBaseFilter - an rtp source filters.
  101. Return Value:
  102. HRESULT
  103. --*/
  104. {
  105. LOG((MSP_TRACE, "EnableRTCPEvents"));
  106. /*
  107. HRESULT hr;
  108. // Get the IRTCPStream interface pointer on the filter.
  109. CComQIPtr<IRTCPStream,
  110. &__uuidof(IRTCPStream)> pIRTCPStream(pIBaseFilter);
  111. if (pIRTCPStream == NULL)
  112. {
  113. LOG((MSP_ERROR, "get RTCP Stream interface"));
  114. return E_NOINTERFACE;
  115. }
  116. // enable events.
  117. if (FAILED(hr = pIRTCPStream->ModifyRTCPEventMask(
  118. (1 << DXMRTP_NEW_SOURCE_EVENT) |
  119. (1 << DXMRTP_RECV_RTCP_SNDR_REPORT_EVENT) |
  120. (1 << DXMRTP_RECV_RTCP_RECV_REPORT_EVENT) |
  121. (1 << DXMRTP_TIMEOUT_EVENT) |
  122. (1 << DXMRTP_BYE_EVENT)
  123. , 1
  124. )))
  125. {
  126. LOG((MSP_ERROR, "set Address. %x", hr));
  127. return hr;
  128. }
  129. */ return S_OK;
  130. }
  131. HRESULT
  132. SetLoopbackOption(
  133. IN IBaseFilter *pIBaseFilter,
  134. IN MULTICAST_LOOPBACK_MODE LoopbackMode
  135. )
  136. /*++
  137. Routine Description:
  138. Enable of disable loopback based on registry settings.
  139. Arguments:
  140. pIBaseFilter - rtp source filter.
  141. bLoopback - enable loopback or not.
  142. Return Value:
  143. HRESULT
  144. --*/
  145. {
  146. LOG((MSP_TRACE, "SetLoopbackOption"));
  147. HRESULT hr;
  148. /*
  149. // Get the IRTPStream interface pointer on the filter.
  150. CComQIPtr<IRTPStream,
  151. &__uuidof(IRTPStream)> pIRTPStream(pIBaseFilter);
  152. if (pIRTPStream == NULL)
  153. {
  154. LOG((MSP_ERROR, "get RTP Stream interface"));
  155. return E_NOINTERFACE;
  156. }
  157. _ASSERT(MM_NO_LOOPBACK == DXMRTP_NO_MULTICAST_LOOPBACK);
  158. _ASSERT(MM_FULL_LOOPBACK == DXMRTP_FULL_MULTICAST_LOOPBACK);
  159. _ASSERT(MM_SELECTIVE_LOOPBACK == DXMRTP_SELECTIVE_MULTICAST_LOOPBACK);
  160. // Set the loopback mode used in the filter.
  161. if (FAILED(hr = pIRTPStream->SetMulticastLoopBack(
  162. (DXMRTP_MULTICAST_LOOPBACK_MODE)LoopbackMode)))
  163. {
  164. LOG((MSP_ERROR, "set loopback. %x", hr));
  165. return hr;
  166. }
  167. LOG((MSP_INFO, "loopback enabled."));
  168. return hr;
  169. */
  170. return E_NOTIMPL;
  171. }
  172. HRESULT
  173. SetQOSOption(
  174. IN IBaseFilter * pIBaseFilter,
  175. IN DWORD dwPayloadType,
  176. IN DWORD dwMaxBitRate,
  177. IN BOOL bFailIfNoQOS,
  178. IN BOOL bReceive,
  179. IN DWORD dwNumStreams,
  180. IN BOOL bCIF
  181. )
  182. /*++
  183. Routine Description:
  184. Enable QOS.
  185. Arguments:
  186. pIBaseFilter - rtp source filter.
  187. dwPayloadType - the rtp payload type of this stream.
  188. bFailIfNoQOS - fail the stream is QOS is not available.
  189. bReceive - if this stream is a receiving stream.
  190. dwNumStreams - the number of streams reserved.
  191. bCIF - CIF or QCIF.
  192. Return Value:
  193. HRESULT
  194. --*/
  195. {
  196. /*
  197. LOG((MSP_TRACE, "SetQOSOption"));
  198. char * szQOSName;
  199. DWORD fSharedStyle = DXMRTP_RESERVE_EXPLICIT;
  200. switch (dwPayloadType)
  201. {
  202. case PAYLOAD_G711U:
  203. case PAYLOAD_G711A:
  204. szQOSName = "G711";
  205. fSharedStyle = DXMRTP_RESERVE_WILCARD;
  206. break;
  207. case PAYLOAD_GSM:
  208. szQOSName = "GSM6.10";
  209. fSharedStyle = DXMRTP_RESERVE_WILCARD;
  210. break;
  211. case PAYLOAD_G723:
  212. szQOSName = "G723";
  213. fSharedStyle = DXMRTP_RESERVE_WILCARD;
  214. break;
  215. case PAYLOAD_H261:
  216. szQOSName = (bCIF) ? "H261CIF" : "H261QCIF";
  217. break;
  218. case PAYLOAD_H263:
  219. szQOSName = (bCIF) ? "H263CIF" : "H263QCIF";
  220. break;
  221. default:
  222. LOG((MSP_WARN, "Don't know the QOS name for payload type: %d",
  223. dwPayloadType));
  224. return S_FALSE;
  225. }
  226. // Get the IRTPStream interface pointer on the filter.
  227. CComQIPtr<IRTPStream,
  228. &__uuidof(IRTPStream)> pIRTPStream(pIBaseFilter);
  229. if (pIRTPStream == NULL)
  230. {
  231. LOG((MSP_ERROR, "get RTP Stream interface"));
  232. return E_NOINTERFACE;
  233. }
  234. HRESULT hr;
  235. // Enable QOS,
  236. if (FAILED(hr = pIRTPStream->SetQOSByName(szQOSName, bFailIfNoQOS)))
  237. {
  238. LOG((MSP_ERROR, "set QOS by name. %x", hr));
  239. return hr;
  240. }
  241. // Get the IRTPParticipant interface pointer on the filter.
  242. CComQIPtr<IRTPParticipant,
  243. &__uuidof(IRTPParticipant)> pIRTPParticipant(pIBaseFilter);
  244. if (pIRTPParticipant == NULL)
  245. {
  246. LOG((MSP_ERROR, "get RTP participant interface"));
  247. return E_NOINTERFACE;
  248. }
  249. if (FAILED(hr = pIRTPParticipant->SetMaxQOSEnabledParticipants(
  250. (bReceive) ? dwNumStreams : 1,
  251. dwMaxBitRate,
  252. fSharedStyle
  253. )))
  254. {
  255. LOG((MSP_ERROR, "SetMaxQOSEnabledParticipants. %x", hr));
  256. return hr;
  257. }
  258. DWORD dwQOSEventMask =
  259. (1 << DXMRTP_QOSEVENT_NOQOS) |
  260. (1 << DXMRTP_QOSEVENT_REQUEST_CONFIRMED) |
  261. (1 << DXMRTP_QOSEVENT_ADMISSION_FAILURE) |
  262. (1 << DXMRTP_QOSEVENT_POLICY_FAILURE) |
  263. (1 << DXMRTP_QOSEVENT_BAD_STYLE) |
  264. (1 << DXMRTP_QOSEVENT_BAD_OBJECT) |
  265. (1 << DXMRTP_QOSEVENT_TRAFFIC_CTRL_ERROR) |
  266. (1 << DXMRTP_QOSEVENT_GENERIC_ERROR);
  267. if (bReceive)
  268. {
  269. dwQOSEventMask |=
  270. (1 << DXMRTP_QOSEVENT_SENDERS) |
  271. (1 << DXMRTP_QOSEVENT_NO_SENDERS);
  272. }
  273. else
  274. {
  275. dwQOSEventMask |=
  276. (1 << DXMRTP_QOSEVENT_RECEIVERS) |
  277. (1 << DXMRTP_QOSEVENT_NO_RECEIVERS) |
  278. (1 << DXMRTP_QOSEVENT_NOT_ALLOWEDTOSEND) |
  279. (1 << DXMRTP_QOSEVENT_ALLOWEDTOSEND);
  280. }
  281. // enable events.
  282. if (FAILED(hr = pIRTPStream->ModifyQOSEventMask(dwQOSEventMask, 1)))
  283. {
  284. LOG((MSP_ERROR, "set QOSEventMask. %x", hr));
  285. return hr;
  286. }
  287. LOG((MSP_INFO, "enabled qos for %s.", szQOSName));
  288. return hr;
  289. */
  290. return E_NOTIMPL;
  291. }
  292. HRESULT
  293. FindPin(
  294. IN IBaseFilter * pIFilter,
  295. OUT IPin ** ppIPin,
  296. IN PIN_DIRECTION direction,
  297. IN BOOL bFree
  298. )
  299. /*++
  300. Routine Description:
  301. Find a input pin or output pin on a filter.
  302. Arguments:
  303. pIFilter - the filter that has pins.
  304. ppIPin - the place to store the returned interface pointer.
  305. direction - PINDIR_INPUT or PINDIR_OUTPUT.
  306. bFree - look for a free pin or not.
  307. Return Value:
  308. HRESULT
  309. --*/
  310. {
  311. _ASSERTE(ppIPin != NULL);
  312. HRESULT hr;
  313. DWORD dwFeched;
  314. // Get the enumerator of pins on the filter.
  315. CComPtr<IEnumPins> pIEnumPins;
  316. if (FAILED(hr = pIFilter->EnumPins(&pIEnumPins)))
  317. {
  318. LOG((MSP_ERROR, "enumerate pins on the filter %x", hr));
  319. return hr;
  320. }
  321. IPin * pIPin = NULL;
  322. // Enumerate all the pins and break on the
  323. // first pin that meets requirement.
  324. for (;;)
  325. {
  326. if (pIEnumPins->Next(1, &pIPin, &dwFeched) != S_OK)
  327. {
  328. LOG((MSP_ERROR, "find pin on filter."));
  329. return E_FAIL;
  330. }
  331. if (0 == dwFeched)
  332. {
  333. LOG((MSP_ERROR, "get 0 pin from filter."));
  334. return E_FAIL;
  335. }
  336. PIN_DIRECTION dir;
  337. if (FAILED(hr = pIPin->QueryDirection(&dir)))
  338. {
  339. LOG((MSP_ERROR, "query pin direction. %x", hr));
  340. pIPin->Release();
  341. return hr;
  342. }
  343. if (direction == dir)
  344. {
  345. if (!bFree)
  346. {
  347. break;
  348. }
  349. // Check to see if the pin is free.
  350. CComPtr<IPin> pIPinConnected;
  351. hr = pIPin->ConnectedTo(&pIPinConnected);
  352. if (pIPinConnected == NULL)
  353. {
  354. break;
  355. }
  356. }
  357. pIPin->Release();
  358. }
  359. *ppIPin = pIPin;
  360. return S_OK;
  361. }
  362. HRESULT
  363. ConnectFilters(
  364. IN IGraphBuilder * pIGraph,
  365. IN IBaseFilter * pIFilter1,
  366. IN IBaseFilter * pIFilter2,
  367. IN BOOL fDirect,
  368. IN AM_MEDIA_TYPE * pmt
  369. )
  370. /*++
  371. Routine Description:
  372. Connect the output pin of the first filter to the input pin of the
  373. second filter.
  374. Arguments:
  375. pIGraph - the filter graph.
  376. pIFilter1 - the filter that has the output pin.
  377. pIFilter2 - the filter that has the input pin.
  378. pmt - a pointer to a AM_MEDIA_TYPE used in the connection.
  379. Return Value:
  380. HRESULT
  381. --*/
  382. {
  383. LOG((MSP_TRACE, "ConnectFilters"));
  384. HRESULT hr;
  385. CComPtr<IPin> pIPinOutput;
  386. if (FAILED(hr = ::FindPin(pIFilter1, &pIPinOutput, PINDIR_OUTPUT)))
  387. {
  388. LOG((MSP_ERROR, "find output pin on filter1. %x", hr));
  389. return hr;
  390. }
  391. CComPtr<IPin> pIPinInput;
  392. if (FAILED(hr = ::FindPin(pIFilter2, &pIPinInput, PINDIR_INPUT)))
  393. {
  394. LOG((MSP_ERROR, "find input pin on filter2. %x", hr));
  395. return hr;
  396. }
  397. if (fDirect)
  398. {
  399. if (FAILED(hr = pIGraph->ConnectDirect(pIPinOutput, pIPinInput, pmt)))
  400. {
  401. LOG((MSP_ERROR, "connect pins direct failed: %x", hr));
  402. return hr;
  403. }
  404. }
  405. else
  406. {
  407. if (FAILED(hr = pIGraph->Connect(pIPinOutput, pIPinInput)))
  408. {
  409. LOG((MSP_ERROR, "connect pins %x", hr));
  410. return hr;
  411. }
  412. }
  413. return S_OK;
  414. }
  415. HRESULT
  416. ConnectFilters(
  417. IN IGraphBuilder * pIGraph,
  418. IN IPin * pIPinOutput,
  419. IN IBaseFilter * pIFilter,
  420. IN BOOL fDirect,
  421. IN AM_MEDIA_TYPE * pmt
  422. )
  423. /*++
  424. Routine Description:
  425. Connect an output pin to the input pin of a filter.
  426. Arguments:
  427. pIGraph - the filter graph.
  428. pIPinOutput - an output pin.
  429. pIFilter - a filter that has the input pin.
  430. pmt - a pointer to a AM_MEDIA_TYPE used in the connection.
  431. Return Value:
  432. HRESULT
  433. --*/
  434. {
  435. LOG((MSP_TRACE, "ConnectFilters"));
  436. HRESULT hr;
  437. CComPtr<IPin> pIPinInput;
  438. if (FAILED(hr = ::FindPin(pIFilter, &pIPinInput, PINDIR_INPUT)))
  439. {
  440. LOG((MSP_ERROR, "find input pin on filter. %x", hr));
  441. return hr;
  442. }
  443. if (fDirect)
  444. {
  445. if (FAILED(hr = pIGraph->ConnectDirect(pIPinOutput, pIPinInput, pmt)))
  446. {
  447. LOG((MSP_ERROR, "connect pins direct failed: %x", hr));
  448. return hr;
  449. }
  450. }
  451. else
  452. {
  453. if (FAILED(hr = pIGraph->Connect(pIPinOutput, pIPinInput)))
  454. {
  455. LOG((MSP_ERROR, "connect pins %x", hr));
  456. return hr;
  457. }
  458. }
  459. return S_OK;
  460. }
  461. HRESULT
  462. ConnectFilters(
  463. IN IGraphBuilder * pIGraph,
  464. IN IBaseFilter * pIFilter,
  465. IN IPin * pIPinInput,
  466. IN BOOL fDirect,
  467. IN AM_MEDIA_TYPE * pmt
  468. )
  469. /*++
  470. Routine Description:
  471. Connect an filter to the input pin of a filter.
  472. Arguments:
  473. pIGraph - the filter graph.
  474. pIPinOutput - an output pin.
  475. pIFilter - a filter that has the input pin.
  476. pmt - a pointer to a AM_MEDIA_TYPE used in the connection.
  477. Return Value:
  478. HRESULT
  479. --*/
  480. {
  481. LOG((MSP_TRACE, "ConnectFilters"));
  482. HRESULT hr;
  483. CComPtr<IPin> pIPinOutput;
  484. if (FAILED(hr = ::FindPin(pIFilter, &pIPinOutput, PINDIR_OUTPUT)))
  485. {
  486. LOG((MSP_ERROR, "find input pin on filter. %x", hr));
  487. return hr;
  488. }
  489. if (fDirect)
  490. {
  491. if (FAILED(hr = pIGraph->ConnectDirect(pIPinOutput, pIPinInput, pmt)))
  492. {
  493. LOG((MSP_ERROR, "connect pins direct failed: %x", hr));
  494. return hr;
  495. }
  496. }
  497. else
  498. {
  499. if (FAILED(hr = pIGraph->Connect(pIPinOutput, pIPinInput)))
  500. {
  501. LOG((MSP_ERROR, "connect pins %x", hr));
  502. return hr;
  503. }
  504. }
  505. return S_OK;
  506. }
  507. void WINAPI MSPDeleteMediaType(AM_MEDIA_TYPE *pmt)
  508. /*++
  509. Routine Description:
  510. Delete a AM media type returned by the filters.
  511. Arguments:
  512. pmt - a pointer to a AM_MEDIA_TYPE structure.
  513. Return Value:
  514. HRESULT
  515. --*/
  516. {
  517. // allow NULL pointers for coding simplicity
  518. if (pmt == NULL) {
  519. return;
  520. }
  521. if (pmt->cbFormat != 0) {
  522. CoTaskMemFree((PVOID)pmt->pbFormat);
  523. // Strictly unnecessary but tidier
  524. pmt->cbFormat = 0;
  525. pmt->pbFormat = NULL;
  526. }
  527. if (pmt->pUnk != NULL) {
  528. pmt->pUnk->Release();
  529. pmt->pUnk = NULL;
  530. }
  531. CoTaskMemFree((PVOID)pmt);
  532. }
  533. BOOL
  534. GetRegValue(
  535. IN LPCWSTR szName,
  536. OUT DWORD *pdwValue
  537. )
  538. /*++
  539. Routine Description:
  540. Get a dword from the registry in the ipconfmsp key.
  541. Arguments:
  542. szName - The name of the value.
  543. pdwValue - a pointer to the dword returned.
  544. Return Value:
  545. TURE - SUCCEED.
  546. FALSE - MSP_ERROR
  547. --*/
  548. {
  549. HKEY hKey;
  550. DWORD dwDataSize, dwDataType, dwValue;
  551. if (::RegOpenKeyEx(
  552. HKEY_LOCAL_MACHINE,
  553. gszSDPMSPKey,
  554. 0,
  555. KEY_READ,
  556. &hKey) != NOERROR)
  557. {
  558. return FALSE;
  559. }
  560. dwDataSize = sizeof(DWORD);
  561. if (::RegQueryValueExW(
  562. hKey,
  563. szName,
  564. 0,
  565. &dwDataType,
  566. (LPBYTE) &dwValue,
  567. &dwDataSize) != NOERROR)
  568. {
  569. RegCloseKey (hKey);
  570. return FALSE;
  571. }
  572. *pdwValue = dwValue;
  573. RegCloseKey (hKey);
  574. return TRUE;
  575. }
  576. HRESULT
  577. FindACMAudioCodec(
  578. IN DWORD dwPayloadType,
  579. OUT IBaseFilter **ppIBaseFilter
  580. )
  581. /*++
  582. Routine Description:
  583. Find the audio codec filter based on the payload type.
  584. Arguments:
  585. dwPayloadType - The rtp payload type.
  586. ppIBaseFilter - The returned interface pointer.
  587. Return Value:
  588. HRESULT
  589. --*/
  590. {
  591. LOG((MSP_TRACE, "Find audio codec Called."));
  592. _ASSERTE(ppIBaseFilter != NULL);
  593. HRESULT hr;
  594. int AcmId;
  595. switch (dwPayloadType)
  596. {
  597. case PAYLOAD_G711A:
  598. AcmId = WAVE_FORMAT_ALAW;
  599. break;
  600. case PAYLOAD_G711U:
  601. AcmId = WAVE_FORMAT_MULAW;
  602. break;
  603. case PAYLOAD_GSM:
  604. AcmId = WAVE_FORMAT_GSM610;
  605. break;
  606. case PAYLOAD_MSAUDIO:
  607. AcmId = WAVE_FORMAT_MSAUDIO1;
  608. break;
  609. case PAYLOAD_G721:
  610. AcmId = WAVE_FORMAT_ADPCM;
  611. break;
  612. case PAYLOAD_DVI4_8:
  613. AcmId = WAVE_FORMAT_DVI_ADPCM;
  614. break;
  615. default:
  616. return E_FAIL;
  617. }
  618. //
  619. // Create the DirectShow Category enumerator Creator
  620. //
  621. CComPtr<ICreateDevEnum> pCreateDevEnum;
  622. CComPtr<IEnumMoniker> pCatEnum;
  623. hr = CoCreateInstance(
  624. CLSID_SystemDeviceEnum,
  625. NULL,
  626. CLSCTX_INPROC_SERVER | CLSCTX_NO_CODE_DOWNLOAD,
  627. __uuidof(ICreateDevEnum),
  628. (void**)&pCreateDevEnum);
  629. if (FAILED(hr))
  630. {
  631. LOG((MSP_ERROR, "Create system device enum - hr: %8x", hr));
  632. return hr;
  633. }
  634. hr = pCreateDevEnum->CreateClassEnumerator(
  635. CLSID_CAcmCoClassManager,
  636. &pCatEnum,
  637. 0
  638. );
  639. if (hr != S_OK)
  640. {
  641. LOG((MSP_ERROR, "CreateClassEnumerator - hr: %8x", hr));
  642. return hr;
  643. }
  644. // find the acm wrapper we want to use.
  645. for (;;)
  646. {
  647. ULONG cFetched;
  648. CComPtr<IMoniker> pMoniker;
  649. if (S_OK != (hr = pCatEnum->Next(1, &pMoniker, &cFetched)))
  650. {
  651. break;
  652. }
  653. // Get the ACMid for this filter out of the property bag.
  654. CComPtr<IPropertyBag> pBag;
  655. hr = pMoniker->BindToStorage(0, 0, __uuidof(IPropertyBag), (void **)&pBag);
  656. if (FAILED(hr))
  657. {
  658. LOG((MSP_ERROR, "get property bag - hr: %8x", hr));
  659. continue;
  660. }
  661. VARIANT var;
  662. var.vt = VT_I4;
  663. hr = pBag->Read(L"AcmId", &var, 0);
  664. if (FAILED(hr))
  665. {
  666. LOG((MSP_ERROR, "read acmid - hr: %8x", hr));
  667. continue;
  668. }
  669. if (AcmId == V_I4(&var))
  670. {
  671. // Now make the filter for this.
  672. hr = pMoniker->BindToObject(
  673. 0,
  674. 0,
  675. __uuidof(IBaseFilter),
  676. (void**)ppIBaseFilter
  677. );
  678. if (FAILED(hr))
  679. {
  680. LOG((MSP_ERROR, "BindToObject - hr: %8x", hr));
  681. }
  682. break;
  683. }
  684. }
  685. return hr;
  686. }
  687. HRESULT SetAudioFormat(
  688. IN IUnknown* pIUnknown,
  689. IN WORD wBitPerSample,
  690. IN DWORD dwSampleRate
  691. )
  692. /*++
  693. Routine Description:
  694. Get the IAMStreamConfig interface on the pin and config the
  695. audio format by using WAVEFORMATEX.
  696. Arguments:
  697. pIUnknown - an object to configure.
  698. wBitPerSample - the number of bits in each sample.
  699. dwSampleRate - number of samples per second.
  700. Return Value:
  701. HRESULT
  702. --*/
  703. {
  704. LOG((MSP_TRACE, "SetAudioFormat entered"));
  705. HRESULT hr;
  706. CComPtr<IAMStreamConfig> pIAMStreamConfig;
  707. if (FAILED(hr = pIUnknown->QueryInterface(
  708. __uuidof(IAMStreamConfig),
  709. (void **)&pIAMStreamConfig
  710. )))
  711. {
  712. LOG((MSP_ERROR, "Can't get IAMStreamConfig interface.%8x", hr));
  713. return hr;
  714. }
  715. AM_MEDIA_TYPE mt;
  716. WAVEFORMATEX wfx;
  717. wfx.wFormatTag = WAVE_FORMAT_PCM;
  718. wfx.wBitsPerSample = wBitPerSample;
  719. wfx.nChannels = 1;
  720. wfx.nSamplesPerSec = dwSampleRate;
  721. wfx.nBlockAlign = wfx.wBitsPerSample * wfx.nChannels / 8;
  722. wfx.nAvgBytesPerSec = ((DWORD) wfx.nBlockAlign * wfx.nSamplesPerSec);
  723. wfx.cbSize = 0;
  724. mt.majortype = MEDIATYPE_Audio;
  725. mt.subtype = MEDIASUBTYPE_PCM;
  726. mt.bFixedSizeSamples = TRUE;
  727. mt.bTemporalCompression = FALSE;
  728. mt.lSampleSize = 0;
  729. mt.formattype = FORMAT_WaveFormatEx;
  730. mt.pUnk = NULL;
  731. mt.cbFormat = sizeof(WAVEFORMATEX);
  732. mt.pbFormat = (BYTE*)&wfx;
  733. // set the format of the audio capture terminal.
  734. if (FAILED(hr = pIAMStreamConfig->SetFormat(&mt)))
  735. {
  736. LOG((MSP_ERROR, "SetFormat returns error: %8x", hr));
  737. return hr;
  738. }
  739. return S_OK;
  740. }
  741. HRESULT SetAudioBufferSize(
  742. IN IUnknown* pIUnknown,
  743. IN DWORD dwNumBuffers,
  744. IN DWORD dwBufferSize
  745. )
  746. /*++
  747. Routine Description:
  748. Set the audio capture output pin's buffer size. The buffer size
  749. determins how many milliseconds worth of samples are contained
  750. in a buffer.
  751. Arguments:
  752. pIUnknown - an object to configure.
  753. dwNumBuffers - the number of buffers to be allocated. Too few buffers
  754. might cause starvation on the capture device.
  755. dwBufferSize - The size of each buffer.
  756. Return Value:
  757. HRESULT
  758. --*/
  759. {
  760. LOG((MSP_TRACE, "SetAudioBufferSize, dwNumBuffers %d, dwBuffersize %d",
  761. dwNumBuffers, dwBufferSize));
  762. _ASSERTE(dwNumBuffers != 0 && dwBufferSize != 0);
  763. HRESULT hr;
  764. CComPtr<IAMBufferNegotiation> pBN;
  765. if (FAILED(hr = pIUnknown->QueryInterface(
  766. __uuidof(IAMBufferNegotiation),
  767. (void **)&pBN
  768. )))
  769. {
  770. LOG((MSP_ERROR, "Can't get buffer negotiation.%8x", hr));
  771. return hr;
  772. }
  773. ALLOCATOR_PROPERTIES prop;
  774. // Set the number of buffers.
  775. prop.cBuffers = dwNumBuffers;
  776. prop.cbBuffer = dwBufferSize;
  777. prop.cbAlign = -1;
  778. prop.cbPrefix = -1;
  779. if (FAILED(hr = pBN->SuggestAllocatorProperties(&prop)))
  780. {
  781. LOG((MSP_ERROR, "SuggestAllocatorProperties returns error: %8x", hr));
  782. }
  783. else
  784. {
  785. LOG((MSP_INFO,
  786. "SetAudioBuffersize"
  787. " buffers: %d, buffersize: %d, align: %d, Prefix: %d",
  788. prop.cBuffers,
  789. prop.cbBuffer,
  790. prop.cbAlign,
  791. prop.cbPrefix
  792. ));
  793. }
  794. return hr;
  795. }
  796. /* Init reference time */
  797. void CMSPStreamClock::InitReferenceTime(void)
  798. {
  799. m_lPerfFrequency = 0;
  800. /* NOTE The fact that having multiprocessor makes the
  801. * performance counter to be unreliable (in some machines)
  802. * unless I set the processor affinity, which I can not
  803. * because any thread can request the time, so use it only on
  804. * uniprocessor machines */
  805. /* MAYDO Would be nice to enable this also in multiprocessor
  806. * machines, if I could specify what procesor's performance
  807. * counter to read or if I had a processor independent
  808. * performance counter */
  809. /* Actually the error should be quite smaller than 1ms, making
  810. * this bug irrelevant for my porpuses, so alway use performance
  811. * counter if available */
  812. QueryPerformanceFrequency((LARGE_INTEGER *)&m_lPerfFrequency);
  813. if (m_lPerfFrequency)
  814. {
  815. QueryPerformanceCounter((LARGE_INTEGER *)&m_lRtpRefTime);
  816. /* Arbitrarily start time not at zero but at 100ms */
  817. m_lRtpRefTime -= m_lPerfFrequency/10;
  818. }
  819. else
  820. {
  821. m_dwRtpRefTime = timeGetTime();
  822. /* Arbitrarily start time not at zero but at 100ms */
  823. m_dwRtpRefTime -= 100;
  824. }
  825. }
  826. /* Return time in 100's of nanoseconds since the object was
  827. * initialized */
  828. HRESULT CMSPStreamClock::GetTimeOfDay(OUT REFERENCE_TIME *pTime)
  829. {
  830. union {
  831. DWORD dwCurTime;
  832. LONGLONG lCurTime;
  833. };
  834. LONGLONG lTime;
  835. if (m_lPerfFrequency)
  836. {
  837. QueryPerformanceCounter((LARGE_INTEGER *)&lTime);
  838. lCurTime = lTime - m_lRtpRefTime;
  839. *pTime = (REFERENCE_TIME)(lCurTime * 10000000 / m_lPerfFrequency);
  840. }
  841. else
  842. {
  843. dwCurTime = timeGetTime() - m_dwRtpRefTime;
  844. *pTime = (REFERENCE_TIME)(dwCurTime * 10000);
  845. }
  846. return(S_OK);
  847. }