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.

1156 lines
30 KiB

  1. #include "precomp.h"
  2. #include "mixer.h"
  3. #include "agc.h"
  4. // #define LOGSTATISTICS_ON 1
  5. DWORD SendAudioStream::RecordingThread ()
  6. {
  7. HRESULT hr = DPR_SUCCESS;
  8. MediaPacket *pPacket;
  9. DWORD dwWait;
  10. HANDLE hEvent;
  11. DWORD dwDuplexType;
  12. DWORD dwVoiceSwitch;
  13. DWORD_PTR dwPropVal;
  14. DWORD dwSamplesPerPkt;
  15. DWORD dwSamplesPerSec;
  16. DWORD dwSilenceLimit, dwMaxStrength, dwLengthMS;
  17. WORD wPeakStrength;
  18. UINT u, uBufferSize;
  19. UINT uSilenceCount = 0;
  20. UINT uPrefeed = 0;
  21. UINT uTimeout = 0;
  22. DevMediaQueue dq;
  23. BOOL fSilent;
  24. AGC agc(NULL); // audio gain control object
  25. CMixerDevice *pMixer = NULL;
  26. int nFailCount = 0;
  27. bool bCanSignalOpen=true; // should we signal that the device is open
  28. // note: pMC is an artifact of when this thread was in the Datapump
  29. // namespace. We can probably start phasing this variable out.
  30. // in the mean time: "pMC = this" will suffice
  31. // SendAudioStream *pMC = (SendAudioStream *)(m_pDP->m_Audio.pSendStream);
  32. SendAudioStream *pMC = this;
  33. ASSERT(pMC && (pMC->m_DPFlags & DPFLAG_INITIALIZED));
  34. TxStream *pStream = pMC->m_SendStream;
  35. AcmFilter *pAudioFilter = pMC->m_pAudioFilter;
  36. // warning: typecasting a base class ptr to a derived class ptr.
  37. WaveInControl *pMediaCtrl = (WaveInControl *)pMC->m_InMedia;
  38. FX_ENTRY ("DP::RcrdTh:")
  39. // get thread context
  40. if (pStream == NULL || pAudioFilter == NULL || pMediaCtrl == NULL)
  41. {
  42. return DPR_INVALID_PARAMETER;
  43. }
  44. // Enter critical section: QoS thread also reads the statistics
  45. EnterCriticalSection(&pMC->m_crsQos);
  46. // Initialize QoS structure
  47. ZeroMemory(&pMC->m_Stats, 4UL * sizeof(DWORD));
  48. // Initialize oldest QoS callback timestamp
  49. pMC->m_Stats.dwNewestTs = pMC->m_Stats.dwOldestTs = timeGetTime();
  50. // Leave critical section
  51. LeaveCriticalSection(&pMC->m_crsQos);
  52. pMediaCtrl->GetProp(MC_PROP_MEDIA_DEV_ID, &dwPropVal);
  53. if (dwPropVal != (DWORD)WAVE_MAPPER)
  54. {
  55. pMixer = CMixerDevice::GetMixerForWaveDevice(NULL, (DWORD)dwPropVal, MIXER_OBJECTF_WAVEIN);
  56. }
  57. // even if pMixer is null, this is fine, AGC will catch subsequent errors
  58. agc.SetMixer(pMixer);
  59. // get thresholds
  60. pMediaCtrl->GetProp (MC_PROP_TIMEOUT, &dwPropVal);
  61. uTimeout = (DWORD)dwPropVal;
  62. pMediaCtrl->GetProp (MC_PROP_PREFEED, &dwPropVal);
  63. uPrefeed = (DWORD)dwPropVal;
  64. // get duplex type
  65. pMediaCtrl->GetProp (MC_PROP_DUPLEX_TYPE, &dwPropVal);
  66. dwDuplexType = (DWORD)dwPropVal;
  67. // get Samples/Pkt and Samples/Sec
  68. pMediaCtrl->GetProp (MC_PROP_SPP, &dwPropVal);
  69. dwSamplesPerPkt = (DWORD)dwPropVal;
  70. pMediaCtrl->GetProp (MC_PROP_SPS, &dwPropVal);
  71. dwSamplesPerSec = (DWORD)dwPropVal;
  72. pMediaCtrl->GetProp (MC_PROP_SILENCE_DURATION, &dwPropVal);
  73. dwSilenceLimit = (DWORD)dwPropVal;
  74. // calculate silence limit in units of packets
  75. // silence_time_in_ms/packet_duration_in_ms
  76. dwSilenceLimit = dwSilenceLimit*dwSamplesPerSec/(dwSamplesPerPkt*1000);
  77. // length of a packet in millisecs
  78. dwLengthMS = (dwSamplesPerPkt * 1000) / dwSamplesPerSec;
  79. dq.SetSize (MAX_TXRING_SIZE);
  80. WaitForSignal:
  81. // DEBUGMSG (1, ("%s: WaitForSignal\r\n", _fx_));
  82. {
  83. pMediaCtrl->GetProp (MC_PROP_MEDIA_DEV_HANDLE, &dwPropVal);
  84. if (dwPropVal)
  85. {
  86. DEBUGMSG (ZONE_DP, ("%s: already open\r\n", _fx_));
  87. goto SendLoop; // sound device already open
  88. }
  89. // in the full-duplex case, open and prepare the device and charge ahead.
  90. // in the half duplex case wait for playback's signal before opening the device
  91. while (TRUE)
  92. {
  93. // should I stop now???
  94. if (pMC->m_ThreadFlags & DPTFLAG_STOP_RECORD)
  95. {
  96. DEBUGMSG (ZONE_DP, ("%s: STOP_1\r\n", _fx_));
  97. goto MyEndThread;
  98. }
  99. dwWait = (dwDuplexType & DP_FLAG_HALF_DUPLEX) ? WaitForSingleObject (g_hEventHalfDuplex, uTimeout)
  100. : WAIT_OBJECT_0;
  101. // now, let's check why I don't need to wait
  102. if (dwWait == WAIT_OBJECT_0)
  103. {
  104. //DEBUGMSG (ZONE_DP, ("%s: try to open audio dev\r\n", _fx_));
  105. LOG((LOGMSG_OPEN_AUDIO));
  106. hr = pMediaCtrl->Open ();
  107. if (hr != DPR_SUCCESS)
  108. {
  109. DEBUGMSG (ZONE_DP, ("%s: MediaCtrl::Open failed, hr=0x%lX\r\n", _fx_, hr));
  110. pMediaCtrl->SetProp(MC_PROP_AUDIO_JAMMED, TRUE);
  111. SetEvent(g_hEventHalfDuplex);
  112. nFailCount++;
  113. if (nFailCount == MAX_FAILCOUNT)
  114. {
  115. // three attempts to open the device have failed
  116. // signal to the UI that something is wrong
  117. m_pDP->StreamEvent(MCF_SEND, MCF_AUDIO, STREAM_EVENT_DEVICE_FAILURE, 0);
  118. bCanSignalOpen = true;
  119. }
  120. Sleep(2000); // Sleep for two seconds
  121. continue;
  122. }
  123. // Notification is not used. if needed do it thru Channel
  124. //pMC->m_Connection->DoNotification(CONNECTION_OPEN_MIC);
  125. pMediaCtrl->PrepareHeaders ();
  126. goto SendLoop;
  127. }
  128. } // while
  129. }
  130. SendLoop:
  131. nFailCount = 0;
  132. pMediaCtrl->SetProp(MC_PROP_AUDIO_JAMMED, FALSE);
  133. if (bCanSignalOpen)
  134. {
  135. m_pDP->StreamEvent(MCF_SEND, MCF_AUDIO, STREAM_EVENT_DEVICE_OPEN, 0);
  136. bCanSignalOpen = false; // don't signal more than once per session
  137. }
  138. // DEBUGMSG (1, ("%s: SendLoop\r\n", _fx_));
  139. // get event handle
  140. pMediaCtrl->GetProp (MC_PROP_EVENT_HANDLE, &dwPropVal);
  141. hEvent = (HANDLE) dwPropVal;
  142. if (hEvent == NULL)
  143. {
  144. DEBUGMSG (ZONE_DP, ("%s: invalid event\r\n", _fx_));
  145. return DPR_CANT_CREATE_EVENT;
  146. }
  147. // hey, in the very beginning, let's 'Start' it
  148. hr = pMediaCtrl->Start ();
  149. if (hr != DPR_SUCCESS)
  150. {
  151. DEBUGMSG (ZONE_DP, ("%s: MediaControl::Start failed, hr=0x%lX\r\n", _fx_, hr));
  152. goto MyEndThread;
  153. }
  154. // update timestamp to account for the 'sleep' period
  155. pMC->m_SendTimestamp += (GetTickCount() - pMC->m_SavedTickCount)*dwSamplesPerSec/1000;
  156. // let's feed four buffers first
  157. for (u = 0; u < uPrefeed; u++)
  158. {
  159. if ((pPacket = pStream->GetFree ()) != NULL)
  160. {
  161. if ((hr = pPacket->Record ()) != DPR_SUCCESS)
  162. {
  163. DEBUGMSG (ZONE_DP, ("%s: Record failed, hr=0x%lX\r\n", _fx_, hr));
  164. }
  165. dq.Put (pPacket);
  166. }
  167. }
  168. // let's get into the loop, mm system notification loop
  169. pMC->m_fSending= FALSE;
  170. while (TRUE)
  171. {
  172. dwWait = WaitForSingleObject (hEvent, uTimeout);
  173. // should I stop now???
  174. if (pMC->m_ThreadFlags & DPTFLAG_STOP_RECORD)
  175. {
  176. DEBUGMSG (ZONE_DP, ("%s: STOP_3\r\n", _fx_));
  177. goto HalfDuplexYield;
  178. }
  179. // get current voice switching mode
  180. pMediaCtrl->GetProp (MC_PROP_VOICE_SWITCH, &dwPropVal);
  181. dwVoiceSwitch = (DWORD)dwPropVal;
  182. // see why I don't need to wait
  183. if (dwWait != WAIT_TIMEOUT)
  184. {
  185. while (TRUE)
  186. {
  187. if ((pPacket = dq.Peek ()) != NULL)
  188. {
  189. if (! pPacket->IsBufferDone ())
  190. {
  191. break;
  192. }
  193. else
  194. {
  195. if (pMC->m_mmioSrc.fPlayFromFile && pMC->m_mmioSrc.hmmioSrc)
  196. pPacket->ReadFromFile (&pMC->m_mmioSrc);
  197. u--; // one less buffer with the wave device
  198. }
  199. }
  200. else
  201. {
  202. DEBUGMSG (ZONE_VERBOSE, ("%s: Peek is NULL\r\n", _fx_));
  203. break;
  204. }
  205. pPacket = dq.Get ();
  206. ((AudioPacket*)pPacket)->ComputePower (&dwMaxStrength, &wPeakStrength);
  207. // is this packet silent?
  208. fSilent = pMC->m_AudioMonitor.SilenceDetect((WORD)dwMaxStrength);
  209. if((dwVoiceSwitch == DP_FLAG_AUTO_SWITCH)
  210. && fSilent)
  211. {
  212. // pPacket->SetState (MP_STATE_RESET); // note: done in Recycle
  213. if (++uSilenceCount >= dwSilenceLimit)
  214. {
  215. pMC->m_fSending = FALSE; // stop sending packets
  216. // if half duplex mode and playback thread may be waiting
  217. if (dwDuplexType & DP_FLAG_HALF_DUPLEX)
  218. {
  219. IMediaChannel *pIMC = NULL;
  220. RecvMediaStream *pRecv;
  221. m_pDP->GetMediaChannelInterface(MCF_RECV | MCF_AUDIO, &pIMC);
  222. if (pIMC)
  223. {
  224. pRecv = static_cast<RecvMediaStream *> (pIMC);
  225. if (pRecv->IsEmpty()==FALSE)
  226. {
  227. //DEBUGMSG (ZONE_DP, ("%s: too many silence and Yield\r\n", _fx_));
  228. LOG((LOGMSG_REC_YIELD));
  229. pPacket->Recycle ();
  230. pStream->PutNextRecorded (pPacket);
  231. uSilenceCount = 0;
  232. pIMC->Release();
  233. goto HalfDuplexYield;
  234. }
  235. pIMC->Release();
  236. }
  237. }
  238. }
  239. }
  240. else
  241. {
  242. switch(dwVoiceSwitch)
  243. {
  244. // either there was NO silence, or manual switching is in effect
  245. default:
  246. case DP_FLAG_AUTO_SWITCH: // this proves no silence (in this path because of non-silence)
  247. case DP_FLAG_MIC_ON:
  248. pMC->m_fSending = TRUE;
  249. uSilenceCount = 0;
  250. break;
  251. case DP_FLAG_MIC_OFF:
  252. pMC->m_fSending = FALSE;
  253. break;
  254. }
  255. }
  256. if (pMC->m_fSending)
  257. {
  258. pPacket->SetState (MP_STATE_RECORDED);
  259. // do AUTOMIX, but ignore DTMF tones
  260. if (pMC->m_bAutoMix)
  261. {
  262. agc.Update(wPeakStrength, dwLengthMS);
  263. }
  264. }
  265. else
  266. {
  267. pPacket->Recycle();
  268. // Enter critical section: QoS thread also reads the statistics
  269. EnterCriticalSection(&pMC->m_crsQos);
  270. // Update total number of packets recorded
  271. pMC->m_Stats.dwCount++;
  272. // Leave critical section
  273. LeaveCriticalSection(&pMC->m_crsQos);
  274. }
  275. pPacket->SetProp(MP_PROP_TIMESTAMP,pMC->m_SendTimestamp);
  276. // pPacket->SetProp(MP_PROP_TIMESTAMP,GetTickCount());
  277. pMC->m_SendTimestamp += dwSamplesPerPkt;
  278. pStream->PutNextRecorded (pPacket);
  279. } // while
  280. }
  281. else
  282. {
  283. if (dwDuplexType & DP_FLAG_HALF_DUPLEX)
  284. {
  285. DEBUGMSG (ZONE_DP, ("%s: Timeout and Yield\r\n", _fx_));
  286. goto HalfDuplexYield;
  287. }
  288. } // if
  289. pMC->Send();
  290. // Make sure the recorder has an adequate number of buffers
  291. while ((pPacket = pStream->GetFree()) != NULL)
  292. {
  293. if ((hr = pPacket->Record ()) == DPR_SUCCESS)
  294. {
  295. dq.Put (pPacket);
  296. }
  297. else
  298. {
  299. dq.Put (pPacket);
  300. DEBUGMSG (ZONE_DP, ("%s: Record FAILED, hr=0x%lX\r\n", _fx_, hr));
  301. break;
  302. }
  303. u++;
  304. }
  305. if (u < uPrefeed)
  306. {
  307. DEBUGMSG (ZONE_DP, ("%s: NO FREE BUFFERS\r\n", _fx_));
  308. }
  309. } // while TRUE
  310. goto MyEndThread;
  311. HalfDuplexYield:
  312. // stop and reset audio device
  313. pMediaCtrl->Reset ();
  314. // flush dq
  315. while ((pPacket = dq.Get ()) != NULL)
  316. {
  317. pStream->PutNextRecorded (pPacket);
  318. pPacket->Recycle ();
  319. }
  320. // save real time so we can update the timestamp when we restart
  321. pMC->m_SavedTickCount = GetTickCount();
  322. // reset the event
  323. ResetEvent (hEvent);
  324. // close audio device
  325. pMediaCtrl->UnprepareHeaders ();
  326. pMediaCtrl->Close ();
  327. // signal playback thread to start
  328. SetEvent (g_hEventHalfDuplex);
  329. if (!(pMC->m_ThreadFlags & DPTFLAG_STOP_RECORD)) {
  330. // yield
  331. // playback has to claim the device within 100ms or we take it back.
  332. Sleep (100);
  333. // wait for playback's signal
  334. goto WaitForSignal;
  335. }
  336. MyEndThread:
  337. if (pMixer)
  338. delete pMixer;
  339. pMediaCtrl->SetProp(MC_PROP_AUDIO_JAMMED, FALSE);
  340. pMC->m_fSending = FALSE;
  341. DEBUGMSG (ZONE_DP, ("%s: Exiting.\r\n", _fx_));
  342. return hr;
  343. }
  344. DWORD RecvAudioStream::PlaybackThread ( void)
  345. {
  346. HRESULT hr = DPR_SUCCESS;
  347. MediaPacket * pPacket;
  348. MediaPacket * pPrevPacket;
  349. MediaPacket * pNextPacket;
  350. DWORD dwWait;
  351. HANDLE hEvent;
  352. DWORD dwDuplexType;
  353. DWORD_PTR dwPropVal;
  354. UINT u;
  355. UINT uMissingCount = 0;
  356. UINT uPrefeed = 0;
  357. UINT uTimeout = 0;
  358. UINT uSamplesPerPkt=0;
  359. DevMediaQueue dq;
  360. UINT uGoodPacketsQueued = 0;
  361. int nFailCount = 0;
  362. bool bCanSignalOpen=true;
  363. //warning: casting from base to dervied class
  364. // note: pMC is an artifact of when this thread was in the Datapump
  365. // namespace. We can probably start phasing this variable out.
  366. // in the mean time: "pMC = this" will suffice
  367. // RecvAudioStream *pMC = (RecvAudioStream *)(m_pDP->m_Audio.pRecvStream);
  368. RecvAudioStream *pMC = this;
  369. RxStream *pStream = pMC->m_RecvStream;
  370. MediaControl *pMediaCtrl = pMC->m_OutMedia;
  371. #if 0
  372. NETBUF * pStaticNetBuf;
  373. #endif
  374. FX_ENTRY ("DP::PlayTh")
  375. if (pStream == NULL || m_pAudioFilter == NULL || pMediaCtrl == NULL)
  376. {
  377. return DPR_INVALID_PARAMETER;
  378. }
  379. // get event handle
  380. pMediaCtrl->GetProp (MC_PROP_EVENT_HANDLE, &dwPropVal);
  381. hEvent = (HANDLE) dwPropVal;
  382. if (hEvent == NULL)
  383. {
  384. DEBUGMSG (ZONE_DP, ("%s: invalid event\r\n", _fx_));
  385. return DPR_CANT_CREATE_EVENT;
  386. }
  387. // get thresholds
  388. pMediaCtrl->GetProp (MC_PROP_TIMEOUT, &dwPropVal);
  389. uTimeout = (DWORD)dwPropVal;
  390. uPrefeed = pStream->BufferDelay();
  391. // get samples per pkt
  392. pMediaCtrl->GetProp(MC_PROP_SPP, &dwPropVal);
  393. uSamplesPerPkt = (DWORD)dwPropVal;
  394. // get duplex type
  395. pMediaCtrl->GetProp (MC_PROP_DUPLEX_TYPE, &dwPropVal);
  396. dwDuplexType = (DWORD)dwPropVal;
  397. // set dq size
  398. dq.SetSize (uPrefeed);
  399. WaitForSignal:
  400. // DEBUGMSG (1, ("%s: WaitForSignal\r\n", _fx_));
  401. pMediaCtrl->GetProp (MC_PROP_MEDIA_DEV_HANDLE, &dwPropVal);
  402. if (dwPropVal)
  403. {
  404. DEBUGMSG (ZONE_DP, ("%s: already open\r\n", _fx_));
  405. goto RecvLoop; // already open
  406. }
  407. // in the full-duplex case, open and prepare the device and charge ahead.
  408. // in the half duplex case wait for playback's signal before opening the device
  409. while (TRUE)
  410. {
  411. // should I stop now???
  412. if (pMC->m_ThreadFlags & DPTFLAG_STOP_PLAY)
  413. {
  414. DEBUGMSG (ZONE_VERBOSE, ("%s: STOP_1\r\n", _fx_));
  415. goto MyEndThread;
  416. }
  417. dwWait = (dwDuplexType & DP_FLAG_HALF_DUPLEX) ? WaitForSingleObject (g_hEventHalfDuplex, uTimeout)
  418. : WAIT_OBJECT_0;
  419. // to see why I don't need to wait
  420. if (dwWait == WAIT_OBJECT_0)
  421. {
  422. // DEBUGMSG (1, ("%s: try to open audio dev\r\n", _fx_));
  423. pStream->FastForward(FALSE); // GJ - flush receive queue
  424. hr = pMediaCtrl->Open ();
  425. if (hr != DPR_SUCCESS)
  426. {
  427. // somebody may have commandeered the wave out device
  428. // this could be a temporary problem so lets give it some time
  429. DEBUGMSG (ZONE_DP, ("%s: MediaControl::Open failed, hr=0x%lX\r\n", _fx_, hr));
  430. pMediaCtrl->SetProp(MC_PROP_AUDIO_JAMMED, TRUE);
  431. SetEvent(g_hEventHalfDuplex);
  432. nFailCount++;
  433. if (nFailCount == MAX_FAILCOUNT)
  434. {
  435. // three attempts to open the device have failed
  436. // signal to the UI that something is wrong
  437. m_pDP->StreamEvent(MCF_RECV, MCF_AUDIO, STREAM_EVENT_DEVICE_FAILURE, 0);
  438. bCanSignalOpen = true;
  439. }
  440. Sleep(2000); // sleep for two seconds
  441. continue;
  442. }
  443. // Notification is not used. if needed do it thru Channel
  444. //pMC->m_Connection->DoNotification(CONNECTION_OPEN_SPK);
  445. pMediaCtrl->PrepareHeaders ();
  446. goto RecvLoop;
  447. }
  448. } // while
  449. RecvLoop:
  450. nFailCount = 0;
  451. pMediaCtrl->SetProp(MC_PROP_AUDIO_JAMMED, FALSE);
  452. if (bCanSignalOpen)
  453. {
  454. m_pDP->StreamEvent(MCF_RECV, MCF_AUDIO, STREAM_EVENT_DEVICE_OPEN, 0);
  455. bCanSignalOpen = false; // don't signal open more than once per session
  456. }
  457. // Set my thread priority high
  458. // This thread doesnt do any compute intensive work (except maybe
  459. // interpolate?).
  460. // Its sole purpose is to stream ready buffers to the sound device
  461. SetThreadPriority(pMC->m_hRenderingThread, THREAD_PRIORITY_HIGHEST);
  462. // DEBUGMSG (1, ("%s: SendLoop\r\n", _fx_));
  463. // let's feed four buffers first
  464. // But make sure the receive stream has enough buffering delay
  465. // so we dont read past the last packet.
  466. //if (uPrefeed > pStream->BufferDelay())
  467. uGoodPacketsQueued = 0;
  468. for (u = 0; u < uPrefeed; u++)
  469. {
  470. if ((pPacket = pStream->GetNextPlay ()) != NULL)
  471. {
  472. if (pPacket->GetState () == MP_STATE_RESET)
  473. {
  474. // hr = pPacket->Play (pStaticNetBuf);
  475. hr = pPacket->Play (&pMC->m_mmioDest, MP_DATATYPE_SILENCE);
  476. }
  477. else
  478. {
  479. // hr = pPacket->Play ();
  480. hr = pPacket->Play (&pMC->m_mmioDest, MP_DATATYPE_FROMWIRE);
  481. uGoodPacketsQueued++;
  482. }
  483. if (hr != DPR_SUCCESS)
  484. {
  485. DEBUGMSG (ZONE_DP, ("%s: Play failed, hr=0x%lX\r\n", _fx_, hr));
  486. SetEvent(hEvent);
  487. }
  488. dq.Put (pPacket);
  489. }
  490. }
  491. pMC->m_fReceiving = TRUE;
  492. // let's get into the loop
  493. uMissingCount = 0;
  494. while (TRUE)
  495. {
  496. dwWait = WaitForSingleObject (hEvent, uTimeout);
  497. // should I stop now???
  498. if (pMC->m_ThreadFlags & DPTFLAG_STOP_PLAY)
  499. {
  500. DEBUGMSG (ZONE_VERBOSE, ("%s: STOP_3\r\n", _fx_));
  501. goto HalfDuplexYield;
  502. }
  503. // see why I don't need to wait
  504. if (dwWait != WAIT_TIMEOUT)
  505. {
  506. while (TRUE)
  507. {
  508. if ((pPacket = dq.Peek ()) != NULL)
  509. {
  510. if (! pPacket->IsBufferDone ())
  511. {
  512. break;
  513. }
  514. }
  515. else
  516. {
  517. DEBUGMSG (ZONE_VERBOSE, ("%s: Peek is NULL\r\n", _fx_));
  518. break;
  519. }
  520. pPacket = dq.Get ();
  521. if (pPacket->GetState() != MP_STATE_PLAYING_SILENCE)
  522. uGoodPacketsQueued--; // a non-empty buffer just got done
  523. pMC->m_PlaybackTimestamp = pPacket->GetTimestamp() + uSamplesPerPkt;
  524. pPacket->Recycle ();
  525. pStream->Release (pPacket);
  526. if ((pPacket = pStream->GetNextPlay ()) != NULL)
  527. {
  528. // check if we are in half-duplex mode and also if
  529. // the recording thread is around.
  530. if (dwDuplexType & DP_FLAG_HALF_DUPLEX)
  531. {
  532. IMediaChannel *pIMC = NULL;
  533. BOOL fSending = FALSE;
  534. m_pDP->GetMediaChannelInterface(MCF_SEND | MCF_AUDIO, &pIMC);
  535. if (pIMC)
  536. {
  537. fSending = (pIMC->GetState() == MSSTATE_STARTED);
  538. pIMC->Release();
  539. }
  540. if (fSending) {
  541. if (pPacket->GetState () == MP_STATE_RESET)
  542. {
  543. // Decide if its time to yield
  544. // Dont want to yield until we've finished playing all data packets
  545. //
  546. if (!uGoodPacketsQueued &&
  547. (pStream->IsEmpty() || ++uMissingCount >= DEF_MISSING_LIMIT))
  548. {
  549. //DEBUGMSG (ZONE_DP, ("%s: too many missings and Yield\r\n", _fx_));
  550. LOG( (LOGMSG_PLAY_YIELD));
  551. pPacket->Recycle ();
  552. pStream->Release (pPacket);
  553. goto HalfDuplexYield;
  554. }
  555. }
  556. else
  557. {
  558. uMissingCount = 0;
  559. }
  560. }
  561. }
  562. if (pPacket->GetState () == MP_STATE_RESET)
  563. {
  564. pPrevPacket = pStream->PeekPrevPlay ();
  565. pNextPacket = pStream->PeekNextPlay ();
  566. hr = pPacket->Interpolate(pPrevPacket, pNextPacket);
  567. if (hr != DPR_SUCCESS)
  568. {
  569. //DEBUGMSG (ZONE_DP, ("%s: Interpolate failed, hr=0x%lX\r\n", _fx_, hr));
  570. hr = pPacket->Play (&pMC->m_mmioDest, MP_DATATYPE_SILENCE);
  571. }
  572. else
  573. hr = pPacket->Play (&pMC->m_mmioDest, MP_DATATYPE_INTERPOLATED);
  574. }
  575. else
  576. {
  577. // hr = pPacket->Play ();
  578. hr = pPacket->Play (&pMC->m_mmioDest, MP_DATATYPE_FROMWIRE);
  579. uGoodPacketsQueued++;
  580. }
  581. if (hr != DPR_SUCCESS)
  582. {
  583. DEBUGMSG (ZONE_DP, ("%s: Play failed, hr=0x%lX\r\n", _fx_, hr));
  584. SetEvent(hEvent);
  585. }
  586. dq.Put (pPacket);
  587. } else {
  588. DEBUGMSG( ZONE_DP, ("%s: NO PLAY BUFFERS!",_fx_));
  589. }
  590. } // while
  591. }
  592. else
  593. {
  594. if (dwDuplexType & DP_FLAG_HALF_DUPLEX)
  595. {
  596. DEBUGMSG (ZONE_DP, ("%s: Timeout and Yield!\r\n", _fx_));
  597. goto HalfDuplexYield;
  598. }
  599. }
  600. } // while TRUE
  601. goto MyEndThread;
  602. HalfDuplexYield:
  603. pMC->m_fReceiving = FALSE;
  604. // stop and reset audio device
  605. pMediaCtrl->Reset ();
  606. // flush dq
  607. while ((pPacket = dq.Get ()) != NULL)
  608. {
  609. pPacket->Recycle ();
  610. pStream->Release (pPacket);
  611. }
  612. // reset the event
  613. ResetEvent (hEvent);
  614. // close audio device
  615. pMediaCtrl->UnprepareHeaders ();
  616. pMediaCtrl->Close ();
  617. // signal recording thread to start
  618. SetEvent (g_hEventHalfDuplex);
  619. if (!(pMC->m_ThreadFlags & DPTFLAG_STOP_PLAY)) {
  620. // yield
  621. Sleep (0);
  622. // wait for recording's signal
  623. // restore thread priority
  624. SetThreadPriority(pMC->m_hRenderingThread,THREAD_PRIORITY_NORMAL);
  625. goto WaitForSignal;
  626. }
  627. MyEndThread:
  628. pMediaCtrl->SetProp(MC_PROP_AUDIO_JAMMED, FALSE);
  629. DEBUGMSG(ZONE_DP, ("%s: Exiting.\n", _fx_));
  630. return hr;
  631. }
  632. DWORD SendAudioStream::Send()
  633. {
  634. MMRESULT mmr;
  635. MediaPacket *pAP;
  636. void *pBuffer;
  637. DWORD dwBeforeEncode;
  638. DWORD dwAfterEncode;
  639. DWORD dwPacketSize;
  640. UINT uBytesSent;
  641. #ifdef LOGSTATISTICS_ON
  642. char szDebug[256];
  643. DWORD dwDebugSaveBits;
  644. #endif
  645. while ( pAP = m_SendStream->GetNext()) {
  646. if (!(m_ThreadFlags & DPTFLAG_PAUSE_SEND)) {
  647. dwBeforeEncode = timeGetTime();
  648. mmr = m_pAudioFilter->Convert((AudioPacket*)pAP, AP_ENCODE);
  649. if (mmr == MMSYSERR_NOERROR)
  650. {
  651. pAP->SetState(MP_STATE_ENCODED);
  652. }
  653. // Time the encoding operation
  654. dwAfterEncode = timeGetTime() - dwBeforeEncode;
  655. if (mmr == MMSYSERR_NOERROR)
  656. {
  657. SendPacket((AudioPacket*)pAP, &uBytesSent);
  658. }
  659. else
  660. {
  661. uBytesSent = 0;
  662. }
  663. UPDATE_COUNTER(g_pctrAudioSendBytes, uBytesSent*8);
  664. // Enter critical section: QoS thread also reads the statistics
  665. EnterCriticalSection(&m_crsQos);
  666. // Update total number of packets recorded
  667. m_Stats.dwCount++;
  668. // Save the perfs in our stats structure for QoS
  669. #ifdef LOGSTATISTICS_ON
  670. dwDebugSaveBits = m_Stats.dwBits;
  671. #endif
  672. // Add this new frame size to the cumulated size
  673. m_Stats.dwBits += (uBytesSent * 8);
  674. // Add this compression time to total compression time
  675. m_Stats.dwMsComp += dwAfterEncode;
  676. #ifdef LOGSTATISTICS_ON
  677. wsprintf(szDebug, " A: (Voiced) dwBits = %ld up from %ld (file: %s line: %ld)\r\n", m_Stats.dwBits, dwDebugSaveBits, __FILE__, __LINE__);
  678. OutputDebugString(szDebug);
  679. #endif
  680. // Leave critical section
  681. LeaveCriticalSection(&m_crsQos);
  682. }
  683. // whether or not we sent the packet, we need to return
  684. // it to the free queue
  685. pAP->m_fMark=0;
  686. pAP->SetState(MP_STATE_RESET);
  687. m_SendStream->Release(pAP);
  688. }
  689. return DPR_SUCCESS;
  690. }
  691. // queues and sends the packet
  692. // if the packet failed the encode process, it doesn't get sent
  693. HRESULT SendAudioStream::SendPacket(AudioPacket *pAP, UINT *puBytesSent)
  694. {
  695. PS_QUEUE_ELEMENT psq;
  696. UINT uLength;
  697. int nPacketsSent=0;
  698. if (pAP->GetState() != MP_STATE_ENCODED)
  699. {
  700. DEBUGMSG (ZONE_ACM, ("SendAudioStream::SendPacket: Packet not compressed\r\n"));
  701. *puBytesSent = 0;
  702. return E_FAIL;
  703. }
  704. ASSERT(m_pRTPSend);
  705. psq.pMP = pAP;
  706. psq.dwPacketType = PS_AUDIO;
  707. psq.pRTPSend = m_pRTPSend;
  708. pAP->GetNetData((void**)(&(psq.data)), &uLength);
  709. ASSERT(psq.data);
  710. psq.dwSize = uLength;
  711. psq.fMark = pAP->m_fMark;
  712. psq.pHeaderInfo = NULL;
  713. psq.dwHdrSize = 0;
  714. *puBytesSent = uLength + sizeof(RTP_HDR) + IP_HEADER_SIZE + UDP_HEADER_SIZE;
  715. // add audio packets to the front of the queue
  716. m_pDP->m_PacketSender.m_SendQueue.PushFront(psq);
  717. while (m_pDP->m_PacketSender.SendPacket())
  718. {
  719. ;
  720. }
  721. return S_OK;
  722. };
  723. #ifdef OLDSTUFF
  724. /*
  725. // Winsock 1 receive thread
  726. // Creates a hidden window and a message loop to process WINSOCK window
  727. // messages. Also processes private messages from the datapump to start/stop
  728. // receiving on a particular media stream
  729. */
  730. DWORD
  731. DataPump::CommonRecvThread (void )
  732. {
  733. HRESULT hr;
  734. HWND hWnd = (HWND)NULL;
  735. RecvMediaStream *pRecvMC;
  736. BOOL fChange = FALSE;
  737. MSG msg;
  738. DWORD curTime, nextUpdateTime = 0, t;
  739. UINT timerId = 0;
  740. FX_ENTRY ("DP::RecvTh")
  741. // Create hidden window
  742. hWnd =
  743. CreateWindowEx(
  744. WS_EX_NOPARENTNOTIFY,
  745. "SockMgrWClass", /* See RegisterClass() call. */
  746. NULL,
  747. WS_CHILD , /* Window style. */
  748. CW_USEDEFAULT,
  749. CW_USEDEFAULT,
  750. CW_USEDEFAULT,
  751. CW_USEDEFAULT,
  752. m_hAppWnd, /* the application window is the parent. */
  753. (HMENU)this, /* hardcoded ID */
  754. m_hAppInst, /* the application owns this window. */
  755. NULL /* Pointer not needed. */
  756. );
  757. if(!hWnd)
  758. {
  759. hr = GetLastError();
  760. DEBUGMSG(ZONE_DP,("CreateWindow returned %d\n",hr));
  761. goto CLEANUPEXIT;
  762. }
  763. SetThreadPriority(m_hRecvThread, THREAD_PRIORITY_ABOVE_NORMAL);
  764. // This function is guaranteed to create a queue on this thread
  765. PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  766. // notify thread creator that we're ready to recv messages
  767. SetEvent(m_hRecvThreadAckEvent);
  768. // Wait for control messages from Start()/Stop() or Winsock messages directed to
  769. // our hidden window
  770. while (GetMessage(&msg, NULL, 0, 0)) {
  771. switch(msg.message) {
  772. case MSG_START_RECV:
  773. // Start receiving on the specified media stream
  774. DEBUGMSG(ZONE_VERBOSE,("%s: MSG_START_RECV\n",_fx_));
  775. pRecvMC = (RecvMediaStream *)msg.lParam;
  776. // call the stream to post recv buffers and
  777. // tell Winsock to start sending socket msgs to our window
  778. pRecvMC->StartRecv(hWnd);
  779. fChange = TRUE;
  780. break;
  781. case MSG_STOP_RECV:
  782. // Stop receiving on the specified media stream
  783. DEBUGMSG(ZONE_VERBOSE,("%s: MSG_STOP_RECV\n",_fx_));
  784. pRecvMC = (RecvMediaStream *)msg.lParam;
  785. // call the stream to cancel outstanding recvs etc.
  786. // currently we assume this can be done synchronously
  787. pRecvMC->StopRecv();
  788. fChange = TRUE;
  789. break;
  790. case MSG_EXIT_RECV:
  791. // Exit the recv thread.
  792. // Assume that we are not currently receving on any stream.
  793. DEBUGMSG(ZONE_VERBOSE,("%s: MSG_EXIT_RECV\n",_fx_));
  794. fChange = TRUE;
  795. if (DestroyWindow(hWnd)) {
  796. break;
  797. }
  798. DEBUGMSG(ZONE_DP,("DestroyWindow returned %d\n",GetLastError()));
  799. // fall thru to PostQuitMessage()
  800. case WM_DESTROY:
  801. PostQuitMessage(0);
  802. break;
  803. case WM_TIMER:
  804. if (msg.hwnd == NULL) {
  805. // this timer is for the benefit of ThreadTimer::UpdateTime()
  806. // however, we are calling UpdateTime after every message (see below)
  807. // so we dont do anything special here.
  808. break;
  809. }
  810. default:
  811. TranslateMessage(&msg);
  812. DispatchMessage(&msg);
  813. }
  814. if (fChange) {
  815. // the thread MSGs need to be acked
  816. SetEvent(m_hRecvThreadAckEvent);
  817. fChange = FALSE;
  818. }
  819. t = m_RecvTimer.UpdateTime(curTime=GetTickCount());
  820. if (t != nextUpdateTime) {
  821. // Thread timer wants to change its update time
  822. nextUpdateTime = t;
  823. if (timerId) {
  824. KillTimer(NULL,timerId);
  825. timerId = 0;
  826. }
  827. // if nextTime is zero, there are no scheduled timeouts so we dont need to call UpdateTime
  828. if (nextUpdateTime)
  829. timerId = SetTimer(NULL, 0, nextUpdateTime - curTime + 50, NULL);
  830. }
  831. }
  832. CLEANUPEXIT:
  833. DEBUGMSG(ZONE_DP,("%s terminating.\n", _fx_));
  834. return hr;
  835. }
  836. #endif
  837. /*
  838. Winsock 2 receive thread. Main differnce here is that it has a WaitEx loop
  839. where we wait for Start/Stop commands from the datapump while allowing
  840. WS2 APCs to be handled.
  841. Note: Only way to use the same thread routine for WS1 and WS2 is with
  842. MsgWaitForMultipleObjectsEx, which unfortunately is not implemented in Win95
  843. */
  844. DWORD
  845. DataPump::CommonWS2RecvThread (void )
  846. {
  847. HRESULT hr;
  848. RecvMediaStream *pRecvMC;
  849. BOOL fChange = FALSE, fExit = FALSE;
  850. DWORD dwWaitStatus;
  851. DWORD curTime, t;
  852. FX_ENTRY ("DP::WS2RecvTh")
  853. SetThreadPriority(m_hRecvThread, THREAD_PRIORITY_ABOVE_NORMAL);
  854. // notify thread creator that we're ready to recv messages
  855. SetEvent(m_hRecvThreadAckEvent);
  856. while (!fExit) {
  857. // Wait for control messages from Start()/Stop() or Winsock async
  858. // thread callbacks
  859. // dispatch expired timeouts and check how long we need to wait
  860. t = m_RecvTimer.UpdateTime(curTime=GetTickCount());
  861. t = (t ? t-curTime+50 : INFINITE);
  862. dwWaitStatus = WaitForSingleObjectEx(m_hRecvThreadSignalEvent,t,TRUE);
  863. if (dwWaitStatus == WAIT_OBJECT_0) {
  864. switch(m_CurRecvMsg) {
  865. case MSG_START_RECV:
  866. // Start receiving on the specified media stream
  867. DEBUGMSG(ZONE_VERBOSE,("%s: MSG_START_RECV\n",_fx_));
  868. pRecvMC = m_pCurRecvStream;
  869. // call the stream to post recv buffers and
  870. // tell Winsock to start sending socket msgs to our window
  871. pRecvMC->StartRecv(NULL);
  872. fChange = TRUE;
  873. break;
  874. case MSG_STOP_RECV:
  875. // Stop receiving on the specified media stream
  876. DEBUGMSG(ZONE_VERBOSE,("%s: MSG_STOP_RECV\n",_fx_));
  877. pRecvMC = m_pCurRecvStream;
  878. // call the stream to cancel outstanding recvs etc.
  879. // currently we assume this can be done synchronously
  880. pRecvMC->StopRecv();
  881. fChange = TRUE;
  882. break;
  883. case MSG_EXIT_RECV:
  884. // Exit the recv thread.
  885. // Assume that we are not currently receving on any stream.
  886. DEBUGMSG(ZONE_VERBOSE,("%s: MSG_EXIT_RECV\n",_fx_));
  887. fChange = TRUE;
  888. fExit = TRUE;
  889. break;
  890. case MSG_PLAY_SOUND:
  891. fChange = TRUE;
  892. pRecvMC->OnDTMFBeep();
  893. break;
  894. default:
  895. // shouldnt be anything else
  896. ASSERT(0);
  897. }
  898. if (fChange) {
  899. // the thread MSGs need to be acked
  900. SetEvent(m_hRecvThreadAckEvent);
  901. fChange = FALSE;
  902. }
  903. } else if (dwWaitStatus == WAIT_IO_COMPLETION) {
  904. // nothing to do here
  905. } else if (dwWaitStatus != WAIT_TIMEOUT) {
  906. DEBUGMSG(ZONE_DP,("%s: Wait failed with %d",_fx_,GetLastError()));
  907. fExit=TRUE;
  908. }
  909. }
  910. DEBUGMSG(ZONE_DP,("%s terminating.\n", _fx_));
  911. return 0;
  912. }
  913. void ThreadTimer::SetTimeout(TTimeout *pTObj)
  914. {
  915. DWORD time = pTObj->GetDueTime();
  916. // insert in increasing order of timeout
  917. for (TTimeout *pT = m_TimeoutList.pNext; pT != &m_TimeoutList; pT = pT->pNext) {
  918. if ((int)(pT->m_DueTime- m_CurTime) > (int) (time - m_CurTime))
  919. break;
  920. }
  921. pTObj->InsertAfter(pT->pPrev);
  922. }
  923. void ThreadTimer::CancelTimeout(TTimeout *pTObj)
  924. {
  925. pTObj->Remove(); // remove from list
  926. }
  927. // Called by thread with the current time as input (usually obtained from GetTickCount())
  928. // Returns the time by which UpdateTime() should be called again or currentTime+0xFFFFFFFF if there
  929. // are no scheduled timeouts
  930. DWORD ThreadTimer::UpdateTime(DWORD curTime)
  931. {
  932. TTimeout *pT;
  933. m_CurTime = curTime;
  934. // figure out which timeouts have elapsed and do the callbacks
  935. while (!IsEmpty()) {
  936. pT = m_TimeoutList.pNext;
  937. if ((int)(pT->m_DueTime-m_CurTime) <= 0) {
  938. pT->Remove();
  939. pT->TimeoutIndication();
  940. } else
  941. break;
  942. }
  943. return (IsEmpty() ? m_CurTime+INFINITE : m_TimeoutList.pNext->m_DueTime);
  944. }
  945.