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.

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