dsound.c 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024
  1. /**
  2. * OpenAL cross platform audio library
  3. * Copyright (C) 1999-2007 by authors.
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Library General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public
  15. * License along with this library; if not, write to the
  16. * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  17. * Boston, MA 02111-1307, USA.
  18. * Or go to http://www.gnu.org/copyleft/lgpl.html
  19. */
  20. #include "config.h"
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <memory.h>
  24. #include <dsound.h>
  25. #include <cguid.h>
  26. #include <mmreg.h>
  27. #ifndef _WAVEFORMATEXTENSIBLE_
  28. #include <ks.h>
  29. #include <ksmedia.h>
  30. #endif
  31. #include "alMain.h"
  32. #include "AL/al.h"
  33. #include "AL/alc.h"
  34. #ifndef DSSPEAKER_5POINT1
  35. #define DSSPEAKER_5POINT1 6
  36. #endif
  37. #ifndef DSSPEAKER_7POINT1
  38. #define DSSPEAKER_7POINT1 7
  39. #endif
  40. DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
  41. DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
  42. static void *ds_handle;
  43. static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID pcGuidDevice, IDirectSound **ppDS, IUnknown *pUnkOuter);
  44. static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, void *pContext);
  45. static HRESULT (WINAPI *pDirectSoundCaptureCreate)(LPCGUID pcGuidDevice, IDirectSoundCapture **ppDSC, IUnknown *pUnkOuter);
  46. static HRESULT (WINAPI *pDirectSoundCaptureEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, void *pContext);
  47. #define DirectSoundCreate pDirectSoundCreate
  48. #define DirectSoundEnumerateA pDirectSoundEnumerateA
  49. #define DirectSoundCaptureCreate pDirectSoundCaptureCreate
  50. #define DirectSoundCaptureEnumerateA pDirectSoundCaptureEnumerateA
  51. typedef struct {
  52. // DirectSound Playback Device
  53. IDirectSound *lpDS;
  54. IDirectSoundBuffer *DSpbuffer;
  55. IDirectSoundBuffer *DSsbuffer;
  56. IDirectSoundNotify *DSnotify;
  57. HANDLE hNotifyEvent;
  58. volatile int killNow;
  59. ALvoid *thread;
  60. } DSoundPlaybackData;
  61. typedef struct {
  62. // DirectSound Capture Device
  63. IDirectSoundCapture *lpDSC;
  64. IDirectSoundCaptureBuffer *DSCbuffer;
  65. DWORD dwBufferBytes;
  66. DWORD dwCursor;
  67. RingBuffer *pRing;
  68. } DSoundCaptureData;
  69. typedef struct {
  70. ALCchar *name;
  71. GUID guid;
  72. } DevMap;
  73. static DevMap *PlaybackDeviceList;
  74. static ALuint NumPlaybackDevices;
  75. static DevMap *CaptureDeviceList;
  76. static ALuint NumCaptureDevices;
  77. #define MAX_UPDATES 128
  78. static ALCboolean DSoundLoad(void)
  79. {
  80. if(!ds_handle)
  81. {
  82. ds_handle = LoadLib("dsound.dll");
  83. if(ds_handle == NULL)
  84. {
  85. ERR("Failed to load dsound.dll\n");
  86. return ALC_FALSE;
  87. }
  88. #define LOAD_FUNC(f) do { \
  89. p##f = GetSymbol(ds_handle, #f); \
  90. if(p##f == NULL) { \
  91. CloseLib(ds_handle); \
  92. ds_handle = NULL; \
  93. return ALC_FALSE; \
  94. } \
  95. } while(0)
  96. LOAD_FUNC(DirectSoundCreate);
  97. LOAD_FUNC(DirectSoundEnumerateA);
  98. LOAD_FUNC(DirectSoundCaptureCreate);
  99. LOAD_FUNC(DirectSoundCaptureEnumerateA);
  100. #undef LOAD_FUNC
  101. }
  102. return ALC_TRUE;
  103. }
  104. static BOOL CALLBACK DSoundEnumPlaybackDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
  105. {
  106. LPOLESTR guidstr = NULL;
  107. char str[1024];
  108. HRESULT hr;
  109. void *temp;
  110. int count;
  111. ALuint i;
  112. (void)data;
  113. (void)drvname;
  114. if(!guid)
  115. return TRUE;
  116. count = 0;
  117. do {
  118. if(count == 0)
  119. snprintf(str, sizeof(str), "%s", desc);
  120. else
  121. snprintf(str, sizeof(str), "%s #%d", desc, count+1);
  122. count++;
  123. for(i = 0;i < NumPlaybackDevices;i++)
  124. {
  125. if(strcmp(str, PlaybackDeviceList[i].name) == 0)
  126. break;
  127. }
  128. } while(i != NumPlaybackDevices);
  129. hr = StringFromCLSID(guid, &guidstr);
  130. if(SUCCEEDED(hr))
  131. {
  132. TRACE("Got device \"%s\", GUID \"%ls\"\n", str, guidstr);
  133. CoTaskMemFree(guidstr);
  134. }
  135. temp = realloc(PlaybackDeviceList, sizeof(DevMap) * (NumPlaybackDevices+1));
  136. if(temp)
  137. {
  138. PlaybackDeviceList = temp;
  139. PlaybackDeviceList[NumPlaybackDevices].name = strdup(str);
  140. PlaybackDeviceList[NumPlaybackDevices].guid = *guid;
  141. NumPlaybackDevices++;
  142. }
  143. return TRUE;
  144. }
  145. static BOOL CALLBACK DSoundEnumCaptureDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
  146. {
  147. LPOLESTR guidstr = NULL;
  148. char str[1024];
  149. HRESULT hr;
  150. void *temp;
  151. int count;
  152. ALuint i;
  153. (void)data;
  154. (void)drvname;
  155. if(!guid)
  156. return TRUE;
  157. count = 0;
  158. do {
  159. if(count == 0)
  160. snprintf(str, sizeof(str), "%s", desc);
  161. else
  162. snprintf(str, sizeof(str), "%s #%d", desc, count+1);
  163. count++;
  164. for(i = 0;i < NumCaptureDevices;i++)
  165. {
  166. if(strcmp(str, CaptureDeviceList[i].name) == 0)
  167. break;
  168. }
  169. } while(i != NumCaptureDevices);
  170. hr = StringFromCLSID(guid, &guidstr);
  171. if(SUCCEEDED(hr))
  172. {
  173. TRACE("Got device \"%s\", GUID \"%ls\"\n", str, guidstr);
  174. CoTaskMemFree(guidstr);
  175. }
  176. temp = realloc(CaptureDeviceList, sizeof(DevMap) * (NumCaptureDevices+1));
  177. if(temp)
  178. {
  179. CaptureDeviceList = temp;
  180. CaptureDeviceList[NumCaptureDevices].name = strdup(str);
  181. CaptureDeviceList[NumCaptureDevices].guid = *guid;
  182. NumCaptureDevices++;
  183. }
  184. return TRUE;
  185. }
  186. static ALuint DSoundPlaybackProc(ALvoid *ptr)
  187. {
  188. ALCdevice *pDevice = (ALCdevice*)ptr;
  189. DSoundPlaybackData *pData = (DSoundPlaybackData*)pDevice->ExtraData;
  190. DSBCAPS DSBCaps;
  191. DWORD LastCursor = 0;
  192. DWORD PlayCursor;
  193. VOID *WritePtr1, *WritePtr2;
  194. DWORD WriteCnt1, WriteCnt2;
  195. BOOL Playing = FALSE;
  196. DWORD FrameSize;
  197. DWORD FragSize;
  198. DWORD avail;
  199. HRESULT err;
  200. SetRTPriority();
  201. memset(&DSBCaps, 0, sizeof(DSBCaps));
  202. DSBCaps.dwSize = sizeof(DSBCaps);
  203. err = IDirectSoundBuffer_GetCaps(pData->DSsbuffer, &DSBCaps);
  204. if(FAILED(err))
  205. {
  206. ERR("Failed to get buffer caps: 0x%lx\n", err);
  207. aluHandleDisconnect(pDevice);
  208. return 1;
  209. }
  210. FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
  211. FragSize = pDevice->UpdateSize * FrameSize;
  212. IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &LastCursor, NULL);
  213. while(!pData->killNow)
  214. {
  215. // Get current play cursor
  216. IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL);
  217. avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes;
  218. if(avail < FragSize)
  219. {
  220. if(!Playing)
  221. {
  222. err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING);
  223. if(FAILED(err))
  224. {
  225. ERR("Failed to play buffer: 0x%lx\n", err);
  226. aluHandleDisconnect(pDevice);
  227. return 1;
  228. }
  229. Playing = TRUE;
  230. }
  231. avail = WaitForSingleObjectEx(pData->hNotifyEvent, 2000, FALSE);
  232. if(avail != WAIT_OBJECT_0)
  233. ERR("WaitForSingleObjectEx error: 0x%lx\n", avail);
  234. continue;
  235. }
  236. avail -= avail%FragSize;
  237. // Lock output buffer
  238. WriteCnt1 = 0;
  239. WriteCnt2 = 0;
  240. err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
  241. // If the buffer is lost, restore it and lock
  242. if(err == DSERR_BUFFERLOST)
  243. {
  244. WARN("Buffer lost, restoring...\n");
  245. err = IDirectSoundBuffer_Restore(pData->DSsbuffer);
  246. if(SUCCEEDED(err))
  247. {
  248. Playing = FALSE;
  249. LastCursor = 0;
  250. err = IDirectSoundBuffer_Lock(pData->DSsbuffer, 0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
  251. }
  252. }
  253. // Successfully locked the output buffer
  254. if(SUCCEEDED(err))
  255. {
  256. // If we have an active context, mix data directly into output buffer otherwise fill with silence
  257. aluMixData(pDevice, WritePtr1, WriteCnt1/FrameSize);
  258. aluMixData(pDevice, WritePtr2, WriteCnt2/FrameSize);
  259. // Unlock output buffer only when successfully locked
  260. IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
  261. }
  262. else
  263. {
  264. ERR("Buffer lock error: %#lx\n", err);
  265. aluHandleDisconnect(pDevice);
  266. return 1;
  267. }
  268. // Update old write cursor location
  269. LastCursor += WriteCnt1+WriteCnt2;
  270. LastCursor %= DSBCaps.dwBufferBytes;
  271. }
  272. return 0;
  273. }
  274. static ALCenum DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
  275. {
  276. DSoundPlaybackData *pData = NULL;
  277. LPGUID guid = NULL;
  278. HRESULT hr;
  279. if(!PlaybackDeviceList)
  280. {
  281. hr = DirectSoundEnumerateA(DSoundEnumPlaybackDevices, NULL);
  282. if(FAILED(hr))
  283. ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
  284. }
  285. if(!deviceName && NumPlaybackDevices > 0)
  286. {
  287. deviceName = PlaybackDeviceList[0].name;
  288. guid = &PlaybackDeviceList[0].guid;
  289. }
  290. else
  291. {
  292. ALuint i;
  293. for(i = 0;i < NumPlaybackDevices;i++)
  294. {
  295. if(strcmp(deviceName, PlaybackDeviceList[i].name) == 0)
  296. {
  297. guid = &PlaybackDeviceList[i].guid;
  298. break;
  299. }
  300. }
  301. if(i == NumPlaybackDevices)
  302. return ALC_INVALID_VALUE;
  303. }
  304. //Initialise requested device
  305. pData = calloc(1, sizeof(DSoundPlaybackData));
  306. if(!pData)
  307. return ALC_OUT_OF_MEMORY;
  308. hr = DS_OK;
  309. pData->hNotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  310. if(pData->hNotifyEvent == NULL)
  311. hr = E_FAIL;
  312. //DirectSound Init code
  313. if(SUCCEEDED(hr))
  314. hr = DirectSoundCreate(guid, &pData->lpDS, NULL);
  315. if(SUCCEEDED(hr))
  316. hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY);
  317. if(FAILED(hr))
  318. {
  319. if(pData->lpDS)
  320. IDirectSound_Release(pData->lpDS);
  321. if(pData->hNotifyEvent)
  322. CloseHandle(pData->hNotifyEvent);
  323. free(pData);
  324. ERR("Device init failed: 0x%08lx\n", hr);
  325. return ALC_INVALID_VALUE;
  326. }
  327. device->szDeviceName = strdup(deviceName);
  328. device->ExtraData = pData;
  329. return ALC_NO_ERROR;
  330. }
  331. static void DSoundClosePlayback(ALCdevice *device)
  332. {
  333. DSoundPlaybackData *pData = device->ExtraData;
  334. if(pData->DSnotify)
  335. IDirectSoundNotify_Release(pData->DSnotify);
  336. pData->DSnotify = NULL;
  337. if(pData->DSsbuffer)
  338. IDirectSoundBuffer_Release(pData->DSsbuffer);
  339. pData->DSsbuffer = NULL;
  340. if(pData->DSpbuffer != NULL)
  341. IDirectSoundBuffer_Release(pData->DSpbuffer);
  342. pData->DSpbuffer = NULL;
  343. IDirectSound_Release(pData->lpDS);
  344. CloseHandle(pData->hNotifyEvent);
  345. free(pData);
  346. device->ExtraData = NULL;
  347. }
  348. static ALCboolean DSoundResetPlayback(ALCdevice *device)
  349. {
  350. DSoundPlaybackData *pData = (DSoundPlaybackData*)device->ExtraData;
  351. DSBUFFERDESC DSBDescription;
  352. WAVEFORMATEXTENSIBLE OutputType;
  353. DWORD speakers;
  354. HRESULT hr;
  355. memset(&OutputType, 0, sizeof(OutputType));
  356. if(pData->DSnotify)
  357. IDirectSoundNotify_Release(pData->DSnotify);
  358. pData->DSnotify = NULL;
  359. if(pData->DSsbuffer)
  360. IDirectSoundBuffer_Release(pData->DSsbuffer);
  361. pData->DSsbuffer = NULL;
  362. if(pData->DSpbuffer != NULL)
  363. IDirectSoundBuffer_Release(pData->DSpbuffer);
  364. pData->DSpbuffer = NULL;
  365. switch(device->FmtType)
  366. {
  367. case DevFmtByte:
  368. device->FmtType = DevFmtUByte;
  369. break;
  370. case DevFmtUShort:
  371. device->FmtType = DevFmtShort;
  372. break;
  373. case DevFmtUInt:
  374. device->FmtType = DevFmtInt;
  375. break;
  376. case DevFmtUByte:
  377. case DevFmtShort:
  378. case DevFmtInt:
  379. case DevFmtFloat:
  380. break;
  381. }
  382. hr = IDirectSound_GetSpeakerConfig(pData->lpDS, &speakers);
  383. if(SUCCEEDED(hr))
  384. {
  385. if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
  386. {
  387. speakers = DSSPEAKER_CONFIG(speakers);
  388. if(speakers == DSSPEAKER_MONO)
  389. device->FmtChans = DevFmtMono;
  390. else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE)
  391. device->FmtChans = DevFmtStereo;
  392. else if(speakers == DSSPEAKER_QUAD)
  393. device->FmtChans = DevFmtQuad;
  394. else if(speakers == DSSPEAKER_5POINT1)
  395. device->FmtChans = DevFmtX51;
  396. else if(speakers == DSSPEAKER_7POINT1)
  397. device->FmtChans = DevFmtX71;
  398. else
  399. ERR("Unknown system speaker config: 0x%lx\n", speakers);
  400. }
  401. switch(device->FmtChans)
  402. {
  403. case DevFmtMono:
  404. OutputType.dwChannelMask = SPEAKER_FRONT_CENTER;
  405. break;
  406. case DevFmtStereo:
  407. OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  408. SPEAKER_FRONT_RIGHT;
  409. break;
  410. case DevFmtQuad:
  411. OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  412. SPEAKER_FRONT_RIGHT |
  413. SPEAKER_BACK_LEFT |
  414. SPEAKER_BACK_RIGHT;
  415. break;
  416. case DevFmtX51:
  417. OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  418. SPEAKER_FRONT_RIGHT |
  419. SPEAKER_FRONT_CENTER |
  420. SPEAKER_LOW_FREQUENCY |
  421. SPEAKER_BACK_LEFT |
  422. SPEAKER_BACK_RIGHT;
  423. break;
  424. case DevFmtX51Side:
  425. OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  426. SPEAKER_FRONT_RIGHT |
  427. SPEAKER_FRONT_CENTER |
  428. SPEAKER_LOW_FREQUENCY |
  429. SPEAKER_SIDE_LEFT |
  430. SPEAKER_SIDE_RIGHT;
  431. break;
  432. case DevFmtX61:
  433. OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  434. SPEAKER_FRONT_RIGHT |
  435. SPEAKER_FRONT_CENTER |
  436. SPEAKER_LOW_FREQUENCY |
  437. SPEAKER_BACK_CENTER |
  438. SPEAKER_SIDE_LEFT |
  439. SPEAKER_SIDE_RIGHT;
  440. break;
  441. case DevFmtX71:
  442. OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  443. SPEAKER_FRONT_RIGHT |
  444. SPEAKER_FRONT_CENTER |
  445. SPEAKER_LOW_FREQUENCY |
  446. SPEAKER_BACK_LEFT |
  447. SPEAKER_BACK_RIGHT |
  448. SPEAKER_SIDE_LEFT |
  449. SPEAKER_SIDE_RIGHT;
  450. break;
  451. }
  452. retry_open:
  453. hr = S_OK;
  454. OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
  455. OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
  456. OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
  457. OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8;
  458. OutputType.Format.nSamplesPerSec = device->Frequency;
  459. OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign;
  460. OutputType.Format.cbSize = 0;
  461. }
  462. if(OutputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat)
  463. {
  464. OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
  465. OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
  466. OutputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
  467. if(device->FmtType == DevFmtFloat)
  468. OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
  469. else
  470. OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
  471. if(pData->DSpbuffer)
  472. IDirectSoundBuffer_Release(pData->DSpbuffer);
  473. pData->DSpbuffer = NULL;
  474. }
  475. else
  476. {
  477. if(SUCCEEDED(hr))
  478. {
  479. memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
  480. DSBDescription.dwSize=sizeof(DSBUFFERDESC);
  481. DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER;
  482. hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSpbuffer, NULL);
  483. }
  484. if(SUCCEEDED(hr))
  485. hr = IDirectSoundBuffer_SetFormat(pData->DSpbuffer,&OutputType.Format);
  486. }
  487. if(SUCCEEDED(hr))
  488. {
  489. if(device->NumUpdates > MAX_UPDATES)
  490. {
  491. device->UpdateSize = (device->UpdateSize*device->NumUpdates +
  492. MAX_UPDATES-1) / MAX_UPDATES;
  493. device->NumUpdates = MAX_UPDATES;
  494. }
  495. memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
  496. DSBDescription.dwSize=sizeof(DSBUFFERDESC);
  497. DSBDescription.dwFlags=DSBCAPS_CTRLPOSITIONNOTIFY|DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_GLOBALFOCUS;
  498. DSBDescription.dwBufferBytes=device->UpdateSize * device->NumUpdates *
  499. OutputType.Format.nBlockAlign;
  500. DSBDescription.lpwfxFormat=&OutputType.Format;
  501. hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL);
  502. if(FAILED(hr) && device->FmtType == DevFmtFloat)
  503. {
  504. device->FmtType = DevFmtShort;
  505. goto retry_open;
  506. }
  507. }
  508. if(SUCCEEDED(hr))
  509. {
  510. hr = IDirectSoundBuffer_QueryInterface(pData->DSsbuffer, &IID_IDirectSoundNotify, (LPVOID *)&pData->DSnotify);
  511. if(SUCCEEDED(hr))
  512. {
  513. DSBPOSITIONNOTIFY notifies[MAX_UPDATES];
  514. ALuint i;
  515. for(i = 0;i < device->NumUpdates;++i)
  516. {
  517. notifies[i].dwOffset = i * device->UpdateSize *
  518. OutputType.Format.nBlockAlign;
  519. notifies[i].hEventNotify = pData->hNotifyEvent;
  520. }
  521. if(IDirectSoundNotify_SetNotificationPositions(pData->DSnotify, device->NumUpdates, notifies) != DS_OK)
  522. hr = E_FAIL;
  523. }
  524. }
  525. if(FAILED(hr))
  526. {
  527. if(pData->DSnotify != NULL)
  528. IDirectSoundNotify_Release(pData->DSnotify);
  529. pData->DSnotify = NULL;
  530. if(pData->DSsbuffer != NULL)
  531. IDirectSoundBuffer_Release(pData->DSsbuffer);
  532. pData->DSsbuffer = NULL;
  533. if(pData->DSpbuffer != NULL)
  534. IDirectSoundBuffer_Release(pData->DSpbuffer);
  535. pData->DSpbuffer = NULL;
  536. return ALC_FALSE;
  537. }
  538. ResetEvent(pData->hNotifyEvent);
  539. SetDefaultWFXChannelOrder(device);
  540. return ALC_TRUE;
  541. }
  542. static ALCboolean DSoundStartPlayback(ALCdevice *device)
  543. {
  544. DSoundPlaybackData *pData = (DSoundPlaybackData*)device->ExtraData;
  545. pData->thread = StartThread(DSoundPlaybackProc, device);
  546. if(pData->thread == NULL)
  547. return ALC_FALSE;
  548. return ALC_TRUE;
  549. }
  550. static void DSoundStopPlayback(ALCdevice *device)
  551. {
  552. DSoundPlaybackData *pData = device->ExtraData;
  553. if(!pData->thread)
  554. return;
  555. pData->killNow = 1;
  556. StopThread(pData->thread);
  557. pData->thread = NULL;
  558. pData->killNow = 0;
  559. IDirectSoundBuffer_Stop(pData->DSsbuffer);
  560. }
  561. static ALCenum DSoundOpenCapture(ALCdevice *device, const ALCchar *deviceName)
  562. {
  563. DSoundCaptureData *pData = NULL;
  564. WAVEFORMATEXTENSIBLE InputType;
  565. DSCBUFFERDESC DSCBDescription;
  566. LPGUID guid = NULL;
  567. HRESULT hr, hrcom;
  568. ALuint samples;
  569. if(!CaptureDeviceList)
  570. {
  571. /* Initialize COM to prevent name truncation */
  572. hrcom = CoInitialize(NULL);
  573. hr = DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices, NULL);
  574. if(FAILED(hr))
  575. ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
  576. if(SUCCEEDED(hrcom))
  577. CoUninitialize();
  578. }
  579. if(!deviceName && NumCaptureDevices > 0)
  580. {
  581. deviceName = CaptureDeviceList[0].name;
  582. guid = &CaptureDeviceList[0].guid;
  583. }
  584. else
  585. {
  586. ALuint i;
  587. for(i = 0;i < NumCaptureDevices;i++)
  588. {
  589. if(strcmp(deviceName, CaptureDeviceList[i].name) == 0)
  590. {
  591. guid = &CaptureDeviceList[i].guid;
  592. break;
  593. }
  594. }
  595. if(i == NumCaptureDevices)
  596. return ALC_INVALID_VALUE;
  597. }
  598. switch(device->FmtType)
  599. {
  600. case DevFmtByte:
  601. case DevFmtUShort:
  602. case DevFmtUInt:
  603. WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
  604. return ALC_INVALID_ENUM;
  605. case DevFmtUByte:
  606. case DevFmtShort:
  607. case DevFmtInt:
  608. case DevFmtFloat:
  609. break;
  610. }
  611. //Initialise requested device
  612. pData = calloc(1, sizeof(DSoundCaptureData));
  613. if(!pData)
  614. return ALC_OUT_OF_MEMORY;
  615. hr = DS_OK;
  616. //DirectSoundCapture Init code
  617. if(SUCCEEDED(hr))
  618. hr = DirectSoundCaptureCreate(guid, &pData->lpDSC, NULL);
  619. if(SUCCEEDED(hr))
  620. {
  621. memset(&InputType, 0, sizeof(InputType));
  622. switch(device->FmtChans)
  623. {
  624. case DevFmtMono:
  625. InputType.dwChannelMask = SPEAKER_FRONT_CENTER;
  626. break;
  627. case DevFmtStereo:
  628. InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  629. SPEAKER_FRONT_RIGHT;
  630. break;
  631. case DevFmtQuad:
  632. InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  633. SPEAKER_FRONT_RIGHT |
  634. SPEAKER_BACK_LEFT |
  635. SPEAKER_BACK_RIGHT;
  636. break;
  637. case DevFmtX51:
  638. InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  639. SPEAKER_FRONT_RIGHT |
  640. SPEAKER_FRONT_CENTER |
  641. SPEAKER_LOW_FREQUENCY |
  642. SPEAKER_BACK_LEFT |
  643. SPEAKER_BACK_RIGHT;
  644. break;
  645. case DevFmtX51Side:
  646. InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  647. SPEAKER_FRONT_RIGHT |
  648. SPEAKER_FRONT_CENTER |
  649. SPEAKER_LOW_FREQUENCY |
  650. SPEAKER_SIDE_LEFT |
  651. SPEAKER_SIDE_RIGHT;
  652. break;
  653. case DevFmtX61:
  654. InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  655. SPEAKER_FRONT_RIGHT |
  656. SPEAKER_FRONT_CENTER |
  657. SPEAKER_LOW_FREQUENCY |
  658. SPEAKER_BACK_CENTER |
  659. SPEAKER_SIDE_LEFT |
  660. SPEAKER_SIDE_RIGHT;
  661. break;
  662. case DevFmtX71:
  663. InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  664. SPEAKER_FRONT_RIGHT |
  665. SPEAKER_FRONT_CENTER |
  666. SPEAKER_LOW_FREQUENCY |
  667. SPEAKER_BACK_LEFT |
  668. SPEAKER_BACK_RIGHT |
  669. SPEAKER_SIDE_LEFT |
  670. SPEAKER_SIDE_RIGHT;
  671. break;
  672. }
  673. InputType.Format.wFormatTag = WAVE_FORMAT_PCM;
  674. InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
  675. InputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
  676. InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8;
  677. InputType.Format.nSamplesPerSec = device->Frequency;
  678. InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign;
  679. InputType.Format.cbSize = 0;
  680. if(InputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat)
  681. {
  682. InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
  683. InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
  684. InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample;
  685. if(device->FmtType == DevFmtFloat)
  686. InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
  687. else
  688. InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
  689. }
  690. samples = device->UpdateSize * device->NumUpdates;
  691. samples = maxu(samples, 100 * device->Frequency / 1000);
  692. memset(&DSCBDescription, 0, sizeof(DSCBUFFERDESC));
  693. DSCBDescription.dwSize = sizeof(DSCBUFFERDESC);
  694. DSCBDescription.dwFlags = 0;
  695. DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign;
  696. DSCBDescription.lpwfxFormat = &InputType.Format;
  697. hr = IDirectSoundCapture_CreateCaptureBuffer(pData->lpDSC, &DSCBDescription, &pData->DSCbuffer, NULL);
  698. }
  699. if(SUCCEEDED(hr))
  700. {
  701. pData->pRing = CreateRingBuffer(InputType.Format.nBlockAlign, device->UpdateSize * device->NumUpdates);
  702. if(pData->pRing == NULL)
  703. hr = DSERR_OUTOFMEMORY;
  704. }
  705. if(FAILED(hr))
  706. {
  707. ERR("Device init failed: 0x%08lx\n", hr);
  708. DestroyRingBuffer(pData->pRing);
  709. pData->pRing = NULL;
  710. if(pData->DSCbuffer != NULL)
  711. IDirectSoundCaptureBuffer_Release(pData->DSCbuffer);
  712. pData->DSCbuffer = NULL;
  713. if(pData->lpDSC)
  714. IDirectSoundCapture_Release(pData->lpDSC);
  715. pData->lpDSC = NULL;
  716. free(pData);
  717. return ALC_INVALID_VALUE;
  718. }
  719. pData->dwBufferBytes = DSCBDescription.dwBufferBytes;
  720. SetDefaultWFXChannelOrder(device);
  721. device->szDeviceName = strdup(deviceName);
  722. device->ExtraData = pData;
  723. return ALC_NO_ERROR;
  724. }
  725. static void DSoundCloseCapture(ALCdevice *device)
  726. {
  727. DSoundCaptureData *pData = device->ExtraData;
  728. DestroyRingBuffer(pData->pRing);
  729. pData->pRing = NULL;
  730. if(pData->DSCbuffer != NULL)
  731. {
  732. IDirectSoundCaptureBuffer_Stop(pData->DSCbuffer);
  733. IDirectSoundCaptureBuffer_Release(pData->DSCbuffer);
  734. pData->DSCbuffer = NULL;
  735. }
  736. IDirectSoundCapture_Release(pData->lpDSC);
  737. pData->lpDSC = NULL;
  738. free(pData);
  739. device->ExtraData = NULL;
  740. }
  741. static void DSoundStartCapture(ALCdevice *device)
  742. {
  743. DSoundCaptureData *pData = device->ExtraData;
  744. HRESULT hr;
  745. hr = IDirectSoundCaptureBuffer_Start(pData->DSCbuffer, DSCBSTART_LOOPING);
  746. if(FAILED(hr))
  747. {
  748. ERR("start failed: 0x%08lx\n", hr);
  749. aluHandleDisconnect(device);
  750. }
  751. }
  752. static void DSoundStopCapture(ALCdevice *device)
  753. {
  754. DSoundCaptureData *pData = device->ExtraData;
  755. HRESULT hr;
  756. hr = IDirectSoundCaptureBuffer_Stop(pData->DSCbuffer);
  757. if(FAILED(hr))
  758. {
  759. ERR("stop failed: 0x%08lx\n", hr);
  760. aluHandleDisconnect(device);
  761. }
  762. }
  763. static ALCenum DSoundCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
  764. {
  765. DSoundCaptureData *pData = pDevice->ExtraData;
  766. ReadRingBuffer(pData->pRing, pBuffer, lSamples);
  767. return ALC_NO_ERROR;
  768. }
  769. static ALCuint DSoundAvailableSamples(ALCdevice *pDevice)
  770. {
  771. DSoundCaptureData *pData = pDevice->ExtraData;
  772. DWORD dwRead, dwCursor, dwBufferBytes, dwNumBytes;
  773. void *pvAudio1, *pvAudio2;
  774. DWORD dwAudioBytes1, dwAudioBytes2;
  775. DWORD FrameSize;
  776. HRESULT hr;
  777. if(!pDevice->Connected)
  778. goto done;
  779. FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
  780. dwBufferBytes = pData->dwBufferBytes;
  781. dwCursor = pData->dwCursor;
  782. hr = IDirectSoundCaptureBuffer_GetCurrentPosition(pData->DSCbuffer, NULL, &dwRead);
  783. if(SUCCEEDED(hr))
  784. {
  785. dwNumBytes = (dwBufferBytes + dwRead - dwCursor) % dwBufferBytes;
  786. if(dwNumBytes == 0)
  787. goto done;
  788. hr = IDirectSoundCaptureBuffer_Lock(pData->DSCbuffer,
  789. dwCursor, dwNumBytes,
  790. &pvAudio1, &dwAudioBytes1,
  791. &pvAudio2, &dwAudioBytes2, 0);
  792. }
  793. if(SUCCEEDED(hr))
  794. {
  795. WriteRingBuffer(pData->pRing, pvAudio1, dwAudioBytes1/FrameSize);
  796. if(pvAudio2 != NULL)
  797. WriteRingBuffer(pData->pRing, pvAudio2, dwAudioBytes2/FrameSize);
  798. hr = IDirectSoundCaptureBuffer_Unlock(pData->DSCbuffer,
  799. pvAudio1, dwAudioBytes1,
  800. pvAudio2, dwAudioBytes2);
  801. pData->dwCursor = (dwCursor + dwAudioBytes1 + dwAudioBytes2) % dwBufferBytes;
  802. }
  803. if(FAILED(hr))
  804. {
  805. ERR("update failed: 0x%08lx\n", hr);
  806. aluHandleDisconnect(pDevice);
  807. }
  808. done:
  809. return RingBufferSize(pData->pRing);
  810. }
  811. static const BackendFuncs DSoundFuncs = {
  812. DSoundOpenPlayback,
  813. DSoundClosePlayback,
  814. DSoundResetPlayback,
  815. DSoundStartPlayback,
  816. DSoundStopPlayback,
  817. DSoundOpenCapture,
  818. DSoundCloseCapture,
  819. DSoundStartCapture,
  820. DSoundStopCapture,
  821. DSoundCaptureSamples,
  822. DSoundAvailableSamples
  823. };
  824. ALCboolean alcDSoundInit(BackendFuncs *FuncList)
  825. {
  826. if(!DSoundLoad())
  827. return ALC_FALSE;
  828. *FuncList = DSoundFuncs;
  829. return ALC_TRUE;
  830. }
  831. void alcDSoundDeinit(void)
  832. {
  833. ALuint i;
  834. for(i = 0;i < NumPlaybackDevices;++i)
  835. free(PlaybackDeviceList[i].name);
  836. free(PlaybackDeviceList);
  837. PlaybackDeviceList = NULL;
  838. NumPlaybackDevices = 0;
  839. for(i = 0;i < NumCaptureDevices;++i)
  840. free(CaptureDeviceList[i].name);
  841. free(CaptureDeviceList);
  842. CaptureDeviceList = NULL;
  843. NumCaptureDevices = 0;
  844. if(ds_handle)
  845. CloseLib(ds_handle);
  846. ds_handle = NULL;
  847. }
  848. void alcDSoundProbe(enum DevProbe type)
  849. {
  850. HRESULT hr, hrcom;
  851. ALuint i;
  852. switch(type)
  853. {
  854. case ALL_DEVICE_PROBE:
  855. for(i = 0;i < NumPlaybackDevices;++i)
  856. free(PlaybackDeviceList[i].name);
  857. free(PlaybackDeviceList);
  858. PlaybackDeviceList = NULL;
  859. NumPlaybackDevices = 0;
  860. hr = DirectSoundEnumerateA(DSoundEnumPlaybackDevices, NULL);
  861. if(FAILED(hr))
  862. ERR("Error enumerating DirectSound playback devices (%#x)!\n", (unsigned int)hr);
  863. else
  864. {
  865. for(i = 0;i < NumPlaybackDevices;i++)
  866. AppendAllDeviceList(PlaybackDeviceList[i].name);
  867. }
  868. break;
  869. case CAPTURE_DEVICE_PROBE:
  870. for(i = 0;i < NumCaptureDevices;++i)
  871. free(CaptureDeviceList[i].name);
  872. free(CaptureDeviceList);
  873. CaptureDeviceList = NULL;
  874. NumCaptureDevices = 0;
  875. /* Initialize COM to prevent name truncation */
  876. hrcom = CoInitialize(NULL);
  877. hr = DirectSoundCaptureEnumerateA(DSoundEnumCaptureDevices, NULL);
  878. if(FAILED(hr))
  879. ERR("Error enumerating DirectSound capture devices (%#x)!\n", (unsigned int)hr);
  880. else
  881. {
  882. for(i = 0;i < NumCaptureDevices;i++)
  883. AppendCaptureDeviceList(CaptureDeviceList[i].name);
  884. }
  885. if(SUCCEEDED(hrcom))
  886. CoUninitialize();
  887. break;
  888. }
  889. }