Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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