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.

1644 lines
43 KiB

  1. #include "precomp.h"
  2. #include <nmdsprv.h>
  3. //bytes <-> PCM16 samples
  4. inline UINT BYTESTOSAMPLES(UINT bytes) { return bytes/2;}
  5. inline UINT SAMPLESTOBYTES(UINT samples) {return samples*2;}
  6. // 'quick' modulo operator. reason its quick is because it only works if -mod < x < 2*mod
  7. inline UINT QMOD(const int x, const int mod)
  8. { if (x >= mod)
  9. return (x-mod);
  10. if (x < 0)
  11. return (x+mod);
  12. else
  13. return x;
  14. }
  15. #define BUFFER_RECEIVED 1 // used to indicate that the buffer is ready to play
  16. #define BUFFER_SILENT 2 // buffer appears to be silent
  17. #define DSFLAG_ALLOCATED 1
  18. const int MIN_DSBUF_SIZE = 4000;
  19. struct DSINFO {
  20. struct DSINFO *pNext;
  21. DWORD flags;
  22. GUID guid;
  23. LPSTR pszDescription;
  24. LPSTR pszModule;
  25. LPDIRECTSOUND pDS;
  26. LPDIRECTSOUNDBUFFER pDSPrimaryBuf;
  27. UINT uRef;
  28. };
  29. // initial all the globals
  30. DSINFO *DirectSoundMgr::m_pDSInfoList = NULL;
  31. BOOL DirectSoundMgr::m_fInitialized = FALSE;
  32. HINSTANCE DirectSoundMgr::m_hDS = NULL;
  33. LPFNDSCREATE DirectSoundMgr::m_pDirectSoundCreate=NULL;
  34. LPFNDSENUM DirectSoundMgr::m_pDirectSoundEnumerate=NULL;
  35. GUID myNullGuid = {0};
  36. HRESULT DirectSoundMgr::Initialize()
  37. {
  38. HRESULT hr;
  39. // currently there seems no need to re-enumerate the list of devices
  40. // but that can be changed if the need arises
  41. if (m_fInitialized)
  42. return (m_pDSInfoList == NULL ? DPR_NO_PLAY_CAP : S_OK);
  43. ASSERT(!m_pDSInfoList);
  44. m_hDS = ::LoadLibrary("DSOUND");
  45. if (m_hDS != NULL)
  46. {
  47. if (GetProcAddress(m_hDS, "DirectSoundCaptureCreate") // this identifies DS5 or later
  48. && (m_pDirectSoundCreate = (LPFNDSCREATE)GetProcAddress(m_hDS,"DirectSoundCreate"))
  49. && (m_pDirectSoundEnumerate = (LPFNDSENUM)GetProcAddress(m_hDS,"DirectSoundEnumerateA"))
  50. )
  51. {
  52. if ((hr=(*m_pDirectSoundEnumerate)(DSEnumCallback, 0)) != S_OK)
  53. {
  54. DEBUGMSG(ZONE_DP,("DSEnumerate failed with %x\n",hr));
  55. } else {
  56. if (!m_pDSInfoList) {
  57. DEBUGMSG(ZONE_DP,("DSEnumerate - no devices found\n"));
  58. hr = DPR_NO_PLAY_CAP; // no devices were found
  59. }
  60. }
  61. } else {
  62. hr = DPR_INVALID_PLATFORM; // better error code?
  63. }
  64. if (hr != S_OK) {
  65. FreeLibrary(m_hDS);
  66. m_hDS = NULL;
  67. }
  68. }
  69. else
  70. {
  71. DEBUGMSG(ZONE_INIT,("LoadLibrary(DSOUND) failed"));
  72. hr = DPR_NO_PLAY_CAP;
  73. }
  74. m_fInitialized = TRUE;
  75. return hr;
  76. }
  77. HRESULT DirectSoundMgr::UnInitialize()
  78. {
  79. DSINFO *pDSINFO = m_pDSInfoList, *pDSNEXT;
  80. if (m_fInitialized)
  81. {
  82. while (pDSINFO)
  83. {
  84. pDSNEXT = pDSINFO->pNext;
  85. delete [] pDSINFO->pszDescription;
  86. delete [] pDSINFO->pszModule;
  87. delete pDSINFO;
  88. pDSINFO = pDSNEXT;
  89. }
  90. m_fInitialized = FALSE;
  91. m_pDSInfoList = NULL;
  92. }
  93. return S_OK;
  94. }
  95. BOOL __stdcall DirectSoundMgr::DSEnumCallback(
  96. LPGUID lpGuid,
  97. LPCSTR lpstrDescription,
  98. LPCSTR lpstrModule,
  99. LPVOID lpContext
  100. )
  101. {
  102. DSINFO *pDSInfo;
  103. DBG_SAVE_FILE_LINE
  104. pDSInfo = new DSINFO;
  105. if (pDSInfo) {
  106. pDSInfo->uRef = 0;
  107. pDSInfo->guid = (lpGuid ? *lpGuid : GUID_NULL);
  108. DBG_SAVE_FILE_LINE
  109. pDSInfo->pszDescription = new CHAR [lstrlen(lpstrDescription)+1];
  110. if (pDSInfo->pszDescription)
  111. lstrcpy(pDSInfo->pszDescription, lpstrDescription);
  112. DBG_SAVE_FILE_LINE
  113. pDSInfo->pszModule = new CHAR [lstrlen(lpstrModule)+1];
  114. if (pDSInfo->pszModule)
  115. lstrcpy(pDSInfo->pszModule, lpstrModule);
  116. // append to list
  117. pDSInfo->pNext = m_pDSInfoList;
  118. m_pDSInfoList = pDSInfo;
  119. }
  120. DEBUGMSG(ZONE_DP,("DSound device found: (%s) ; driver (%s);\n",lpstrDescription, lpstrModule));
  121. return TRUE;
  122. }
  123. HRESULT
  124. DirectSoundMgr::MapWaveIdToGuid(UINT waveId, GUID *pGuid)
  125. {
  126. // try to figure out which Guid maps to a wave id
  127. // Do this by opening the wave device corresponding to the wave id and then
  128. // all the DS devices in sequence and see which one fails.
  129. // Yes, this is a monstrous hack and clearly unreliable
  130. HWAVEOUT hWaveOut = NULL;
  131. MMRESULT mmr;
  132. HRESULT hr;
  133. DSINFO *pDSInfo;
  134. LPDIRECTSOUND pDS;
  135. DSCAPS dscaps;
  136. BOOL fEmulFound;
  137. WAVEFORMATEX wfPCM8K16 = {WAVE_FORMAT_PCM,1,8000,16000,2,16,0};
  138. WAVEOUTCAPS waveOutCaps;
  139. if (!m_fInitialized)
  140. Initialize(); // get the list of DS devices
  141. if (!m_pDSInfoList)
  142. return DPR_CANT_OPEN_DEV;
  143. else if (waveId == WAVE_MAPPER || waveOutGetNumDevs()==1) {
  144. // we want the default or there is only one DS device, take the easy way out
  145. *pGuid = GUID_NULL;
  146. return S_OK;
  147. }
  148. // try using the IKsProperty interface on a DirectSoundPrivate object
  149. // to find out what GUID maps to the waveId in question
  150. // Only likely to work on Win98 and NT 5.
  151. ZeroMemory(&waveOutCaps, sizeof(WAVEOUTCAPS));
  152. mmr = waveOutGetDevCaps(waveId, &waveOutCaps, sizeof(WAVEOUTCAPS));
  153. if (mmr == MMSYSERR_NOERROR)
  154. {
  155. hr = DsprvGetWaveDeviceMapping(waveOutCaps.szPname, FALSE, pGuid);
  156. if (SUCCEEDED(hr))
  157. {
  158. return hr;
  159. }
  160. // if we failed to make a mapping, fall through to the old code path
  161. }
  162. mmr = waveOutOpen(&hWaveOut, waveId,
  163. &wfPCM8K16,
  164. 0, 0, CALLBACK_NULL);
  165. if (mmr != MMSYSERR_NOERROR) {
  166. DEBUGMSG(ZONE_DP,("MapWaveIdToGuid - cannot open wave(%d)\n", waveId));
  167. return DPR_CANT_OPEN_DEV;
  168. }
  169. // now open all the DS devices in turn
  170. for (pDSInfo = m_pDSInfoList; pDSInfo; pDSInfo = pDSInfo->pNext) {
  171. hr = (*m_pDirectSoundCreate)(&pDSInfo->guid, &pDS, NULL);
  172. if (hr != S_OK) {
  173. pDSInfo->flags |= DSFLAG_ALLOCATED; // this is a candidate
  174. } else {
  175. pDSInfo->flags &= ~DSFLAG_ALLOCATED;
  176. pDS->Release();
  177. }
  178. }
  179. waveOutClose(hWaveOut);
  180. hr = DPR_CANT_OPEN_DEV;
  181. dscaps.dwSize = sizeof(dscaps);
  182. fEmulFound = FALSE;
  183. // try opening the DS devices that failed the first time
  184. for (pDSInfo = m_pDSInfoList; pDSInfo; pDSInfo = pDSInfo->pNext) {
  185. if (pDSInfo->flags & DSFLAG_ALLOCATED) {
  186. hr = (*m_pDirectSoundCreate)(&pDSInfo->guid, &pDS, NULL);
  187. if (hr == S_OK) {
  188. *pGuid = pDSInfo->guid;
  189. // get dsound capabilities.
  190. // NOTE: consider putting the caps in DSINFO if its used often
  191. pDS->GetCaps(&dscaps);
  192. pDS->Release();
  193. DEBUGMSG(ZONE_DP,("mapped waveid %d to DS device(%s)\n", waveId, pDSInfo->pszDescription));
  194. if (dscaps.dwFlags & DSCAPS_EMULDRIVER)
  195. fEmulFound = TRUE; // keep looking in case there's also a native driver
  196. else
  197. break; // native DS driver. Look no further
  198. }
  199. }
  200. }
  201. if (fEmulFound)
  202. hr = S_OK;
  203. if (hr != S_OK) {
  204. DEBUGMSG(ZONE_DP,("Cant map id %d to DSound guid!\n", waveId));
  205. hr = DPR_CANT_OPEN_DEV;
  206. }
  207. return hr;
  208. }
  209. HRESULT
  210. DirectSoundMgr::Instance(LPGUID pDeviceGuid,LPDIRECTSOUND *ppDS, HWND hwnd, WAVEFORMATEX *pwf)
  211. {
  212. DSINFO *pDSInfo = m_pDSInfoList;
  213. HRESULT hr;
  214. DSBUFFERDESC dsBufDesc;
  215. FX_ENTRY("DirectSoundInstance");
  216. if (pDeviceGuid == NULL)
  217. pDeviceGuid = &myNullGuid;
  218. // search for the Guid in the list
  219. *ppDS = NULL;
  220. if (!m_fInitialized)
  221. Initialize();
  222. while (pDSInfo) {
  223. if (pDSInfo->guid == *pDeviceGuid)
  224. break;
  225. pDSInfo = pDSInfo->pNext;
  226. }
  227. ASSERT (pDSInfo);
  228. if (!pDSInfo || !pDSInfo->pDS) {
  229. // need to create DS object
  230. PlaySound(NULL,NULL,0); // hack to stop system sounds
  231. hr = (*m_pDirectSoundCreate)((*pDeviceGuid==GUID_NULL ? NULL: pDeviceGuid), ppDS, NULL);
  232. //set priority cooperative level, so we can set the format of the primary buffer.
  233. if (hr == S_OK && (hr = (*ppDS)->SetCooperativeLevel(hwnd,DSSCL_PRIORITY)) == S_OK)
  234. {
  235. if (!pDSInfo) {
  236. DEBUGMSG(ZONE_DP,("%s: GUID not in List!\n",_fx_));
  237. // BUGBUG: remove this block. Enumerate should have created the entry (except for NULL guid?)
  238. DBG_SAVE_FILE_LINE
  239. pDSInfo = new DSINFO;
  240. if (pDSInfo) {
  241. pDSInfo->uRef = 0;
  242. pDSInfo->guid = *pDeviceGuid;
  243. pDSInfo->pNext = m_pDSInfoList;
  244. m_pDSInfoList = pDSInfo;
  245. } else {
  246. (*ppDS)->Release();
  247. return DPR_OUT_OF_MEMORY;
  248. }
  249. }
  250. pDSInfo->pDS = *ppDS;
  251. ++pDSInfo->uRef;
  252. // Create a primary buffer only to set the format
  253. // (what if its already set?)
  254. ZeroMemory(&dsBufDesc,sizeof(dsBufDesc));
  255. dsBufDesc.dwSize = sizeof(dsBufDesc);
  256. dsBufDesc.dwFlags = DSBCAPS_PRIMARYBUFFER|DSBCAPS_STICKYFOCUS;
  257. // STICKYFOCUS flags is supposed to preserve the format
  258. // when the app is not in-focus.
  259. hr = pDSInfo->pDS->CreateSoundBuffer(&dsBufDesc,&pDSInfo->pDSPrimaryBuf,NULL);
  260. if (hr == S_OK && pwf) {
  261. pDSInfo->pDSPrimaryBuf->SetFormat(pwf);
  262. } else {
  263. DEBUGMSG (ZONE_DP, ("%s: Create PrimarySoundBuffer failed, hr=0x%lX\r\n", _fx_, hr));
  264. hr = S_OK; // Non fatal error
  265. }
  266. //DEBUGMSG(ZONE_DP, ("%s: Created Direct Sound object (%s)\n", _fx_,pDSInfo->pszDescription));
  267. } else {
  268. DEBUGMSG(ZONE_DP, ("%s: Could not create DS object (%s)\n", _fx_,pDSInfo->pszDescription));
  269. }
  270. LOG((LOGMSG_DSCREATE, hr));
  271. } else {
  272. *ppDS = pDSInfo->pDS;
  273. ++pDSInfo->uRef;
  274. hr = S_OK;
  275. }
  276. return hr;
  277. }
  278. HRESULT
  279. DirectSoundMgr::ReleaseInstance(LPDIRECTSOUND pDS)
  280. {
  281. // deref the DS object and release it if necessary
  282. DSINFO *pDSInfo = m_pDSInfoList;
  283. while (pDSInfo) {
  284. if (pDSInfo->pDS == pDS) {
  285. ASSERT(pDSInfo->uRef > 0);
  286. if (--pDSInfo->uRef == 0) {
  287. ULONG uref;
  288. if (pDSInfo->pDSPrimaryBuf) {
  289. pDSInfo->pDSPrimaryBuf->Release();
  290. pDSInfo->pDSPrimaryBuf = NULL;
  291. }
  292. uref = pDS->Release();
  293. pDSInfo->pDS = 0;
  294. LOG((LOGMSG_DSRELEASE, uref));
  295. //DEBUGMSG(ZONE_DP, ("Release Direct Sound object (%s) uref=%d\n", pDSInfo->pszDescription, uref));
  296. // dont bother freeing DSINFO. Its okay
  297. // to keep it around till the process dies
  298. }
  299. break;
  300. }
  301. pDSInfo = pDSInfo->pNext;
  302. }
  303. return (pDSInfo ? S_OK : DPR_INVALID_PARAMETER);
  304. }
  305. void DSTimeout::TimeoutIndication()
  306. {
  307. ASSERT(m_pRDSStream);
  308. m_pRDSStream->RecvTimeout();
  309. }
  310. HRESULT STDMETHODCALLTYPE RecvDSAudioStream::QueryInterface(REFIID iid, void **ppVoid)
  311. {
  312. // resolve duplicate inheritance to the SendMediaStream;
  313. extern IID IID_IProperty;
  314. if (iid == IID_IUnknown)
  315. {
  316. *ppVoid = (IUnknown*)((RecvMediaStream*)this);
  317. }
  318. else if (iid == IID_IMediaChannel)
  319. {
  320. *ppVoid = (IMediaChannel*)((RecvMediaStream *)this);
  321. }
  322. else if (iid == IID_IAudioChannel)
  323. {
  324. *ppVoid = (IAudioChannel*)this;
  325. }
  326. else if (iid == IID_IProperty)
  327. {
  328. *ppVoid = NULL;
  329. ERROR_OUT(("Don't QueryInterface for IID_IProperty, use IMediaChannel"));
  330. return E_NOINTERFACE;
  331. }
  332. else
  333. {
  334. *ppVoid = NULL;
  335. return E_NOINTERFACE;
  336. }
  337. AddRef();
  338. return S_OK;
  339. }
  340. ULONG STDMETHODCALLTYPE RecvDSAudioStream::AddRef(void)
  341. {
  342. return InterlockedIncrement(&m_lRefCount);
  343. }
  344. ULONG STDMETHODCALLTYPE RecvDSAudioStream::Release(void)
  345. {
  346. LONG lRet;
  347. lRet = InterlockedDecrement(&m_lRefCount);
  348. if (lRet == 0)
  349. {
  350. delete this;
  351. return 0;
  352. }
  353. else
  354. return lRet;
  355. }
  356. HRESULT
  357. RecvDSAudioStream::Initialize( DataPump *pDP)
  358. {
  359. HRESULT hr = DPR_OUT_OF_MEMORY;
  360. DWORD dwFlags = DP_FLAG_ACM| DP_FLAG_DIRECTSOUND | DP_FLAG_HALF_DUPLEX | DP_FLAG_AUTO_SWITCH ;
  361. MEDIACTRLINIT mcInit;
  362. FX_ENTRY ("RecvDSAudioStream::Initialize")
  363. InitializeCriticalSection(&m_crsAudQoS);
  364. // enable Recv by default
  365. m_DPFlags = dwFlags | DPFLAG_ENABLE_RECV;
  366. // store a back pointer to the datapump container
  367. m_pDP = pDP;
  368. m_Net = NULL;
  369. m_dwSrcSize = 0;
  370. m_pIRTPRecv = NULL;
  371. m_nFailCount = 0;
  372. m_bJammed = FALSE;
  373. m_bCanSignalOpen = TRUE;
  374. // Initialize data (should be in constructor)
  375. m_DSguid = GUID_NULL; // use default device
  376. // Create decode audio filters
  377. m_hStrmConv = NULL; // replaced by AcmFilter
  378. DBG_SAVE_FILE_LINE
  379. m_pAudioFilter = new AcmFilter;
  380. if (!m_pAudioFilter)
  381. {
  382. DEBUGMSG (ZONE_DP, ("%s: AcmManager new failed\r\n", _fx_));
  383. goto FilterAllocError;
  384. }
  385. ZeroMemory (&m_StrmConvHdr, sizeof (ACMSTREAMHEADER));
  386. // determine if the wave devices are available
  387. if (waveOutGetNumDevs()) m_DPFlags |= DP_FLAG_PLAY_CAP;
  388. m_DPFlags |= DPFLAG_INITIALIZED;
  389. UPDATE_REPORT_ENTRY(g_prptSystemSettings, 1, REP_SYS_AUDIO_DSOUND);
  390. RETAILMSG(("NAC: Audio Subsystem: DirectSound"));
  391. return DPR_SUCCESS;
  392. FilterAllocError:
  393. if (m_pAudioFilter) delete m_pAudioFilter;
  394. ERRORMESSAGE( ("%s: exit, hr=0x%lX\r\n", _fx_, hr));
  395. return hr;
  396. }
  397. RecvDSAudioStream::~RecvDSAudioStream()
  398. {
  399. if (m_DPFlags & DPFLAG_INITIALIZED) {
  400. m_DPFlags &= ~DPFLAG_INITIALIZED;
  401. if (m_DPFlags & DPFLAG_CONFIGURED_RECV)
  402. UnConfigure();
  403. if (m_pIRTPRecv)
  404. {
  405. m_pIRTPRecv->Release();
  406. m_pIRTPRecv = NULL;
  407. }
  408. if (m_pAudioFilter)
  409. delete m_pAudioFilter;
  410. m_pDP->RemoveMediaChannel(MCF_RECV|MCF_AUDIO, (IMediaChannel*)(RecvMediaStream*)this);
  411. }
  412. DeleteCriticalSection(&m_crsAudQoS);
  413. }
  414. extern UINT ChoosePacketSize(WAVEFORMATEX *pwf);
  415. extern UINT g_MaxAudioDelayMs;
  416. extern UINT g_MinWaveAudioDelayMs;
  417. extern UINT g_MinDSEmulAudioDelayMs; // emulated DS driver delay
  418. HRESULT STDMETHODCALLTYPE RecvDSAudioStream::Configure(
  419. BYTE *pFormat,
  420. UINT cbFormat,
  421. BYTE *pChannelParams,
  422. UINT cbParams,
  423. IUnknown *pUnknown)
  424. {
  425. HRESULT hr=E_FAIL;
  426. BOOL fRet;
  427. DWORD dwMaxDecompressedSize;
  428. UINT cbSamplesPerPkt;
  429. DWORD dwPropVal;
  430. DWORD dwFlags;
  431. UINT uAudioCodec;
  432. AUDIO_CHANNEL_PARAMETERS audChannelParams;
  433. UINT ringSize = MAX_RXRING_SIZE;
  434. WAVEFORMATEX *pwfRecv;
  435. UINT maxRingSamples;
  436. MMRESULT mmr;
  437. FX_ENTRY ("RecvDSAudioStream::Configure")
  438. // m_Net = pNet;
  439. if (m_DPFlags & DPFLAG_STARTED_RECV)
  440. {
  441. return DPR_IO_PENDING; // anything better to return
  442. }
  443. if (m_DPFlags & DPFLAG_CONFIGURED_RECV)
  444. {
  445. DEBUGMSG(ZONE_DP, ("Stream Re-Configuration - calling UnConfigure"));
  446. UnConfigure(); // a re-configure will release the RTP object, need to call SetNetworkInterface again
  447. }
  448. if ((NULL == pFormat) ||
  449. (NULL == pChannelParams) ||
  450. (cbParams != sizeof(audChannelParams)) ||
  451. (cbFormat < sizeof(WAVEFORMATEX)) )
  452. {
  453. return DPR_INVALID_PARAMETER;
  454. }
  455. audChannelParams = *(AUDIO_CHANNEL_PARAMETERS *)pChannelParams;
  456. pwfRecv = (WAVEFORMATEX *)pFormat;
  457. if (! (m_DPFlags & DPFLAG_INITIALIZED))
  458. return DPR_OUT_OF_MEMORY; //BUGBUG: return proper error;
  459. // if (m_Net)
  460. // {
  461. // hr = m_Net->QueryInterface(IID_IRTPRecv, (void **)&m_pIRTPRecv);
  462. // if (!SUCCEEDED(hr))
  463. // return hr;
  464. // }
  465. AcmFilter::SuggestDecodeFormat(pwfRecv, &m_fDevRecv);
  466. UPDATE_REPORT_ENTRY(g_prptCallParameters, pwfRecv->wFormatTag, REP_RECV_AUDIO_FORMAT);
  467. UPDATE_REPORT_ENTRY(g_prptCallParameters, pwfRecv->nSamplesPerSec, REP_RECV_AUDIO_SAMPLING);
  468. UPDATE_REPORT_ENTRY(g_prptCallParameters, pwfRecv->nAvgBytesPerSec*8, REP_RECV_AUDIO_BITRATE);
  469. 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" : "??????"));
  470. RETAILMSG(("NAC: Audio Recv Sampling Rate (Hz): %ld", pwfRecv->nSamplesPerSec));
  471. RETAILMSG(("NAC: Audio Recv Bitrate (w/o network overhead - bps): %ld", pwfRecv->nAvgBytesPerSec*8));
  472. // note that parameters such as samples/packet are channel specific
  473. cbSamplesPerPkt = audChannelParams.ns_params.wFrameSize
  474. *audChannelParams.ns_params.wFramesPerPkt;
  475. // turn on receive silence detection only if the sender is not using
  476. // silence suppression
  477. if (!audChannelParams.ns_params.UseSilenceDet)
  478. m_DPFlags |= DP_FLAG_AUTO_SILENCE_DETECT;
  479. else
  480. m_DPFlags &= ~DP_FLAG_AUTO_SILENCE_DETECT;
  481. UPDATE_REPORT_ENTRY(g_prptCallParameters, cbSamplesPerPkt, REP_RECV_AUDIO_PACKET);
  482. RETAILMSG(("NAC: Audio Recv Packetization (ms/packet): %ld", pwfRecv->nSamplesPerSec ? cbSamplesPerPkt * 1000UL / pwfRecv->nSamplesPerSec : 0));
  483. INIT_COUNTER_MAX(g_pctrAudioReceiveBytes, (pwfRecv->nAvgBytesPerSec * 8 + pwfRecv->nSamplesPerSec * (sizeof(RTP_HDR) + IP_HEADER_SIZE + UDP_HEADER_SIZE) / cbSamplesPerPkt) << 3);
  484. // make the ring buffer size large enought to hold 4 seconds of audio
  485. // This seems to be suitable for congested networks, in which
  486. // packets can get delayed and them for many to suddelnly arrive at once
  487. maxRingSamples = (pwfRecv->nSamplesPerSec * MIN_DSBUF_SIZE)/1000;
  488. // describe the DirectSound buffer
  489. ZeroMemory(&m_DSBufDesc,sizeof(m_DSBufDesc));
  490. m_DSBufDesc.dwSize = sizeof (m_DSBufDesc);
  491. m_DSBufDesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS | DSBCAPS_GETCURRENTPOSITION2;
  492. m_DSBufDesc.dwBufferBytes = maxRingSamples * (m_fDevRecv.wBitsPerSample/8);
  493. m_DSBufDesc.dwReserved = 0;
  494. m_DSBufDesc.lpwfxFormat = &m_fDevRecv;
  495. m_pDS = NULL;
  496. m_pDSBuf = NULL;
  497. // Initialize the recv-stream filter manager object
  498. dwMaxDecompressedSize = cbSamplesPerPkt * (m_fDevRecv.nBlockAlign);
  499. mmr = m_pAudioFilter->Open(pwfRecv, &m_fDevRecv);
  500. if (mmr != 0)
  501. {
  502. DEBUGMSG (ZONE_DP, ("%s: AcmFilter->Open failed, mmr=%d\r\n", _fx_, mmr));
  503. hr = DPR_CANT_OPEN_CODEC;
  504. goto RecvFilterInitError;
  505. }
  506. // set up the decode buffer
  507. m_pAudioFilter->SuggestSrcSize(dwMaxDecompressedSize, &m_dwSrcSize);
  508. ZeroMemory (&m_StrmConvHdr, sizeof (ACMSTREAMHEADER));
  509. m_StrmConvHdr.cbStruct = sizeof (ACMSTREAMHEADER);
  510. DBG_SAVE_FILE_LINE
  511. m_StrmConvHdr.pbSrc = new BYTE[m_dwSrcSize];
  512. m_StrmConvHdr.cbSrcLength = m_dwSrcSize; // may change for variable bit rate codecs
  513. DBG_SAVE_FILE_LINE
  514. m_StrmConvHdr.pbDst = new BYTE[dwMaxDecompressedSize];
  515. m_StrmConvHdr.cbDstLength = dwMaxDecompressedSize;
  516. mmr = m_pAudioFilter->PrepareHeader(&m_StrmConvHdr);
  517. if (mmr != MMSYSERR_NOERROR)
  518. {
  519. DEBUGMSG (ZONE_DP, ("%s: AcmFilter->Open failed, mmr=%d\r\n", _fx_, mmr));
  520. hr = DPR_CANT_OPEN_CODEC;
  521. goto RecvFilterInitError;
  522. }
  523. // Initialize the recv stream
  524. m_BufSizeT = BYTESTOSAMPLES(m_DSBufDesc.dwBufferBytes);
  525. m_fEmpty = TRUE;
  526. m_MinDelayT = 0;
  527. m_MaxDelayT = g_MaxAudioDelayMs * m_fDevRecv.nSamplesPerSec /1000;
  528. m_ArrT = m_ArrivalT0 = 0;
  529. m_ScaledAvgVarDelay = 0;
  530. m_DelayT = m_MinDelayT;
  531. m_SilenceDurationT = 0;
  532. InitAudioFlowspec(&m_flowspec, pwfRecv, m_dwSrcSize);
  533. m_DPFlags |= DPFLAG_CONFIGURED_RECV;
  534. return DPR_SUCCESS;
  535. RecvFilterInitError:
  536. if (m_pIRTPRecv)
  537. {
  538. m_pIRTPRecv->Release();
  539. m_pIRTPRecv = NULL;
  540. }
  541. m_pAudioFilter->Close();
  542. delete [] m_StrmConvHdr.pbSrc;
  543. delete [] m_StrmConvHdr.pbDst;
  544. m_StrmConvHdr.pbSrc=NULL;
  545. m_StrmConvHdr.pbDst = NULL;
  546. ERRORMESSAGE(("%s: failed, hr=0%u\r\n", _fx_, hr));
  547. return hr;
  548. }
  549. void RecvDSAudioStream::UnConfigure()
  550. {
  551. if ((m_DPFlags & DPFLAG_CONFIGURED_RECV))
  552. {
  553. Stop();
  554. // Close the RTP state if its open
  555. m_Net = NULL;
  556. // release DS buffer and DS object
  557. //ReleaseDSBuffer();
  558. ASSERT(!m_pDSBuf); // released in StopRecv()
  559. // Close the filters
  560. m_StrmConvHdr.cbSrcLength = m_dwSrcSize;
  561. m_pAudioFilter->UnPrepareHeader(&m_StrmConvHdr);
  562. m_pAudioFilter->Close();
  563. delete [] m_StrmConvHdr.pbSrc;
  564. delete [] m_StrmConvHdr.pbDst;
  565. m_StrmConvHdr.pbSrc=NULL;
  566. m_StrmConvHdr.pbDst = NULL;
  567. m_nFailCount = 0;
  568. m_bJammed = FALSE;
  569. m_bCanSignalOpen = TRUE;
  570. // Close the receive streams
  571. //m_RecvStream->Destroy();
  572. m_DPFlags &= ~(DPFLAG_CONFIGURED_RECV);
  573. }
  574. }
  575. HRESULT
  576. RecvDSAudioStream::Start()
  577. {
  578. HRESULT hr;
  579. IMediaChannel *pISendAudio;
  580. BOOL fStoppedRecording;
  581. FX_ENTRY ("RecvDSAudioStream::Start");
  582. if (m_DPFlags & DPFLAG_STARTED_RECV)
  583. return DPR_SUCCESS;
  584. // TODO: remove this check once audio UI calls the IComChan PAUSE_RECV prop
  585. if (!(m_DPFlags & DPFLAG_ENABLE_RECV))
  586. return DPR_SUCCESS;
  587. if ((!(m_DPFlags & DPFLAG_CONFIGURED_RECV)) || (!m_pIRTPRecv))
  588. return DPR_NOT_CONFIGURED;
  589. ASSERT(!m_hRenderingThread );
  590. m_ThreadFlags &= ~(DPTFLAG_STOP_PLAY|DPTFLAG_STOP_RECV);
  591. SetFlowSpec();
  592. pISendAudio = NULL;
  593. fStoppedRecording = FALSE;
  594. if (!(m_DPFlags & DP_FLAG_HALF_DUPLEX))
  595. {
  596. // make sure the recording device is closed before creating the DS object
  597. // Why ? Because SoundBlaster either sounds lousy or doesnt work at all if
  598. // you open waveIn before waveOut or DirectSound.
  599. m_pDP->GetMediaChannelInterface(MCF_AUDIO|MCF_SEND, &pISendAudio);
  600. if (pISendAudio && pISendAudio->GetState()== MSSTATE_STARTED
  601. && pISendAudio->Stop() == S_OK)
  602. {
  603. fStoppedRecording = TRUE;
  604. DEBUGMSG(ZONE_DP,("%s:Stopped Recording\n",_fx_));
  605. }
  606. }
  607. // Start receive thread. This will create the DSound object
  608. m_pDP->StartReceiving(this);
  609. if (pISendAudio) {
  610. if (fStoppedRecording)
  611. pISendAudio->Start();
  612. pISendAudio->Release();
  613. }
  614. m_DPFlags |= DPFLAG_STARTED_RECV;
  615. return DPR_SUCCESS;
  616. }
  617. // LOOK: Identical to RecvVideoStream version.
  618. HRESULT
  619. RecvDSAudioStream::Stop()
  620. {
  621. FX_ENTRY ("RecvDSAudioStream::Stop");
  622. if(!(m_DPFlags & DPFLAG_STARTED_RECV))
  623. {
  624. return DPR_SUCCESS;
  625. }
  626. m_ThreadFlags = m_ThreadFlags |
  627. DPTFLAG_STOP_RECV | DPTFLAG_STOP_PLAY ;
  628. // delink from receive thread
  629. m_pDP->StopReceiving(this);
  630. if (m_pDSBuf)
  631. m_pDSBuf->Stop();
  632. //This is per channel, but the variable is "DPFlags"
  633. m_DPFlags &= ~DPFLAG_STARTED_RECV;
  634. return DPR_SUCCESS;
  635. }
  636. // IProperty::GetProperty / SetProperty
  637. // (DataPump::MediaChannel::GetProperty)
  638. // Properties of the MediaChannel. Supports properties for both audio
  639. // and video channels.
  640. STDMETHODIMP
  641. RecvDSAudioStream::GetProperty(
  642. DWORD prop,
  643. PVOID pBuf,
  644. LPUINT pcbBuf
  645. )
  646. {
  647. HRESULT hr = DPR_SUCCESS;
  648. RTP_STATS RTPStats;
  649. DWORD dwValue;
  650. UINT len = sizeof(DWORD); // most props are DWORDs
  651. if (!pBuf || *pcbBuf < len)
  652. {
  653. *pcbBuf = len;
  654. return DPR_INVALID_PARAMETER;
  655. }
  656. switch (prop)
  657. {
  658. case PROP_RECV_AUDIO_STRENGTH:
  659. {
  660. return GetSignalLevel((UINT*)pBuf);
  661. }
  662. #ifdef OLDSTUFF
  663. case PROP_NET_RECV_STATS:
  664. if (m_Net && *pcbBuf >= sizeof(RTP_STATS))
  665. {
  666. m_Net->GetRecvStats((RTP_STATS *)pBuf);
  667. *pcbBuf = sizeof(RTP_STATS);
  668. } else
  669. hr = DPR_INVALID_PROP_VAL;
  670. break;
  671. #endif
  672. //case PROP_VOLUME:
  673. case PROP_DUPLEX_TYPE:
  674. if(m_DPFlags & DP_FLAG_HALF_DUPLEX)
  675. *(DWORD*)pBuf = DUPLEX_TYPE_HALF;
  676. else
  677. *(DWORD*)pBuf = DUPLEX_TYPE_FULL;
  678. break;
  679. case PROP_WAVE_DEVICE_TYPE:
  680. *(DWORD*)pBuf = m_DPFlags & DP_MASK_WAVE_DEVICE;
  681. break;
  682. case PROP_PLAY_ON:
  683. *(DWORD *)pBuf = (m_ThreadFlags & DPFLAG_ENABLE_RECV)!=0;
  684. break;
  685. case PROP_PLAYBACK_DEVICE:
  686. *(DWORD *)pBuf = m_RenderingDevice;
  687. break;
  688. case PROP_VIDEO_AUDIO_SYNC:
  689. *(DWORD*)pBuf = ((m_DPFlags & DPFLAG_AV_SYNC) != 0);
  690. break;
  691. default:
  692. hr = DPR_INVALID_PROP_ID;
  693. break;
  694. }
  695. return hr;
  696. }
  697. // low order word is the signal strength
  698. // high order work contains bits to indicate status
  699. // (0x01 - transmitting)
  700. // (0x02 - audio device is jammed)
  701. STDMETHODIMP RecvDSAudioStream::GetSignalLevel(UINT *pSignalStrength)
  702. {
  703. DWORD dwLevel;
  704. DWORD dwJammed;
  705. if ((!(m_DPFlags & DPFLAG_STARTED_RECV)) || (m_fEmpty) ||
  706. (m_ThreadFlags & DPTFLAG_PAUSE_RECV) )
  707. {
  708. dwLevel = 0;
  709. }
  710. else
  711. {
  712. dwLevel = GetSignalStrength();
  713. dwLevel = LogScale[(dwLevel >> 8) & 0x00ff];
  714. if (m_bJammed)
  715. {
  716. dwLevel |= (2 << 16);
  717. }
  718. dwLevel |= (1 << 16);
  719. }
  720. *pSignalStrength = dwLevel;
  721. return S_OK;
  722. };
  723. DWORD
  724. RecvDSAudioStream::GetSignalStrength()
  725. {
  726. BYTE bMax, bMin, *pb;
  727. short sMax, sMin, *ps;
  728. UINT cbSize;
  729. DWORD dwMaxStrength = 0;
  730. cbSize = m_StrmConvHdr.cbDstLengthUsed;
  731. if (cbSize==0)
  732. return 0;
  733. switch (m_fDevRecv.wBitsPerSample)
  734. {
  735. case 8: // unsigned char
  736. pb = (PBYTE) (m_StrmConvHdr.pbDst);
  737. bMax = 0;
  738. bMin = 255;
  739. for ( ; cbSize; cbSize--, pb++)
  740. {
  741. if (*pb > bMax) bMax = *pb;
  742. if (*pb < bMin) bMin = *pb;
  743. }
  744. // 2^9 <-- 2^16 / 2^7
  745. dwMaxStrength = ((DWORD) (bMax - bMin)) << 8;
  746. break;
  747. case 16: // (signed) short
  748. ps = (short *) (m_StrmConvHdr.pbDst);
  749. cbSize = m_StrmConvHdr.cbDstLengthUsed;
  750. sMax = sMin = 0;
  751. for (cbSize >>= 1; cbSize; cbSize--, ps++)
  752. {
  753. if (*ps > sMax) sMax = *ps;
  754. if (*ps < sMin) sMin = *ps;
  755. }
  756. dwMaxStrength = (DWORD) (sMax - sMin); // drop sign bit
  757. break;
  758. }
  759. return dwMaxStrength;
  760. }
  761. STDMETHODIMP
  762. RecvDSAudioStream::SetProperty(
  763. DWORD prop,
  764. PVOID pBuf,
  765. UINT cbBuf
  766. )
  767. {
  768. DWORD dw;
  769. HRESULT hr = S_OK;
  770. if (cbBuf < sizeof (DWORD))
  771. return DPR_INVALID_PARAMETER;
  772. switch (prop)
  773. {
  774. //case PROP_VOLUME:
  775. case PROP_DUPLEX_TYPE:
  776. ASSERT(0); // dead code for this case type;
  777. break;
  778. case DP_PROP_DUPLEX_TYPE:
  779. // internal version, called by DataPump::SetDuplexMode() after ensuring streams are stopped
  780. dw = *(DWORD *)pBuf;
  781. if (dw & DP_FLAG_HALF_DUPLEX)
  782. m_DPFlags |= DP_FLAG_HALF_DUPLEX;
  783. else
  784. m_DPFlags &= ~DP_FLAG_HALF_DUPLEX;
  785. break;
  786. case PROP_PLAY_ON:
  787. {
  788. if (*(DWORD *)pBuf) // unmute
  789. {
  790. m_ThreadFlags &= ~DPTFLAG_PAUSE_RECV;
  791. }
  792. else // mute
  793. {
  794. m_ThreadFlags |= DPTFLAG_PAUSE_RECV;
  795. }
  796. // DWORD flag = DPFLAG_ENABLE_RECV;
  797. // if (*(DWORD *)pBuf) {
  798. // m_DPFlags |= flag; // set the flag
  799. // hr = Start();
  800. // }
  801. // else
  802. // {
  803. // m_DPFlags &= ~flag; // clear the flag
  804. // hr = Stop();
  805. // }
  806. RETAILMSG(("NAC: RecvAudioStream: %s", *(DWORD*)pBuf ? "Enabling":"Disabling"));
  807. break;
  808. }
  809. case PROP_PLAYBACK_DEVICE:
  810. m_RenderingDevice = *(DWORD*)pBuf;
  811. RETAILMSG(("NAC: Setting default playback device to %d", m_RenderingDevice));
  812. if (m_RenderingDevice != WAVE_MAPPER)
  813. hr = DirectSoundMgr::MapWaveIdToGuid(m_RenderingDevice,&m_DSguid);
  814. break;
  815. case PROP_VIDEO_AUDIO_SYNC:
  816. if (*(DWORD *)pBuf)
  817. m_DPFlags |= DPFLAG_AV_SYNC;
  818. else
  819. m_DPFlags &= ~DPFLAG_AV_SYNC;
  820. break;
  821. default:
  822. return DPR_INVALID_PROP_ID;
  823. break;
  824. }
  825. return hr;
  826. }
  827. HRESULT
  828. RecvDSAudioStream::GetCurrentPlayNTPTime(NTP_TS *pNtpTime)
  829. {
  830. DWORD rtpTime;
  831. #ifdef OLDSTUFF
  832. if ((m_DPFlags & DPFLAG_STARTED_RECV) && m_fReceiving) {
  833. if (m_Net->RTPtoNTP(m_PlaybackTimestamp,pNtpTime))
  834. return S_OK;
  835. }
  836. #endif
  837. return 0xff; // return proper error
  838. }
  839. BOOL RecvDSAudioStream::IsEmpty() {
  840. // check if anything in DSBuffer or in decode buffer
  841. return (m_fEmpty && !(m_StrmConvHdr.dwDstUser & BUFFER_RECEIVED));
  842. }
  843. /*
  844. Called by the recv thread to setup the stream for receiving.
  845. Post the initial recv buffer(s). Subsequently, the buffers are posted
  846. in the RTPRecvCallback()
  847. */
  848. HRESULT
  849. RecvDSAudioStream::StartRecv(HWND hWnd)
  850. {
  851. HRESULT hr = S_OK;
  852. DWORD dwPropVal = 0;
  853. FX_ENTRY ("RecvDSAudioStream::StartRecv");
  854. if ((!(m_ThreadFlags & DPTFLAG_STOP_RECV) ) && (m_DPFlags & DPFLAG_CONFIGURED_RECV)){
  855. if (!(m_DPFlags & DP_FLAG_HALF_DUPLEX) && !m_pDSBuf) {
  856. // Create the DS object only if its full-duplex
  857. // In the half-duplex case the DSbuffer is created
  858. // when the first packet is received
  859. // only reason its here is so that SetDuplexMode can take effect right away
  860. // BUGBUG: opening waveIn before DS causes death of the waveOut on Memphis!!
  861. hr = CreateDSBuffer();
  862. if (hr != S_OK) {
  863. DEBUGMSG (ZONE_DP, ("%s: CreateSoundBuffer create failed, hr=0x%lX\r\n", _fx_, hr));
  864. return hr;
  865. }
  866. }
  867. if (m_pDSBuf)
  868. hr = m_pDSBuf->Play(0,0,DSBPLAY_LOOPING);
  869. // m_RecvFilter->GetProp (FM_PROP_SRC_SIZE, &dwPropVal);
  870. //hr = m_Net->SetRecvNotification(&RTPRecvDSCallback, (DWORD)this, 2, dwPropVal, hWnd); // for WS1 only
  871. hr =m_pIRTPRecv->SetRecvNotification(&RTPRecvCallback,(DWORD_PTR)this, 2);
  872. }
  873. return hr;
  874. }
  875. /*
  876. Called by the recv thread to suspend receiving on this RTP session
  877. If there are outstanding receive buffers they have to be recovered
  878. */
  879. HRESULT
  880. RecvDSAudioStream::StopRecv()
  881. {
  882. // dont recv on this stream
  883. m_pIRTPRecv->CancelRecvNotification();
  884. // cancel any pending timeout. (its okay if it wasnt scheduled )
  885. m_pDP->m_RecvTimer.CancelTimeout(&m_TimeoutObj);
  886. // Release DirectSound object
  887. ReleaseDSBuffer();
  888. return S_OK;
  889. }
  890. /*
  891. Create a DirectSound object and a DirectSound secondary buffer.
  892. This routine is called after the stream is configured, so the wave format has been set
  893. and the DSBUFFERDESC struct has been initialized.
  894. */
  895. HRESULT
  896. RecvDSAudioStream::CreateDSBuffer()
  897. {
  898. HRESULT hr;
  899. HWAVEOUT hwo=NULL;
  900. DSCAPS dscaps;
  901. FX_ENTRY ("RecvDSAudioStream::CreateDSBuffer");
  902. ASSERT(!m_pDSBuf);
  903. if (m_DPFlags & DP_FLAG_HALF_DUPLEX) {
  904. DWORD dwStatus;
  905. // Got to take the half duplex event
  906. // BUGBUG: this method wont cut it if there is more than one send and one recv stream
  907. dwStatus = WaitForSingleObject(g_hEventHalfDuplex, 0);
  908. if (dwStatus != WAIT_OBJECT_0)
  909. return DPR_CANT_OPEN_DEV;
  910. }
  911. // Stop any high level ("PlaySound()") usage of wave device.
  912. // Create the direct sound object (if necessary)
  913. hr = DirectSoundMgr::Instance(m_RenderingDevice==WAVE_MAPPER ? NULL: &m_DSguid, &m_pDS, m_pDP->m_hAppWnd, &m_fDevRecv);
  914. if (hr == S_OK)
  915. {
  916. hr = m_pDS->CreateSoundBuffer(&m_DSBufDesc,&m_pDSBuf,NULL);
  917. if (hr == DSERR_INVALIDPARAM)
  918. {
  919. // if global focus (DX3) is not supported, try sticky focus
  920. m_DSBufDesc.dwFlags ^= (DSBCAPS_GLOBALFOCUS|DSBCAPS_STICKYFOCUS);
  921. hr = m_pDS->CreateSoundBuffer(&m_DSBufDesc,&m_pDSBuf,NULL);
  922. }
  923. m_PlayPosT = 0; // DS play position is initially at the start of the buffer
  924. if (hr != S_OK)
  925. {
  926. DEBUGMSG (ZONE_DP, ("%s: CreateSoundBuffer create failed, hr=0x%lX\r\n", _fx_, hr));
  927. m_nFailCount++;
  928. if (m_nFailCount == MAX_FAILCOUNT)
  929. {
  930. m_pDP->StreamEvent(MCF_RECV, MCF_AUDIO, STREAM_EVENT_DEVICE_FAILURE, 0);
  931. m_bJammed = TRUE;
  932. m_bCanSignalOpen = TRUE;
  933. }
  934. }
  935. dscaps.dwSize = sizeof(dscaps);
  936. dscaps.dwFlags = 0;
  937. m_pDS->GetCaps(&dscaps); // get DirectSound object attributes
  938. m_DSFlags = dscaps.dwFlags;
  939. if (m_DSFlags & DSCAPS_EMULDRIVER)
  940. {
  941. // use g_MinDSEmulAudioDelay since this is the emulated driver
  942. m_MinDelayT = (m_fDevRecv.nSamplesPerSec * g_MinDSEmulAudioDelayMs) / 1000;
  943. m_DelayT = m_MinDelayT;
  944. };
  945. }
  946. else
  947. {
  948. DEBUGMSG (ZONE_DP, ("%s: DirectSound create failed, hr=0x%lX\r\n", _fx_, hr));
  949. m_nFailCount++;
  950. if (m_nFailCount == MAX_FAILCOUNT)
  951. {
  952. m_pDP->StreamEvent(MCF_RECV, MCF_AUDIO, STREAM_EVENT_DEVICE_FAILURE, 0);
  953. m_bJammed = TRUE;
  954. m_bCanSignalOpen = TRUE;
  955. }
  956. }
  957. if (hr == S_OK)
  958. {
  959. if (m_DPFlags & DPFLAG_STARTED_RECV)
  960. {
  961. m_pDSBuf->Play(0,0,DSBPLAY_LOOPING);
  962. }
  963. if (m_bCanSignalOpen)
  964. {
  965. m_pDP->StreamEvent(MCF_RECV, MCF_AUDIO, STREAM_EVENT_DEVICE_OPEN, 0);
  966. m_bCanSignalOpen = FALSE; // don't signal open condition anymore
  967. }
  968. m_bJammed = FALSE;
  969. m_nFailCount = 0;
  970. }
  971. else
  972. {
  973. ReleaseDSBuffer();
  974. }
  975. return hr;
  976. }
  977. HRESULT
  978. RecvDSAudioStream::ReleaseDSBuffer()
  979. {
  980. m_fEmpty = TRUE;
  981. if (m_pDSBuf) {
  982. ULONG uref;
  983. uref = m_pDSBuf->Release();
  984. m_pDSBuf = NULL;
  985. //DEBUGMSG(ZONE_DP,("Releasing DirectSound buffer (%d)\n", uref));
  986. }
  987. if (m_pDS) {
  988. DirectSoundMgr::ReleaseInstance(m_pDS);
  989. m_pDS = NULL;
  990. if (m_DPFlags & DP_FLAG_HALF_DUPLEX)
  991. SetEvent(g_hEventHalfDuplex);
  992. }
  993. return S_OK;
  994. }
  995. HRESULT
  996. RecvDSAudioStream::Decode(UCHAR *pData, UINT cbData)
  997. {
  998. MMRESULT mmr;
  999. HRESULT hr=S_OK;
  1000. FX_ENTRY ("RecvDSAudioStream::Decode");
  1001. UINT uDstLength;
  1002. if (m_dwSrcSize < cbData)
  1003. {
  1004. DEBUGMSG (ZONE_DP, ("%s: RecvDSAudioStream::Decode failed - buffer larger than expected\r\n", _fx_));
  1005. return DPR_CONVERSION_FAILED;
  1006. }
  1007. CopyMemory(m_StrmConvHdr.pbSrc, pData, cbData);
  1008. m_StrmConvHdr.cbSrcLength = cbData;
  1009. mmr = m_pAudioFilter->Convert(&m_StrmConvHdr);
  1010. if (mmr != MMSYSERR_NOERROR)
  1011. {
  1012. DEBUGMSG (ZONE_DP, ("%s: acmStreamConvert failed, mmr=%ld\r\n", _fx_, (ULONG) mmr));
  1013. hr = DPR_CONVERSION_FAILED;
  1014. }
  1015. else
  1016. {
  1017. m_StrmConvHdr.dwDstUser = BUFFER_RECEIVED; // buffer is ready to play
  1018. // if receive side silence detection is turned on,
  1019. // check decoded buffer signal level
  1020. if (m_DPFlags & DP_FLAG_AUTO_SILENCE_DETECT)
  1021. {
  1022. if (m_AudioMonitor.SilenceDetect((WORD) GetSignalStrength()))
  1023. {
  1024. m_StrmConvHdr.dwDstUser = BUFFER_SILENT;
  1025. }
  1026. }
  1027. }
  1028. return hr;
  1029. // end
  1030. }
  1031. // insert the decoded buf at the appropriate location in the DirectSound buffer
  1032. HRESULT
  1033. RecvDSAudioStream::PlayBuf(DWORD timestamp, UINT seq, BOOL fMark)
  1034. {
  1035. UINT lenT = BYTESTOSAMPLES(m_StrmConvHdr.cbDstLengthUsed);
  1036. DWORD curPlayPosT, curWritePosT, curWriteLagT;
  1037. LPVOID p1, p2;
  1038. DWORD cb1, cb2;
  1039. HRESULT hr;
  1040. DWORD dwDSStatus = 0;
  1041. /*
  1042. All of the following are expressed in samples:
  1043. m_NextTimeT is timestamp of next expected packet. Usually timestamp equals m_NextT
  1044. m_BufSizeT is the total buffer size in samples.
  1045. m_NextPosT is the write position corresponding to m_NextT.
  1046. m_PlayPosT is the current play position
  1047. m_DelayT is the ideal playback delay
  1048. */
  1049. LOG((LOGMSG_DSTIME, GetTickCount()));
  1050. LOG((LOGMSG_DSENTRY, timestamp, seq, fMark));
  1051. m_pDSBuf->GetCurrentPosition(&curPlayPosT,&curWritePosT);
  1052. curPlayPosT = BYTESTOSAMPLES(curPlayPosT);
  1053. curWritePosT = BYTESTOSAMPLES(curWritePosT);
  1054. m_pDSBuf->GetStatus(&dwDSStatus);
  1055. if (!m_fEmpty)
  1056. {
  1057. // wasn't empty last time we checked but is it empty now?
  1058. if (QMOD(curPlayPosT-m_PlayPosT, m_BufSizeT) > QMOD(m_NextPosT-m_PlayPosT, m_BufSizeT))
  1059. {
  1060. // play cursor has advanced beyond the last written byte
  1061. m_fEmpty = TRUE;
  1062. LOG((LOGMSG_DSEMPTY, curPlayPosT, m_PlayPosT, m_NextPosT));
  1063. }
  1064. // write silence into the part of the buffer that just played
  1065. hr = m_pDSBuf->Lock(SAMPLESTOBYTES(m_PlayPosT),SAMPLESTOBYTES(QMOD(curPlayPosT-m_PlayPosT, m_BufSizeT)), &p1, &cb1, &p2, &cb2, 0);
  1066. if (hr == S_OK)
  1067. {
  1068. ZeroMemory(p1,cb1);
  1069. if (cb2)
  1070. ZeroMemory(p2,cb2);
  1071. m_pDSBuf->Unlock(p1,cb1,p2,cb2);
  1072. }
  1073. }
  1074. hr = S_OK;
  1075. // calculate minimum write-behind margin.
  1076. // This is low for native sound drivers and high for emulated drivers, so , assuming it's accurate
  1077. // there's no need to distinguish between emulated and native drivers.
  1078. curWriteLagT = QMOD(curWritePosT-curPlayPosT, m_BufSizeT);
  1079. if (m_fEmpty)
  1080. {
  1081. // the DS buffer only has silence in it. In this state, m_NextPosT and m_NextTimeT are irrelevant.
  1082. // We get to put the new buffer wherever we choose, so we put it m_DelayT after the current write position.
  1083. curWritePosT = QMOD(curWritePosT+m_DelayT, m_BufSizeT);
  1084. }
  1085. else
  1086. {
  1087. if (TS_EARLIER(timestamp, m_NextTimeT))
  1088. hr = DPR_OUT_OF_SEQUENCE; // act dumb and discard misordered packets
  1089. else
  1090. {
  1091. UINT curDelayT = QMOD(m_NextPosT - curPlayPosT, m_BufSizeT);
  1092. if (fMark)
  1093. {
  1094. // we have some leeway in choosing the insertion point, because this is the start of a talkspurt
  1095. if (curDelayT > m_DelayT + curWriteLagT)
  1096. {
  1097. // put it right after the last sample
  1098. curWritePosT = m_NextPosT;
  1099. }
  1100. else
  1101. {
  1102. // put it m_DelayT after the current write position
  1103. curWritePosT = QMOD(curWritePosT+m_DelayT, m_BufSizeT);
  1104. }
  1105. }
  1106. else
  1107. {
  1108. // bytes in
  1109. if ((timestamp-m_NextTimeT + curDelayT) < m_BufSizeT)
  1110. {
  1111. curWritePosT = QMOD(m_NextPosT +timestamp-m_NextTimeT, m_BufSizeT);
  1112. }
  1113. else
  1114. {
  1115. // overflow!! Could either dump whats in buffer or dump the packet
  1116. // dumping the packet is easier for now
  1117. hr = DPR_OUT_OF_SEQUENCE;
  1118. }
  1119. }
  1120. }
  1121. }
  1122. if ((dwDSStatus & DSBSTATUS_PLAYING) && (seq != INVALID_RTP_SEQ_NUMBER))
  1123. UpdateVariableDelay(timestamp,curPlayPosT );
  1124. // When receive silence detection is enabled:
  1125. // dont play the packet if we have received at least a quarter second of silent packets.
  1126. // This will enable switch to talk (in half-duplex mode).
  1127. if (m_StrmConvHdr.dwDstUser == BUFFER_SILENT)
  1128. m_SilenceDurationT += lenT;
  1129. else
  1130. m_SilenceDurationT = 0;
  1131. if (hr == S_OK && m_SilenceDurationT < m_fDevRecv.nSamplesPerSec/4)
  1132. {
  1133. LOG((LOGMSG_DSPLAY,curPlayPosT, curWritePosT, lenT));
  1134. // check if we have space for the whole packet
  1135. if (QMOD(curWritePosT-curPlayPosT, m_BufSizeT) > m_BufSizeT - lenT)
  1136. {
  1137. // no
  1138. curPlayPosT = QMOD(curWritePosT + lenT + 1000, m_BufSizeT);
  1139. hr = m_pDSBuf->SetCurrentPosition(SAMPLESTOBYTES(curPlayPosT));
  1140. LOG((LOGMSG_DSMOVPOS,curPlayPosT, hr));
  1141. }
  1142. hr = m_pDSBuf->Lock(SAMPLESTOBYTES(curWritePosT),m_StrmConvHdr.cbDstLengthUsed, &p1, &cb1, &p2, &cb2, 0);
  1143. if (hr == S_OK)
  1144. {
  1145. CopyMemory(p1, m_StrmConvHdr.pbDst, cb1);
  1146. if (cb2)
  1147. CopyMemory(p2, m_StrmConvHdr.pbDst+cb1, cb2);
  1148. m_pDSBuf->Unlock(p1,cb1,p2,cb2);
  1149. m_fEmpty = FALSE;
  1150. }
  1151. else
  1152. {
  1153. DEBUGMSG(ZONE_DP,("DirectSoundBuffer->Lock failed with %x\n",hr));
  1154. }
  1155. m_StrmConvHdr.dwDstUser = 0; // to indicate that the decode buffer is empty again
  1156. m_NextTimeT = timestamp + lenT;
  1157. m_NextPosT = QMOD(curWritePosT+lenT, m_BufSizeT);
  1158. // now calculate total queued length
  1159. lenT = QMOD(m_NextPosT- curPlayPosT, m_BufSizeT);
  1160. // Reset the timer to trigger shortly after the last valid sample has played
  1161. // The timer serves two purposes:
  1162. // - ensure that the DS buffer is silenced before it wraps around
  1163. // - allow the DS object to be released in the half-duplex case, once the remote stops sending
  1164. // convert to millisecs
  1165. // Need to make sure the timeout happens before the DS buffer wrapsaround.
  1166. if (lenT > m_BufSizeT/2)
  1167. lenT = m_BufSizeT/2;
  1168. lenT = lenT * 1000/ m_fDevRecv.nSamplesPerSec;
  1169. m_pDP->m_RecvTimer.CancelTimeout(&m_TimeoutObj);
  1170. m_TimeoutObj.SetDueTime(GetTickCount()+lenT+100);
  1171. m_pDP->m_RecvTimer.SetTimeout(&m_TimeoutObj);
  1172. }
  1173. m_PlayPosT = curPlayPosT;
  1174. return hr;
  1175. }
  1176. // This routine is called on every packet to perform the adaptive delay calculation
  1177. // Remote time is measured by the RTP timestamp and local time is measured by the DirectSound
  1178. // play pointer.
  1179. // The general idea is to average how much a packet is later than its 'expected' arrival time,
  1180. // assuming the packet with the shortest trip delay is dead on time.
  1181. //
  1182. void
  1183. RecvDSAudioStream::UpdateVariableDelay(DWORD sendT, DWORD curPlayPosT)
  1184. {
  1185. #define PLAYOUT_DELAY_FACTOR 2
  1186. LONG deltaA, deltaS;
  1187. DWORD delay;
  1188. // update arrival time based on how much the DS play pointer has advanced
  1189. // since the last packet
  1190. m_ArrT += QMOD(curPlayPosT-m_PlayPosT, m_BufSizeT);
  1191. // m_ArrivalT0 and m_SendT0 are the arrival and send timestamps of the packet
  1192. // with the shortest trip delay. We could have just stored (m_ArrivalT0 - m_SendT0)
  1193. // but since the local and remote clocks are completely unsynchronized, there would
  1194. // be signed/unsigned complications.
  1195. deltaS = sendT - m_SendT0;
  1196. deltaA = m_ArrT - m_ArrivalT0;
  1197. if (deltaA < deltaS // this packet took less time
  1198. || deltaA > (int)m_fDevRecv.nSamplesPerSec*8 // reset every 8 secs
  1199. || deltaS < -(int)m_fDevRecv.nSamplesPerSec // or after big timestamp jumps
  1200. )
  1201. {
  1202. delay = 0;
  1203. // delay = deltaS - deltaA
  1204. // replace shortest trip delay times
  1205. m_SendT0 = sendT;
  1206. m_ArrivalT0 = m_ArrT;
  1207. } else {
  1208. // variable delay is how much longer this packet took
  1209. delay = deltaA - deltaS;
  1210. }
  1211. // now update average variable delay according to
  1212. // m_AvgVarDelay = m_AvgVarDelay + (delay - m_AvgVarDelay)*1/16;
  1213. // however we are storing the scaled average, with a scaling
  1214. // factor of 16. So the calculation becomes
  1215. m_ScaledAvgVarDelay = m_ScaledAvgVarDelay + (delay - m_ScaledAvgVarDelay/16);
  1216. // now calculate actual buffering delay we will use
  1217. // MinDelay adds some slack (may be necessary for some drivers)
  1218. m_DelayT = m_MinDelayT + PLAYOUT_DELAY_FACTOR * m_ScaledAvgVarDelay/16;
  1219. if (m_DelayT > m_MaxDelayT) m_DelayT = m_MaxDelayT;
  1220. LOG((LOGMSG_JITTER,delay, m_ScaledAvgVarDelay/16, m_DelayT));
  1221. UPDATE_COUNTER(g_pctrAudioJBDelay, (m_DelayT * 1000)/m_fDevRecv.nSamplesPerSec);
  1222. }
  1223. void
  1224. RecvDSAudioStream::RecvTimeout()
  1225. {
  1226. DWORD curPlayPosT, curWritePosT;
  1227. LPVOID p1, p2;
  1228. DWORD cb1, cb2;
  1229. UINT lenT;
  1230. HRESULT hr;
  1231. if (m_pDSBuf == NULL)
  1232. {
  1233. WARNING_OUT(("RecvDSAudioStream::RecvTimeout - DirectSoundBuffer is not valid\r\n"));
  1234. return;
  1235. }
  1236. m_pDSBuf->GetCurrentPosition(&curPlayPosT,&curWritePosT);
  1237. curPlayPosT = BYTESTOSAMPLES(curPlayPosT);
  1238. curWritePosT = BYTESTOSAMPLES(curWritePosT);
  1239. // this part is cut and pasted from PlayBuf
  1240. if (!m_fEmpty) {
  1241. // wasn't empty last time we checked but is it empty now?
  1242. if (QMOD(curPlayPosT-m_PlayPosT, m_BufSizeT) > QMOD(m_NextPosT-m_PlayPosT, m_BufSizeT)) {
  1243. // play cursor has advanced beyond the last written byte
  1244. m_fEmpty = TRUE;
  1245. }
  1246. // write silence into the part of the buffer that just played
  1247. hr = m_pDSBuf->Lock(SAMPLESTOBYTES(m_PlayPosT),SAMPLESTOBYTES(QMOD(curPlayPosT-m_PlayPosT, m_BufSizeT)), &p1, &cb1, &p2, &cb2, 0);
  1248. if (hr == S_OK) {
  1249. ZeroMemory(p1,cb1);
  1250. if (cb2)
  1251. ZeroMemory(p2,cb2);
  1252. m_pDSBuf->Unlock(p1,cb1,p2,cb2);
  1253. }
  1254. }
  1255. LOG((LOGMSG_DSTIMEOUT, curPlayPosT, m_NextPosT, GetTickCount()));
  1256. m_PlayPosT = curPlayPosT;
  1257. if (!m_fEmpty) {
  1258. // The buffer isnt quite empty yet!
  1259. // Reschedule??
  1260. DEBUGMSG(ZONE_DP,("DSBuffer not empty after timeout\n"));
  1261. lenT = QMOD(m_NextPosT- curPlayPosT, m_BufSizeT);
  1262. // Reset the timer to trigger shortly after the last valid sample has played
  1263. // Need to make sure the timeout happens before the DS buffer wrapsaround.
  1264. if (lenT > m_BufSizeT/2)
  1265. lenT = m_BufSizeT/2;
  1266. // convert to millisecs
  1267. lenT = lenT * 1000/ m_fDevRecv.nSamplesPerSec;
  1268. m_TimeoutObj.SetDueTime(GetTickCount()+lenT+100);
  1269. m_pDP->m_RecvTimer.SetTimeout(&m_TimeoutObj);
  1270. }
  1271. else if (m_DPFlags & DP_FLAG_HALF_DUPLEX)
  1272. {
  1273. // need to release the DSBuffer and DSObject
  1274. ReleaseDSBuffer();
  1275. }
  1276. }
  1277. HRESULT RecvDSAudioStream::RTPCallback(WSABUF *pWsaBuf, DWORD timestamp, UINT seq, UINT fMark)
  1278. {
  1279. HRESULT hr;
  1280. if (m_ThreadFlags & DPTFLAG_PAUSE_RECV)
  1281. {
  1282. return E_FAIL;
  1283. }
  1284. // update number of bits received
  1285. UPDATE_COUNTER(g_pctrAudioReceiveBytes,(pWsaBuf->len + IP_HEADER_SIZE + UDP_HEADER_SIZE)*8);
  1286. hr = Decode((BYTE *)pWsaBuf->buf + sizeof(RTP_HDR), pWsaBuf->len - sizeof(RTP_HDR));
  1287. if (hr == S_OK )
  1288. {
  1289. // Have we initialized DirectSound?
  1290. // Yes, unless its half-duplex
  1291. if (!m_pDSBuf)
  1292. {
  1293. hr = CreateDSBuffer();
  1294. }
  1295. if (hr == S_OK)
  1296. {
  1297. PlayBuf(timestamp, seq, fMark);
  1298. }
  1299. }
  1300. m_pIRTPRecv->FreePacket(pWsaBuf);
  1301. return S_OK;
  1302. }
  1303. // this method called from the UI thread only
  1304. HRESULT RecvDSAudioStream::DTMFBeep()
  1305. {
  1306. if ( (!(m_DPFlags & DPFLAG_STARTED_RECV)) ||
  1307. (m_ThreadFlags & DPTFLAG_PAUSE_RECV) )
  1308. {
  1309. return E_FAIL;
  1310. }
  1311. m_pDP->RecvThreadMessage(MSG_PLAY_SOUND, this);
  1312. return S_OK;
  1313. }
  1314. HRESULT RecvDSAudioStream::OnDTMFBeep()
  1315. {
  1316. int nBeeps;
  1317. DWORD dwBufSize = m_StrmConvHdr.cbDstLength;
  1318. HRESULT hr=S_OK;
  1319. int nIndex;
  1320. if ( (!(m_DPFlags & DPFLAG_STARTED_RECV)) ||
  1321. (m_ThreadFlags & DPTFLAG_PAUSE_RECV) )
  1322. {
  1323. return E_FAIL;
  1324. }
  1325. if (dwBufSize == 0)
  1326. {
  1327. return E_FAIL;
  1328. }
  1329. nBeeps = DTMF_FEEDBACK_BEEP_MS / ((dwBufSize * 1000) / m_fDevRecv.nAvgBytesPerSec);
  1330. if (nBeeps == 0)
  1331. {
  1332. nBeeps = 1;
  1333. }
  1334. MakeDTMFBeep(&m_fDevRecv, m_StrmConvHdr.pbDst , m_StrmConvHdr.cbDstLength);
  1335. if (!m_pDSBuf)
  1336. {
  1337. hr = CreateDSBuffer();
  1338. if (FAILED(hr))
  1339. {
  1340. return hr;
  1341. }
  1342. }
  1343. m_StrmConvHdr.dwDstUser = BUFFER_RECEIVED;
  1344. PlayBuf(m_NextTimeT , INVALID_RTP_SEQ_NUMBER, true);
  1345. nBeeps--;
  1346. for (nIndex = 0; nIndex < nBeeps; nIndex++)
  1347. {
  1348. m_StrmConvHdr.dwDstUser = BUFFER_RECEIVED;
  1349. PlayBuf(m_NextTimeT, INVALID_RTP_SEQ_NUMBER, false);
  1350. }
  1351. return S_OK;
  1352. }
  1353.