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.

959 lines
24 KiB

  1. #include "precomp.h"
  2. #ifdef PLS_DEBUG
  3. #include "plog.h"
  4. extern CPacketLog *g_pPacketLog;
  5. #endif
  6. // #define LOGSTATISTICS_ON 1
  7. UINT g_MinWaveAudioDelayMs=240; // minimum millisecs of introduced playback delay (Wave)
  8. UINT g_MaxAudioDelayMs=750; // maximum milliesecs of introduced playback delay
  9. UINT g_MinDSEmulAudioDelayMs=240; // minimum delay (DirectSound on emulated driver)
  10. HRESULT STDMETHODCALLTYPE RecvAudioStream::QueryInterface(REFIID iid, void **ppVoid)
  11. {
  12. // resolve duplicate inheritance to the RecvMediaStream;
  13. extern IID IID_IProperty;
  14. if (iid == IID_IUnknown)
  15. {
  16. *ppVoid = (IUnknown*)((RecvMediaStream*)this);
  17. }
  18. else if (iid == IID_IMediaChannel)
  19. {
  20. *ppVoid = (IMediaChannel*)((RecvMediaStream *)this);
  21. }
  22. else if (iid == IID_IAudioChannel)
  23. {
  24. *ppVoid = (IAudioChannel*)this;
  25. }
  26. else if (iid == IID_IProperty)
  27. {
  28. *ppVoid = NULL;
  29. ERROR_OUT(("Don't QueryInterface for IID_IProperty, use IMediaChannel"));
  30. return E_NOINTERFACE;
  31. }
  32. else
  33. {
  34. *ppVoid = NULL;
  35. return E_NOINTERFACE;
  36. }
  37. AddRef();
  38. return S_OK;
  39. }
  40. ULONG STDMETHODCALLTYPE RecvAudioStream::AddRef(void)
  41. {
  42. return InterlockedIncrement(&m_lRefCount);
  43. }
  44. ULONG STDMETHODCALLTYPE RecvAudioStream::Release(void)
  45. {
  46. LONG lRet;
  47. lRet = InterlockedDecrement(&m_lRefCount);
  48. if (lRet == 0)
  49. {
  50. delete this;
  51. return 0;
  52. }
  53. else
  54. return lRet;
  55. }
  56. HRESULT
  57. RecvAudioStream::Initialize( DataPump *pDP)
  58. {
  59. HRESULT hr = DPR_OUT_OF_MEMORY;
  60. DWORD dwFlags = DP_FLAG_FULL_DUPLEX | DP_FLAG_AUTO_SWITCH ;
  61. MEDIACTRLINIT mcInit;
  62. FX_ENTRY ("RecvAudioStream::Initialize")
  63. InitializeCriticalSection(&m_crsAudQoS);
  64. dwFlags |= DP_FLAG_ACM | DP_FLAG_MMSYSTEM | DP_FLAG_AUTO_SILENCE_DETECT;
  65. // store the platform flags
  66. // enable Send and Recv by default
  67. m_DPFlags = (dwFlags & DP_MASK_PLATFORM) | DPFLAG_ENABLE_SEND | DPFLAG_ENABLE_RECV;
  68. // store a back pointer to the datapump container
  69. m_pDP = pDP;
  70. m_pIRTPRecv = NULL;
  71. m_Net = NULL; // this object (m_Net) no longer used (at least for now)
  72. m_dwSrcSize = 0;
  73. // Initialize data (should be in constructor)
  74. m_RenderingDevice = (UINT) -1; // use VIDEO_MAPPER
  75. // Create Receive and Transmit audio streams
  76. DBG_SAVE_FILE_LINE
  77. m_RecvStream = new RxStream(MAX_RXRING_SIZE);
  78. if (!m_RecvStream )
  79. {
  80. DEBUGMSG (ZONE_DP, ("%s: RxStream or TxStream new failed\r\n", _fx_));
  81. goto StreamAllocError;
  82. }
  83. // Create Input and Output audio filters
  84. DBG_SAVE_FILE_LINE
  85. m_pAudioFilter = new AcmFilter();
  86. if (!m_pAudioFilter)
  87. {
  88. DEBUGMSG (ZONE_DP, ("%s: AcmManager new failed\r\n", _fx_));
  89. goto FilterAllocError;
  90. }
  91. //Create MultiMedia device control objects
  92. DBG_SAVE_FILE_LINE
  93. m_OutMedia = new WaveOutControl();
  94. if ( !m_OutMedia)
  95. {
  96. DEBUGMSG (ZONE_DP, ("%s: MediaControl new failed\r\n", _fx_));
  97. goto MediaAllocError;
  98. }
  99. // Initialize the recv-stream media control object
  100. mcInit.dwFlags = dwFlags | DP_FLAG_RECV;
  101. hr = m_OutMedia->Initialize(&mcInit);
  102. if (hr != DPR_SUCCESS)
  103. {
  104. DEBUGMSG (ZONE_DP, ("%s: OMedia->Init failed, hr=0x%lX\r\n", _fx_, hr));
  105. goto MediaAllocError;
  106. }
  107. // determine if the wave devices are available
  108. if (waveOutGetNumDevs()) m_DPFlags |= DP_FLAG_PLAY_CAP;
  109. // set media to half duplex mode by default
  110. m_OutMedia->SetProp(MC_PROP_DUPLEX_TYPE, DP_FLAG_HALF_DUPLEX);
  111. m_DPFlags |= DPFLAG_INITIALIZED;
  112. UPDATE_REPORT_ENTRY(g_prptSystemSettings, 0, REP_SYS_AUDIO_DSOUND);
  113. RETAILMSG(("NAC: Audio Subsystem: WAVE"));
  114. return DPR_SUCCESS;
  115. MediaAllocError:
  116. if (m_OutMedia) delete m_OutMedia;
  117. FilterAllocError:
  118. if (m_pAudioFilter) delete m_pAudioFilter;
  119. StreamAllocError:
  120. if (m_RecvStream) delete m_RecvStream;
  121. ERRORMESSAGE( ("%s: exit, hr=0x%lX\r\n", _fx_, hr));
  122. return hr;
  123. }
  124. RecvAudioStream::~RecvAudioStream()
  125. {
  126. if (m_DPFlags & DPFLAG_INITIALIZED) {
  127. m_DPFlags &= ~DPFLAG_INITIALIZED;
  128. if (m_DPFlags & DPFLAG_CONFIGURED_RECV)
  129. UnConfigure();
  130. if (m_pIRTPRecv)
  131. {
  132. m_pIRTPRecv->Release();
  133. m_pIRTPRecv = NULL;
  134. }
  135. // Close the receive and transmit streams
  136. if (m_RecvStream) delete m_RecvStream;
  137. // Close the wave devices
  138. if (m_OutMedia) { delete m_OutMedia;}
  139. // close the filter
  140. if (m_pAudioFilter)
  141. delete m_pAudioFilter;
  142. m_pDP->RemoveMediaChannel(MCF_RECV|MCF_AUDIO, (IMediaChannel*)(RecvMediaStream*)this);
  143. }
  144. DeleteCriticalSection(&m_crsAudQoS);
  145. }
  146. HRESULT STDMETHODCALLTYPE RecvAudioStream::Configure(
  147. BYTE *pFormat,
  148. UINT cbFormat,
  149. BYTE *pChannelParams,
  150. UINT cbParams,
  151. IUnknown *pUnknown)
  152. {
  153. HRESULT hr;
  154. BOOL fRet;
  155. MEDIAPACKETINIT apInit;
  156. MEDIACTRLCONFIG mcConfig;
  157. MediaPacket **ppAudPckt;
  158. ULONG cAudPckt;
  159. DWORD_PTR dwPropVal;
  160. DWORD dwFlags;
  161. AUDIO_CHANNEL_PARAMETERS audChannelParams;
  162. UINT uAudioCodec;
  163. UINT ringSize = MAX_RXRING_SIZE;
  164. WAVEFORMATEX *pwfRecv;
  165. UINT maxRingSamples;
  166. MMRESULT mmr;
  167. FX_ENTRY ("RecvAudioStream::Configure")
  168. if (m_DPFlags & DPFLAG_STARTED_RECV)
  169. {
  170. return DPR_IO_PENDING; // anything better to return
  171. }
  172. if (m_DPFlags & DPFLAG_CONFIGURED_RECV)
  173. {
  174. DEBUGMSG(ZONE_DP, ("Stream Re-Configuration - calling UnConfigure"));
  175. UnConfigure();
  176. }
  177. // get format details
  178. if ((NULL == pFormat) || (NULL == pChannelParams) ||
  179. (cbFormat < sizeof(WAVEFORMATEX)) )
  180. {
  181. return DPR_INVALID_PARAMETER;
  182. }
  183. audChannelParams = *(AUDIO_CHANNEL_PARAMETERS *)pChannelParams;
  184. pwfRecv = (WAVEFORMATEX *)pFormat;
  185. if (! (m_DPFlags & DPFLAG_INITIALIZED))
  186. return DPR_OUT_OF_MEMORY; //BUGBUG: return proper error;
  187. // full or half duplex ? get flags from media control - use the record side
  188. hr = m_OutMedia->GetProp(MC_PROP_DUPLEX_TYPE, &dwPropVal);
  189. dwFlags = (DWORD)dwPropVal;
  190. if(!HR_SUCCEEDED(hr))
  191. {
  192. dwFlags = DP_FLAG_HALF_DUPLEX | DP_FLAG_AUTO_SWITCH;
  193. }
  194. // if (m_Net)
  195. // {
  196. // hr = m_Net->QueryInterface(IID_IRTPRecv, (void **)&m_pIRTPRecv);
  197. // if (!SUCCEEDED(hr))
  198. // return hr;
  199. // }
  200. mcConfig.uDuration = MC_USING_DEFAULT; // set duration by samples per pkt
  201. mmr = AcmFilter::SuggestDecodeFormat(pwfRecv, &m_fDevRecv);
  202. UPDATE_REPORT_ENTRY(g_prptCallParameters, pwfRecv->wFormatTag, REP_RECV_AUDIO_FORMAT);
  203. UPDATE_REPORT_ENTRY(g_prptCallParameters, pwfRecv->nSamplesPerSec, REP_RECV_AUDIO_SAMPLING);
  204. UPDATE_REPORT_ENTRY(g_prptCallParameters, pwfRecv->nAvgBytesPerSec*8, REP_RECV_AUDIO_BITRATE);
  205. RETAILMSG(("NAC: Audio Recv Format: %s", (pwfRecv->wFormatTag == 66) ? "G723.1" : (pwfRecv->wFormatTag == 112) ? "LHCELP" : (pwfRecv->wFormatTag == 113) ? "LHSB08" : (pwfRecv->wFormatTag == 114) ? "LHSB12" : (pwfRecv->wFormatTag == 115) ? "LHSB16" : (pwfRecv->wFormatTag == 6) ? "MSALAW" : (pwfRecv->wFormatTag == 7) ? "MSULAW" : (pwfRecv->wFormatTag == 130) ? "MSRT24" : "??????"));
  206. RETAILMSG(("NAC: Audio Recv Sampling Rate (Hz): %ld", pwfRecv->nSamplesPerSec));
  207. RETAILMSG(("NAC: Audio Recv Bitrate (w/o network overhead - bps): %ld", pwfRecv->nAvgBytesPerSec*8));
  208. // Initialize the recv-stream media control object
  209. mcConfig.pDevFmt = &m_fDevRecv;
  210. mcConfig.hStrm = (DPHANDLE) m_RecvStream;
  211. mcConfig.uDevId = m_RenderingDevice;
  212. mcConfig.cbSamplesPerPkt = audChannelParams.ns_params.wFrameSize
  213. *audChannelParams.ns_params.wFramesPerPkt;
  214. UPDATE_REPORT_ENTRY(g_prptCallParameters, mcConfig.cbSamplesPerPkt, REP_RECV_AUDIO_PACKET);
  215. RETAILMSG(("NAC: Audio Recv Packetization (ms/packet): %ld", pwfRecv->nSamplesPerSec ? mcConfig.cbSamplesPerPkt * 1000UL / pwfRecv->nSamplesPerSec : 0));
  216. INIT_COUNTER_MAX(g_pctrAudioReceiveBytes, (pwfRecv->nAvgBytesPerSec + pwfRecv->nSamplesPerSec * (sizeof(RTP_HDR) + IP_HEADER_SIZE + UDP_HEADER_SIZE) / mcConfig.cbSamplesPerPkt) << 3);
  217. hr = m_OutMedia->Configure(&mcConfig);
  218. // Check if we can open the wave device. This is just to give advance notice of
  219. // sound card being busy.
  220. // Stop any high level ("PlaySound()") usage of wave device.
  221. //
  222. PlaySound(NULL,NULL, 0);
  223. // if (hr == DPR_SUCCESS && !(dwFlags & DP_FLAG_HALF_DUPLEX)) {
  224. // hr = m_OutMedia->Open ();
  225. // }
  226. // if (hr != DPR_SUCCESS)
  227. // {
  228. // DEBUGMSG (ZONE_DP, ("%s: OMedia->Config failed, hr=0x%lX\r\n", _fx_, hr));
  229. // goto OMediaInitError;
  230. // }
  231. mmr = m_pAudioFilter->Open(pwfRecv, &m_fDevRecv);
  232. if (mmr != 0)
  233. {
  234. DEBUGMSG (ZONE_DP, ("%s: AcmFilter->Open failed, mmr=%d\r\n", _fx_, mmr));
  235. hr = DPR_CANT_OPEN_CODEC;
  236. goto RecvFilterInitError;
  237. }
  238. // Initialize the recv stream
  239. ZeroMemory (&apInit, sizeof (apInit));
  240. apInit.dwFlags = DP_FLAG_RECV | DP_FLAG_ACM | DP_FLAG_MMSYSTEM;
  241. apInit.pStrmConvSrcFmt = pwfRecv;
  242. apInit.pStrmConvDstFmt = &m_fDevRecv;
  243. m_OutMedia->FillMediaPacketInit (&apInit);
  244. apInit.cbSizeRawData = apInit.cbSizeDevData;
  245. m_pAudioFilter->SuggestSrcSize(apInit.cbSizeDevData, &m_dwSrcSize);
  246. apInit.cbSizeNetData = m_dwSrcSize;
  247. apInit.cbOffsetNetData = sizeof (RTP_HDR);
  248. m_OutMedia->GetProp (MC_PROP_SPP, &dwPropVal);
  249. // set our total receive buffering capacity to somewhere between
  250. // 2 and 4 seconds.
  251. // Also make sure that the buffering capacity is at least one
  252. // second more than maxAudioDelay
  253. maxRingSamples = pwfRecv->nSamplesPerSec + pwfRecv->nSamplesPerSec*g_MaxAudioDelayMs/1000;
  254. if (maxRingSamples < 4*pwfRecv->nSamplesPerSec)
  255. maxRingSamples = 4*pwfRecv->nSamplesPerSec;
  256. while (ringSize* dwPropVal > maxRingSamples && ringSize > 8)
  257. ringSize = ringSize/2;
  258. dwFlags = DP_FLAG_MMSYSTEM;
  259. // if sender is not doing silence detection, we do it
  260. // on the receive side
  261. if (!audChannelParams.ns_params.UseSilenceDet)
  262. dwFlags |= DP_FLAG_AUTO_SILENCE_DETECT;
  263. fRet = m_RecvStream->Initialize (dwFlags, ringSize, NULL, &apInit, (DWORD)dwPropVal, pwfRecv->nSamplesPerSec, m_pAudioFilter);
  264. if (! fRet)
  265. {
  266. DEBUGMSG (ZONE_DP, ("%s: RxStream->Init failed, fRet=0%u\r\n", _fx_, fRet));
  267. hr = DPR_CANT_INIT_RX_STREAM;
  268. goto RxStreamInitError;
  269. }
  270. // WS2Qos will be called in Start to communicate stream reservations to the
  271. // remote endpoint using a RESV message
  272. //
  273. // We use a peak-rate allocation approach based on our target bitrates
  274. // Note that for the token bucket size and the maximum SDU size, we now
  275. // account for IP header overhead, and use the max frame fragment size
  276. // instead of the maximum compressed image size returned by the codec
  277. //
  278. // Some of the parameters are left unspecified because they are set
  279. // in the sender Tspec.
  280. InitAudioFlowspec(&m_flowspec, pwfRecv, m_dwSrcSize);
  281. // prepare headers for RxStream
  282. m_RecvStream->GetRing (&ppAudPckt, &cAudPckt);
  283. m_OutMedia->RegisterData (ppAudPckt, cAudPckt);
  284. // m_OutMedia->PrepareHeaders ();
  285. m_pAudioFilter->PrepareAudioPackets((AudioPacket**)ppAudPckt, cAudPckt, AP_DECODE);
  286. // Open the record to wav file
  287. AudioFile::OpenDestFile(&m_mmioDest, &m_fDevRecv);
  288. m_DPFlags |= DPFLAG_CONFIGURED_RECV;
  289. #ifdef TEST
  290. LOG((LOGMSG_TIME_RECV_AUDIO_CONFIGURE,GetTickCount() - dwTicks));
  291. #endif
  292. return DPR_SUCCESS;
  293. RxStreamInitError:
  294. RecvFilterInitError:
  295. m_pAudioFilter->Close();
  296. m_OutMedia->Close();
  297. //OMediaInitError:
  298. if (m_pIRTPRecv)
  299. {
  300. m_pIRTPRecv->Release();
  301. m_pIRTPRecv = NULL;
  302. }
  303. ERRORMESSAGE(("%s: failed, hr=0%u\r\n", _fx_, hr));
  304. return hr;
  305. }
  306. void RecvAudioStream::UnConfigure()
  307. {
  308. AudioPacket **ppAudPckt=NULL;
  309. ULONG uPackets;
  310. #ifdef TEST
  311. DWORD dwTicks;
  312. dwTicks = GetTickCount();
  313. #endif
  314. if ((m_DPFlags & DPFLAG_CONFIGURED_RECV)) {
  315. Stop();
  316. // Close the RTP state if its open
  317. //m_Net->Close(); We should be able to do this in Disconnect()
  318. m_Net = NULL;
  319. m_OutMedia->Reset();
  320. m_OutMedia->UnprepareHeaders();
  321. m_OutMedia->Close();
  322. // Close the record to wav file
  323. AudioFile::CloseDestFile(&m_mmioDest);
  324. // Close the filters
  325. m_RecvStream->GetRing ((MediaPacket***)&ppAudPckt, &uPackets);
  326. m_pAudioFilter->UnPrepareAudioPackets(ppAudPckt, uPackets, AP_DECODE);
  327. m_pAudioFilter->Close();
  328. // Close the receive streams
  329. m_RecvStream->Destroy();
  330. m_DPFlags &= ~(DPFLAG_CONFIGURED_RECV);
  331. }
  332. #ifdef TEST
  333. LOG((LOGMSG_TIME_RECV_AUDIO_UNCONFIGURE,GetTickCount() - dwTicks));
  334. #endif
  335. }
  336. DWORD CALLBACK RecvAudioStream::StartPlaybackThread(LPVOID pVoid)
  337. {
  338. RecvAudioStream *pThisStream = (RecvAudioStream *)pVoid;
  339. return pThisStream->PlaybackThread();
  340. }
  341. HRESULT
  342. RecvAudioStream::Start()
  343. {
  344. FX_ENTRY ("RecvAudioStream::Start");
  345. if (m_DPFlags & DPFLAG_STARTED_RECV)
  346. return DPR_SUCCESS;
  347. // TODO: remove this check once audio UI calls the IComChan PAUSE_RECV prop
  348. if (!(m_DPFlags & DPFLAG_ENABLE_RECV))
  349. return DPR_SUCCESS;
  350. if ((!(m_DPFlags & DPFLAG_CONFIGURED_RECV)) || (NULL==m_pIRTPRecv))
  351. return DPR_NOT_CONFIGURED;
  352. ASSERT(!m_hRenderingThread );
  353. m_ThreadFlags &= ~(DPTFLAG_STOP_PLAY|DPTFLAG_STOP_RECV);
  354. SetFlowSpec();
  355. // Start playback thread
  356. if (!(m_ThreadFlags & DPTFLAG_STOP_PLAY))
  357. m_hRenderingThread = CreateThread(NULL,0,RecvAudioStream::StartPlaybackThread,this,0,&m_RenderingThId);
  358. // Start receive thread
  359. m_pDP->StartReceiving(this);
  360. m_DPFlags |= DPFLAG_STARTED_RECV;
  361. DEBUGMSG (ZONE_DP, ("%s: Play ThId=%x\r\n",_fx_, m_RenderingThId));
  362. return DPR_SUCCESS;
  363. }
  364. // LOOK: Identical to RecvVideoStream version.
  365. HRESULT
  366. RecvAudioStream::Stop()
  367. {
  368. DWORD dwWait;
  369. FX_ENTRY ("RecvAudioStream::Stop");
  370. if(!(m_DPFlags & DPFLAG_STARTED_RECV))
  371. {
  372. return DPR_SUCCESS;
  373. }
  374. m_ThreadFlags = m_ThreadFlags |
  375. DPTFLAG_STOP_RECV | DPTFLAG_STOP_PLAY ;
  376. m_pDP->StopReceiving(this);
  377. DEBUGMSG (ZONE_VERBOSE, ("%s: hRenderingThread=%x\r\n",_fx_, m_hRenderingThread));
  378. /*
  379. * we want to wait for all the threads to exit, but we need to handle windows
  380. * messages (mostly from winsock) while waiting.
  381. */
  382. if(m_hRenderingThread)
  383. {
  384. dwWait = WaitForSingleObject(m_hRenderingThread, INFINITE);
  385. DEBUGMSG (ZONE_VERBOSE, ("%s: dwWait =%d\r\n", _fx_, dwWait));
  386. ASSERT(dwWait != WAIT_FAILED);
  387. CloseHandle(m_hRenderingThread);
  388. m_hRenderingThread = NULL;
  389. }
  390. //This is per channel, but the variable is "DPFlags"
  391. m_DPFlags &= ~DPFLAG_STARTED_RECV;
  392. return DPR_SUCCESS;
  393. }
  394. // low order word is the signal strength
  395. // high order work contains bits to indicate status
  396. // (0x01 - receiving (actually playing))
  397. // (0x02 - audio device is jammed)
  398. STDMETHODIMP RecvAudioStream::GetSignalLevel(UINT *pSignalStrength)
  399. {
  400. DWORD dwLevel;
  401. DWORD dwJammed;
  402. DWORD_PTR dwPropVal;
  403. if ( (!(m_DPFlags & DPFLAG_STARTED_RECV)) ||
  404. (m_ThreadFlags & DPTFLAG_PAUSE_RECV))
  405. {
  406. dwLevel = 0;
  407. }
  408. else
  409. {
  410. m_RecvStream->GetSignalStrength(&dwLevel);
  411. dwLevel = (dwLevel >> 8) & 0x00ff;
  412. dwLevel = LogScale[dwLevel];
  413. m_OutMedia->GetProp(MC_PROP_AUDIO_JAMMED, &dwPropVal);
  414. dwJammed = (DWORD)dwPropVal;
  415. if (dwJammed)
  416. {
  417. dwLevel = (2 << 16);
  418. }
  419. else if (m_fReceiving)
  420. {
  421. dwLevel |= (1 << 16);
  422. }
  423. }
  424. *pSignalStrength = dwLevel;
  425. return S_OK;
  426. };
  427. // IProperty::GetProperty / SetProperty
  428. // (DataPump::MediaChannel::GetProperty)
  429. // Properties of the MediaChannel. Supports properties for both audio
  430. // and video channels.
  431. STDMETHODIMP
  432. RecvAudioStream::GetProperty(
  433. DWORD prop,
  434. PVOID pBuf,
  435. LPUINT pcbBuf
  436. )
  437. {
  438. HRESULT hr = DPR_SUCCESS;
  439. RTP_STATS RTPStats;
  440. DWORD_PTR dwPropVal;
  441. UINT len = sizeof(DWORD); // most props are DWORDs
  442. if (!pBuf || *pcbBuf < len)
  443. {
  444. *pcbBuf = len;
  445. return DPR_INVALID_PARAMETER;
  446. }
  447. switch (prop)
  448. {
  449. case PROP_RECV_AUDIO_STRENGTH:
  450. return GetSignalLevel((UINT *)pBuf);
  451. case PROP_AUDIO_JAMMED:
  452. hr = m_OutMedia->GetProp(MC_PROP_AUDIO_JAMMED, &dwPropVal);
  453. *(DWORD *)pBuf = (DWORD)dwPropVal;
  454. break;
  455. #ifdef OLDSTUFF
  456. case PROP_NET_RECV_STATS:
  457. if (m_Net && *pcbBuf >= sizeof(RTP_STATS))
  458. {
  459. m_Net->GetRecvStats((RTP_STATS *)pBuf);
  460. *pcbBuf = sizeof(RTP_STATS);
  461. } else
  462. hr = DPR_INVALID_PROP_VAL;
  463. break;
  464. #endif
  465. case PROP_DURATION:
  466. hr = m_OutMedia->GetProp(MC_PROP_DURATION, &dwPropVal);
  467. *(DWORD *)pBuf = (DWORD)dwPropVal;
  468. break;
  469. case PROP_VOLUME:
  470. hr = m_OutMedia->GetProp(MC_PROP_VOLUME, &dwPropVal);
  471. *(DWORD *)pBuf = (DWORD)dwPropVal;
  472. break;
  473. case PROP_DUPLEX_TYPE:
  474. hr = m_OutMedia->GetProp(MC_PROP_DUPLEX_TYPE, &dwPropVal);
  475. if(HR_SUCCEEDED(hr))
  476. {
  477. if(dwPropVal & DP_FLAG_FULL_DUPLEX)
  478. *(DWORD *)pBuf = DUPLEX_TYPE_FULL;
  479. else
  480. *(DWORD *)pBuf = DUPLEX_TYPE_HALF;
  481. }
  482. break;
  483. case PROP_AUDIO_SPP:
  484. hr = m_OutMedia->GetProp(MC_PROP_SPP, &dwPropVal);
  485. *(DWORD *)pBuf = (DWORD)dwPropVal;
  486. break;
  487. case PROP_AUDIO_SPS:
  488. hr = m_OutMedia->GetProp(MC_PROP_SPS, &dwPropVal);
  489. *(DWORD *)pBuf = (DWORD)dwPropVal;
  490. break;
  491. case PROP_WAVE_DEVICE_TYPE:
  492. *(DWORD *)pBuf = m_DPFlags & DP_MASK_WAVE_DEVICE;
  493. break;
  494. case PROP_PLAY_ON:
  495. *(DWORD *)pBuf = (m_ThreadFlags & DPFLAG_ENABLE_RECV)!=0;
  496. break;
  497. case PROP_PLAYBACK_DEVICE:
  498. *(DWORD *)pBuf = m_RenderingDevice;
  499. break;
  500. case PROP_VIDEO_AUDIO_SYNC:
  501. *(DWORD *)pBuf = ((m_DPFlags & DPFLAG_AV_SYNC) != 0);
  502. break;
  503. default:
  504. hr = DPR_INVALID_PROP_ID;
  505. break;
  506. }
  507. return hr;
  508. }
  509. STDMETHODIMP
  510. RecvAudioStream::SetProperty(
  511. DWORD prop,
  512. PVOID pBuf,
  513. UINT cbBuf
  514. )
  515. {
  516. DWORD_PTR dwPropVal;
  517. HRESULT hr = S_OK;
  518. if (cbBuf < sizeof (DWORD))
  519. return DPR_INVALID_PARAMETER;
  520. switch (prop)
  521. {
  522. case PROP_VOLUME:
  523. dwPropVal = *(DWORD *)pBuf;
  524. hr = m_OutMedia->SetProp(MC_PROP_VOLUME, dwPropVal);
  525. break;
  526. case PROP_DUPLEX_TYPE:
  527. ASSERT(0);
  528. break;
  529. case DP_PROP_DUPLEX_TYPE:
  530. // internal version, called by DataPump::SetDuplexMode() after ensuring streams are stopped
  531. dwPropVal = *(DWORD *)pBuf;
  532. if (dwPropVal)
  533. {
  534. dwPropVal = DP_FLAG_FULL_DUPLEX;
  535. }
  536. else
  537. {
  538. dwPropVal = DP_FLAG_HALF_DUPLEX;
  539. }
  540. m_OutMedia->SetProp(MC_PROP_DUPLEX_TYPE, dwPropVal);
  541. break;
  542. case PROP_PLAY_ON:
  543. {
  544. if (*(DWORD *)pBuf) // unmute
  545. {
  546. m_ThreadFlags &= ~DPTFLAG_PAUSE_RECV;
  547. }
  548. else // mute
  549. {
  550. m_ThreadFlags |= DPTFLAG_PAUSE_RECV;
  551. }
  552. // DWORD flag = DPFLAG_ENABLE_RECV;
  553. // if (*(DWORD *)pBuf) {
  554. // m_DPFlags |= flag; // set the flag
  555. // hr = Start();
  556. // }
  557. // else
  558. // {
  559. // m_DPFlags &= ~flag; // clear the flag
  560. // hr = Stop();
  561. // }
  562. RETAILMSG(("NAC: %s", *(DWORD *)pBuf ? "Enabling":"Disabling"));
  563. break;
  564. }
  565. case PROP_PLAYBACK_DEVICE:
  566. m_RenderingDevice = *(DWORD *)pBuf;
  567. RETAILMSG(("NAC: Setting default playback device to %d", m_RenderingDevice));
  568. break;
  569. case PROP_VIDEO_AUDIO_SYNC:
  570. if (*(DWORD *)pBuf)
  571. m_DPFlags |= DPFLAG_AV_SYNC;
  572. else
  573. m_DPFlags &= ~DPFLAG_AV_SYNC;
  574. break;
  575. default:
  576. return DPR_INVALID_PROP_ID;
  577. break;
  578. }
  579. return hr;
  580. }
  581. HRESULT
  582. RecvAudioStream::GetCurrentPlayNTPTime(NTP_TS *pNtpTime)
  583. {
  584. DWORD rtpTime;
  585. #ifdef OLDSTUFF
  586. if ((m_DPFlags & DPFLAG_STARTED_RECV) && m_fReceiving) {
  587. if (m_Net->RTPtoNTP(m_PlaybackTimestamp,pNtpTime))
  588. return S_OK;
  589. }
  590. #endif
  591. return 0xff; // return proper error
  592. }
  593. BOOL RecvAudioStream::IsEmpty() {
  594. return m_RecvStream->IsEmpty();
  595. }
  596. /*
  597. Called by the recv thread to setup the stream for receiving.
  598. Post the initial recv buffer(s). Subsequently, the buffers are posted
  599. in the RTPRecvCallback()
  600. */
  601. HRESULT
  602. RecvAudioStream::StartRecv(HWND hWnd)
  603. {
  604. HRESULT hr = S_OK;
  605. DWORD dwPropVal = 0;
  606. if ((!(m_ThreadFlags & DPTFLAG_STOP_RECV) ) && (m_DPFlags & DPFLAG_CONFIGURED_RECV)){
  607. // m_RecvFilter->GetProp (FM_PROP_SRC_SIZE, &dwPropVal);
  608. hr =m_pIRTPRecv->SetRecvNotification(&RTPRecvCallback, (DWORD_PTR)this, 2);
  609. }
  610. return hr;
  611. }
  612. /*
  613. Called by the recv thread to suspend receiving on this RTP session
  614. If there are outstanding receive buffers they have to be recovered
  615. */
  616. HRESULT
  617. RecvAudioStream::StopRecv()
  618. {
  619. // dont recv on this stream
  620. m_pIRTPRecv->CancelRecvNotification();
  621. return S_OK;
  622. }
  623. HRESULT RecvAudioStream::RTPCallback(WSABUF *pWsaBuf, DWORD timestamp, UINT seq, UINT fMark)
  624. {
  625. HRESULT hr;
  626. DWORD_PTR dwPropVal;
  627. // if we are paused, reject the packet
  628. if (m_ThreadFlags & DPTFLAG_PAUSE_RECV)
  629. {
  630. return E_FAIL;
  631. }
  632. // The last two parameters are only used by the recv video stream
  633. hr = m_RecvStream->PutNextNetIn(pWsaBuf, timestamp, seq, fMark, NULL, NULL);
  634. m_pIRTPRecv->FreePacket(pWsaBuf);
  635. if (SUCCEEDED(hr))
  636. {
  637. m_OutMedia->GetProp (MC_PROP_EVENT_HANDLE, &dwPropVal);
  638. if (dwPropVal)
  639. {
  640. SetEvent( (HANDLE) dwPropVal);
  641. }
  642. else
  643. {
  644. DEBUGMSG(ZONE_DP,("PutNextNetIn (ts=%d,seq=%d,fMark=%d) failed with 0x%lX\r\n",timestamp,seq,fMark,hr));
  645. }
  646. }
  647. return S_OK;
  648. }
  649. // global RTP callback function for all receive streams
  650. BOOL
  651. RTPRecvCallback(
  652. DWORD_PTR dwCallback,
  653. WSABUF *pNetRecvBuf
  654. )
  655. {
  656. HRESULT hr;
  657. DWORD timestamp;
  658. UINT seq;
  659. BOOL fMark;
  660. RecvMediaStream *pRecvMC = (RecvMediaStream *)dwCallback;
  661. RTP_HDR *pRTPHdr;
  662. pRTPHdr = (RTP_HDR *)pNetRecvBuf->buf;
  663. timestamp = pRTPHdr->ts;
  664. seq = pRTPHdr->seq;
  665. fMark = pRTPHdr->m;
  666. // packet looks okay
  667. LOG((LOGMSG_NET_RECVD,timestamp,seq,GetTickCount()));
  668. hr = pRecvMC->RTPCallback(pNetRecvBuf,timestamp,seq,fMark);
  669. if (SUCCEEDED(hr))
  670. {
  671. return TRUE;
  672. }
  673. return FALSE;
  674. }
  675. #define MAX_SILENCE_LEVEL 75*256
  676. #define MIN_SILENCE_LEVEL 10*256
  677. AudioSilenceDetector::AudioSilenceDetector()
  678. {
  679. // initialize silence detector stats
  680. // start with a high value because the estimator falls fast but rises slowly
  681. m_iSilenceAvg = MAX_SILENCE_LEVEL - MIN_SILENCE_LEVEL;
  682. m_iTalkAvg = 0;
  683. m_iSilenceLevel = MAX_SILENCE_LEVEL;
  684. m_uManualSilenceLevel = 1000; // use auto mode.
  685. }
  686. // update adaptive silence threshold variables in SendAudioStats
  687. // using m_dwMaxStrength (the max. peak to peak value in a buffer)
  688. // return TRUE if below threshold
  689. BOOL AudioSilenceDetector::SilenceDetect(WORD wStrength)
  690. {
  691. int fSilence;
  692. INT strength;
  693. m_dwMaxStrength = wStrength;
  694. strength = LogScale[m_dwMaxStrength >> 8] << 8;
  695. // UI sets the silence threshold high ( == 1000/1000) to indicate
  696. // automatic silence detection
  697. if (m_uManualSilenceLevel >= 1000) {
  698. LOG((LOGMSG_AUTO_SILENCE,strength >> 8,m_iSilenceLevel >> 8,m_iSilenceAvg>>8));
  699. if (strength > m_iSilenceLevel) {
  700. // talking
  701. // increase threshold slowly
  702. // BUGBUG: should depend on time interval
  703. m_iSilenceLevel += 50; //increased from 25- GJ
  704. m_iTalkAvg += (strength -m_iTalkAvg)/16;
  705. fSilence = FALSE;
  706. } else {
  707. // silence
  708. // update the average silence level
  709. m_iSilenceAvg += (strength - m_iSilenceAvg)/16;
  710. // set the threshold to the avg silence + a constant
  711. m_iSilenceLevel = m_iSilenceAvg + MIN_SILENCE_LEVEL;
  712. fSilence = TRUE;
  713. }
  714. if (m_iSilenceLevel > MAX_SILENCE_LEVEL)
  715. m_iSilenceLevel = MAX_SILENCE_LEVEL;
  716. } else {
  717. // use the user-specified silence threshold
  718. // oddly, the manual silence level is in a different range [0,1000]
  719. DWORD dwSilenceLevel = m_uManualSilenceLevel * 65536/1000;
  720. fSilence = (m_dwMaxStrength < dwSilenceLevel);
  721. LOG((LOGMSG_AUTO_SILENCE,m_dwMaxStrength, dwSilenceLevel ,0));
  722. }
  723. return fSilence;
  724. }
  725. // this method called from the UI thread only
  726. HRESULT RecvAudioStream::DTMFBeep()
  727. {
  728. int nBeeps;
  729. MediaPacket **ppAudPckt=NULL, *pPacket=NULL;
  730. void *pBuffer;
  731. ULONG uCount;
  732. UINT uBufferSize=0;
  733. if ( (!(m_DPFlags & DPFLAG_STARTED_RECV)) ||
  734. (m_ThreadFlags & DPTFLAG_PAUSE_RECV) )
  735. {
  736. return E_FAIL;
  737. }
  738. // how many packets do we inject into the stream ?
  739. m_RecvStream->GetRing(&ppAudPckt, &uCount);
  740. pPacket = ppAudPckt[0];
  741. pPacket->GetDevData(&pBuffer, &uBufferSize);
  742. if (uBufferSize == 0)
  743. {
  744. return E_FAIL;
  745. }
  746. nBeeps = DTMF_FEEDBACK_BEEP_MS / ((uBufferSize * 1000) / m_fDevRecv.nAvgBytesPerSec);
  747. if (nBeeps == 0)
  748. {
  749. nBeeps = 1;
  750. }
  751. m_RecvStream->InjectBeeps(nBeeps);
  752. return S_OK;
  753. }
  754.