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.

566 lines
13 KiB

  1. #include "precomp.h"
  2. #include "datapump.h"
  3. #include "DSCStream.h"
  4. #include "agc.h"
  5. static const int DSC_TIMEOUT = 1000;
  6. static const int DSC_MAX_LAG = 500;
  7. static const int DSC_SUCCESS = 0;
  8. static const int DSC_NEED_TO_EXIT = 1;
  9. static const int DSC_FRAME_SENT = 2;
  10. static const int DSC_SILENCE_DETECT = 3;
  11. static const int DSC_ERROR = 4;
  12. static const int SILENCE_TIMEOUT= 600; // milliseconds
  13. static const int HEADER_SIZE = sizeof(RTP_HDR) + IP_HEADER_SIZE + UDP_HEADER_SIZE;
  14. static const UINT DSC_QOS_INITIALIZE = 100;
  15. static const UINT DSC_QOS_PACKET_SENT = 101;
  16. static inline UINT QMOD(const int x, const int mod)
  17. {
  18. if (x >= mod)
  19. return (x-mod);
  20. if (x < 0)
  21. return (x+mod);
  22. else
  23. return x;
  24. }
  25. BOOL SendDSCStream::UpdateQosStats(UINT uStatType, UINT uStatValue1, UINT uStatValue2)
  26. {
  27. EnterCriticalSection(&m_crsQos);
  28. switch (uStatType)
  29. {
  30. case DSC_QOS_INITIALIZE:
  31. {
  32. m_Stats.dwMsCap = m_Stats.dwMsComp = m_Stats.dwBits = m_Stats.dwCount = 0;
  33. m_Stats.dwNewestTs = m_Stats.dwOldestTs = timeGetTime();
  34. break;
  35. }
  36. case DSC_QOS_PACKET_SENT:
  37. {
  38. // uStatvalue1 is the CPU time, uStatvalue2 is the size in bytes
  39. m_Stats.dwCount++;
  40. m_Stats.dwMsComp += uStatValue1;
  41. m_Stats.dwBits += (uStatValue2) * 8;
  42. // statview really wants bits per second
  43. UPDATE_COUNTER(g_pctrAudioSendBytes, uStatValue2*8);
  44. break;
  45. }
  46. };
  47. LeaveCriticalSection(&m_crsQos);
  48. return TRUE;
  49. }
  50. inline BOOL SendDSCStream::ThreadExitCheck()
  51. {
  52. return (m_ThreadFlags & DPTFLAG_STOP_RECORD);
  53. }
  54. // resyncs the Timestamp with the last known timestamp
  55. inline void SendDSCStream::UpdateTimestamp()
  56. {
  57. UINT uTime;
  58. uTime = (timeGetTime() - m_SavedTickCount)*((m_wfPCM.nSamplesPerSec)/1000);
  59. // if (uTime < 0)
  60. // uTime = 0;
  61. m_SendTimestamp += uTime;
  62. }
  63. // WaitForControl - Thread Function
  64. // opens the DirectSound device or waits for it to become available
  65. // returns either DSC_SUCCESS or DSC_NEED_TO_EXIT
  66. DWORD SendDSCStream::WaitForControl()
  67. {
  68. DWORD dwRet;
  69. HRESULT hr=E_FAIL;
  70. while (!(m_ThreadFlags & DPTFLAG_STOP_RECORD))
  71. {
  72. if (m_bFullDuplex == FALSE)
  73. {
  74. dwRet = WaitForSingleObject(g_hEventHalfDuplex, 1000);
  75. if (dwRet == WAIT_TIMEOUT)
  76. continue;
  77. }
  78. hr = CreateDSCBuffer();
  79. if (FAILED(hr))
  80. {
  81. m_nFailCount++;
  82. Sleep(2000); // wait and try again
  83. hr = CreateDSCBuffer();
  84. }
  85. if (SUCCEEDED(hr))
  86. {
  87. break;
  88. }
  89. m_nFailCount++;
  90. if ((m_nFailCount >= MAX_FAILCOUNT) && m_bCanSignalFail)
  91. {
  92. m_pDP->StreamEvent(MCF_SEND, MCF_AUDIO, STREAM_EVENT_DEVICE_FAILURE, 0);
  93. m_bCanSignalOpen = TRUE;
  94. m_bCanSignalFail = FALSE; // don't signal failure more than once
  95. m_bJammed = TRUE;
  96. }
  97. // if we can't open the device, even after being signaled
  98. // then yield some time to playback in hopes that it becomes available again
  99. // check the thread flags again such so that we don't
  100. // hold up the client for too long when he calls Stop()
  101. if (!(m_ThreadFlags & DPTFLAG_STOP_RECORD))
  102. {
  103. SetEvent(g_hEventHalfDuplex);
  104. Sleep(2000);
  105. }
  106. }
  107. if (m_ThreadFlags & DPTFLAG_STOP_RECORD)
  108. {
  109. return DSC_NEED_TO_EXIT;
  110. }
  111. m_bJammed = FALSE;
  112. m_nFailCount = 0;
  113. m_bCanSignalFail = TRUE;
  114. if (m_bCanSignalOpen)
  115. {
  116. m_pDP->StreamEvent(MCF_SEND, MCF_AUDIO, STREAM_EVENT_DEVICE_OPEN, 0);
  117. m_bCanSignalOpen = FALSE; // don't signal more than once per session
  118. }
  119. return DSC_SUCCESS;
  120. }
  121. // YieldControl is a thread function
  122. // It releases the DirectSound device
  123. // and signals the half duplex event
  124. DWORD SendDSCStream::YieldControl()
  125. {
  126. ReleaseDSCBuffer();
  127. SetEvent(g_hEventHalfDuplex);
  128. if (m_ThreadFlags & DPTFLAG_STOP_RECORD)
  129. {
  130. return DSC_NEED_TO_EXIT;
  131. }
  132. // half duplex yielding
  133. // playback has 100ms to grab device otherwise we take it back
  134. Sleep(100);
  135. return DSC_SUCCESS;
  136. }
  137. // ProcessFrame is a thread function
  138. // Given a position in the DirectSoundCapture buffer,
  139. // it will apply silence detection to the frame, and send it if
  140. // appropriate
  141. // returns DSC_FRAME_SENT or DSC_SILENCE_DETECT
  142. DWORD SendDSCStream::ProcessFrame(DWORD dwBufferPos, BOOL fMark)
  143. {
  144. HRESULT hr;
  145. DWORD dwSize1=0, dwSize2=0, dwMaxStrength;
  146. WORD wPeakStrength;
  147. VOID *pBuf1=NULL, *pBuf2=NULL;
  148. void *pPacketBuffer = NULL;
  149. UINT uSize, uLength;
  150. AudioPacket *pAP = m_aPackets[0];
  151. BOOL fSilent, bRet;
  152. pAP->GetDevData(&pPacketBuffer, &uSize);
  153. pAP->SetProp(MP_PROP_TIMESTAMP,m_SendTimestamp);
  154. pAP->m_fMark = fMark;
  155. ASSERT(uSize == m_dwFrameSize);
  156. // copy the frame out of the DSC buffer and into the packet object
  157. hr = m_pDSCBuffer->Lock(dwBufferPos, m_dwFrameSize, &pBuf1, &dwSize1, &pBuf2, &dwSize2, 0);
  158. if (SUCCEEDED(hr))
  159. {
  160. CopyMemory((BYTE*)pPacketBuffer, pBuf1, dwSize1);
  161. if (pBuf2 && dwSize2)
  162. {
  163. CopyMemory(((BYTE*)pPacketBuffer)+dwSize1, pBuf2, dwSize2);
  164. }
  165. m_pDSCBuffer->Unlock(pBuf1, dwSize2, pBuf2, dwSize2);
  166. pAP->SetState(MP_STATE_RECORDED);
  167. }
  168. else
  169. {
  170. DEBUGMSG (ZONE_DP, ("SendDSCStream::ProcessFrame - could not lock DSC buffer\r\n"));
  171. return DSC_ERROR;
  172. }
  173. if (m_mmioSrc.fPlayFromFile && m_mmioSrc.hmmioSrc)
  174. {
  175. AudioFile::ReadSourceFile(&m_mmioSrc, (BYTE*)pPacketBuffer, uSize);
  176. }
  177. // do silence detection
  178. pAP->ComputePower(&dwMaxStrength, &wPeakStrength);
  179. fSilent = m_AudioMonitor.SilenceDetect((WORD)dwMaxStrength);
  180. if (fSilent)
  181. {
  182. m_dwSilenceTime += m_dwFrameTimeMS;
  183. if (m_dwSilenceTime < SILENCE_TIMEOUT)
  184. {
  185. fSilent = FALSE;
  186. }
  187. }
  188. else
  189. {
  190. m_dwSilenceTime = 0;
  191. // only do automix on packets above the silence threshold
  192. if (m_bAutoMix)
  193. {
  194. m_agc.Update(wPeakStrength, m_dwFrameTimeMS);
  195. }
  196. }
  197. m_fSending = !(fSilent); // m_fSending indicates that we are transmitting
  198. if (fSilent)
  199. {
  200. // we don't send this packet, but we do cache it because
  201. // if the next one get's sent, we send this one too.
  202. ASSERT(pAP == m_aPackets[0]);
  203. // swap the audio packets
  204. // m_aPackets[1] always holds a cached packet
  205. pAP = m_aPackets[0];
  206. m_aPackets[0] = m_aPackets[1];
  207. m_aPackets[1] = pAP;
  208. pAP = m_aPackets[0];
  209. return DSC_SILENCE_DETECT;
  210. }
  211. // the packet is valid. send it, and maybe the one before it
  212. Send();
  213. return DSC_FRAME_SENT;
  214. }
  215. // this function is called by process frame (thread function)
  216. // sends the current packet, and maybe any packet prior to it.
  217. // returns the number of packets sent
  218. DWORD SendDSCStream::Send()
  219. {
  220. DWORD dwTimestamp0, dwTimestamp1;
  221. DWORD dwState0, dwState1;
  222. DWORD dwCount=0;
  223. MMRESULT mmr;
  224. HRESULT hr;
  225. // we know we have to send m_aPackets[0], and maybe m_aPackets[1]
  226. // we send m_aPackets[1] if it is actually the beginning of this talk spurt
  227. dwTimestamp0 = m_aPackets[0]->GetTimestamp();
  228. dwTimestamp1 = m_aPackets[1]->GetTimestamp();
  229. dwState0 = m_aPackets[0]->GetState();
  230. dwState1 = m_aPackets[1]->GetState();
  231. ASSERT(dwState0 == MP_STATE_RECORDED);
  232. if (dwState0 != MP_STATE_RECORDED)
  233. return 0;
  234. // evaluate if we need to send the prior packet
  235. if (dwState1 == MP_STATE_RECORDED)
  236. {
  237. if ((dwTimestamp1 + m_dwFrameTimeMS) == dwTimestamp0)
  238. {
  239. m_aPackets[1]->m_fMark = TRUE; // set the mark bit on the first packet
  240. m_aPackets[0]->m_fMark = FALSE; // reset the mark bit on the next packet
  241. hr = SendPacket(m_aPackets[1]);
  242. if (SUCCEEDED(hr))
  243. {
  244. dwCount++;
  245. }
  246. }
  247. else
  248. {
  249. m_aPackets[1]->SetState(MP_STATE_RESET);
  250. }
  251. }
  252. hr = SendPacket(m_aPackets[0]);
  253. if (SUCCEEDED(hr))
  254. dwCount++;
  255. return dwCount;
  256. }
  257. // thread function called by Send. Sends a packet to RTP.
  258. HRESULT SendDSCStream::SendPacket(AudioPacket *pAP)
  259. {
  260. MMRESULT mmr;
  261. PS_QUEUE_ELEMENT psq;
  262. UINT uLength;
  263. UINT uEncodeTime;
  264. uEncodeTime = timeGetTime();
  265. mmr = m_pAudioFilter->Convert(pAP, AP_ENCODE);
  266. uEncodeTime = timeGetTime() - uEncodeTime;
  267. if (mmr == MMSYSERR_NOERROR)
  268. {
  269. pAP->SetState(MP_STATE_ENCODED); // do we need to do this ?
  270. psq.pMP = pAP;
  271. psq.dwPacketType = PS_AUDIO;
  272. psq.pRTPSend = m_pRTPSend;
  273. pAP->GetNetData((void**)(&(psq.data)), &uLength);
  274. ASSERT(psq.data);
  275. psq.dwSize = uLength;
  276. psq.fMark = pAP->m_fMark;
  277. psq.pHeaderInfo = NULL;
  278. psq.dwHdrSize = 0;
  279. m_pDP->m_PacketSender.m_SendQueue.PushFront(psq);
  280. while (m_pDP->m_PacketSender.SendPacket())
  281. {
  282. ;
  283. }
  284. UpdateQosStats(DSC_QOS_PACKET_SENT, uEncodeTime, uLength+HEADER_SIZE);
  285. }
  286. pAP->SetState(MP_STATE_RESET);
  287. return S_OK;
  288. }
  289. DWORD SendDSCStream::RecordingThread()
  290. {
  291. HRESULT hr;
  292. DWORD dwWaitTime = DSC_TIMEOUT; // one sec
  293. DWORD dwRet, dwReadPos, dwCapPos;
  294. DWORD dwFirstValidFramePos, dwLastValidFramePos, dwNumFrames;
  295. DWORD dwLag, dwMaxLag, dwLagDiff;
  296. DWORD dwNextExpected, dwCurrentFramePos, dwIndex;
  297. BOOL bNeedToYield;
  298. BOOL fMark;
  299. IMediaChannel *pIMC = NULL;
  300. RecvMediaStream *pRecv = NULL;
  301. CMixerDevice *pMixer = NULL;
  302. // initialize recording thread
  303. m_SendTimestamp = timeGetTime();
  304. m_SavedTickCount = 0;
  305. m_fSending = TRUE;
  306. m_bJammed = FALSE;
  307. m_nFailCount = 0;
  308. m_bCanSignalOpen = TRUE;
  309. m_bCanSignalFail = TRUE;
  310. UpdateQosStats(DSC_QOS_INITIALIZE, 0, 0);
  311. SetThreadPriority(m_hCapturingThread, THREAD_PRIORITY_HIGHEST);
  312. // automix object
  313. pMixer = CMixerDevice::GetMixerForWaveDevice(NULL, m_CaptureDevice, MIXER_OBJECTF_WAVEIN);
  314. m_agc.SetMixer(pMixer); // if pMixer is NULL, then it's still ok
  315. m_agc.Reset();
  316. LOG((LOGMSG_DSC_STATS, m_dwDSCBufferSize, m_dwFrameSize));
  317. while (!(ThreadExitCheck()))
  318. {
  319. dwRet = WaitForControl();
  320. if (dwRet == DSC_NEED_TO_EXIT)
  321. {
  322. break;
  323. }
  324. hr = m_pDSCBuffer->Start(DSCBSTART_LOOPING);
  325. if (FAILED(hr))
  326. {
  327. // ERROR! We expected this call to succeed
  328. YieldControl();
  329. Sleep(1000);
  330. continue;
  331. }
  332. ResetEvent(m_hEvent);
  333. m_pDSCBuffer->GetCurrentPosition(&dwCapPos, &dwReadPos);
  334. // set the next expected position to be on the next logical
  335. // frame boundary up from where it is now
  336. dwNextExpected = QMOD(m_dwFrameSize + (dwReadPos / m_dwFrameSize) * m_dwFrameSize, m_dwDSCBufferSize);
  337. dwMaxLag = (m_dwNumFrames/2) * m_dwFrameSize;
  338. m_dwSilenceTime = 0;
  339. bNeedToYield = FALSE;
  340. fMark = TRUE;
  341. UpdateTimestamp();
  342. while( (bNeedToYield == FALSE) && (!(ThreadExitCheck())) )
  343. {
  344. dwRet = WaitForSingleObject(m_hEvent, dwWaitTime);
  345. LOG((LOGMSG_DSC_TIMESTAMP, timeGetTime()));
  346. m_pDSCBuffer->GetCurrentPosition(&dwCapPos, &dwReadPos);
  347. LOG((LOGMSG_DSC_GETCURRENTPOS, dwCapPos, dwReadPos));
  348. if (dwRet == WAIT_TIMEOUT)
  349. {
  350. DEBUGMSG(ZONE_DP, ("DSCThread.cpp: Timeout on the DSC Buffer has occurred.\r\n"));
  351. LOG((LOGMSG_DSC_LOG_TIMEOUT));
  352. dwNextExpected = QMOD(m_dwFrameSize + (dwReadPos / m_dwFrameSize) * m_dwFrameSize, m_dwDSCBufferSize);
  353. continue;
  354. }
  355. dwLag = QMOD(dwReadPos - dwNextExpected, m_dwDSCBufferSize);
  356. if (dwLag > dwMaxLag)
  357. {
  358. // we got here because of one of two conditions
  359. // 1. WaitFSO above returned earlier than expected.
  360. // This can happen when the previous interation of
  361. // the loop has sent multiple packets. The read cursor
  362. // is most likely only within one frame behind the expected
  363. // cursor.
  364. // In this cases, just keep Waiting for the current
  365. // read position to (dwReadPos) "catch up" to dwNextExpected
  366. // 2. A huge delay or something really bad. ("burp")
  367. // we could simply continue waiting for the read position
  368. // to catch up to dwNextExpected, but it's probably better
  369. // to reposition dwNextExpected so that we don't wait
  370. // too long before sending a frame again
  371. dwLagDiff = QMOD((dwLag + m_dwFrameSize), m_dwDSCBufferSize);
  372. if (dwLagDiff < m_dwFrameSize)
  373. {
  374. LOG((LOGMSG_DSC_EARLY));
  375. // only lagging behind by one frame
  376. // WaitFSO probably returned early
  377. ;
  378. }
  379. else
  380. {
  381. LOG((LOGMSG_DSC_LAGGING, dwLag, dwNextExpected));
  382. // consider repositioning dwNextExpected, advancing
  383. // m_SendTimeStamp, and setting fMark if this condition
  384. // happens a lot
  385. }
  386. continue;
  387. }
  388. dwFirstValidFramePos = QMOD(dwNextExpected - m_dwFrameSize, m_dwDSCBufferSize);
  389. dwLastValidFramePos = (dwReadPos / m_dwFrameSize) * m_dwFrameSize;
  390. dwNumFrames = QMOD(dwLastValidFramePos - dwFirstValidFramePos, m_dwDSCBufferSize) / m_dwFrameSize;
  391. dwCurrentFramePos = dwFirstValidFramePos;
  392. LOG((LOGMSG_DSC_SENDING, dwNumFrames, dwFirstValidFramePos, dwLastValidFramePos));
  393. for (dwIndex = 0; dwIndex < dwNumFrames; dwIndex++)
  394. {
  395. m_SendTimestamp += m_dwSamplesPerFrame; // increment in terms of samples
  396. // Send The data
  397. dwRet = ProcessFrame(dwCurrentFramePos, fMark);
  398. dwCurrentFramePos = QMOD(dwCurrentFramePos + m_dwFrameSize, m_dwDSCBufferSize);
  399. if (dwRet == DSC_FRAME_SENT)
  400. {
  401. fMark = FALSE;
  402. }
  403. else if ((dwRet == DSC_SILENCE_DETECT) && (m_bFullDuplex == FALSE))
  404. {
  405. m_pDP->GetMediaChannelInterface(MCF_RECV | MCF_AUDIO, &pIMC);
  406. fMark = TRUE;
  407. if (pIMC)
  408. {
  409. pRecv = static_cast<RecvMediaStream *> (pIMC);
  410. if (pRecv->IsEmpty() == FALSE)
  411. {
  412. bNeedToYield = TRUE;
  413. }
  414. pIMC->Release();
  415. pIMC = NULL;
  416. if (bNeedToYield)
  417. {
  418. break;
  419. }
  420. }
  421. }
  422. else
  423. {
  424. fMark = TRUE;
  425. }
  426. }
  427. dwNextExpected = QMOD(dwLastValidFramePos + m_dwFrameSize, m_dwDSCBufferSize);
  428. if (bNeedToYield)
  429. {
  430. YieldControl();
  431. m_SavedTickCount = timeGetTime();
  432. }
  433. } // while (!bNeedToYield)
  434. } // while (!ThreadExitCheck())
  435. // time to exit
  436. YieldControl();
  437. delete pMixer;
  438. return TRUE;
  439. }