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.

797 lines
16 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. 0xffffffff, 0
  84. )))
  85. {
  86. LOG((MSP_ERROR, "clear RTCP event mask. %x", hr));
  87. return hr;
  88. }
  89. // enable events.
  90. if (FAILED(hr = pIRTCPStream->ModifyRTCPEventMask(
  91. (1 << DXMRTP_INACTIVE_EVENT) |
  92. (1 << DXMRTP_LOSS_RATE_LOCAL_EVENT) |
  93. (1 << DXMRTP_LOSS_RATE_RR_EVENT) |
  94. (1 << DXMRTP_ACTIVE_AGAIN_EVENT)
  95. , 1
  96. )))
  97. {
  98. LOG((MSP_ERROR, "set RTCP event mask. %x", hr));
  99. return hr;
  100. }
  101. return S_OK;
  102. }
  103. HRESULT
  104. SetQOSOption(
  105. IN IBaseFilter * pIBaseFilter,
  106. IN DWORD dwPayloadType,
  107. IN DWORD dwMaxBandwidth,
  108. IN BOOL bReceive,
  109. IN BOOL bCIF
  110. )
  111. /*++
  112. Routine Description:
  113. Enable QOS based on registry settings.
  114. Arguments:
  115. pIBaseFilter - rtp source filter.
  116. dwPayloadType - the rtp payload type of this stream.
  117. bCIF - CIF or QCIF.
  118. Return Value:
  119. HRESULT
  120. --*/
  121. {
  122. LOG((MSP_TRACE, "SetQOSOption, Payload: %d, bandwidth:%d",
  123. dwPayloadType, dwMaxBandwidth
  124. ));
  125. char * szQOSName;
  126. DWORD fSharedStyle = DXMRTP_RESERVE_EXPLICIT;
  127. switch (dwPayloadType)
  128. {
  129. case PAYLOAD_G711U:
  130. case PAYLOAD_G711A:
  131. szQOSName = "G711";
  132. fSharedStyle = DXMRTP_RESERVE_WILCARD;
  133. break;
  134. case PAYLOAD_G723:
  135. szQOSName = "G723";
  136. fSharedStyle = DXMRTP_RESERVE_WILCARD;
  137. break;
  138. case PAYLOAD_H261:
  139. szQOSName = (bCIF) ? "H261CIF" : "H261QCIF";
  140. break;
  141. case PAYLOAD_H263:
  142. szQOSName = (bCIF) ? "H263CIF" : "H263QCIF";
  143. break;
  144. default:
  145. LOG((MSP_WARN, "Don't know the QOS name for payload type: %d",
  146. dwPayloadType));
  147. return S_FALSE;
  148. }
  149. // Get the IRTPStream interface pointer on the filter.
  150. CComQIPtr<IRTPStream,
  151. &IID_IRTPStream> pIRTPStream(pIBaseFilter);
  152. if (pIRTPStream == NULL)
  153. {
  154. LOG((MSP_ERROR, "get RTP Stream interface"));
  155. return E_NOINTERFACE;
  156. }
  157. HRESULT hr;
  158. // Enable QOS,
  159. if (FAILED(hr = pIRTPStream->SetQOSByName(szQOSName, 0)))
  160. {
  161. LOG((MSP_ERROR, "set QOS by name. %x", hr));
  162. return hr;
  163. }
  164. // Get the IRTPParticipant interface pointer on the filter.
  165. CComQIPtr<IRTPParticipant,
  166. &IID_IRTPParticipant> pIRTPParticipant(pIBaseFilter);
  167. if (pIRTPParticipant == NULL)
  168. {
  169. LOG((MSP_ERROR, "get RTP participant interface"));
  170. return E_NOINTERFACE;
  171. }
  172. if (FAILED(hr = pIRTPParticipant->SetMaxQOSEnabledParticipants(
  173. 1,
  174. dwMaxBandwidth,
  175. fSharedStyle
  176. )))
  177. {
  178. LOG((MSP_ERROR, "SetMaxQOSEnabledParticipants. %x", hr));
  179. return hr;
  180. }
  181. DWORD dwQOSEventMask =
  182. (1 << DXMRTP_QOSEVENT_NOQOS) |
  183. (1 << DXMRTP_QOSEVENT_REQUEST_CONFIRMED) |
  184. (1 << DXMRTP_QOSEVENT_ADMISSION_FAILURE) |
  185. (1 << DXMRTP_QOSEVENT_POLICY_FAILURE) |
  186. (1 << DXMRTP_QOSEVENT_BAD_STYLE) |
  187. (1 << DXMRTP_QOSEVENT_BAD_OBJECT) |
  188. (1 << DXMRTP_QOSEVENT_TRAFFIC_CTRL_ERROR) |
  189. (1 << DXMRTP_QOSEVENT_GENERIC_ERROR);
  190. if (bReceive)
  191. {
  192. dwQOSEventMask |=
  193. (1 << DXMRTP_QOSEVENT_SENDERS) |
  194. (1 << DXMRTP_QOSEVENT_NO_SENDERS);
  195. }
  196. else
  197. {
  198. dwQOSEventMask |=
  199. (1 << DXMRTP_QOSEVENT_RECEIVERS) |
  200. (1 << DXMRTP_QOSEVENT_NO_RECEIVERS) |
  201. (1 << DXMRTP_QOSEVENT_NOT_ALLOWEDTOSEND) |
  202. (1 << DXMRTP_QOSEVENT_ALLOWEDTOSEND);
  203. }
  204. // enable events.
  205. if (FAILED(hr = pIRTPStream->ModifyQOSEventMask(dwQOSEventMask, 1)))
  206. {
  207. LOG((MSP_ERROR, "set QOSEventMask. %x", hr));
  208. return hr;
  209. }
  210. LOG((MSP_INFO, "enabled qos for %s.", szQOSName));
  211. return hr;
  212. }
  213. HRESULT
  214. FindPin(
  215. IN IBaseFilter * pIFilter,
  216. OUT IPin ** ppIPin,
  217. IN PIN_DIRECTION direction,
  218. IN BOOL bFree
  219. )
  220. /*++
  221. Routine Description:
  222. Find a input pin or output pin on a filter.
  223. Arguments:
  224. pIFilter - the filter that has pins.
  225. ppIPin - the place to store the returned interface pointer.
  226. direction - PINDIR_INPUT or PINDIR_OUTPUT.
  227. bFree - look for a free pin or not.
  228. Return Value:
  229. HRESULT
  230. --*/
  231. {
  232. _ASSERTE(ppIPin != NULL);
  233. HRESULT hr;
  234. DWORD dwFeched;
  235. // Get the enumerator of pins on the filter.
  236. CComPtr<IEnumPins> pIEnumPins;
  237. if (FAILED(hr = pIFilter->EnumPins(&pIEnumPins)))
  238. {
  239. LOG((MSP_ERROR, "enumerate pins on the filter %x", hr));
  240. return hr;
  241. }
  242. IPin * pIPin;
  243. // Enumerate all the pins and break on the
  244. // first pin that meets requirement.
  245. for (;;)
  246. {
  247. if (pIEnumPins->Next(1, &pIPin, &dwFeched) != S_OK)
  248. {
  249. LOG((MSP_ERROR, "find pin on filter."));
  250. return E_FAIL;
  251. }
  252. if (0 == dwFeched)
  253. {
  254. LOG((MSP_ERROR, "get 0 pin from filter."));
  255. return E_FAIL;
  256. }
  257. PIN_DIRECTION dir;
  258. if (FAILED(hr = pIPin->QueryDirection(&dir)))
  259. {
  260. LOG((MSP_ERROR, "query pin direction. %x", hr));
  261. pIPin->Release();
  262. return hr;
  263. }
  264. if (direction == dir)
  265. {
  266. if (!bFree)
  267. {
  268. break;
  269. }
  270. // Check to see if the pin is free.
  271. CComPtr<IPin> pIPinConnected;
  272. hr = pIPin->ConnectedTo(&pIPinConnected);
  273. if (pIPinConnected == NULL)
  274. {
  275. break;
  276. }
  277. }
  278. pIPin->Release();
  279. }
  280. *ppIPin = pIPin;
  281. return S_OK;
  282. }
  283. HRESULT
  284. ConnectFilters(
  285. IN IGraphBuilder * pIGraph,
  286. IN IBaseFilter * pIFilter1,
  287. IN IBaseFilter * pIFilter2,
  288. IN BOOL fDirect,
  289. IN AM_MEDIA_TYPE * pmt
  290. )
  291. /*++
  292. Routine Description:
  293. Connect the output pin of the first filter to the input pin of the
  294. second filter.
  295. Arguments:
  296. pIGraph - the filter graph.
  297. pIFilter1 - the filter that has the output pin.
  298. pIFilter2 - the filter that has the input pin.
  299. pmt - a pointer to a AM_MEDIA_TYPE used in the connection.
  300. Return Value:
  301. HRESULT
  302. --*/
  303. {
  304. LOG((MSP_TRACE, "ConnectFilters"));
  305. HRESULT hr;
  306. CComPtr<IPin> pIPinOutput;
  307. if (FAILED(hr = ::FindPin(pIFilter1, &pIPinOutput, PINDIR_OUTPUT)))
  308. {
  309. LOG((MSP_ERROR, "find output pin on filter1. %x", hr));
  310. return hr;
  311. }
  312. CComPtr<IPin> pIPinInput;
  313. if (FAILED(hr = ::FindPin(pIFilter2, &pIPinInput, PINDIR_INPUT)))
  314. {
  315. LOG((MSP_ERROR, "find input pin on filter2. %x", hr));
  316. return hr;
  317. }
  318. if (fDirect)
  319. {
  320. if (FAILED(hr = pIGraph->ConnectDirect(pIPinOutput, pIPinInput, pmt)))
  321. {
  322. LOG((MSP_ERROR, "connect pins direct failed: %x", hr));
  323. return hr;
  324. }
  325. }
  326. else
  327. {
  328. if (FAILED(hr = pIGraph->Connect(pIPinOutput, pIPinInput)))
  329. {
  330. LOG((MSP_ERROR, "connect pins %x", hr));
  331. return hr;
  332. }
  333. }
  334. return S_OK;
  335. }
  336. HRESULT
  337. ConnectFilters(
  338. IN IGraphBuilder * pIGraph,
  339. IN IPin * pIPinOutput,
  340. IN IBaseFilter * pIFilter,
  341. IN BOOL fDirect,
  342. IN AM_MEDIA_TYPE * pmt
  343. )
  344. /*++
  345. Routine Description:
  346. Connect an output pin to the input pin of a filter.
  347. Arguments:
  348. pIGraph - the filter graph.
  349. pIPinOutput - an output pin.
  350. pIFilter - a filter that has the input pin.
  351. pmt - a pointer to a AM_MEDIA_TYPE used in the connection.
  352. Return Value:
  353. HRESULT
  354. --*/
  355. {
  356. LOG((MSP_TRACE, "ConnectFilters"));
  357. HRESULT hr;
  358. CComPtr<IPin> pIPinInput;
  359. if (FAILED(hr = ::FindPin(pIFilter, &pIPinInput, PINDIR_INPUT)))
  360. {
  361. LOG((MSP_ERROR, "find input pin on filter. %x", hr));
  362. return hr;
  363. }
  364. if (fDirect)
  365. {
  366. if (FAILED(hr = pIGraph->ConnectDirect(pIPinOutput, pIPinInput, pmt)))
  367. {
  368. LOG((MSP_ERROR, "connect pins direct failed: %x", hr));
  369. return hr;
  370. }
  371. }
  372. else
  373. {
  374. if (FAILED(hr = pIGraph->Connect(pIPinOutput, pIPinInput)))
  375. {
  376. LOG((MSP_ERROR, "connect pins %x", hr));
  377. return hr;
  378. }
  379. }
  380. return S_OK;
  381. }
  382. HRESULT
  383. ConnectFilters(
  384. IN IGraphBuilder * pIGraph,
  385. IN IBaseFilter * pIFilter,
  386. IN IPin * pIPinInput,
  387. IN BOOL fDirect,
  388. IN AM_MEDIA_TYPE * pmt
  389. )
  390. /*++
  391. Routine Description:
  392. Connect an filter to the input pin of a filter.
  393. Arguments:
  394. pIGraph - the filter graph.
  395. pIPinOutput - an output pin.
  396. pIFilter - a filter that has the input pin.
  397. pmt - a pointer to a AM_MEDIA_TYPE used in the connection.
  398. Return Value:
  399. HRESULT
  400. --*/
  401. {
  402. LOG((MSP_TRACE, "ConnectFilters"));
  403. HRESULT hr;
  404. CComPtr<IPin> pIPinOutput;
  405. if (FAILED(hr = ::FindPin(pIFilter, &pIPinOutput, PINDIR_OUTPUT)))
  406. {
  407. LOG((MSP_ERROR, "find input pin on filter. %x", hr));
  408. return hr;
  409. }
  410. if (fDirect)
  411. {
  412. if (FAILED(hr = pIGraph->ConnectDirect(pIPinOutput, pIPinInput, pmt)))
  413. {
  414. LOG((MSP_ERROR, "connect pins direct failed: %x", hr));
  415. return hr;
  416. }
  417. }
  418. else
  419. {
  420. if (FAILED(hr = pIGraph->Connect(pIPinOutput, pIPinInput)))
  421. {
  422. LOG((MSP_ERROR, "connect pins %x", hr));
  423. return hr;
  424. }
  425. }
  426. return S_OK;
  427. }
  428. void WINAPI DeleteMediaType(AM_MEDIA_TYPE *pmt)
  429. /*++
  430. Routine Description:
  431. Delete a AM media type returned by the filters.
  432. Arguments:
  433. pmt - a pointer to a AM_MEDIA_TYPE structure.
  434. Return Value:
  435. HRESULT
  436. --*/
  437. {
  438. // allow NULL pointers for coding simplicity
  439. if (pmt == NULL) {
  440. return;
  441. }
  442. if (pmt->cbFormat != 0) {
  443. CoTaskMemFree((PVOID)pmt->pbFormat);
  444. // Strictly unnecessary but tidier
  445. pmt->cbFormat = 0;
  446. pmt->pbFormat = NULL;
  447. }
  448. if (pmt->pUnk != NULL) {
  449. pmt->pUnk->Release();
  450. pmt->pUnk = NULL;
  451. }
  452. CoTaskMemFree((PVOID)pmt);
  453. }
  454. BOOL
  455. GetRegValue(
  456. IN LPCWSTR szName,
  457. OUT DWORD *pdwValue
  458. )
  459. /*++
  460. Routine Description:
  461. Get a dword from the registry in the ipH323msp key.
  462. Arguments:
  463. szName - The name of the value.
  464. pdwValue - a pointer to the dword returned.
  465. Return Value:
  466. TURE - SUCCEED.
  467. FALSE - MSP_ERROR
  468. --*/
  469. {
  470. HKEY hKey;
  471. DWORD dwDataSize, dwDataType, dwData = 0;
  472. if (::RegOpenKeyEx(
  473. HKEY_LOCAL_MACHINE,
  474. gszSDPMSPKey,
  475. 0,
  476. KEY_READ,
  477. &hKey) != NOERROR)
  478. {
  479. return FALSE;
  480. }
  481. dwDataSize = sizeof(DWORD);
  482. if (::RegQueryValueExW(
  483. hKey,
  484. szName,
  485. 0,
  486. &dwDataType,
  487. (LPBYTE) dwData,
  488. &dwDataSize) != NOERROR)
  489. {
  490. RegCloseKey (hKey);
  491. return FALSE;
  492. }
  493. RegCloseKey (hKey);
  494. *pdwValue = dwData;
  495. return TRUE;
  496. }
  497. HRESULT SetAudioFormat(
  498. IN IUnknown* pIUnknown,
  499. IN WORD wBitPerSample,
  500. IN DWORD dwSampleRate
  501. )
  502. /*++
  503. Routine Description:
  504. Get the IAMStreamConfig interface on the object and config the
  505. audio format by using WAVEFORMATEX.
  506. Arguments:
  507. pIPin - a capture terminal.
  508. wBitPerSample - the number of bits in each sample.
  509. dwSampleRate - number of samples per second.
  510. Return Value:
  511. HRESULT
  512. --*/
  513. {
  514. LOG((MSP_TRACE, "SetAudioFormat entered"));
  515. HRESULT hr;
  516. CComPtr<IAMStreamConfig> pIAMStreamConfig;
  517. if (FAILED(hr = pIUnknown->QueryInterface(
  518. IID_IAMStreamConfig,
  519. (void **)&pIAMStreamConfig
  520. )))
  521. {
  522. LOG((MSP_ERROR, "Can't get IAMStreamConfig interface.%8x", hr));
  523. return hr;
  524. }
  525. AM_MEDIA_TYPE mt;
  526. WAVEFORMATEX wfx;
  527. wfx.wFormatTag = WAVE_FORMAT_PCM;
  528. wfx.wBitsPerSample = wBitPerSample;
  529. wfx.nChannels = 1;
  530. wfx.nSamplesPerSec = dwSampleRate;
  531. wfx.nBlockAlign = wfx.wBitsPerSample * wfx.nChannels / 8;
  532. wfx.nAvgBytesPerSec = ((DWORD) wfx.nBlockAlign * wfx.nSamplesPerSec);
  533. wfx.cbSize = 0;
  534. mt.majortype = MEDIATYPE_Audio;
  535. mt.subtype = MEDIASUBTYPE_PCM;
  536. mt.bFixedSizeSamples = TRUE;
  537. mt.bTemporalCompression = FALSE;
  538. mt.lSampleSize = 0;
  539. mt.formattype = FORMAT_WaveFormatEx;
  540. mt.pUnk = NULL;
  541. mt.cbFormat = sizeof(WAVEFORMATEX);
  542. mt.pbFormat = (BYTE*)&wfx;
  543. // set the format of the audio capture terminal.
  544. if (FAILED(hr = pIAMStreamConfig->SetFormat(&mt)))
  545. {
  546. LOG((MSP_ERROR, "SetFormat returns error: %8x", hr));
  547. return hr;
  548. }
  549. return S_OK;
  550. }
  551. HRESULT SetAudioBufferSize(
  552. IN IUnknown* pIUnknown,
  553. IN DWORD dwNumBuffers,
  554. IN DWORD dwBufferSize
  555. )
  556. /*++
  557. Routine Description:
  558. Set the audio capture buffer size. The buffer size
  559. determins how many milliseconds worth of samples are contained
  560. in a buffer.
  561. Arguments:
  562. pIUnknown - an object that supports IAMBufferNegotiation.
  563. dwNumBuffers - the number of buffers to be allocated. Too few buffers
  564. might cause starvation on the capture device.
  565. dwBufferSize - The size of each buffer.
  566. Return Value:
  567. HRESULT
  568. --*/
  569. {
  570. LOG((MSP_TRACE, "SetAudioBufferSize, dwNumBuffers %d, dwBuffersize %d",
  571. dwNumBuffers, dwBufferSize));
  572. _ASSERTE(dwNumBuffers != 0 && dwBufferSize != 0);
  573. HRESULT hr;
  574. CComPtr<IAMBufferNegotiation> pBN;
  575. if (FAILED(hr = pIUnknown->QueryInterface(
  576. IID_IAMBufferNegotiation,
  577. (void **)&pBN
  578. )))
  579. {
  580. LOG((MSP_ERROR, "Can't get buffer negotiation.%8x", hr));
  581. return hr;
  582. }
  583. ALLOCATOR_PROPERTIES prop;
  584. // Set the number of buffers.
  585. prop.cBuffers = dwNumBuffers;
  586. prop.cbBuffer = dwBufferSize;
  587. prop.cbAlign = -1;
  588. prop.cbPrefix = -1;
  589. if (FAILED(hr = pBN->SuggestAllocatorProperties(&prop)))
  590. {
  591. LOG((MSP_ERROR, "SuggestAllocatorProperties returns error: %8x", hr));
  592. }
  593. else
  594. {
  595. LOG((MSP_INFO,
  596. "SetAudioBuffersize"
  597. " buffers: %d, buffersize: %d, align: %d, Prefix: %d",
  598. prop.cBuffers,
  599. prop.cbBuffer,
  600. prop.cbAlign,
  601. prop.cbPrefix
  602. ));
  603. }
  604. return hr;
  605. }