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.

1997 lines
49 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. confaud.cpp
  5. Abstract:
  6. This module contains implementation of the audio send and receive
  7. stream implementations.
  8. Author:
  9. Mu Han (muhan) 15-September-1999
  10. --*/
  11. #include "stdafx.h"
  12. #include "common.h"
  13. #include <initguid.h>
  14. #include <amrtpnet.h> // rtp guids
  15. #include <amrtpdmx.h> // demux guid
  16. #include <amrtpuid.h> // AMRTP media types
  17. #include <amrtpss.h> // for silence suppression filter
  18. #include <irtprph.h> // for IRTPRPHFilter
  19. #include <irtpsph.h> // for IRTPSPHFilter
  20. #include <mixflter.h> // audio mixer
  21. #include <g711uids.h> // for G711 codec CLSID
  22. #include <g723uids.h> // for G723 codec CLSID
  23. //#define DISABLE_MIXER 1
  24. /////////////////////////////////////////////////////////////////////////////
  25. //
  26. // CStreamAudioRecv
  27. //
  28. /////////////////////////////////////////////////////////////////////////////
  29. CStreamAudioRecv::CStreamAudioRecv()
  30. : CIPConfMSPStream(),
  31. m_pWaveFormatEx(NULL),
  32. m_dwSizeWaveFormatEx(0),
  33. m_fUseACM(FALSE),
  34. m_dwMaxPacketSize(0),
  35. m_dwAudioSampleRate(0)
  36. {
  37. m_szName = L"AudioRecv";
  38. }
  39. void CStreamAudioRecv::FinalRelease()
  40. {
  41. CIPConfMSPStream::FinalRelease();
  42. if (m_pWaveFormatEx)
  43. {
  44. free(m_pWaveFormatEx);
  45. }
  46. }
  47. HRESULT CStreamAudioRecv::Configure(
  48. IN STREAMSETTINGS &StreamSettings
  49. )
  50. /*++
  51. Routine Description:
  52. Configure the settings of this stream.
  53. Arguments:
  54. StreamSettings - The setting structure got from the SDP blob.
  55. Return Value:
  56. HRESULT.
  57. --*/
  58. {
  59. LOG((MSP_TRACE, "AudioRecv Configure entered."));
  60. CLock lock(m_lock);
  61. _ASSERTE(m_fIsConfigured == FALSE);
  62. switch (StreamSettings.dwPayloadType)
  63. {
  64. case PAYLOAD_G711U:
  65. // The mixer can convert them, no codec needed.
  66. m_pClsidCodecFilter = &GUID_NULL;
  67. m_pRPHInputMinorType = &MEDIASUBTYPE_RTP_Payload_G711U;
  68. m_pClsidPHFilter = &CLSID_INTEL_RPHAUD;
  69. m_dwMaxPacketSize = g_dwMaxG711PacketSize;
  70. m_dwAudioSampleRate = g_dwG711AudioSampleRate;
  71. break;
  72. case PAYLOAD_G711A:
  73. m_pClsidCodecFilter = &CLSID_G711Codec;
  74. m_pRPHInputMinorType = &MEDIASUBTYPE_RTP_Payload_G711A;
  75. m_pClsidPHFilter = &CLSID_INTEL_RPHAUD;
  76. m_dwMaxPacketSize = g_dwMaxG711PacketSize;
  77. m_dwAudioSampleRate = g_dwG711AudioSampleRate;
  78. break;
  79. case PAYLOAD_GSM:
  80. m_fUseACM = TRUE;
  81. m_pClsidCodecFilter = &CLSID_ACMWrapper;
  82. m_pRPHInputMinorType = &MEDIASUBTYPE_RTP_Payload_ANY;
  83. m_pClsidPHFilter = &CLSID_INTEL_RPHGENA;
  84. m_dwMaxPacketSize = g_dwMaxGSMPacketSize;
  85. m_dwAudioSampleRate = g_dwGSMAudioSampleRate;
  86. {
  87. GSM610WAVEFORMAT * pWaveFormat =
  88. (GSM610WAVEFORMAT *)malloc(sizeof GSM610WAVEFORMAT);
  89. if (pWaveFormat == NULL)
  90. {
  91. return E_OUTOFMEMORY;
  92. }
  93. pWaveFormat->wfx.wFormatTag = WAVE_FORMAT_GSM610;
  94. pWaveFormat->wfx.wBitsPerSample = 0;
  95. pWaveFormat->wfx.nChannels = g_wAudioChannels;
  96. pWaveFormat->wfx.nSamplesPerSec = m_dwAudioSampleRate;
  97. pWaveFormat->wfx.nAvgBytesPerSec = g_dwGSMBytesPerSecond;
  98. pWaveFormat->wfx.nBlockAlign = g_wGSMBlockAlignment;
  99. pWaveFormat->wfx.cbSize =
  100. sizeof GSM610WAVEFORMAT - sizeof WAVEFORMATEX;
  101. pWaveFormat->wSamplesPerBlock = g_wGSMSamplesPerBlock;
  102. m_pWaveFormatEx = (BYTE *)pWaveFormat;
  103. m_dwSizeWaveFormatEx = sizeof GSM610WAVEFORMAT;
  104. }
  105. break;
  106. // This is a test of the MSAudio wideband codec
  107. case PAYLOAD_MSAUDIO:
  108. m_fUseACM = TRUE;
  109. m_pClsidCodecFilter = &CLSID_ACMWrapper;
  110. m_pRPHInputMinorType = &MEDIASUBTYPE_RTP_Payload_ANY;
  111. m_pClsidPHFilter = &CLSID_INTEL_RPHGENA;
  112. m_dwMaxPacketSize = g_dwMaxMSAudioPacketSize;
  113. m_dwAudioSampleRate = g_dwMSAudioSampleRate;
  114. {
  115. MSAUDIO1WAVEFORMAT * pWaveFormat =
  116. (MSAUDIO1WAVEFORMAT *)malloc(sizeof MSAUDIO1WAVEFORMAT);
  117. if (pWaveFormat == NULL)
  118. {
  119. return E_OUTOFMEMORY;
  120. }
  121. pWaveFormat->wfx.wFormatTag = WAVE_FORMAT_MSAUDIO1;
  122. pWaveFormat->wfx.wBitsPerSample = MSAUDIO1_BITS_PER_SAMPLE;
  123. pWaveFormat->wfx.nChannels = MSAUDIO1_MAX_CHANNELS;
  124. pWaveFormat->wfx.nSamplesPerSec = m_dwAudioSampleRate;
  125. pWaveFormat->wfx.nAvgBytesPerSec = g_dwMSAudioBytesPerSecond;
  126. pWaveFormat->wfx.nBlockAlign = g_wMSAudioBlockAlignment;
  127. pWaveFormat->wfx.cbSize =
  128. sizeof MSAUDIO1WAVEFORMAT - sizeof WAVEFORMATEX;
  129. pWaveFormat->wSamplesPerBlock = g_wMSAudioSamplesPerBlock;
  130. m_pWaveFormatEx = (BYTE *)pWaveFormat;
  131. m_dwSizeWaveFormatEx = sizeof MSAUDIO1WAVEFORMAT;
  132. }
  133. break;
  134. #ifdef DVI
  135. case PAYLOAD_DVI4_8:
  136. m_fUseACM = TRUE;
  137. m_pClsidCodecFilter = &CLSID_ACMWrapper;
  138. m_pRPHInputMinorType = &MEDIASUBTYPE_RTP_Payload_ANY;
  139. m_pClsidPHFilter = &CLSID_INTEL_RPHGENA;
  140. m_dwMaxPacketSize = g_dwMaxDVI4PacketSize;
  141. m_dwAudioSampleRate = g_dwDVI4AudioSampleRate;
  142. {
  143. IMAADPCMWAVEFORMAT * pWaveFormat =
  144. (IMAADPCMWAVEFORMAT *)malloc(sizeof IMAADPCMWAVEFORMAT);
  145. if (pWaveFormat == NULL)
  146. {
  147. return E_OUTOFMEMORY;
  148. }
  149. pWaveFormat->wfx.wFormatTag = WAVE_FORMAT_IMA_ADPCM;
  150. pWaveFormat->wfx.wBitsPerSample = g_wDVI4BitsPerSample;
  151. pWaveFormat->wfx.nChannels = g_wAudioChannels;
  152. pWaveFormat->wfx.nSamplesPerSec = m_dwAudioSampleRate;
  153. pWaveFormat->wfx.nAvgBytesPerSec = g_dwDVI4BytesPerSecond;
  154. pWaveFormat->wfx.nBlockAlign = g_wDVI4BlockAlignment;
  155. pWaveFormat->wfx.cbSize =
  156. sizeof IMAADPCMWAVEFORMAT - sizeof WAVEFORMATEX;
  157. pWaveFormat->wSamplesPerBlock = g_wDVI4SamplesPerBlock;
  158. m_pWaveFormatEx = (BYTE *)pWaveFormat;
  159. m_dwSizeWaveFormatEx = sizeof IMAADPCMWAVEFORMAT;
  160. }
  161. break;
  162. #endif
  163. default:
  164. LOG((MSP_ERROR, "unknown payload type, %x", StreamSettings.dwPayloadType));
  165. return E_FAIL;
  166. }
  167. m_Settings = StreamSettings;
  168. m_fIsConfigured = TRUE;
  169. return InternalConfigure();
  170. }
  171. HRESULT CStreamAudioRecv::ConfigureRTPFilter(
  172. IN IBaseFilter * pIBaseFilter
  173. )
  174. /*++
  175. Routine Description:
  176. Configure the source RTP filter. Including set the address, port, TTL,
  177. QOS, thread priority, clcokrate, etc.
  178. Arguments:
  179. pIBaseFilter - The source RTP Filter.
  180. Return Value:
  181. HRESULT.
  182. --*/
  183. {
  184. LOG((MSP_TRACE, "AudioRecv ConfigureRTPFilter"));
  185. HRESULT hr;
  186. // Get the IRTPStream interface pointer on the filter.
  187. CComQIPtr<IRTPStream, &IID_IRTPStream> pIRTPStream(pIBaseFilter);
  188. if (pIRTPStream == NULL)
  189. {
  190. LOG((MSP_ERROR, "get RTP Stream interface"));
  191. return E_NOINTERFACE;
  192. }
  193. LOG((MSP_INFO, "set remote Address:%x, port:%d",
  194. m_Settings.dwIPRemote, m_Settings.wRTPPortRemote));
  195. // Set the address and port used in the filter.
  196. if (FAILED(hr = pIRTPStream->SetAddress(
  197. htons(m_Settings.wRTPPortRemote), // local port to listen on.
  198. 0, // remote port.
  199. htonl(m_Settings.dwIPRemote) // remote address.
  200. )))
  201. {
  202. LOG((MSP_ERROR, "set remote Address, hr:%x", hr));
  203. return hr;
  204. }
  205. // Set the TTL used in the filter.
  206. if (FAILED(hr = pIRTPStream->SetMulticastScope(m_Settings.dwTTL)))
  207. {
  208. LOG((MSP_ERROR, "set TTL. %x", hr));
  209. return hr;
  210. }
  211. if (m_Settings.dwIPLocal != INADDR_ANY)
  212. {
  213. // set the local interface that the socket should bind to
  214. LOG((MSP_INFO, "set locol Address:%x", m_Settings.dwIPLocal));
  215. if (FAILED(hr = pIRTPStream->SelectLocalIPAddress(
  216. htonl(m_Settings.dwIPLocal)
  217. )))
  218. {
  219. LOG((MSP_ERROR, "set locol Address, hr:%x", hr));
  220. return hr;
  221. }
  222. }
  223. // Set the priority of the session
  224. if (FAILED(hr = pIRTPStream->SetSessionClassPriority(
  225. RTP_CLASS_AUDIO,
  226. g_dwAudioThreadPriority
  227. )))
  228. {
  229. LOG((MSP_WARN, "set session class and priority. %x", hr));
  230. }
  231. // Set the sample rate of the session
  232. LOG((MSP_INFO, "setting session sample rate to %d", m_dwAudioSampleRate));
  233. if (FAILED(hr = pIRTPStream->SetDataClock(m_dwAudioSampleRate)))
  234. {
  235. LOG((MSP_WARN, "set session sample rate. %x", hr));
  236. }
  237. // Enable the RTCP events
  238. if (FAILED(hr = ::EnableRTCPEvents(pIBaseFilter)))
  239. {
  240. LOG((MSP_WARN, "can not enable RTCP events %x", hr));
  241. }
  242. DWORD dwLoopback = 0;
  243. if (TRUE == ::GetRegValue(gszMSPLoopback, &dwLoopback)
  244. && dwLoopback != 0)
  245. {
  246. // Loopback is required.
  247. if (FAILED(hr = ::SetLoopbackOption(pIBaseFilter, dwLoopback)))
  248. {
  249. LOG((MSP_ERROR, "set loopback option. %x", hr));
  250. return hr;
  251. }
  252. }
  253. if (m_Settings.dwQOSLevel != QSL_BEST_EFFORT)
  254. {
  255. if (FAILED(hr = ::SetQOSOption(
  256. pIBaseFilter,
  257. m_Settings.dwPayloadType, // payload
  258. -1, // use the default bitrate
  259. (m_Settings.dwQOSLevel == QSL_NEEDED), // fail if no qos.
  260. TRUE, // receive stream.
  261. g_wAudioDemuxPins // number of streams reserved.
  262. )))
  263. {
  264. LOG((MSP_ERROR, "set QOS option. %x", hr));
  265. return hr;
  266. }
  267. }
  268. SetLocalInfoOnRTPFilter(pIBaseFilter);
  269. return S_OK;
  270. }
  271. HRESULT CStreamAudioRecv::ConnectTerminal(
  272. IN ITTerminal * pITTerminal
  273. )
  274. /*++
  275. Routine Description:
  276. connect the mixer to the audio render terminal.
  277. Arguments:
  278. pITTerminal - The terminal to be connected.
  279. Return Value:
  280. HRESULT.
  281. --*/
  282. {
  283. LOG((MSP_TRACE, "AudioRecv.ConnectTerminal, pITTerminal %p", pITTerminal));
  284. HRESULT hr;
  285. // if our filters have not been contructed, do it now.
  286. if (m_pEdgeFilter == NULL)
  287. {
  288. hr = SetUpInternalFilters();
  289. if (FAILED(hr))
  290. {
  291. LOG((MSP_ERROR, "Set up internal filter failed, %x", hr));
  292. CleanUpFilters();
  293. return hr;
  294. }
  295. }
  296. // get the terminal control interface.
  297. CComQIPtr<ITTerminalControl, &IID_ITTerminalControl>
  298. pTerminal(pITTerminal);
  299. if (pTerminal == NULL)
  300. {
  301. LOG((MSP_ERROR, "can't get Terminal Control interface"));
  302. SendStreamEvent(
  303. CALL_TERMINAL_FAIL,
  304. CALL_CAUSE_BAD_DEVICE,
  305. E_NOINTERFACE,
  306. pITTerminal
  307. );
  308. return E_NOINTERFACE;
  309. }
  310. const DWORD MAXPINS = 8;
  311. DWORD dwNumPins = MAXPINS;
  312. IPin * Pins[MAXPINS];
  313. // Get the pins.
  314. hr = pTerminal->ConnectTerminal(
  315. m_pIGraphBuilder, 0, &dwNumPins, Pins
  316. );
  317. if (FAILED(hr))
  318. {
  319. LOG((MSP_ERROR, "can't connect to terminal, %x", hr));
  320. SendStreamEvent(
  321. CALL_TERMINAL_FAIL,
  322. CALL_CAUSE_BAD_DEVICE,
  323. hr,
  324. pITTerminal
  325. );
  326. return hr;
  327. }
  328. // the pin count should never be 0.
  329. if (dwNumPins == 0)
  330. {
  331. LOG((MSP_ERROR, "terminal has no pins."));
  332. SendStreamEvent(
  333. CALL_TERMINAL_FAIL,
  334. CALL_CAUSE_BAD_DEVICE,
  335. hr,
  336. pITTerminal
  337. );
  338. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  339. return E_UNEXPECTED;
  340. }
  341. // Connect the mixer filter to the audio render terminal.
  342. hr = ::ConnectFilters(
  343. m_pIGraphBuilder,
  344. (IBaseFilter *)m_pEdgeFilter,
  345. (IPin *)Pins[0]
  346. );
  347. // release the refcounts on the pins.
  348. for (DWORD i = 0; i < dwNumPins; i ++)
  349. {
  350. Pins[i]->Release();
  351. }
  352. if (FAILED(hr))
  353. {
  354. LOG((MSP_ERROR, "connect to the mixer filter. %x", hr));
  355. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  356. return hr;
  357. }
  358. //
  359. // Now we are actually connected. Update our state and perform postconnection
  360. // (ignore postconnection error code).
  361. //
  362. pTerminal->CompleteConnectTerminal();
  363. return hr;
  364. }
  365. HRESULT CStreamAudioRecv::SetUpInternalFilters()
  366. /*++
  367. Routine Description:
  368. set up the filters used in the stream.
  369. RTP->Demux->RPH(->DECODER)->Mixer
  370. Arguments:
  371. Return Value:
  372. HRESULT.
  373. --*/
  374. {
  375. LOG((MSP_TRACE, "AudioRecv.SetUpInternalFilters"));
  376. CComPtr<IBaseFilter> pSourceFilter;
  377. HRESULT hr;
  378. // create and add the source fitler.
  379. if (FAILED(hr = ::AddFilter(
  380. m_pIGraphBuilder,
  381. CLSID_RTPSourceFilter,
  382. L"RtpSource",
  383. &pSourceFilter)))
  384. {
  385. LOG((MSP_ERROR, "adding source filter. %x", hr));
  386. return hr;
  387. }
  388. if (FAILED(hr = ConfigureRTPFilter(pSourceFilter)))
  389. {
  390. LOG((MSP_ERROR, "configure RTP source filter. %x", hr));
  391. return hr;
  392. }
  393. CComPtr<IBaseFilter> pDemuxFilter;
  394. // create and add the demux fitler.
  395. if (FAILED(hr = ::AddFilter(
  396. m_pIGraphBuilder,
  397. CLSID_IntelRTPDemux,
  398. L"RtpDemux",
  399. &pDemuxFilter)))
  400. {
  401. LOG((MSP_ERROR, "adding demux filter. %x", hr));
  402. return hr;
  403. }
  404. // Connect the source filter and the demux filter.
  405. if (FAILED(hr = ::ConnectFilters(
  406. m_pIGraphBuilder,
  407. (IBaseFilter *)pSourceFilter,
  408. (IBaseFilter *)pDemuxFilter)))
  409. {
  410. LOG((MSP_ERROR, "connect source filter and demux filter. %x", hr));
  411. return hr;
  412. }
  413. // Get the IRTPDemuxFilter interface used in configuring the demux filter.
  414. CComQIPtr<IRTPDemuxFilter, &IID_IRTPDemuxFilter> pIRTPDemux(pDemuxFilter);
  415. if (pIRTPDemux == NULL)
  416. {
  417. LOG((MSP_ERROR, "get RTP Demux interface"));
  418. return E_NOINTERFACE;
  419. }
  420. // Set the number of output pins on the demux filter based on the number
  421. // of channels needed.
  422. if (FAILED(hr = pIRTPDemux->SetPinCount(
  423. g_wAudioDemuxPins
  424. )))
  425. {
  426. LOG((MSP_ERROR, "set demux output pin count"));
  427. return hr;
  428. }
  429. LOG((MSP_INFO,
  430. "set demux output pin count to %d",
  431. g_wAudioDemuxPins
  432. ));
  433. // Get the enumerator of pins on the demux filter.
  434. CComPtr<IEnumPins> pIEnumPins;
  435. if (FAILED(hr = pDemuxFilter->EnumPins(&pIEnumPins)))
  436. {
  437. LOG((MSP_ERROR, "enumerate pins on the demux filter %x", hr));
  438. return hr;
  439. }
  440. #ifndef DISABLE_MIXER
  441. // Create and add the mixer filter into the filtergraph.
  442. CComPtr<IBaseFilter> pIMixerFilter;
  443. if (FAILED(hr = ::AddFilter(
  444. m_pIGraphBuilder,
  445. CLSID_AudioMixFilter,
  446. L"Mixer",
  447. &pIMixerFilter
  448. )))
  449. {
  450. LOG((MSP_ERROR, "add Mixer filter. %x", hr));
  451. return hr;
  452. }
  453. LOG((MSP_INFO, "Added Mixer filter"));
  454. // currently we support only one format for each stream.
  455. #endif
  456. #ifndef DISABLE_MIXER
  457. for (DWORD i = 0; i < g_wAudioDemuxPins; i++)
  458. #else
  459. CComPtr<IBaseFilter> pIFilter;
  460. for (DWORD i = 0; i < 1; i++)
  461. #endif
  462. {
  463. // Find the next output pin on the demux fitler.
  464. CComPtr<IPin> pIPinOutput;
  465. for (;;)
  466. {
  467. if ((hr = pIEnumPins->Next(1, &pIPinOutput, NULL)) != S_OK)
  468. {
  469. LOG((MSP_ERROR, "find output pin on demux."));
  470. break;
  471. }
  472. PIN_DIRECTION dir;
  473. if (FAILED(hr = pIPinOutput->QueryDirection(&dir)))
  474. {
  475. LOG((MSP_ERROR, "query pin direction. %x", hr));
  476. pIPinOutput.Release();
  477. break;
  478. }
  479. if (PINDIR_OUTPUT == dir)
  480. {
  481. break;
  482. }
  483. pIPinOutput.Release();
  484. }
  485. if (hr != S_OK)
  486. {
  487. // There is no more output pin on the demux filter.
  488. // This should never happen.
  489. hr = E_UNEXPECTED;
  490. break;
  491. }
  492. // Set the media type on this output pin.
  493. if (FAILED(hr = pIRTPDemux->SetPinTypeInfo(
  494. pIPinOutput,
  495. (BYTE)m_Settings.dwPayloadType,
  496. *m_pRPHInputMinorType
  497. )))
  498. {
  499. LOG((MSP_ERROR, "set demux output pin type info"));
  500. break;
  501. }
  502. LOG((MSP_INFO,
  503. "set demux output pin payload type to %d",
  504. m_Settings.dwPayloadType
  505. ));
  506. // Create and add the payload handler into the filtergraph.
  507. CComPtr<IBaseFilter> pIRPHFilter;
  508. if (FAILED(hr = ::AddFilter(
  509. m_pIGraphBuilder,
  510. *m_pClsidPHFilter,
  511. L"RPH",
  512. &pIRPHFilter
  513. )))
  514. {
  515. LOG((MSP_ERROR, "add RPH filter. %x", hr));
  516. break;
  517. }
  518. // Connect the payload handler to the output pin on the demux.
  519. if (FAILED(hr = ::ConnectFilters(
  520. m_pIGraphBuilder,
  521. (IPin *)pIPinOutput,
  522. (IBaseFilter *)pIRPHFilter
  523. )))
  524. {
  525. LOG((MSP_ERROR, "connect demux and RPH filter. %x", hr));
  526. break;
  527. }
  528. // Get the IRTPRPHFilter interface.
  529. CComQIPtr<IRTPRPHFilter, &IID_IRTPRPHFilter>pIRTPRPHFilter(pIRPHFilter);
  530. if (pIRTPRPHFilter == NULL)
  531. {
  532. LOG((MSP_ERROR, "get IRTPRPHFilter interface"));
  533. break;
  534. }
  535. // set the media buffer size so that the receive buffers are of the
  536. // right size. Note, G723 needs smaller buffers than G711.
  537. if (FAILED(hr = pIRTPRPHFilter->SetMediaBufferSize(
  538. m_dwMaxPacketSize
  539. )))
  540. {
  541. LOG((MSP_ERROR, "Set media buffer size. %x", hr));
  542. break;
  543. }
  544. LOG((MSP_INFO, "Set RPH media buffer size to %d", m_dwMaxPacketSize));
  545. if (m_fUseACM)
  546. {
  547. // We are using the ACM codec, so we have to set the media types
  548. AM_MEDIA_TYPE mt;
  549. mt.majortype = MEDIATYPE_Audio;
  550. mt.subtype = MEDIASUBTYPE_NULL;
  551. mt.bFixedSizeSamples = TRUE;
  552. mt.bTemporalCompression = FALSE;
  553. mt.lSampleSize = 0;
  554. mt.formattype = FORMAT_WaveFormatEx;
  555. mt.pUnk = NULL;
  556. mt.cbFormat = m_dwSizeWaveFormatEx;
  557. mt.pbFormat = m_pWaveFormatEx;
  558. if (FAILED(hr = pIRTPRPHFilter->SetOutputPinMediaType(&mt)))
  559. {
  560. LOG((MSP_ERROR, "Set RPHGENA output pin media type. %x", hr));
  561. return FALSE;
  562. }
  563. if (FAILED(hr = pIRTPRPHFilter->OverridePayloadType(
  564. (BYTE)m_Settings.dwPayloadType
  565. )))
  566. {
  567. LOG((MSP_ERROR, "Set RPHGENA output pin media type. %x", hr));
  568. return FALSE;
  569. }
  570. }
  571. #ifndef DISABLE_MIXER
  572. CComPtr<IBaseFilter> pIFilter;
  573. #endif
  574. // connect the codec filter if it is needed.
  575. if (*m_pClsidCodecFilter != GUID_NULL)
  576. {
  577. if (FAILED(hr = ::AddFilter(
  578. m_pIGraphBuilder,
  579. *m_pClsidCodecFilter,
  580. L"codec",
  581. &pIFilter
  582. )))
  583. {
  584. LOG((MSP_ERROR, "add Codec filter. %x", hr));
  585. break;
  586. }
  587. // Connect the payload handler to the output pin on the demux.
  588. if (FAILED(hr = ::ConnectFilters(
  589. m_pIGraphBuilder,
  590. (IBaseFilter *)pIRPHFilter,
  591. (IBaseFilter *)pIFilter
  592. )))
  593. {
  594. LOG((MSP_ERROR, "connect RPH filter and codec. %x", hr));
  595. break;
  596. }
  597. }
  598. else
  599. {
  600. pIFilter = pIRPHFilter;
  601. }
  602. #ifndef DISABLE_MIXER
  603. // Connect the payload handler or the codec filter to the mixer filter.
  604. if (FAILED(hr = ::ConnectFilters(
  605. m_pIGraphBuilder,
  606. (IBaseFilter *)pIFilter,
  607. (IBaseFilter *)pIMixerFilter
  608. )))
  609. {
  610. LOG((MSP_ERROR, "connect to the mixer filter. %x", hr));
  611. break;
  612. }
  613. #endif
  614. }
  615. if (SUCCEEDED(hr))
  616. {
  617. // keep a reference to the last filter so that the change of terminal
  618. // will not require a recreating of all the filters.
  619. #ifndef DISABLE_MIXER
  620. m_pEdgeFilter = pIMixerFilter;
  621. #else
  622. m_pEdgeFilter = pIFilter;
  623. #endif
  624. m_pEdgeFilter->AddRef();
  625. // Get the IRTPParticipant interface pointer on the RTP filter.
  626. CComQIPtr<IRTPParticipant,
  627. &IID_IRTPParticipant> pIRTPParticipant(pSourceFilter);
  628. if (pIRTPParticipant == NULL)
  629. {
  630. LOG((MSP_WARN, "can't get RTP participant interface"));
  631. }
  632. else
  633. {
  634. m_pRTPFilter = pIRTPParticipant;
  635. m_pRTPFilter->AddRef();
  636. }
  637. }
  638. return hr;
  639. }
  640. HRESULT CStreamAudioRecv::SetUpFilters()
  641. /*++
  642. Routine Description:
  643. Insert filters into the graph and connect to the terminals.
  644. Arguments:
  645. Return Value:
  646. HRESULT.
  647. --*/
  648. {
  649. LOG((MSP_TRACE, "AudioRecv SetupFilters entered."));
  650. HRESULT hr;
  651. // we only support one terminal for this stream.
  652. if (m_Terminals.GetSize() != 1)
  653. {
  654. return E_UNEXPECTED;
  655. }
  656. // Connect the mixer to the terminal.
  657. if (FAILED(hr = ConnectTerminal(
  658. m_Terminals[0]
  659. )))
  660. {
  661. LOG((MSP_ERROR, "connect the mixer filter to terminal. %x", hr));
  662. return hr;
  663. }
  664. return hr;
  665. }
  666. HRESULT CStreamAudioRecv::ProcessSSRCMappedEvent(
  667. IN DWORD dwSSRC
  668. )
  669. /*++
  670. Routine Description:
  671. a SSRC is active, file a participant active event.
  672. Arguments:
  673. dwSSRC - the SSRC of the participant.
  674. Return Value:
  675. S_OK,
  676. E_UNEXPECTED
  677. --*/
  678. {
  679. LOG((MSP_TRACE, "%ls Processes pin mapped event, pIPin: %p", m_szName, dwSSRC));
  680. CLock lock(m_lock);
  681. ITParticipant * pITParticipant = NULL;
  682. // find the SSRC in our participant list.
  683. for (int i = 0; i < m_Participants.GetSize(); i ++)
  684. {
  685. if (((CParticipant *)m_Participants[i])->
  686. HasSSRC((ITStream *)this, dwSSRC))
  687. {
  688. pITParticipant = m_Participants[i];
  689. }
  690. }
  691. // if the participant is not there yet, put the event in a queue and it
  692. // will be fired when we have the CName fo the participant.
  693. if (!pITParticipant)
  694. {
  695. LOG((MSP_INFO, "can't find a participant that has SSRC %x", dwSSRC));
  696. m_PendingSSRCs.Add(dwSSRC);
  697. LOG((MSP_INFO, "added the event to pending list, new list size:%d",
  698. m_PendingSSRCs.GetSize()));
  699. return S_OK;
  700. }
  701. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  702. PE_PARTICIPANT_ACTIVE,
  703. pITParticipant
  704. );
  705. return S_OK;
  706. }
  707. HRESULT CStreamAudioRecv::NewParticipantPostProcess(
  708. IN DWORD dwSSRC,
  709. IN ITParticipant *pITParticipant
  710. )
  711. /*++
  712. Routine Description:
  713. A mapped event happended when we didn't have the participant's name so
  714. it was queued in a list. Now that we have a new participant, let's check
  715. if this is the same participant. If it is, we complete the mapped event
  716. by sending the app an notification.
  717. Arguments:
  718. dwSSRC - the SSRC of the participant.
  719. pITParticipant - the participant object.
  720. Return Value:
  721. S_OK,
  722. E_UNEXPECTED
  723. --*/
  724. {
  725. LOG((MSP_TRACE, "%ls Check pending mapped event, dwSSRC: %x", m_szName, dwSSRC));
  726. // look at the pending SSRC list and find out if this report
  727. // fits in the list.
  728. int i = m_PendingSSRCs.Find(dwSSRC);
  729. if (i < 0)
  730. {
  731. // the SSRC is not in the list of pending PinMappedEvents.
  732. LOG((MSP_TRACE, "the SSRC %x is not in the pending list", dwSSRC));
  733. return S_OK;
  734. }
  735. // get rid of the peding SSRC.
  736. m_PendingSSRCs.RemoveAt(i);
  737. // complete the event.
  738. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  739. PE_PARTICIPANT_ACTIVE,
  740. pITParticipant
  741. );
  742. return S_OK;
  743. }
  744. HRESULT CStreamAudioRecv::ProcessSSRCUnmapEvent(
  745. IN DWORD dwSSRC
  746. )
  747. /*++
  748. Routine Description:
  749. A SSRC just got unmapped by the demux. Notify the app that a participant
  750. becomes inactive.
  751. Arguments:
  752. dwSSRC - the SSRC of the participant.
  753. Return Value:
  754. S_OK,
  755. E_UNEXPECTED
  756. --*/
  757. {
  758. LOG((MSP_TRACE, "%ls Processes SSRC unmapped event, pIPin: %p", m_szName, dwSSRC));
  759. CLock lock(m_lock);
  760. // look at the pending SSRC list and find out if it is in the pending list.
  761. int i = m_PendingSSRCs.Find(dwSSRC);
  762. // if the SSRC is in the pending list, just remove it.
  763. if (i >= 0)
  764. {
  765. m_PendingSSRCs.RemoveAt(i);
  766. return S_OK;
  767. }
  768. ITParticipant *pITParticipant = NULL;
  769. // find the SSRC in our participant list.
  770. for (i = 0; i < m_Participants.GetSize(); i ++)
  771. {
  772. if (((CParticipant *)m_Participants[i])->
  773. HasSSRC((ITStream *)this, dwSSRC))
  774. {
  775. pITParticipant = m_Participants[i];
  776. }
  777. }
  778. if (pITParticipant)
  779. {
  780. // fire an event to tell the app that the participant is inactive.
  781. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  782. PE_PARTICIPANT_INACTIVE,
  783. pITParticipant
  784. );
  785. }
  786. return S_OK;
  787. }
  788. HRESULT CStreamAudioRecv::ProcessParticipantLeave(
  789. IN DWORD dwSSRC
  790. )
  791. /*++
  792. Routine Description:
  793. When participant left the session, remove the stream from the participant
  794. object's list of streams. If all streams are removed, remove the
  795. participant from the call object's list too.
  796. Arguments:
  797. dwSSRC - the SSRC of the participant left.
  798. Return Value:
  799. HRESULT.
  800. --*/
  801. {
  802. LOG((MSP_TRACE, "%ls ProcessParticipantLeave, SSRC: %x", m_szName, dwSSRC));
  803. CLock lock(m_lock);
  804. // look at the pending SSRC list and find out if it is in the pending list.
  805. int i = m_PendingSSRCs.Find(dwSSRC);
  806. // if the SSRC is in the pending list, remove it.
  807. if (i >= 0)
  808. {
  809. m_PendingSSRCs.RemoveAt(i);
  810. }
  811. CParticipant *pParticipant;
  812. BOOL fLast = FALSE;
  813. HRESULT hr = E_FAIL;
  814. // first try to find the SSRC in our participant list.
  815. for (i = 0; i < m_Participants.GetSize(); i ++)
  816. {
  817. pParticipant = (CParticipant *)m_Participants[i];
  818. hr = pParticipant->RemoveStream(
  819. (ITStream *)this,
  820. dwSSRC,
  821. &fLast
  822. );
  823. if (SUCCEEDED(hr))
  824. {
  825. break;
  826. }
  827. }
  828. // if the participant is not found
  829. if (FAILED(hr))
  830. {
  831. LOG((MSP_WARN, "%ws, can't find the SSRC %x", m_szName, dwSSRC));
  832. return hr;
  833. }
  834. ITParticipant *pITParticipant = m_Participants[i];
  835. // fire an event to tell the app that the participant is in active.
  836. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  837. PE_PARTICIPANT_INACTIVE,
  838. pITParticipant
  839. );
  840. m_Participants.RemoveAt(i);
  841. // if this stream is the last stream that the participant is on,
  842. // tell the call object to remove it from its list.
  843. if (fLast)
  844. {
  845. ((CIPConfMSPCall *)m_pMSPCall)->ParticipantLeft(pITParticipant);
  846. }
  847. pITParticipant->Release();
  848. return S_OK;
  849. }
  850. HRESULT CStreamAudioRecv::ProcessGraphEvent(
  851. IN long lEventCode,
  852. IN long lParam1,
  853. IN long lParam2
  854. )
  855. {
  856. LOG((MSP_TRACE, "%ws ProcessGraphEvent %d", m_szName, lEventCode));
  857. switch (lEventCode)
  858. {
  859. case RTPDMX_EVENTBASE + RTPDEMUX_SSRC_MAPPED:
  860. LOG((MSP_INFO, "handling SSRC mapped event, SSRC%x", lParam1));
  861. ProcessSSRCMappedEvent((DWORD)lParam1);
  862. break;
  863. case RTPDMX_EVENTBASE + RTPDEMUX_SSRC_UNMAPPED:
  864. LOG((MSP_INFO, "handling SSRC unmap event, SSRC%x", lParam1));
  865. ProcessSSRCUnmapEvent((DWORD)lParam1);
  866. break;
  867. default:
  868. return CIPConfMSPStream::ProcessGraphEvent(
  869. lEventCode, lParam1, lParam2
  870. );
  871. }
  872. return S_OK;
  873. }
  874. /////////////////////////////////////////////////////////////////////////////
  875. //
  876. // CStreamAudioSend
  877. //
  878. /////////////////////////////////////////////////////////////////////////////
  879. CStreamAudioSend::CStreamAudioSend()
  880. : CIPConfMSPStream(),
  881. m_iACMID(0),
  882. m_dwMSPerPacket(0),
  883. m_fUseACM(FALSE),
  884. m_dwMaxPacketSize(0),
  885. m_dwAudioSampleRate(0)
  886. {
  887. m_szName = L"AudioSend";
  888. }
  889. HRESULT CStreamAudioSend::Configure(
  890. IN STREAMSETTINGS &StreamSettings
  891. )
  892. /*++
  893. Routine Description:
  894. Configure the settings of this stream.
  895. Arguments:
  896. StreamSettings - The setting structure got from the SDP blob.
  897. Return Value:
  898. HRESULT.
  899. --*/
  900. {
  901. LOG((MSP_TRACE, "AudioSend Configure entered."));
  902. CLock lock(m_lock);
  903. _ASSERTE(m_fIsConfigured == FALSE);
  904. switch (StreamSettings.dwPayloadType)
  905. {
  906. case PAYLOAD_G711U:
  907. case PAYLOAD_G711A:
  908. m_pClsidCodecFilter = &CLSID_G711Codec;
  909. m_pClsidPHFilter = &CLSID_INTEL_SPHAUD;
  910. m_dwMSPerPacket = g_dwG711MSPerPacket;
  911. m_dwMaxPacketSize = g_dwG711BytesPerPacket + g_dwRTPHeaderSize;
  912. m_dwAudioSampleRate = g_dwG711AudioSampleRate;
  913. if (StreamSettings.dwMSPerPacket != 0)
  914. {
  915. m_dwMSPerPacket = StreamSettings.dwMSPerPacket;
  916. m_dwMaxPacketSize = m_dwMSPerPacket * m_dwAudioSampleRate / 1000
  917. + g_dwRTPHeaderSize;
  918. }
  919. break;
  920. #ifdef DVI
  921. case PAYLOAD_DVI4_8:
  922. m_fUseACM = TRUE;
  923. m_iACMID = WAVE_FORMAT_IMA_ADPCM;
  924. m_pClsidCodecFilter = &CLSID_ACMWrapper;
  925. m_pRPHInputMinorType = &MEDIASUBTYPE_RTP_Payload_ANY;
  926. m_pClsidPHFilter = &CLSID_INTEL_SPHGENA;
  927. m_dwMSPerPacket = g_dwDVI4MSPerPacket;
  928. m_dwMaxPacketSize = g_dwDVI4BytesPerPacket + g_dwRTPHeaderSize;
  929. m_dwAudioSampleRate = g_dwDVI4AudioSampleRate;
  930. break;
  931. #endif
  932. case PAYLOAD_GSM:
  933. m_fUseACM = TRUE;
  934. m_iACMID = WAVE_FORMAT_GSM610;
  935. m_pClsidCodecFilter = &CLSID_ACMWrapper;
  936. m_pRPHInputMinorType = &MEDIASUBTYPE_RTP_Payload_ANY;
  937. m_pClsidPHFilter = &CLSID_INTEL_SPHGENA;
  938. m_dwMSPerPacket = g_dwGSMMSPerPacket;
  939. m_dwMaxPacketSize = g_dwGSMBytesPerPacket + g_dwRTPHeaderSize;
  940. m_dwAudioSampleRate = g_dwGSMAudioSampleRate;
  941. break;
  942. case PAYLOAD_MSAUDIO:
  943. m_fUseACM = TRUE;
  944. m_iACMID = WAVE_FORMAT_MSAUDIO1;
  945. m_pClsidCodecFilter = &CLSID_ACMWrapper;
  946. m_pRPHInputMinorType = &MEDIASUBTYPE_RTP_Payload_ANY;
  947. m_pClsidPHFilter = &CLSID_INTEL_SPHGENA;
  948. m_dwMSPerPacket = g_dwMSAudioMSPerPacket;
  949. m_dwMaxPacketSize = g_dwMaxMSAudioPacketSize;
  950. m_dwAudioSampleRate = g_dwMSAudioSampleRate;
  951. break;
  952. default:
  953. LOG((MSP_ERROR,
  954. "unknow payload type, %x", StreamSettings.dwPayloadType));
  955. return E_FAIL;
  956. }
  957. m_Settings = StreamSettings;
  958. m_fIsConfigured = TRUE;
  959. return InternalConfigure();
  960. }
  961. HRESULT CStreamAudioSend::ConfigureAudioCaptureTerminal(
  962. IN ITTerminalControl * pTerminal,
  963. OUT IPin ** ppIPin
  964. )
  965. /*++
  966. Routine Description:
  967. Configure the audio capture terminal. This function gets a output pin from
  968. the capture terminal and the configure the audio format and media type.
  969. Arguments:
  970. pTerminal - An audio capture terminal.
  971. ppIPin - the address to hold the returned pointer to IPin interface.
  972. Return Value:
  973. HRESULT
  974. --*/
  975. {
  976. LOG((MSP_TRACE, "AudioSend configure audio capture terminal."));
  977. const DWORD MAXPINS = 8;
  978. DWORD dwNumPins = MAXPINS;
  979. IPin * Pins[MAXPINS];
  980. // Get the pins from the first terminal because we only use on terminal
  981. // on this stream.
  982. HRESULT hr = pTerminal->ConnectTerminal(
  983. m_pIGraphBuilder, 0, &dwNumPins, Pins
  984. );
  985. if (FAILED(hr))
  986. {
  987. LOG((MSP_ERROR, "can't connect to terminal, %x", hr));
  988. return hr;
  989. }
  990. // The number of pins should never be 0.
  991. if (dwNumPins == 0)
  992. {
  993. LOG((MSP_ERROR, "terminal has no pins."));
  994. return E_UNEXPECTED;
  995. }
  996. // Save the first pin and release the others.
  997. CComPtr <IPin> pIPin = Pins[0];
  998. for (DWORD i = 0; i < dwNumPins; i ++)
  999. {
  1000. Pins[i]->Release();
  1001. }
  1002. // Set the format of the audio to 8KHZ, 16Bit/Sample, MONO.
  1003. hr = SetAudioFormat(
  1004. pIPin,
  1005. g_wAudioCaptureBitPerSample,
  1006. m_dwAudioSampleRate
  1007. );
  1008. if (FAILED(hr))
  1009. {
  1010. LOG((MSP_ERROR, "can't set audio format, %x", hr));
  1011. return hr;
  1012. }
  1013. // Set the capture buffer size.
  1014. hr = SetAudioBufferSize(
  1015. pIPin,
  1016. g_dwAudioCaptureNumBufffers,
  1017. AudioCaptureBufferSize(m_dwMSPerPacket, m_dwAudioSampleRate)
  1018. );
  1019. if (FAILED(hr))
  1020. {
  1021. LOG((MSP_ERROR, "can't set aduio capture buffer size, %x", hr));
  1022. return hr;
  1023. }
  1024. pIPin->AddRef();
  1025. *ppIPin = pIPin;
  1026. return hr;
  1027. }
  1028. HRESULT CStreamAudioSend::ConnectTerminal(
  1029. IN ITTerminal * pITTerminal
  1030. )
  1031. /*++
  1032. Routine Description:
  1033. connect the audio capture terminal to the stream.
  1034. Arguments:
  1035. pITTerminal - The terminal to be connected.
  1036. Return Value:
  1037. HRESULT.
  1038. --*/
  1039. {
  1040. LOG((MSP_TRACE, "AudioSend ConnectTerminal, pITTerminal %p", pITTerminal));
  1041. CComQIPtr<ITTerminalControl, &IID_ITTerminalControl>
  1042. pTerminal(pITTerminal);
  1043. if (pTerminal == NULL)
  1044. {
  1045. LOG((MSP_ERROR, "can't get Terminal Control interface"));
  1046. SendStreamEvent(
  1047. CALL_TERMINAL_FAIL,
  1048. CALL_CAUSE_BAD_DEVICE,
  1049. E_NOINTERFACE,
  1050. pITTerminal
  1051. );
  1052. return E_NOINTERFACE;
  1053. }
  1054. // configure the terminal.
  1055. CComPtr<IPin> pIPin;
  1056. HRESULT hr = ConfigureAudioCaptureTerminal(pTerminal, &pIPin);
  1057. if (FAILED(hr))
  1058. {
  1059. LOG((MSP_ERROR, "configure audio capture termianl failed. %x", hr));
  1060. SendStreamEvent(
  1061. CALL_TERMINAL_FAIL,
  1062. CALL_CAUSE_BAD_DEVICE,
  1063. hr,
  1064. pITTerminal
  1065. );
  1066. return hr;
  1067. }
  1068. // Create other filters to be use in the stream.
  1069. hr = CreateSendFilters(pIPin);
  1070. if (FAILED(hr))
  1071. {
  1072. LOG((MSP_ERROR, "Create audio send filters failed. %x", hr));
  1073. pTerminal->DisconnectTerminal(m_pIGraphBuilder, 0);
  1074. // clean up internal filters as well.
  1075. CleanUpFilters();
  1076. return hr;
  1077. }
  1078. //
  1079. // Now we are actually connected. Update our state and perform postconnection
  1080. // (ignore postconnection error code).
  1081. //
  1082. pTerminal->CompleteConnectTerminal();
  1083. return hr;
  1084. }
  1085. HRESULT CStreamAudioSend::SetUpFilters()
  1086. /*++
  1087. Routine Description:
  1088. Insert filters into the graph and connect to the terminals.
  1089. Arguments:
  1090. Return Value:
  1091. HRESULT.
  1092. --*/
  1093. {
  1094. LOG((MSP_TRACE, "AudioSend SetUpFilters"));
  1095. // we only support one terminal for this stream.
  1096. if (m_Terminals.GetSize() != 1)
  1097. {
  1098. return E_UNEXPECTED;
  1099. }
  1100. HRESULT hr;
  1101. // Connect the terminal to the rest of the stream.
  1102. if (FAILED(hr = ConnectTerminal(
  1103. m_Terminals[0]
  1104. )))
  1105. {
  1106. LOG((MSP_ERROR, "connect the terminal to the filters. %x", hr));
  1107. return hr;
  1108. }
  1109. return hr;
  1110. }
  1111. HRESULT CStreamAudioSend::ConfigureRTPFilter(
  1112. IN IBaseFilter * pIBaseFilter
  1113. )
  1114. /*++
  1115. Routine Description:
  1116. Configure the source RTP filter. Including set the address, port, TTL,
  1117. QOS, thread priority, clcokrate, etc.
  1118. Arguments:
  1119. pIBaseFilter - The source RTP Filter.
  1120. Return Value:
  1121. HRESULT.
  1122. --*/
  1123. {
  1124. LOG((MSP_TRACE, "AudioSend ConfigureRTPFilter"));
  1125. HRESULT hr;
  1126. // Get the IRTPStream interface pointer on the filter.
  1127. CComQIPtr<IRTPStream, &IID_IRTPStream> pIRTPStream(pIBaseFilter);
  1128. if (pIRTPStream == NULL)
  1129. {
  1130. LOG((MSP_ERROR, "get IRTPStream interface"));
  1131. return E_NOINTERFACE;
  1132. }
  1133. LOG((MSP_INFO, "set remote Address:%x, port:%d, TTL:%d",
  1134. m_Settings.dwIPRemote, m_Settings.wRTPPortRemote, m_Settings.dwTTL));
  1135. // Set the remote address and port used in the filter.
  1136. if (FAILED(hr = pIRTPStream->SetAddress(
  1137. 0, // local port.
  1138. htons(m_Settings.wRTPPortRemote), // remote port.
  1139. htonl(m_Settings.dwIPRemote)
  1140. )))
  1141. {
  1142. LOG((MSP_ERROR, "set remote Address, hr:%x", hr));
  1143. return hr;
  1144. }
  1145. // Set the TTL used in the filter.
  1146. if (FAILED(hr = pIRTPStream->SetMulticastScope(m_Settings.dwTTL)))
  1147. {
  1148. LOG((MSP_ERROR, "set TTL. %x", hr));
  1149. return hr;
  1150. }
  1151. if (m_Settings.dwIPLocal != INADDR_ANY)
  1152. {
  1153. // set the local interface that the socket should bind to
  1154. LOG((MSP_INFO, "set locol Address:%x", m_Settings.dwIPLocal));
  1155. if (FAILED(hr = pIRTPStream->SelectLocalIPAddress(
  1156. htonl(m_Settings.dwIPLocal)
  1157. )))
  1158. {
  1159. LOG((MSP_ERROR, "set local Address, hr:%x", hr));
  1160. return hr;
  1161. }
  1162. }
  1163. // Set the priority of the session
  1164. if (FAILED(hr = pIRTPStream->SetSessionClassPriority(
  1165. RTP_CLASS_AUDIO,
  1166. g_dwAudioThreadPriority
  1167. )))
  1168. {
  1169. LOG((MSP_WARN, "set session class and priority. %x", hr));
  1170. }
  1171. // Set the sample rate of the session
  1172. LOG((MSP_INFO, "setting session sample rate to %d", m_dwAudioSampleRate));
  1173. if (FAILED(hr = pIRTPStream->SetDataClock(m_dwAudioSampleRate)))
  1174. {
  1175. LOG((MSP_WARN, "set session sample rate. %x", hr));
  1176. }
  1177. // Enable the RTCP events
  1178. if (FAILED(hr = ::EnableRTCPEvents(pIBaseFilter)))
  1179. {
  1180. LOG((MSP_WARN, "can not enable RTCP events %x", hr));
  1181. }
  1182. if (m_Settings.dwQOSLevel != QSL_BEST_EFFORT)
  1183. {
  1184. if (FAILED(hr = ::SetQOSOption(
  1185. pIBaseFilter,
  1186. m_Settings.dwPayloadType, // payload
  1187. -1, // use the default bitrate
  1188. (m_Settings.dwQOSLevel == QSL_NEEDED) // fail if no qos.
  1189. )))
  1190. {
  1191. LOG((MSP_ERROR, "set QOS option. %x", hr));
  1192. return hr;
  1193. }
  1194. }
  1195. SetLocalInfoOnRTPFilter(pIBaseFilter);
  1196. return S_OK;
  1197. }
  1198. HRESULT CStreamAudioSend::CreateSendFilters(
  1199. IN IPin *pPin
  1200. )
  1201. /*++
  1202. Routine Description:
  1203. Insert filters into the graph and connect to the capture pin.
  1204. Capturepin->SilenceSuppressor->Encoder->SPH->RTPRender
  1205. Arguments:
  1206. pPin - The output pin on the capture filter.
  1207. Return Value:
  1208. HRESULT.
  1209. --*/
  1210. {
  1211. LOG((MSP_TRACE, "AudioSend.CreateSendFilters"));
  1212. HRESULT hr;
  1213. // if the the internal filters have been created before, just
  1214. // connect the terminal to the first filter in the chain.
  1215. if (m_pEdgeFilter != NULL)
  1216. {
  1217. if (FAILED(hr = ::ConnectFilters(
  1218. m_pIGraphBuilder,
  1219. pPin,
  1220. (IBaseFilter *)m_pEdgeFilter
  1221. )))
  1222. {
  1223. LOG((MSP_ERROR, "connect capture and ss %x", hr));
  1224. return hr;
  1225. }
  1226. return hr;
  1227. }
  1228. // Create the silence suppression filter and add it into the graph.
  1229. CComPtr<IBaseFilter> pISSFilter;
  1230. if (FAILED(hr = ::AddFilter(
  1231. m_pIGraphBuilder,
  1232. CLSID_SilenceSuppressionFilter,
  1233. L"SS",
  1234. &pISSFilter
  1235. )))
  1236. {
  1237. LOG((MSP_ERROR, "can't add SS filter, %x", hr));
  1238. return hr;
  1239. }
  1240. DWORD dwAGC = 0;
  1241. if (FALSE == ::GetRegValue(L"AGC", &dwAGC) || dwAGC != 0)
  1242. {
  1243. // AGC is not disabled, just do it.
  1244. CComQIPtr<ISilenceSuppressor, &IID_ISilenceSuppressor>
  1245. pISilcnecSuppressor(pISSFilter);
  1246. if (pISilcnecSuppressor != NULL)
  1247. {
  1248. hr = pISilcnecSuppressor->EnableEvents(
  1249. (1 << AGC_INCREASE_GAIN) |
  1250. (1 << AGC_DECREASE_GAIN) |
  1251. (1 << AGC_TALKING) |
  1252. (1 << AGC_SILENCE),
  1253. 2000 // no more that an event every two seconds.
  1254. );
  1255. if (FAILED(hr))
  1256. {
  1257. LOG((MSP_WARN, "can't enable AGC events, %x", hr));
  1258. }
  1259. }
  1260. }
  1261. // connect the capture pin with the SS filter.
  1262. if (FAILED(hr = ::ConnectFilters(
  1263. m_pIGraphBuilder,
  1264. pPin,
  1265. (IBaseFilter *)pISSFilter
  1266. )))
  1267. {
  1268. LOG((MSP_ERROR, "connect capture and ss %x", hr));
  1269. return hr;
  1270. }
  1271. // Create the codec filter and add it into the graph.
  1272. CComPtr<IBaseFilter> pICodecFilter;
  1273. if (m_fUseACM)
  1274. {
  1275. if (S_OK != (hr = ::FindACMAudioCodec(
  1276. m_Settings.dwPayloadType,
  1277. &pICodecFilter
  1278. )))
  1279. {
  1280. LOG((MSP_ERROR, "Find Codec filter. %x", hr));
  1281. return hr;
  1282. }
  1283. if (FAILED(hr = m_pIGraphBuilder->AddFilter(
  1284. pICodecFilter, L"AudioCodec"
  1285. )))
  1286. {
  1287. LOG((MSP_ERROR, "add codec filter. %x", hr));
  1288. return hr;
  1289. }
  1290. }
  1291. else
  1292. {
  1293. if (FAILED(hr = ::AddFilter(
  1294. m_pIGraphBuilder,
  1295. *m_pClsidCodecFilter,
  1296. L"Encoder",
  1297. &pICodecFilter)))
  1298. {
  1299. LOG((MSP_ERROR, "add Codec filter. %x", hr));
  1300. return hr;
  1301. }
  1302. }
  1303. // connect the SS filter and the Codec filter.
  1304. if (FAILED(hr = ::ConnectFilters(
  1305. m_pIGraphBuilder,
  1306. (IBaseFilter *)pISSFilter,
  1307. (IBaseFilter *)pICodecFilter
  1308. )))
  1309. {
  1310. LOG((MSP_ERROR, "connect ss filter and codec filter. %x", hr));
  1311. return hr;
  1312. }
  1313. // Create the send payload handler and add it into the graph.
  1314. CComPtr<IBaseFilter> pISPHFilter;
  1315. if (FAILED(hr = ::AddFilter(
  1316. m_pIGraphBuilder,
  1317. *m_pClsidPHFilter,
  1318. L"SPH",
  1319. &pISPHFilter
  1320. )))
  1321. {
  1322. LOG((MSP_ERROR, "add SPH filter. %x", hr));
  1323. return hr;
  1324. }
  1325. // Get the IRTPSPHFilter interface.
  1326. CComQIPtr<IRTPSPHFilter,
  1327. &IID_IRTPSPHFilter> pIRTPSPHFilter(pISPHFilter);
  1328. if (pIRTPSPHFilter == NULL)
  1329. {
  1330. LOG((MSP_ERROR, "get IRTPSPHFilter interface"));
  1331. return E_NOINTERFACE;
  1332. }
  1333. // Set the packetSize.
  1334. if (FAILED(hr= pIRTPSPHFilter->SetMaxPacketSize(m_dwMaxPacketSize)))
  1335. {
  1336. LOG((MSP_ERROR, "set SPH filter Max packet size: %d hr: %x",
  1337. m_dwMaxPacketSize, hr));
  1338. return hr;
  1339. }
  1340. if (FAILED(hr = pIRTPSPHFilter->OverridePayloadType(
  1341. (BYTE)m_Settings.dwPayloadType
  1342. )))
  1343. {
  1344. LOG((MSP_ERROR, "Set SPHGENA payload type. %x", hr));
  1345. return hr;
  1346. }
  1347. // Connect the Codec filter with the SPH filter .
  1348. if (FAILED(hr = ::ConnectFilters(
  1349. m_pIGraphBuilder,
  1350. (IBaseFilter *)pICodecFilter,
  1351. (IBaseFilter *)pISPHFilter
  1352. )))
  1353. {
  1354. LOG((MSP_ERROR, "connect codec filter and SPH filter. %x", hr));
  1355. return hr;
  1356. }
  1357. // Create the RTP render filter and add it into the graph.
  1358. CComPtr<IBaseFilter> pRenderFilter;
  1359. if (FAILED(hr = ::AddFilter(
  1360. m_pIGraphBuilder,
  1361. CLSID_RTPRenderFilter,
  1362. L"RtpRender",
  1363. &pRenderFilter)))
  1364. {
  1365. LOG((MSP_ERROR, "adding render filter. %x", hr));
  1366. return hr;
  1367. }
  1368. // Set the address for the render fitler.
  1369. if (FAILED(hr = ConfigureRTPFilter(pRenderFilter)))
  1370. {
  1371. LOG((MSP_ERROR, "set destination address. %x", hr));
  1372. return hr;
  1373. }
  1374. // Connect the SPH filter with the RTP Render filter.
  1375. if (FAILED(hr = ::ConnectFilters(
  1376. m_pIGraphBuilder,
  1377. (IBaseFilter *)pISPHFilter,
  1378. (IBaseFilter *)pRenderFilter
  1379. )))
  1380. {
  1381. LOG((MSP_ERROR, "connect SPH filter and Render filter. %x", hr));
  1382. return hr;
  1383. }
  1384. // remember the first filter after the terminal
  1385. m_pEdgeFilter = pISSFilter;
  1386. m_pEdgeFilter->AddRef();
  1387. // Get the IRTPParticipant interface pointer on the RTP filter.
  1388. CComQIPtr<IRTPParticipant,
  1389. &IID_IRTPParticipant> pIRTPParticipant(pRenderFilter);
  1390. if (pIRTPParticipant == NULL)
  1391. {
  1392. LOG((MSP_WARN, "can't get RTP participant interface"));
  1393. }
  1394. else
  1395. {
  1396. m_pRTPFilter = pIRTPParticipant;
  1397. m_pRTPFilter->AddRef();
  1398. }
  1399. return S_OK;
  1400. }
  1401. HRESULT AdjustGain(
  1402. IN IUnknown * pIUnknown,
  1403. IN long lPercent
  1404. )
  1405. /*++
  1406. Routine Description:
  1407. This function uses IAMAudioInputMixer interface to adjust the gain.
  1408. Arguments:
  1409. pIUnknown - the object that supports IAMAudioInputMixer
  1410. lPercent - the adjustment, a negative value means decrease.
  1411. Return Value:
  1412. S_OK,
  1413. E_NOINTERFACE,
  1414. E_UNEXPECTED
  1415. --*/
  1416. {
  1417. CComPtr <IAMAudioInputMixer> pMixer;
  1418. HRESULT hr = pIUnknown->QueryInterface(
  1419. IID_IAMAudioInputMixer, (void **)&pMixer
  1420. );
  1421. if (FAILED(hr))
  1422. {
  1423. LOG((MSP_ERROR, "can't get IAMAudioInputMixer interface."));
  1424. return hr;
  1425. }
  1426. BOOL fEnabled;
  1427. hr = pMixer->get_Enable(&fEnabled);
  1428. if (SUCCEEDED(hr) && !fEnabled)
  1429. {
  1430. return S_OK;
  1431. }
  1432. double MixLevel;
  1433. hr = pMixer->get_MixLevel(&MixLevel);
  1434. if (FAILED(hr))
  1435. {
  1436. LOG((MSP_ERROR, "get_MixLevel returned %d", hr));
  1437. return hr;
  1438. }
  1439. LOG((MSP_INFO, "get_MixLevel returned %d", hr));
  1440. MixLevel = MixLevel * (100 + lPercent) / 100;
  1441. hr = pMixer->put_MixLevel(MixLevel);
  1442. if (FAILED(hr))
  1443. {
  1444. LOG((MSP_ERROR, "put_MixLevel returned %d", hr));
  1445. return hr;
  1446. }
  1447. return S_OK;
  1448. }
  1449. HRESULT CStreamAudioSend::ProcessAGCEvent(
  1450. IN AGC_EVENT Event,
  1451. IN long lPercent
  1452. )
  1453. /*++
  1454. Routine Description:
  1455. The filters fire AGC events to requste a change in the microphone gain.
  1456. This function finds the capture terminal and adjust the gain on it.
  1457. Arguments:
  1458. Event - either AGC_INCREASE_GAIN or AGC_DECREASE_GAIN.
  1459. Return Value:
  1460. S_OK,
  1461. E_UNEXPECTED
  1462. --*/
  1463. {
  1464. LOG((MSP_TRACE, "ProcessAGCEvent %s %d percent",
  1465. (Event == AGC_INCREASE_GAIN) ? "Increase" : "Decrease",
  1466. lPercent
  1467. ));
  1468. _ASSERTE(lPercent > 0 && lPercent <= 100);
  1469. CLock lock(m_lock);
  1470. if (m_pEdgeFilter == NULL)
  1471. {
  1472. LOG((MSP_ERROR, "No filter to adjust gain."));
  1473. return E_UNEXPECTED;
  1474. }
  1475. CComPtr<IPin> pMyPin, pCapturePin;
  1476. // find the first pin in the stream
  1477. HRESULT hr = ::FindPin(m_pEdgeFilter, &pMyPin, PINDIR_INPUT, FALSE);
  1478. if (FAILED(hr))
  1479. {
  1480. LOG((MSP_ERROR, "can't get find the first pin the stream, %x", hr));
  1481. return hr;
  1482. }
  1483. // find the capture pin that connects to our first pin.
  1484. hr = pMyPin->ConnectedTo(&pCapturePin);
  1485. if (FAILED(hr))
  1486. {
  1487. LOG((MSP_ERROR, "can't find the capture pin, %x", hr));
  1488. return hr;
  1489. }
  1490. // find the filter that has the capture pin.
  1491. PIN_INFO PinInfo;
  1492. hr = pCapturePin->QueryPinInfo(&PinInfo);
  1493. if (FAILED(hr))
  1494. {
  1495. LOG((MSP_ERROR, "can't find the capture filter, %x", hr));
  1496. return hr;
  1497. }
  1498. // save the filter pointer.
  1499. CComPtr<IBaseFilter> pICaptureFilter = PinInfo.pFilter;
  1500. PinInfo.pFilter->Release();
  1501. // get the amount to adjust.
  1502. if (Event == AGC_DECREASE_GAIN)
  1503. {
  1504. lPercent = -lPercent;
  1505. }
  1506. AdjustGain(pICaptureFilter, lPercent);
  1507. // Get the enumerator of pins on the filter.
  1508. CComPtr<IEnumPins> pIEnumPins;
  1509. if (FAILED(hr = pICaptureFilter->EnumPins(&pIEnumPins)))
  1510. {
  1511. LOG((MSP_ERROR, "enumerate pins on the filter %x", hr));
  1512. return hr;
  1513. }
  1514. // Enumerate all the pins and adjust gains on each active one.
  1515. for (;;)
  1516. {
  1517. CComPtr<IPin> pIPin;
  1518. DWORD dwFeched;
  1519. if (pIEnumPins->Next(1, &pIPin, &dwFeched) != S_OK)
  1520. {
  1521. LOG((MSP_ERROR, "find pin on filter."));
  1522. break;
  1523. }
  1524. AdjustGain(pIPin, lPercent);
  1525. }
  1526. return hr;
  1527. }
  1528. HRESULT CStreamAudioSend::ProcessGraphEvent(
  1529. IN long lEventCode,
  1530. IN long lParam1,
  1531. IN long lParam2
  1532. )
  1533. {
  1534. LOG((MSP_TRACE, "%ws ProcessGraphEvent %d", m_szName, lEventCode));
  1535. switch (lEventCode)
  1536. {
  1537. case AGC_EVENTBASE + AGC_INCREASE_GAIN:
  1538. ProcessAGCEvent(AGC_INCREASE_GAIN, lParam1);
  1539. break;
  1540. case AGC_EVENTBASE + AGC_DECREASE_GAIN:
  1541. ProcessAGCEvent(AGC_DECREASE_GAIN, lParam1);
  1542. break;
  1543. case AGC_EVENTBASE + AGC_TALKING:
  1544. m_lock.Lock();
  1545. if (m_pMSPCall != NULL)
  1546. {
  1547. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1548. PE_LOCAL_TALKING,
  1549. NULL
  1550. );
  1551. }
  1552. m_lock.Unlock();
  1553. break;
  1554. case AGC_EVENTBASE + AGC_SILENCE:
  1555. m_lock.Lock();
  1556. if (m_pMSPCall != NULL)
  1557. {
  1558. ((CIPConfMSPCall *)m_pMSPCall)->SendParticipantEvent(
  1559. PE_LOCAL_SILENT,
  1560. NULL
  1561. );
  1562. }
  1563. m_lock.Unlock();
  1564. break;
  1565. default:
  1566. return CIPConfMSPStream::ProcessGraphEvent(
  1567. lEventCode, lParam1, lParam2
  1568. );
  1569. }
  1570. return S_OK;
  1571. }