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.

1087 lines
28 KiB

  1. #include "precomp.h"
  2. #include "dtmf.h"
  3. HRESULT
  4. SendAudioStream::Initialize( DataPump *pDP)
  5. {
  6. HRESULT hr = DPR_OUT_OF_MEMORY;
  7. DWORD dwFlags = DP_FLAG_FULL_DUPLEX | DP_FLAG_AUTO_SWITCH ;
  8. MEDIACTRLINIT mcInit;
  9. FX_ENTRY ("SendAudioStream::Initialize")
  10. dwFlags |= DP_FLAG_ACM | DP_FLAG_MMSYSTEM | DP_FLAG_AUTO_SILENCE_DETECT;
  11. // store the platform flags
  12. // enable Send and Recv by default
  13. m_DPFlags = (dwFlags & DP_MASK_PLATFORM) | DPFLAG_ENABLE_SEND;
  14. // store a back pointer to the datapump container
  15. m_pDP = pDP;
  16. m_Net = NULL; // this object (RTPSession) no longer used;
  17. m_pRTPSend = NULL; // replaced with this object (RTPSend)
  18. // Initialize data (should be in constructor)
  19. m_CaptureDevice = (UINT) -1; // use VIDEO_MAPPER
  20. // Create and Transmit audio streams
  21. DBG_SAVE_FILE_LINE
  22. m_SendStream = new TxStream();
  23. if ( !m_SendStream)
  24. {
  25. DEBUGMSG (ZONE_DP, ("%s: TxStream new failed\r\n", _fx_));
  26. goto StreamAllocError;
  27. }
  28. // Create Input and Output audio filters
  29. DBG_SAVE_FILE_LINE
  30. m_pAudioFilter = new AcmFilter(); // audio filter will replace m_SendFilter
  31. if (!m_pAudioFilter)
  32. {
  33. DEBUGMSG (ZONE_DP, ("%s: FilterManager new failed\r\n", _fx_));
  34. goto FilterAllocError;
  35. }
  36. //Create MultiMedia device control objects
  37. DBG_SAVE_FILE_LINE
  38. m_InMedia = new WaveInControl();
  39. if (!m_InMedia )
  40. {
  41. DEBUGMSG (ZONE_DP, ("%s: MediaControl new failed\r\n", _fx_));
  42. goto MediaAllocError;
  43. }
  44. // Initialize the send-stream media control object
  45. mcInit.dwFlags = dwFlags | DP_FLAG_SEND;
  46. hr = m_InMedia->Initialize(&mcInit);
  47. if (hr != DPR_SUCCESS)
  48. {
  49. DEBUGMSG (ZONE_DP, ("%s: IMedia->Init failed, hr=0x%lX\r\n", _fx_, hr));
  50. goto MediaAllocError;
  51. }
  52. DBG_SAVE_FILE_LINE
  53. m_pDTMF = new DTMFQueue;
  54. if (!m_pDTMF)
  55. {
  56. return DPR_OUT_OF_MEMORY;
  57. }
  58. // determine if the wave devices are available
  59. if (waveInGetNumDevs()) m_DPFlags |= DP_FLAG_RECORD_CAP;
  60. // set media to half duplex mode by default
  61. m_InMedia->SetProp(MC_PROP_DUPLEX_TYPE, DP_FLAG_HALF_DUPLEX);
  62. m_SavedTickCount = timeGetTime(); //so we start with low timestamps
  63. m_DPFlags |= DPFLAG_INITIALIZED;
  64. m_bAutoMix = FALSE; // where else do you initialize this ?
  65. return DPR_SUCCESS;
  66. MediaAllocError:
  67. if (m_InMedia) delete m_InMedia;
  68. FilterAllocError:
  69. if (m_pAudioFilter) delete m_pAudioFilter;
  70. StreamAllocError:
  71. if (m_SendStream) delete m_SendStream;
  72. ERRORMESSAGE( ("%s: exit, hr=0x%lX\r\n", _fx_, hr));
  73. return hr;
  74. }
  75. SendAudioStream::~SendAudioStream()
  76. {
  77. if (m_DPFlags & DPFLAG_INITIALIZED) {
  78. m_DPFlags &= ~DPFLAG_INITIALIZED;
  79. if (m_DPFlags & DPFLAG_CONFIGURED_SEND )
  80. UnConfigure();
  81. if (m_pRTPSend)
  82. {
  83. m_pRTPSend->Release();
  84. m_pRTPSend = NULL;
  85. }
  86. if (m_pDTMF)
  87. {
  88. delete m_pDTMF;
  89. m_pDTMF = NULL;
  90. }
  91. // Close the receive and transmit streams
  92. if (m_SendStream) delete m_SendStream;
  93. // Close the wave devices
  94. if (m_InMedia) { delete m_InMedia;}
  95. if (m_pAudioFilter)
  96. delete m_pAudioFilter;
  97. m_pDP->RemoveMediaChannel(MCF_SEND|MCF_AUDIO, (IMediaChannel*)(SendMediaStream*)this);
  98. }
  99. }
  100. HRESULT STDMETHODCALLTYPE SendAudioStream::QueryInterface(REFIID iid, void **ppVoid)
  101. {
  102. // resolve duplicate inheritance to the SendMediaStream;
  103. extern IID IID_IProperty;
  104. if (iid == IID_IUnknown)
  105. {
  106. *ppVoid = (IUnknown*)((SendMediaStream*)this);
  107. }
  108. else if (iid == IID_IMediaChannel)
  109. {
  110. *ppVoid = (IMediaChannel*)((SendMediaStream *)this);
  111. }
  112. else if (iid == IID_IAudioChannel)
  113. {
  114. *ppVoid = (IAudioChannel*)this;
  115. }
  116. else if (iid == IID_IDTMFSend)
  117. {
  118. *ppVoid = (IDTMFSend*)this;
  119. }
  120. else if (iid == IID_IProperty)
  121. {
  122. *ppVoid = NULL;
  123. ERROR_OUT(("Don't QueryInterface for IID_IProperty, use IMediaChannel"));
  124. return E_NOINTERFACE;
  125. }
  126. else
  127. {
  128. *ppVoid = NULL;
  129. return E_NOINTERFACE;
  130. }
  131. AddRef();
  132. return S_OK;
  133. }
  134. ULONG STDMETHODCALLTYPE SendAudioStream::AddRef(void)
  135. {
  136. return InterlockedIncrement(&m_lRefCount);
  137. }
  138. ULONG STDMETHODCALLTYPE SendAudioStream::Release(void)
  139. {
  140. LONG lRet;
  141. lRet = InterlockedDecrement(&m_lRefCount);
  142. if (lRet == 0)
  143. {
  144. delete this;
  145. return 0;
  146. }
  147. else
  148. return lRet;
  149. }
  150. HRESULT STDMETHODCALLTYPE SendAudioStream::Configure(
  151. BYTE *pFormat,
  152. UINT cbFormat,
  153. BYTE *pChannelParams,
  154. UINT cbParams,
  155. IUnknown *pUnknown)
  156. {
  157. HRESULT hr;
  158. BOOL fRet;
  159. MEDIAPACKETINIT apInit;
  160. MEDIACTRLCONFIG mcConfig;
  161. MediaPacket **ppAudPckt;
  162. ULONG cAudPckt;
  163. DWORD_PTR dwPropVal;
  164. DWORD dwSourceSize, dwDestSize;
  165. UINT ringSize = MAX_RXRING_SIZE;
  166. WAVEFORMATEX *pwfSend;
  167. DWORD dwPacketDuration, dwPacketSize;
  168. AUDIO_CHANNEL_PARAMETERS audChannelParams;
  169. audChannelParams.RTP_Payload = 0;
  170. MMRESULT mmr;
  171. int nIndex;
  172. FX_ENTRY ("SendAudioStream::Configure")
  173. // basic parameter checking
  174. if (! (m_DPFlags & DPFLAG_INITIALIZED))
  175. return DPR_OUT_OF_MEMORY; //BUGBUG: return proper error;
  176. // Not a good idea to change anything while in mid-stream
  177. if (m_DPFlags & DPFLAG_STARTED_SEND)
  178. {
  179. return DPR_IO_PENDING; // anything better to return
  180. }
  181. if (m_DPFlags & DPFLAG_CONFIGURED_SEND)
  182. {
  183. DEBUGMSG(ZONE_DP, ("Stream Re-Configuration - calling UnConfigure"));
  184. UnConfigure();
  185. }
  186. if ((NULL == pFormat) || (NULL == pChannelParams) ||
  187. (cbParams < sizeof(AUDIO_CHANNEL_PARAMETERS)) ||
  188. (cbFormat < sizeof(WAVEFORMATEX)))
  189. {
  190. return DPR_INVALID_PARAMETER;
  191. }
  192. audChannelParams = *(AUDIO_CHANNEL_PARAMETERS *)pChannelParams;
  193. pwfSend = (WAVEFORMATEX *)pFormat;
  194. m_wfCompressed = *pwfSend;
  195. m_wfCompressed.cbSize = 0;
  196. mmr = AcmFilter::SuggestDecodeFormat(pwfSend, &m_fDevSend);
  197. UPDATE_REPORT_ENTRY(g_prptCallParameters, pwfSend->wFormatTag, REP_SEND_AUDIO_FORMAT);
  198. UPDATE_REPORT_ENTRY(g_prptCallParameters, pwfSend->nSamplesPerSec, REP_SEND_AUDIO_SAMPLING);
  199. UPDATE_REPORT_ENTRY(g_prptCallParameters, pwfSend->nAvgBytesPerSec * 8, REP_SEND_AUDIO_BITRATE);
  200. RETAILMSG(("NAC: Audio Send Format: %s", (pwfSend->wFormatTag == 66) ? "G723.1" : (pwfSend->wFormatTag == 112) ? "LHCELP" : (pwfSend->wFormatTag == 113) ? "LHSB08" : (pwfSend->wFormatTag == 114) ? "LHSB12" : (pwfSend->wFormatTag == 115) ? "LHSB16" : (pwfSend->wFormatTag == 6) ? "MSALAW" : (pwfSend->wFormatTag == 7) ? "MSULAW" : (pwfSend->wFormatTag == 130) ? "MSRT24" : "??????"));
  201. RETAILMSG(("NAC: Audio Send Sampling Rate (Hz): %ld", pwfSend->nSamplesPerSec));
  202. RETAILMSG(("NAC: Audio Send Bitrate (w/o network overhead - bps): %ld", pwfSend->nAvgBytesPerSec*8));
  203. // Initialize the send-stream media control object
  204. mcConfig.uDuration = MC_USING_DEFAULT; // set duration by samples per pkt
  205. mcConfig.pDevFmt = &m_fDevSend;
  206. mcConfig.hStrm = (DPHANDLE) m_SendStream;
  207. mcConfig.uDevId = m_CaptureDevice;
  208. mcConfig.cbSamplesPerPkt = audChannelParams.ns_params.wFrameSize
  209. *audChannelParams.ns_params.wFramesPerPkt;
  210. UPDATE_REPORT_ENTRY(g_prptCallParameters, mcConfig.cbSamplesPerPkt, REP_SEND_AUDIO_PACKET);
  211. RETAILMSG(("NAC: Audio Send Packetization (ms/packet): %ld", pwfSend->nSamplesPerSec ? mcConfig.cbSamplesPerPkt * 1000UL / pwfSend->nSamplesPerSec : 0));
  212. INIT_COUNTER_MAX(g_pctrAudioSendBytes, (pwfSend->nAvgBytesPerSec + pwfSend->nSamplesPerSec * (sizeof(RTP_HDR) + IP_HEADER_SIZE + UDP_HEADER_SIZE) / mcConfig.cbSamplesPerPkt) << 3);
  213. hr = m_InMedia->Configure(&mcConfig);
  214. if (hr != DPR_SUCCESS)
  215. {
  216. DEBUGMSG (ZONE_DP, ("%s: IMedia->Config failed, hr=0x%lX\r\n", _fx_, hr));
  217. goto IMediaInitError;
  218. }
  219. // initialize the ACM filter
  220. mmr = m_pAudioFilter->Open(&m_fDevSend, pwfSend);
  221. if (mmr != 0)
  222. {
  223. DEBUGMSG (ZONE_DP, ("%s: AcmFilter->Open failed, mmr=%d\r\n", _fx_, mmr));
  224. hr = DPR_CANT_OPEN_CODEC;
  225. goto SendFilterInitError;
  226. }
  227. // Initialize the send stream and the packets
  228. ZeroMemory (&apInit, sizeof (apInit));
  229. apInit.dwFlags = DP_FLAG_SEND | DP_FLAG_ACM | DP_FLAG_MMSYSTEM;
  230. m_InMedia->FillMediaPacketInit (&apInit);
  231. m_InMedia->GetProp (MC_PROP_SIZE, &dwPropVal);
  232. dwSourceSize = (DWORD)dwPropVal;
  233. m_pAudioFilter->SuggestDstSize(dwSourceSize, &dwDestSize);
  234. apInit.cbSizeRawData = dwSourceSize;
  235. apInit.cbOffsetRawData = 0;
  236. apInit.cbSizeNetData = dwDestSize;
  237. dwPacketSize = dwDestSize;
  238. apInit.pStrmConvSrcFmt = &m_fDevSend;
  239. apInit.pStrmConvDstFmt = &m_wfCompressed;
  240. m_InMedia->GetProp (MC_PROP_DURATION, &dwPropVal);
  241. dwPacketDuration = (DWORD)dwPropVal;
  242. apInit.cbOffsetNetData = sizeof (RTP_HDR);
  243. apInit.payload = audChannelParams.RTP_Payload;
  244. fRet = m_SendStream->Initialize (DP_FLAG_MMSYSTEM, MAX_TXRING_SIZE, m_pDP, &apInit);
  245. if (! fRet)
  246. {
  247. DEBUGMSG (ZONE_DP, ("%s: TxStream->Init failed, fRet=0%u\r\n", _fx_, fRet));
  248. hr = DPR_CANT_INIT_TX_STREAM;
  249. goto TxStreamInitError;
  250. }
  251. // prepare headers for TxStream
  252. m_SendStream->GetRing (&ppAudPckt, &cAudPckt);
  253. m_InMedia->RegisterData (ppAudPckt, cAudPckt);
  254. m_InMedia->PrepareHeaders ();
  255. m_pAudioFilter->PrepareAudioPackets((AudioPacket**)ppAudPckt, cAudPckt, AP_ENCODE);
  256. // Open the play from wav file
  257. OpenSrcFile();
  258. // Initialize DTMF support
  259. m_pDTMF->Initialize(&m_fDevSend);
  260. m_pDTMF->ClearQueue();
  261. // WS2Qos will be called in Start to communicate stream reservations to the
  262. // remote endpoint using a RESV message
  263. //
  264. // We use a peak-rate allocation approach based on our target bitrates
  265. // Note that for the token bucket size and the maximum SDU size, we now
  266. // account for IP header overhead, and use the max frame fragment size
  267. // instead of the maximum compressed image size returned by the codec
  268. //
  269. // Some of the parameters are left unspecified because they are set
  270. // in the sender Tspec.
  271. InitAudioFlowspec(&m_flowspec, pwfSend, dwPacketSize);
  272. if (m_pDP->m_pIQoS)
  273. {
  274. // Initialize our requests. One for CPU usage, one for bandwidth usage.
  275. m_aRRq.cResourceRequests = 2;
  276. m_aRRq.aResourceRequest[0].resourceID = RESOURCE_OUTGOING_BANDWIDTH;
  277. if (dwPacketDuration)
  278. m_aRRq.aResourceRequest[0].nUnitsMin = (DWORD)(dwPacketSize + sizeof(RTP_HDR) + IP_HEADER_SIZE + UDP_HEADER_SIZE) * 8000 / dwPacketDuration;
  279. else
  280. m_aRRq.aResourceRequest[0].nUnitsMin = 0;
  281. m_aRRq.aResourceRequest[1].resourceID = RESOURCE_CPU_CYCLES;
  282. m_aRRq.aResourceRequest[1].nUnitsMin = 800;
  283. /*
  284. BUGBUG. This is, in theory the correct calculation, but until we do more investigation, go with a known value
  285. m_aRRq.aResourceRequest[1].nUnitsMin = (audDetails.wCPUUtilizationEncode+audDetails.wCPUUtilizationDecode)*10;
  286. */
  287. // Initialize QoS structure
  288. ZeroMemory(&m_Stats, sizeof(m_Stats));
  289. // Initialize oldest QoS callback timestamp
  290. // Register with the QoS module. Even if this call fails, that's Ok, we'll do without the QoS support
  291. m_pDP->m_pIQoS->RequestResources((GUID *)&MEDIA_TYPE_H323AUDIO, (LPRESOURCEREQUESTLIST)&m_aRRq, QosNotifyAudioCB, (DWORD_PTR)this);
  292. }
  293. m_DPFlags |= DPFLAG_CONFIGURED_SEND;
  294. return DPR_SUCCESS;
  295. TxStreamInitError:
  296. SendFilterInitError:
  297. m_InMedia->Close();
  298. m_pAudioFilter->Close();
  299. IMediaInitError:
  300. ERRORMESSAGE(("%s: failed, hr=0%u\r\n", _fx_, hr));
  301. return hr;
  302. }
  303. void SendAudioStream::UnConfigure()
  304. {
  305. AudioPacket **ppAudPckt;
  306. ULONG uPackets;
  307. if ((m_DPFlags & DPFLAG_CONFIGURED_SEND)) {
  308. if (m_hCapturingThread) {
  309. Stop();
  310. }
  311. // Close the wave devices
  312. m_InMedia->Reset();
  313. m_InMedia->UnprepareHeaders();
  314. m_InMedia->Close();
  315. // Close the play from wav file
  316. CloseSrcFile();
  317. // Close the filters
  318. m_SendStream->GetRing ((MediaPacket***)&ppAudPckt, &uPackets);
  319. m_pAudioFilter->UnPrepareAudioPackets(ppAudPckt, uPackets, AP_ENCODE);
  320. m_pAudioFilter->Close();
  321. // Close the transmit streams
  322. m_SendStream->Destroy();
  323. m_DPFlags &= ~DPFLAG_CONFIGURED_SEND;
  324. m_ThreadFlags = 0; // invalidate previous call to SetMaxBitrate
  325. // Release the QoS Resources
  326. // If the associated RequestResources had failed, the ReleaseResources can be
  327. // still called... it will just come back without having freed anything.
  328. if (m_pDP->m_pIQoS)
  329. {
  330. m_pDP->m_pIQoS->ReleaseResources((GUID *)&MEDIA_TYPE_H323AUDIO, (LPRESOURCEREQUESTLIST)&m_aRRq);
  331. }
  332. }
  333. }
  334. DWORD CALLBACK SendAudioStream::StartRecordingThread (LPVOID pVoid)
  335. {
  336. SendAudioStream *pThisStream = (SendAudioStream*)pVoid;
  337. return pThisStream->RecordingThread();
  338. }
  339. // LOOK: identical to SendVideoStream version.
  340. HRESULT
  341. SendAudioStream::Start()
  342. {
  343. FX_ENTRY ("SendAudioStream::Start")
  344. if (m_DPFlags & DPFLAG_STARTED_SEND)
  345. return DPR_SUCCESS;
  346. // TODO: remove this check once audio UI calls the IComChan PAUSE_ prop
  347. if (!(m_DPFlags & DPFLAG_ENABLE_SEND))
  348. return DPR_SUCCESS;
  349. if ((!(m_DPFlags & DPFLAG_CONFIGURED_SEND)) || (m_pRTPSend==NULL))
  350. return DPR_NOT_CONFIGURED;
  351. ASSERT(!m_hCapturingThread);
  352. m_ThreadFlags &= ~(DPTFLAG_STOP_RECORD|DPTFLAG_STOP_SEND);
  353. SetFlowSpec();
  354. // Start recording thread
  355. if (!(m_ThreadFlags & DPTFLAG_STOP_RECORD))
  356. m_hCapturingThread = CreateThread(NULL,0, SendAudioStream::StartRecordingThread,(LPVOID)this,0,&m_CaptureThId);
  357. m_DPFlags |= DPFLAG_STARTED_SEND;
  358. DEBUGMSG (ZONE_DP, ("%s: Record threadid=%x,\r\n", _fx_, m_CaptureThId));
  359. return DPR_SUCCESS;
  360. }
  361. // LOOK: identical to SendVideoStream version.
  362. HRESULT
  363. SendAudioStream::Stop()
  364. {
  365. DWORD dwWait;
  366. if(!(m_DPFlags & DPFLAG_STARTED_SEND))
  367. {
  368. return DPR_SUCCESS;
  369. }
  370. m_ThreadFlags = m_ThreadFlags |
  371. DPTFLAG_STOP_SEND | DPTFLAG_STOP_RECORD ;
  372. if(m_SendStream)
  373. m_SendStream->Stop();
  374. DEBUGMSG (ZONE_VERBOSE, ("STOP1: Waiting for record thread to exit\r\n"));
  375. /*
  376. * we want to wait for all the threads to exit, but we need to handle windows
  377. * messages (mostly from winsock) while waiting.
  378. */
  379. if(m_hCapturingThread)
  380. {
  381. dwWait = WaitForSingleObject (m_hCapturingThread, INFINITE);
  382. DEBUGMSG (ZONE_VERBOSE, ("STOP2: Recording thread exited\r\n"));
  383. ASSERT(dwWait != WAIT_FAILED);
  384. CloseHandle(m_hCapturingThread);
  385. m_hCapturingThread = NULL;
  386. }
  387. m_DPFlags &= ~DPFLAG_STARTED_SEND;
  388. return DPR_SUCCESS;
  389. }
  390. // low order word is the signal strength
  391. // high order work contains bits to indicate status
  392. // (0x01 - transmitting)
  393. // (0x02 - audio device is jammed)
  394. STDMETHODIMP SendAudioStream::GetSignalLevel(UINT *pSignalStrength)
  395. {
  396. UINT uLevel;
  397. DWORD dwJammed;
  398. DWORD_PTR dwPropVal;
  399. if(!(m_DPFlags & DPFLAG_STARTED_SEND))
  400. {
  401. uLevel = 0;
  402. }
  403. else
  404. {
  405. uLevel = m_AudioMonitor.GetSignalStrength();
  406. m_InMedia->GetProp(MC_PROP_AUDIO_JAMMED, &dwPropVal);
  407. dwJammed = (DWORD)dwPropVal;
  408. if (dwJammed)
  409. {
  410. uLevel = (2 << 16); // 0x0200
  411. }
  412. else if (m_fSending)
  413. {
  414. uLevel |= (1 << 16); // 0x0100 + uLevel
  415. }
  416. }
  417. *pSignalStrength = uLevel;
  418. return S_OK;
  419. };
  420. // this interface method is primarily for H.245 flow control messages
  421. // it will pause the stream if uMaxBitrate is less than the codec
  422. // output bitrate. Only valid on a Configure'd stream.
  423. HRESULT STDMETHODCALLTYPE SendAudioStream::SetMaxBitrate(UINT uMaxBitrate)
  424. {
  425. UINT uMinBitrate;
  426. if (!(m_DPFlags & DPFLAG_CONFIGURED_SEND))
  427. {
  428. return DPR_NOT_CONFIGURED;
  429. }
  430. uMinBitrate = 8 * m_wfCompressed.nAvgBytesPerSec;
  431. if (uMaxBitrate < uMinBitrate)
  432. {
  433. DEBUGMSG(1, ("SendAudioStream::SetMaxBitrate - PAUSING"));
  434. m_ThreadFlags |= DPTFLAG_PAUSE_SEND;
  435. }
  436. else
  437. {
  438. DEBUGMSG(1, ("SendAudioStream::SetMaxBitrate - UnPausing"));
  439. m_ThreadFlags = m_ThreadFlags & ~(DPTFLAG_PAUSE_SEND);
  440. }
  441. return S_OK;
  442. }
  443. // IProperty::GetProperty / SetProperty
  444. // (DataPump::MediaChannel::GetProperty)
  445. // Properties of the MediaChannel. Supports properties for both audio
  446. // and video channels.
  447. STDMETHODIMP
  448. SendAudioStream::GetProperty(
  449. DWORD prop,
  450. PVOID pBuf,
  451. LPUINT pcbBuf
  452. )
  453. {
  454. HRESULT hr = DPR_SUCCESS;
  455. RTP_STATS RTPStats;
  456. DWORD_PTR dwPropVal;
  457. UINT len = sizeof(DWORD); // most props are DWORDs
  458. if (!pBuf || *pcbBuf < len)
  459. {
  460. *pcbBuf = len;
  461. return DPR_INVALID_PARAMETER;
  462. }
  463. switch (prop)
  464. {
  465. case PROP_AUDIO_STRENGTH:
  466. return GetSignalLevel((UINT *)pBuf);
  467. case PROP_AUDIO_JAMMED:
  468. hr = m_InMedia->GetProp(MC_PROP_AUDIO_JAMMED, &dwPropVal);
  469. *(DWORD *)pBuf = (DWORD)dwPropVal;
  470. break;
  471. #ifdef OLDSTUFF
  472. case PROP_NET_SEND_STATS:
  473. if (m_Net && *pcbBuf >= sizeof(RTP_STATS))
  474. {
  475. m_Net->GetSendStats((RTP_STATS *)pBuf);
  476. *pcbBuf = sizeof(RTP_STATS);
  477. } else
  478. hr = DPR_INVALID_PROP_VAL;
  479. break;
  480. #endif
  481. case PROP_DURATION:
  482. hr = m_InMedia->GetProp(MC_PROP_DURATION, &dwPropVal);
  483. *(DWORD *)pBuf = (DWORD)dwPropVal;
  484. break;
  485. case PROP_SILENCE_LEVEL:
  486. *(DWORD *)pBuf = m_AudioMonitor.GetSilenceLevel();
  487. break;
  488. case PROP_SILENCE_DURATION:
  489. hr = m_InMedia->GetProp(MC_PROP_SILENCE_DURATION, &dwPropVal);
  490. *(DWORD *)pBuf = (DWORD)dwPropVal;
  491. break;
  492. case PROP_DUPLEX_TYPE:
  493. hr = m_InMedia->GetProp(MC_PROP_DUPLEX_TYPE, &dwPropVal);
  494. if(HR_SUCCEEDED(hr))
  495. {
  496. if(dwPropVal & DP_FLAG_FULL_DUPLEX)
  497. *(DWORD *)pBuf = DUPLEX_TYPE_FULL;
  498. else
  499. *(DWORD *)pBuf = DUPLEX_TYPE_HALF;
  500. }
  501. break;
  502. case PROP_AUDIO_SPP:
  503. hr = m_InMedia->GetProp(MC_PROP_SPP, &dwPropVal);
  504. *(DWORD *)pBuf = (DWORD)dwPropVal;
  505. break;
  506. case PROP_AUDIO_SPS:
  507. hr = m_InMedia->GetProp(MC_PROP_SPS, &dwPropVal);
  508. *(DWORD *)pBuf = (DWORD)dwPropVal;
  509. break;
  510. case PROP_WAVE_DEVICE_TYPE:
  511. *(DWORD *)pBuf = m_DPFlags & DP_MASK_WAVE_DEVICE;
  512. break;
  513. case PROP_RECORD_ON:
  514. *(DWORD *)pBuf = (m_DPFlags & DPFLAG_ENABLE_SEND) !=0;
  515. break;
  516. case PROP_AUDIO_AUTOMIX:
  517. *(DWORD *)pBuf = m_bAutoMix;
  518. break;
  519. case PROP_RECORD_DEVICE:
  520. *(DWORD *)pBuf = m_CaptureDevice;
  521. break;
  522. default:
  523. hr = DPR_INVALID_PROP_ID;
  524. break;
  525. }
  526. return hr;
  527. }
  528. STDMETHODIMP
  529. SendAudioStream::SetProperty(
  530. DWORD prop,
  531. PVOID pBuf,
  532. UINT cbBuf
  533. )
  534. {
  535. DWORD dw;
  536. HRESULT hr = S_OK;
  537. if (cbBuf < sizeof (DWORD))
  538. return DPR_INVALID_PARAMETER;
  539. switch (prop)
  540. {
  541. case PROP_SILENCE_LEVEL:
  542. m_AudioMonitor.SetSilenceLevel(*(DWORD *)pBuf);
  543. RETAILMSG(("NAC: Silence Level set to %d / 1000",*(DWORD*)pBuf));
  544. break;
  545. case PROP_DUPLEX_TYPE:
  546. ASSERT(0);
  547. break;
  548. case DP_PROP_DUPLEX_TYPE:
  549. dw = *(DWORD*)pBuf;
  550. if (dw)
  551. {
  552. dw = DP_FLAG_FULL_DUPLEX;
  553. }
  554. else
  555. {
  556. dw = DP_FLAG_HALF_DUPLEX;
  557. }
  558. m_InMedia->SetProp(MC_PROP_DUPLEX_TYPE, dw);
  559. break;
  560. case PROP_VOICE_SWITCH:
  561. // set duplex type of both input and output
  562. dw = *(DWORD*)pBuf;
  563. switch(dw)
  564. {
  565. case VOICE_SWITCH_MIC_ON:
  566. dw = DP_FLAG_MIC_ON;
  567. break;
  568. case VOICE_SWITCH_MIC_OFF:
  569. dw = DP_FLAG_MIC_OFF;
  570. break;
  571. default:
  572. case VOICE_SWITCH_AUTO:
  573. dw = DP_FLAG_AUTO_SWITCH;
  574. break;
  575. }
  576. hr = m_InMedia->SetProp(MC_PROP_VOICE_SWITCH, dw);
  577. RETAILMSG(("NAC: Setting voice switch to %s", (DP_FLAG_AUTO_SWITCH & dw) ? "Auto" : ((DP_FLAG_MIC_ON & dw)? "MicOn":"MicOff")));
  578. break;
  579. case PROP_SILENCE_DURATION:
  580. hr = m_InMedia->SetProp(MC_PROP_SILENCE_DURATION, *(DWORD*)pBuf);
  581. RETAILMSG(("NAC: setting silence duration to %d ms",*(DWORD*)pBuf));
  582. break;
  583. // TODO: remove this property once UI calls IComChan version
  584. case PROP_RECORD_ON:
  585. {
  586. DWORD flag = DPFLAG_ENABLE_SEND ;
  587. if (*(DWORD *)pBuf) {
  588. m_DPFlags |= flag; // set the flag
  589. Start();
  590. }
  591. else
  592. {
  593. m_DPFlags &= ~flag; // clear the flag
  594. Stop();
  595. }
  596. RETAILMSG(("NAC: %s", *(DWORD*)pBuf ? "Enabling":"Disabling"));
  597. break;
  598. }
  599. case PROP_AUDIO_AUTOMIX:
  600. m_bAutoMix = *(DWORD*)pBuf;
  601. break;
  602. case PROP_RECORD_DEVICE:
  603. m_CaptureDevice = *(DWORD*)pBuf;
  604. RETAILMSG(("NAC: Setting default record device to %d", m_CaptureDevice));
  605. break;
  606. default:
  607. return DPR_INVALID_PROP_ID;
  608. break;
  609. }
  610. return hr;
  611. }
  612. void SendAudioStream::EndSend()
  613. {
  614. }
  615. /*************************************************************************
  616. Function: SendAudioStream::OpenSrcFile(void)
  617. Purpose : Opens wav file to read audio data from.
  618. Returns : HRESULT.
  619. Params : None
  620. Comments: * Registry keys:
  621. \\HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Audio\PlayFromFile\fPlayFromFile
  622. If set to zero, data will not be read from wav file.
  623. If set to a non null value <= INT_MAX, data will be read from wav file.
  624. \\HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Audio\PlayFromFile\szInputFileName
  625. Name of the wav file to read audio data from.
  626. \\HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Audio\PlayFromFile\fLoop
  627. If set to zero, the file will only be read once.
  628. If set to a non null value <= INT_MAX, the file will be read circularly.
  629. \\HKEY_LOCAL_MACHINE\Software\Microsoft\Internet Audio\PlayFromFile\cchIOBuffer
  630. If set to zero, size of the MM IO buffer is set to its default value (8Kbytes).
  631. If set to one, size of the MM IO buffer is set to match maximum size of the wav file.
  632. If set a non null value between 2 and INT_MAX, size of the MM IO buffer is set to cchIOBuffer bytes.
  633. History : Date Reason
  634. 06/02/96 Created - PhilF
  635. *************************************************************************/
  636. HRESULT SendAudioStream::OpenSrcFile (void)
  637. {
  638. return AudioFile::OpenSourceFile(&m_mmioSrc, &m_fDevSend);
  639. }
  640. /*************************************************************************
  641. Function: DataPump::CloseSrcFile(void)
  642. Purpose : Close wav file used to read audio data from.
  643. Returns : HRESULT.
  644. Params : None
  645. Comments:
  646. History : Date Reason
  647. 06/02/96 Created - PhilF
  648. *************************************************************************/
  649. HRESULT SendAudioStream::CloseSrcFile (void)
  650. {
  651. return AudioFile::CloseSourceFile(&m_mmioSrc);
  652. }
  653. HRESULT CALLBACK SendAudioStream::QosNotifyAudioCB(LPRESOURCEREQUESTLIST lpResourceRequestList, DWORD_PTR dwThis)
  654. {
  655. HRESULT hr=NOERROR;
  656. LPRESOURCEREQUESTLIST prrl=lpResourceRequestList;
  657. int i;
  658. #ifdef LOGSTATISTICS_ON
  659. int iMaxBWUsage, iMaxCPUUsage;
  660. char szDebug[256];
  661. #endif
  662. DWORD dwCPUUsage, dwBWUsage;
  663. int iCPUUsageId, iBWUsageId;
  664. UINT dwSize = sizeof(int);
  665. SendMediaStream *pThis = (SendMediaStream *)dwThis;
  666. // Enter critical section to allow QoS thread to read the statistics while recording
  667. EnterCriticalSection(&(pThis->m_crsQos));
  668. // Record the time of this callback call
  669. pThis->m_Stats.dwNewestTs = timeGetTime();
  670. // Only do anything if we have at least captured a frame in the previous epoch
  671. if ((pThis->m_Stats.dwCount) && (pThis->m_Stats.dwNewestTs > pThis->m_Stats.dwOldestTs))
  672. {
  673. #ifdef LOGSTATISTICS_ON
  674. wsprintf(szDebug, " Epoch = %ld\r\n", pThis->m_Stats.dwNewestTs - pThis->m_Stats.dwOldestTs);
  675. OutputDebugString(szDebug);
  676. #endif
  677. // Read the stats
  678. dwCPUUsage = pThis->m_Stats.dwMsComp * 1000UL / (pThis->m_Stats.dwNewestTs - pThis->m_Stats.dwOldestTs);
  679. dwBWUsage = pThis->m_Stats.dwBits * 1000UL / (pThis->m_Stats.dwNewestTs - pThis->m_Stats.dwOldestTs);
  680. // Initialize QoS structure. Only the four first fields should be zeroed.
  681. ZeroMemory(&(pThis->m_Stats), 4UL * sizeof(DWORD));
  682. // Record the time of this call for the next callback call
  683. pThis->m_Stats.dwOldestTs = pThis->m_Stats.dwNewestTs;
  684. }
  685. else
  686. dwBWUsage = dwCPUUsage = 0UL;
  687. // Get the latest RTCP stats and update the counters.
  688. // we do this here because it is called periodically.
  689. if (pThis->m_pRTPSend)
  690. {
  691. UINT lastPacketsLost = pThis->m_RTPStats.packetsLost;
  692. if (g_pctrAudioSendLost && SUCCEEDED(pThis->m_pRTPSend->GetSendStats(&pThis->m_RTPStats)))
  693. UPDATE_COUNTER(g_pctrAudioSendLost, pThis->m_RTPStats.packetsLost-lastPacketsLost);
  694. }
  695. // Leave critical section
  696. LeaveCriticalSection(&(pThis->m_crsQos));
  697. // Get the max for the resources.
  698. #ifdef LOGSTATISTICS_ON
  699. iMaxCPUUsage = -1L; iMaxBWUsage = -1L;
  700. #endif
  701. for (i=0, iCPUUsageId = -1L, iBWUsageId = -1L; i<(int)lpResourceRequestList->cRequests; i++)
  702. if (lpResourceRequestList->aRequests[i].resourceID == RESOURCE_OUTGOING_BANDWIDTH)
  703. iBWUsageId = i;
  704. else if (lpResourceRequestList->aRequests[i].resourceID == RESOURCE_CPU_CYCLES)
  705. iCPUUsageId = i;
  706. #ifdef LOGSTATISTICS_ON
  707. if (iBWUsageId != -1L)
  708. iMaxBWUsage = lpResourceRequestList->aRequests[iBWUsageId].nUnitsMin;
  709. if (iCPUUsageId != -1L)
  710. iMaxCPUUsage = lpResourceRequestList->aRequests[iCPUUsageId].nUnitsMin;
  711. #endif
  712. // Update the QoS resources (only if you need less than what's available)
  713. if (iCPUUsageId != -1L)
  714. {
  715. if ((int)dwCPUUsage < lpResourceRequestList->aRequests[iCPUUsageId].nUnitsMin)
  716. lpResourceRequestList->aRequests[iCPUUsageId].nUnitsMin = dwCPUUsage;
  717. }
  718. if (iBWUsageId != -1L)
  719. {
  720. if ((int)dwBWUsage < lpResourceRequestList->aRequests[iBWUsageId].nUnitsMin)
  721. lpResourceRequestList->aRequests[iBWUsageId].nUnitsMin = dwBWUsage;
  722. }
  723. #ifdef LOGSTATISTICS_ON
  724. // How are we doing?
  725. if (iCPUUsageId != -1L)
  726. {
  727. wsprintf(szDebug, " A: Max CPU Usage: %ld, Current CPU Usage: %ld\r\n", iMaxCPUUsage, dwCPUUsage);
  728. OutputDebugString(szDebug);
  729. }
  730. if (iBWUsageId != -1L)
  731. {
  732. wsprintf(szDebug, " A: Max BW Usage: %ld, Current BW Usage: %ld\r\n", iMaxBWUsage, dwBWUsage);
  733. OutputDebugString(szDebug);
  734. }
  735. #endif
  736. return hr;
  737. }
  738. HRESULT __stdcall SendAudioStream::AddDigit(int nDigit)
  739. {
  740. IMediaChannel *pIMC = NULL;
  741. RecvMediaStream *pRecv = NULL;
  742. BOOL bIsStarted;
  743. if ((!(m_DPFlags & DPFLAG_CONFIGURED_SEND)) || (m_pRTPSend==NULL))
  744. {
  745. return DPR_NOT_CONFIGURED;
  746. }
  747. bIsStarted = (m_DPFlags & DPFLAG_STARTED_SEND);
  748. if (bIsStarted)
  749. {
  750. Stop();
  751. }
  752. m_pDTMF->AddDigitToQueue(nDigit);
  753. SendDTMF();
  754. m_pDP->GetMediaChannelInterface(MCF_RECV | MCF_AUDIO, &pIMC);
  755. if (pIMC)
  756. {
  757. pRecv = static_cast<RecvMediaStream *> (pIMC);
  758. pRecv->DTMFBeep();
  759. pIMC->Release();
  760. }
  761. if (bIsStarted)
  762. {
  763. Start();
  764. }
  765. return S_OK;
  766. }
  767. HRESULT __stdcall SendAudioStream::SendDTMF()
  768. {
  769. HRESULT hr;
  770. MediaPacket **ppAudPckt, *pPacket;
  771. ULONG uCount;
  772. UINT uBufferSize, uBytesSent;
  773. void *pBuffer;
  774. bool bMark = true;
  775. DWORD dwSamplesPerPkt;
  776. MMRESULT mmr;
  777. DWORD dwSamplesPerSec;
  778. DWORD dwPacketTimeMS;
  779. DWORD_PTR dwPropVal;
  780. UINT uTimerID;
  781. HANDLE hEvent = m_pDTMF->GetEvent();
  782. m_InMedia->GetProp (MC_PROP_SPP, &dwPropVal);
  783. dwSamplesPerPkt = (DWORD)dwPropVal;
  784. m_InMedia->GetProp (MC_PROP_SPS, &dwPropVal);
  785. dwSamplesPerSec = (DWORD)dwPropVal;
  786. dwPacketTimeMS = (dwSamplesPerPkt * 1000) / dwSamplesPerSec;
  787. timeBeginPeriod(5);
  788. ResetEvent(hEvent);
  789. uTimerID = timeSetEvent(dwPacketTimeMS-1, 5, (LPTIMECALLBACK)hEvent, 0, TIME_CALLBACK_EVENT_SET|TIME_PERIODIC);
  790. // since the stream is stopped, just grab any packet
  791. // from the TxStream
  792. m_SendStream->GetRing(&ppAudPckt, &uCount);
  793. pPacket = ppAudPckt[0];
  794. pPacket->GetDevData(&pBuffer, &uBufferSize);
  795. hr = m_pDTMF->ReadFromQueue((BYTE*)pBuffer, uBufferSize);
  796. while (SUCCEEDED(hr))
  797. {
  798. // there should be only 1 tone in the queue (it can handle more)
  799. // so assume we only need to set the mark bit on the first packet
  800. pPacket->m_fMark = bMark;
  801. bMark = false;
  802. pPacket->SetProp(MP_PROP_TIMESTAMP, m_SendTimestamp);
  803. m_SendTimestamp += dwSamplesPerPkt;
  804. pPacket->SetState (MP_STATE_RECORDED);
  805. // compress
  806. mmr = m_pAudioFilter->Convert((AudioPacket*)pPacket, AP_ENCODE);
  807. if (mmr == MMSYSERR_NOERROR)
  808. {
  809. pPacket->SetState(MP_STATE_ENCODED);
  810. SendPacket((AudioPacket*)pPacket, &uBytesSent);
  811. pPacket->m_fMark=false;
  812. pPacket->SetState(MP_STATE_RESET);
  813. }
  814. hr = m_pDTMF->ReadFromQueue((BYTE*)pBuffer, uBufferSize);
  815. // so that we don't overload the receive jitter buffer on the remote
  816. // side, sleep a few milliseconds between sending packets
  817. if (SUCCEEDED(hr))
  818. {
  819. WaitForSingleObject(hEvent, dwPacketTimeMS);
  820. ResetEvent(hEvent);
  821. }
  822. }
  823. timeKillEvent(uTimerID);
  824. timeEndPeriod(5);
  825. return S_OK;
  826. }
  827. HRESULT __stdcall SendAudioStream::ResetDTMF()
  828. {
  829. if(!(m_DPFlags & DPFLAG_STARTED_SEND))
  830. {
  831. return S_OK;
  832. }
  833. return m_pDTMF->ClearQueue();
  834. }
  835.