DSoundVoiceAdapter.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. /*
  2. * Copyright (c) 2014, Oculus VR, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. #include "DSoundVoiceAdapter.h"
  11. #include "RakAssert.h"
  12. #include "RakPeerInterface.h"
  13. /// To test sending to myself
  14. //#define _TEST_LOOPBACK
  15. using namespace RakNet;
  16. DSoundVoiceAdapter DSoundVoiceAdapter::instance;
  17. DSoundVoiceAdapter::DSoundVoiceAdapter()
  18. {
  19. rakVoice = 0;
  20. ds = 0;
  21. dsC = 0;
  22. dsbIncoming = 0;
  23. dsbOutgoing = 0;
  24. mute = false;
  25. memset(incomingBufferNotifications,0,sizeof(incomingBufferNotifications));
  26. memset(outgoingBufferNotifications,0,sizeof(outgoingBufferNotifications));
  27. }
  28. DSoundVoiceAdapter* DSoundVoiceAdapter::Instance()
  29. {
  30. return &instance;
  31. }
  32. bool DSoundVoiceAdapter::SetupAdapter(RakVoice *rakVoice, HWND hwnd, DWORD dwCoopLevel)
  33. {
  34. // Check if it was already initialized
  35. RakAssert(ds == 0);
  36. if (ds != 0)
  37. return false;
  38. HRESULT hr;
  39. if (FAILED(hr = DirectSoundCreate8(NULL, &ds, NULL)))
  40. {
  41. DXTRACE_ERR_MSGBOX(L"DirectSoundCreate8, when initiliazing DirectSound", hr);
  42. return false;
  43. }
  44. if (FAILED(hr = ds->SetCooperativeLevel(hwnd, dwCoopLevel)))
  45. {
  46. DXTRACE_ERR_MSGBOX(L"IDirectSound8::SetCooperativeLevel", hr);
  47. Release();
  48. return false;
  49. }
  50. // Check if the rest of the initialization fails, and if so, release any allocated resources
  51. if (SetupAdapter(rakVoice))
  52. {
  53. return true;
  54. }
  55. else
  56. {
  57. Release();
  58. return false;
  59. }
  60. }
  61. bool DSoundVoiceAdapter::SetupAdapter(RakVoice *rakVoice, IDirectSound8 *pDS)
  62. {
  63. // Check if it was already initialized
  64. RakAssert(ds == 0);
  65. if (ds != 0)
  66. return false;
  67. // User provided his own device object, so use it and add another reference
  68. pDS->AddRef();
  69. ds = pDS;
  70. // Check if the rest of the initialization fails, and if so, release any allocated resources
  71. if (SetupAdapter(rakVoice))
  72. {
  73. return true;
  74. }
  75. else
  76. {
  77. Release();
  78. return false;
  79. }
  80. }
  81. bool DSoundVoiceAdapter::SetupAdapter(RakVoice *rakVoice)
  82. {
  83. RakAssert(rakVoice);
  84. // Make sure rakVoice was initialized
  85. RakAssert((rakVoice->IsInitialized())&&(rakVoice->GetRakPeerInterface()!=NULL));
  86. this->rakVoice = rakVoice;
  87. if (!SetupIncomingBuffer())
  88. return false;
  89. return SetupOutgoingBuffer();
  90. }
  91. bool DSoundVoiceAdapter::SetupIncomingBuffer()
  92. {
  93. //
  94. //
  95. // Create the buffer for incoming sound
  96. //
  97. //
  98. WAVEFORMATEX wfx;
  99. DSBUFFERDESC dsbdesc;
  100. LPDIRECTSOUNDBUFFER pDsb = NULL;
  101. HRESULT hr;
  102. // Set up WAV format structure.
  103. memset(&wfx, 0, sizeof(WAVEFORMATEX));
  104. wfx.wFormatTag = WAVE_FORMAT_PCM;
  105. wfx.nChannels = 1;
  106. wfx.nSamplesPerSec = rakVoice->GetSampleRate();
  107. wfx.nBlockAlign = 2;
  108. wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
  109. wfx.wBitsPerSample = 16;
  110. // Set up DSBUFFERDESC structure.
  111. memset(&dsbdesc, 0, sizeof(DSBUFFERDESC));
  112. dsbdesc.dwSize = sizeof(DSBUFFERDESC);
  113. dsbdesc.dwFlags = DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLPOSITIONNOTIFY
  114. | DSBCAPS_LOCSOFTWARE; // Create in software, because DX documentation says its the best option when using notifications
  115. dsbdesc.dwBufferBytes = rakVoice->GetBufferSizeBytes()*FRAMES_IN_SOUND;
  116. dsbdesc.lpwfxFormat = &wfx;
  117. // Create buffer.
  118. if (FAILED(hr = ds->CreateSoundBuffer(&dsbdesc, &pDsb, NULL)))
  119. {
  120. DXTRACE_ERR_MSGBOX(L"IDirectSound8::CreateSoundBuffer, when creating buffer for incoming sound )", hr);
  121. return false;
  122. }
  123. hr = pDsb->QueryInterface(IID_IDirectSoundBuffer8, (LPVOID*) &dsbIncoming);
  124. pDsb->Release();
  125. if (FAILED(hr))
  126. {
  127. DXTRACE_ERR_MSGBOX(L"IDirectSoundBuffer::QueryInterface, when getting IDirectSoundBuffer8 interface for incoming sound", hr);
  128. return false;
  129. }
  130. //
  131. // Setup the notification events
  132. //
  133. for (int i=0; i<FRAMES_IN_SOUND; i++)
  134. {
  135. incomingBufferNotifications[i].dwOffset = i*rakVoice->GetBufferSizeBytes();
  136. #if defined(WINDOWS_PHONE_8)
  137. if ((incomingBufferNotifications[i].hEventNotify = CreateEventEx(0, 0, CREATE_EVENT_MANUAL_RESET, 0))==NULL)
  138. #else
  139. if ((incomingBufferNotifications[i].hEventNotify = CreateEvent(NULL, TRUE, FALSE, NULL))==NULL)
  140. #endif
  141. {
  142. DXTRACE_ERR_MSGBOX(L"CreateEvent", GetLastError());
  143. return false;
  144. }
  145. }
  146. IDirectSoundNotify8 *dsbNotify=0;
  147. if (FAILED(hr=dsbIncoming->QueryInterface(IID_IDirectSoundNotify8, (LPVOID*) &dsbNotify)))
  148. {
  149. DXTRACE_ERR_MSGBOX(L"IDirectSoundBuffer8::QueryInterface, when getting IDirectSoundNotify8 interface for incoming sound", hr);
  150. return false;
  151. }
  152. hr = dsbNotify->SetNotificationPositions(FRAMES_IN_SOUND, incomingBufferNotifications);
  153. dsbNotify->Release();
  154. if (FAILED(hr))
  155. {
  156. DXTRACE_ERR_MSGBOX(L"IDirectSoundNotify8::SetNotificationPositions, when setting notifications for incoming sound", hr);
  157. return false;
  158. }
  159. if (FAILED(hr = dsbIncoming->Play(0,0,DSBPLAY_LOOPING)))
  160. {
  161. DXTRACE_ERR_MSGBOX(L"IDirectSoundBuffer8::Play, when starting incoming sound buffer", hr);
  162. return false;
  163. }
  164. return true;
  165. }
  166. bool DSoundVoiceAdapter::SetupOutgoingBuffer()
  167. {
  168. HRESULT hr;
  169. //
  170. //
  171. // Create the buffer for outgoing sound
  172. //
  173. //
  174. if (FAILED(hr=DirectSoundCaptureCreate8(NULL, &dsC, NULL)))
  175. {
  176. DXTRACE_ERR_MSGBOX(L"DirectSoundCaptureCreate8", hr);
  177. return false;
  178. }
  179. // Set up WAV format structure.
  180. WAVEFORMATEX wfx;
  181. memset(&wfx, 0, sizeof(WAVEFORMATEX));
  182. wfx.wFormatTag = WAVE_FORMAT_PCM;
  183. wfx.nChannels = 1;
  184. wfx.nSamplesPerSec = rakVoice->GetSampleRate();
  185. wfx.nBlockAlign = 2;
  186. wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
  187. wfx.wBitsPerSample = 16;
  188. // Set up DSCBUFFERDESC structure.
  189. DSCBUFFERDESC dscbd;
  190. memset(&dscbd, 0, sizeof(DSCBUFFERDESC));
  191. dscbd.dwSize = sizeof(DSCBUFFERDESC);
  192. dscbd.dwFlags = 0;
  193. dscbd.dwBufferBytes = rakVoice->GetBufferSizeBytes()*FRAMES_IN_SOUND;
  194. dscbd.dwReserved = 0;
  195. dscbd.lpwfxFormat = &wfx;
  196. dscbd.dwFXCount = 0;
  197. dscbd.lpDSCFXDesc = NULL;
  198. // Create capture buffer.
  199. LPDIRECTSOUNDCAPTUREBUFFER pDscb = NULL;
  200. if (FAILED(hr = dsC->CreateCaptureBuffer(&dscbd, &pDscb, NULL)))
  201. {
  202. DXTRACE_ERR_MSGBOX(L"IDirectSoundCapture8::CreateCaptureBuffer, when creating buffer for outgoing sound )", hr);
  203. return false;
  204. }
  205. hr = pDscb->QueryInterface(IID_IDirectSoundCaptureBuffer8, (LPVOID*) &dsbOutgoing);
  206. pDscb->Release();
  207. if (FAILED(hr))
  208. {
  209. DXTRACE_ERR_MSGBOX(L"IDirectSoundBuffer::QueryInterface, when getting IDirectSoundCaptureBuffer8 interface for outgoing sound", hr);
  210. return false;
  211. }
  212. //
  213. // Setup the notification events
  214. //
  215. for (int i=0; i<FRAMES_IN_SOUND; i++)
  216. {
  217. outgoingBufferNotifications[i].dwOffset = i*rakVoice->GetBufferSizeBytes();
  218. if ((outgoingBufferNotifications[i].hEventNotify = CreateEventEx(0, 0, CREATE_EVENT_MANUAL_RESET, 0))==NULL)
  219. {
  220. DXTRACE_ERR_MSGBOX(L"CreateEvent", GetLastError());
  221. return false;
  222. }
  223. }
  224. IDirectSoundNotify8 *dsbNotify=0;
  225. if (FAILED(hr=dsbOutgoing->QueryInterface(IID_IDirectSoundNotify8, (LPVOID*) &dsbNotify)))
  226. {
  227. DXTRACE_ERR_MSGBOX(L"IDirectSoundCaptureBuffer8::QueryInterface, when getting IDirectSoundNotify8 interface for outgoing sound", hr);
  228. return false;
  229. }
  230. hr = dsbNotify->SetNotificationPositions(FRAMES_IN_SOUND, outgoingBufferNotifications);
  231. dsbNotify->Release();
  232. if (FAILED(hr))
  233. {
  234. DXTRACE_ERR_MSGBOX(L"IDirectSoundNotify8::SetNotificationPositions, when setting notifications for outgoing sound", hr);
  235. return false;
  236. }
  237. if (FAILED(hr = dsbOutgoing->Start(DSCBSTART_LOOPING)))
  238. {
  239. DXTRACE_ERR_MSGBOX(L"IDirectSoundCaptureBuffer8::Start, when starting outgoing sound buffer", hr);
  240. return false;
  241. }
  242. return true;
  243. }
  244. void DSoundVoiceAdapter::Release()
  245. {
  246. // Release DirectSound buffer used for incoming voice
  247. if (dsbIncoming)
  248. {
  249. dsbIncoming->Stop();
  250. dsbIncoming->Release();
  251. dsbIncoming = 0;
  252. }
  253. // Release DirectSound buffer used for outgoing voice
  254. if (dsbOutgoing)
  255. {
  256. dsbOutgoing->Stop();
  257. dsbOutgoing->Release();
  258. dsbOutgoing = 0;
  259. }
  260. // Release DirectSound device object
  261. if (ds)
  262. {
  263. ds->Release();
  264. ds = 0;
  265. }
  266. if (dsC)
  267. {
  268. dsC->Release();
  269. dsC = 0;
  270. }
  271. // Release the notification events
  272. for (int i=0; i<FRAMES_IN_SOUND;i++)
  273. {
  274. if (incomingBufferNotifications[i].hEventNotify!=0 && CloseHandle(incomingBufferNotifications[i].hEventNotify)==0)
  275. {
  276. DXTRACE_ERR_MSGBOX(L"CloseHandle", GetLastError());
  277. }
  278. if (outgoingBufferNotifications[i].hEventNotify!=0 && CloseHandle(outgoingBufferNotifications[i].hEventNotify)==0)
  279. {
  280. DXTRACE_ERR_MSGBOX(L"CloseHandle", GetLastError());
  281. }
  282. }
  283. memset(incomingBufferNotifications,0, sizeof(incomingBufferNotifications));
  284. memset(outgoingBufferNotifications,0, sizeof(outgoingBufferNotifications));
  285. }
  286. IDirectSound8* DSoundVoiceAdapter::GetDSDeviceObject()
  287. {
  288. return ds;
  289. }
  290. void DSoundVoiceAdapter::Update()
  291. {
  292. HRESULT hr;
  293. void *audioPtr;
  294. DWORD audioPtrbytes;
  295. for (int i=0; i<FRAMES_IN_SOUND; i++)
  296. {
  297. //
  298. // Update incoming sound
  299. //
  300. if (WaitForSingleObject(incomingBufferNotifications[i].hEventNotify, 0)==WAIT_OBJECT_0)
  301. {
  302. // The lock offset is the buffer right before the one the event refers to
  303. DWORD dwOffset = (i==0) ? incomingBufferNotifications[FRAMES_IN_SOUND-1].dwOffset : incomingBufferNotifications[i-1].dwOffset;
  304. hr = dsbIncoming->Lock(dwOffset, rakVoice->GetBufferSizeBytes(), &audioPtr, &audioPtrbytes, NULL, NULL, 0);
  305. RakAssert(audioPtrbytes==rakVoice->GetBufferSizeBytes());
  306. if (SUCCEEDED(hr))
  307. {
  308. rakVoice->ReceiveFrame(audioPtr);
  309. dsbIncoming->Unlock(audioPtr, audioPtrbytes, NULL, 0);
  310. }
  311. ResetEvent(incomingBufferNotifications[i].hEventNotify);
  312. }
  313. //
  314. // Update outgoing sound
  315. //
  316. if (WaitForSingleObject(outgoingBufferNotifications[i].hEventNotify, 0)==WAIT_OBJECT_0)
  317. {
  318. /* If we're set to mute, we don't send anything, and just reset the event */
  319. if (!mute)
  320. {
  321. // The lock offset is the buffer right before the one the event refers to
  322. DWORD dwOffset = (i==0) ? outgoingBufferNotifications[FRAMES_IN_SOUND-1].dwOffset : outgoingBufferNotifications[i-1].dwOffset;
  323. hr = dsbOutgoing->Lock(dwOffset, rakVoice->GetBufferSizeBytes(), &audioPtr, &audioPtrbytes, NULL, NULL, 0);
  324. RakAssert(audioPtrbytes==rakVoice->GetBufferSizeBytes());
  325. if (SUCCEEDED(hr))
  326. {
  327. BroadcastFrame(audioPtr);
  328. dsbOutgoing->Unlock(audioPtr, audioPtrbytes, NULL, 0);
  329. }
  330. }
  331. ResetEvent(outgoingBufferNotifications[i].hEventNotify);
  332. }
  333. }
  334. }
  335. void DSoundVoiceAdapter::BroadcastFrame(void *ptr)
  336. {
  337. #ifndef _TEST_LOOPBACK
  338. unsigned i;
  339. unsigned int numPeers = rakVoice->GetRakPeerInterface()->GetMaximumNumberOfPeers();
  340. for (i=0; i < numPeers; i++)
  341. {
  342. rakVoice->SendFrame(rakVoice->GetRakPeerInterface()->GetGUIDFromIndex(i), ptr);
  343. }
  344. #else
  345. rakVoice->SendFrame(RakNet::UNASSIGNED_SYSTEM_ADDRESS, ptr);
  346. #endif
  347. }
  348. void DSoundVoiceAdapter::SetMute(bool mute)
  349. {
  350. this->mute = mute;
  351. }
粤ICP备19079148号