dsound.c 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078
  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.,
  17. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 "alu.h"
  33. #include "ringbuffer.h"
  34. #include "threads.h"
  35. #include "compat.h"
  36. #include "alstring.h"
  37. #include "backends/base.h"
  38. #ifndef DSSPEAKER_5POINT1
  39. # define DSSPEAKER_5POINT1 0x00000006
  40. #endif
  41. #ifndef DSSPEAKER_5POINT1_BACK
  42. # define DSSPEAKER_5POINT1_BACK 0x00000006
  43. #endif
  44. #ifndef DSSPEAKER_7POINT1
  45. # define DSSPEAKER_7POINT1 0x00000007
  46. #endif
  47. #ifndef DSSPEAKER_7POINT1_SURROUND
  48. # define DSSPEAKER_7POINT1_SURROUND 0x00000008
  49. #endif
  50. #ifndef DSSPEAKER_5POINT1_SURROUND
  51. # define DSSPEAKER_5POINT1_SURROUND 0x00000009
  52. #endif
  53. DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
  54. DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
  55. #define DEVNAME_HEAD "OpenAL Soft on "
  56. #ifdef HAVE_DYNLOAD
  57. static void *ds_handle;
  58. static HRESULT (WINAPI *pDirectSoundCreate)(const GUID *pcGuidDevice, IDirectSound **ppDS, IUnknown *pUnkOuter);
  59. static HRESULT (WINAPI *pDirectSoundEnumerateW)(LPDSENUMCALLBACKW pDSEnumCallback, void *pContext);
  60. static HRESULT (WINAPI *pDirectSoundCaptureCreate)(const GUID *pcGuidDevice, IDirectSoundCapture **ppDSC, IUnknown *pUnkOuter);
  61. static HRESULT (WINAPI *pDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW pDSEnumCallback, void *pContext);
  62. #define DirectSoundCreate pDirectSoundCreate
  63. #define DirectSoundEnumerateW pDirectSoundEnumerateW
  64. #define DirectSoundCaptureCreate pDirectSoundCaptureCreate
  65. #define DirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW
  66. #endif
  67. static ALCboolean DSoundLoad(void)
  68. {
  69. #ifdef HAVE_DYNLOAD
  70. if(!ds_handle)
  71. {
  72. ds_handle = LoadLib("dsound.dll");
  73. if(ds_handle == NULL)
  74. {
  75. ERR("Failed to load dsound.dll\n");
  76. return ALC_FALSE;
  77. }
  78. #define LOAD_FUNC(f) do { \
  79. p##f = GetSymbol(ds_handle, #f); \
  80. if(p##f == NULL) { \
  81. CloseLib(ds_handle); \
  82. ds_handle = NULL; \
  83. return ALC_FALSE; \
  84. } \
  85. } while(0)
  86. LOAD_FUNC(DirectSoundCreate);
  87. LOAD_FUNC(DirectSoundEnumerateW);
  88. LOAD_FUNC(DirectSoundCaptureCreate);
  89. LOAD_FUNC(DirectSoundCaptureEnumerateW);
  90. #undef LOAD_FUNC
  91. }
  92. #endif
  93. return ALC_TRUE;
  94. }
  95. #define MAX_UPDATES 128
  96. typedef struct {
  97. al_string name;
  98. GUID guid;
  99. } DevMap;
  100. TYPEDEF_VECTOR(DevMap, vector_DevMap)
  101. static vector_DevMap PlaybackDevices;
  102. static vector_DevMap CaptureDevices;
  103. static void clear_devlist(vector_DevMap *list)
  104. {
  105. #define DEINIT_STR(i) AL_STRING_DEINIT((i)->name)
  106. VECTOR_FOR_EACH(DevMap, *list, DEINIT_STR);
  107. VECTOR_RESIZE(*list, 0, 0);
  108. #undef DEINIT_STR
  109. }
  110. static BOOL CALLBACK DSoundEnumDevices(GUID *guid, const WCHAR *desc, const WCHAR* UNUSED(drvname), void *data)
  111. {
  112. vector_DevMap *devices = data;
  113. OLECHAR *guidstr = NULL;
  114. DevMap entry;
  115. HRESULT hr;
  116. int count;
  117. if(!guid)
  118. return TRUE;
  119. AL_STRING_INIT(entry.name);
  120. count = 0;
  121. while(1)
  122. {
  123. const DevMap *iter;
  124. alstr_copy_cstr(&entry.name, DEVNAME_HEAD);
  125. alstr_append_wcstr(&entry.name, desc);
  126. if(count != 0)
  127. {
  128. char str[64];
  129. snprintf(str, sizeof(str), " #%d", count+1);
  130. alstr_append_cstr(&entry.name, str);
  131. }
  132. #define MATCH_ENTRY(i) (alstr_cmp(entry.name, (i)->name) == 0)
  133. VECTOR_FIND_IF(iter, const DevMap, *devices, MATCH_ENTRY);
  134. if(iter == VECTOR_END(*devices)) break;
  135. #undef MATCH_ENTRY
  136. count++;
  137. }
  138. entry.guid = *guid;
  139. hr = StringFromCLSID(guid, &guidstr);
  140. if(SUCCEEDED(hr))
  141. {
  142. TRACE("Got device \"%s\", GUID \"%ls\"\n", alstr_get_cstr(entry.name), guidstr);
  143. CoTaskMemFree(guidstr);
  144. }
  145. VECTOR_PUSH_BACK(*devices, entry);
  146. return TRUE;
  147. }
  148. typedef struct ALCdsoundPlayback {
  149. DERIVE_FROM_TYPE(ALCbackend);
  150. IDirectSound *DS;
  151. IDirectSoundBuffer *PrimaryBuffer;
  152. IDirectSoundBuffer *Buffer;
  153. IDirectSoundNotify *Notifies;
  154. HANDLE NotifyEvent;
  155. ATOMIC(ALenum) killNow;
  156. althrd_t thread;
  157. } ALCdsoundPlayback;
  158. static int ALCdsoundPlayback_mixerProc(void *ptr);
  159. static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device);
  160. static void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self);
  161. static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *name);
  162. static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self);
  163. static ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self);
  164. static void ALCdsoundPlayback_stop(ALCdsoundPlayback *self);
  165. static DECLARE_FORWARD2(ALCdsoundPlayback, ALCbackend, ALCenum, captureSamples, void*, ALCuint)
  166. static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, ALCuint, availableSamples)
  167. static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, ClockLatency, getClockLatency)
  168. static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, lock)
  169. static DECLARE_FORWARD(ALCdsoundPlayback, ALCbackend, void, unlock)
  170. DECLARE_DEFAULT_ALLOCATORS(ALCdsoundPlayback)
  171. DEFINE_ALCBACKEND_VTABLE(ALCdsoundPlayback);
  172. static void ALCdsoundPlayback_Construct(ALCdsoundPlayback *self, ALCdevice *device)
  173. {
  174. ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
  175. SET_VTABLE2(ALCdsoundPlayback, ALCbackend, self);
  176. self->DS = NULL;
  177. self->PrimaryBuffer = NULL;
  178. self->Buffer = NULL;
  179. self->Notifies = NULL;
  180. self->NotifyEvent = NULL;
  181. ATOMIC_INIT(&self->killNow, AL_TRUE);
  182. }
  183. static void ALCdsoundPlayback_Destruct(ALCdsoundPlayback *self)
  184. {
  185. if(self->Notifies)
  186. IDirectSoundNotify_Release(self->Notifies);
  187. self->Notifies = NULL;
  188. if(self->Buffer)
  189. IDirectSoundBuffer_Release(self->Buffer);
  190. self->Buffer = NULL;
  191. if(self->PrimaryBuffer != NULL)
  192. IDirectSoundBuffer_Release(self->PrimaryBuffer);
  193. self->PrimaryBuffer = NULL;
  194. if(self->DS)
  195. IDirectSound_Release(self->DS);
  196. self->DS = NULL;
  197. if(self->NotifyEvent)
  198. CloseHandle(self->NotifyEvent);
  199. self->NotifyEvent = NULL;
  200. ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
  201. }
  202. FORCE_ALIGN static int ALCdsoundPlayback_mixerProc(void *ptr)
  203. {
  204. ALCdsoundPlayback *self = ptr;
  205. ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
  206. DSBCAPS DSBCaps;
  207. DWORD LastCursor = 0;
  208. DWORD PlayCursor;
  209. void *WritePtr1, *WritePtr2;
  210. DWORD WriteCnt1, WriteCnt2;
  211. BOOL Playing = FALSE;
  212. DWORD FrameSize;
  213. DWORD FragSize;
  214. DWORD avail;
  215. HRESULT err;
  216. SetRTPriority();
  217. althrd_setname(althrd_current(), MIXER_THREAD_NAME);
  218. memset(&DSBCaps, 0, sizeof(DSBCaps));
  219. DSBCaps.dwSize = sizeof(DSBCaps);
  220. err = IDirectSoundBuffer_GetCaps(self->Buffer, &DSBCaps);
  221. if(FAILED(err))
  222. {
  223. ERR("Failed to get buffer caps: 0x%lx\n", err);
  224. ALCdevice_Lock(device);
  225. aluHandleDisconnect(device, "Failure retrieving playback buffer info: 0x%lx", err);
  226. ALCdevice_Unlock(device);
  227. return 1;
  228. }
  229. FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
  230. FragSize = device->UpdateSize * FrameSize;
  231. IDirectSoundBuffer_GetCurrentPosition(self->Buffer, &LastCursor, NULL);
  232. while(!ATOMIC_LOAD(&self->killNow, almemory_order_acquire) &&
  233. ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
  234. {
  235. // Get current play cursor
  236. IDirectSoundBuffer_GetCurrentPosition(self->Buffer, &PlayCursor, NULL);
  237. avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes;
  238. if(avail < FragSize)
  239. {
  240. if(!Playing)
  241. {
  242. err = IDirectSoundBuffer_Play(self->Buffer, 0, 0, DSBPLAY_LOOPING);
  243. if(FAILED(err))
  244. {
  245. ERR("Failed to play buffer: 0x%lx\n", err);
  246. ALCdevice_Lock(device);
  247. aluHandleDisconnect(device, "Failure starting playback: 0x%lx", err);
  248. ALCdevice_Unlock(device);
  249. return 1;
  250. }
  251. Playing = TRUE;
  252. }
  253. avail = WaitForSingleObjectEx(self->NotifyEvent, 2000, FALSE);
  254. if(avail != WAIT_OBJECT_0)
  255. ERR("WaitForSingleObjectEx error: 0x%lx\n", avail);
  256. continue;
  257. }
  258. avail -= avail%FragSize;
  259. // Lock output buffer
  260. WriteCnt1 = 0;
  261. WriteCnt2 = 0;
  262. err = IDirectSoundBuffer_Lock(self->Buffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
  263. // If the buffer is lost, restore it and lock
  264. if(err == DSERR_BUFFERLOST)
  265. {
  266. WARN("Buffer lost, restoring...\n");
  267. err = IDirectSoundBuffer_Restore(self->Buffer);
  268. if(SUCCEEDED(err))
  269. {
  270. Playing = FALSE;
  271. LastCursor = 0;
  272. err = IDirectSoundBuffer_Lock(self->Buffer, 0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
  273. }
  274. }
  275. // Successfully locked the output buffer
  276. if(SUCCEEDED(err))
  277. {
  278. // If we have an active context, mix data directly into output buffer otherwise fill with silence
  279. ALCdevice_Lock(device);
  280. aluMixData(device, WritePtr1, WriteCnt1/FrameSize);
  281. aluMixData(device, WritePtr2, WriteCnt2/FrameSize);
  282. ALCdevice_Unlock(device);
  283. // Unlock output buffer only when successfully locked
  284. IDirectSoundBuffer_Unlock(self->Buffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
  285. }
  286. else
  287. {
  288. ERR("Buffer lock error: %#lx\n", err);
  289. ALCdevice_Lock(device);
  290. aluHandleDisconnect(device, "Failed to lock output buffer: 0x%lx", err);
  291. ALCdevice_Unlock(device);
  292. return 1;
  293. }
  294. // Update old write cursor location
  295. LastCursor += WriteCnt1+WriteCnt2;
  296. LastCursor %= DSBCaps.dwBufferBytes;
  297. }
  298. return 0;
  299. }
  300. static ALCenum ALCdsoundPlayback_open(ALCdsoundPlayback *self, const ALCchar *deviceName)
  301. {
  302. ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
  303. const GUID *guid = NULL;
  304. HRESULT hr, hrcom;
  305. if(VECTOR_SIZE(PlaybackDevices) == 0)
  306. {
  307. /* Initialize COM to prevent name truncation */
  308. hrcom = CoInitialize(NULL);
  309. hr = DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices);
  310. if(FAILED(hr))
  311. ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr);
  312. if(SUCCEEDED(hrcom))
  313. CoUninitialize();
  314. }
  315. if(!deviceName && VECTOR_SIZE(PlaybackDevices) > 0)
  316. {
  317. deviceName = alstr_get_cstr(VECTOR_FRONT(PlaybackDevices).name);
  318. guid = &VECTOR_FRONT(PlaybackDevices).guid;
  319. }
  320. else
  321. {
  322. const DevMap *iter;
  323. #define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, deviceName) == 0)
  324. VECTOR_FIND_IF(iter, const DevMap, PlaybackDevices, MATCH_NAME);
  325. #undef MATCH_NAME
  326. if(iter == VECTOR_END(PlaybackDevices))
  327. return ALC_INVALID_VALUE;
  328. guid = &iter->guid;
  329. }
  330. hr = DS_OK;
  331. self->NotifyEvent = CreateEventW(NULL, FALSE, FALSE, NULL);
  332. if(self->NotifyEvent == NULL)
  333. hr = E_FAIL;
  334. //DirectSound Init code
  335. if(SUCCEEDED(hr))
  336. hr = DirectSoundCreate(guid, &self->DS, NULL);
  337. if(SUCCEEDED(hr))
  338. hr = IDirectSound_SetCooperativeLevel(self->DS, GetForegroundWindow(), DSSCL_PRIORITY);
  339. if(FAILED(hr))
  340. {
  341. if(self->DS)
  342. IDirectSound_Release(self->DS);
  343. self->DS = NULL;
  344. if(self->NotifyEvent)
  345. CloseHandle(self->NotifyEvent);
  346. self->NotifyEvent = NULL;
  347. ERR("Device init failed: 0x%08lx\n", hr);
  348. return ALC_INVALID_VALUE;
  349. }
  350. alstr_copy_cstr(&device->DeviceName, deviceName);
  351. return ALC_NO_ERROR;
  352. }
  353. static ALCboolean ALCdsoundPlayback_reset(ALCdsoundPlayback *self)
  354. {
  355. ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
  356. DSBUFFERDESC DSBDescription;
  357. WAVEFORMATEXTENSIBLE OutputType;
  358. DWORD speakers;
  359. HRESULT hr;
  360. memset(&OutputType, 0, sizeof(OutputType));
  361. if(self->Notifies)
  362. IDirectSoundNotify_Release(self->Notifies);
  363. self->Notifies = NULL;
  364. if(self->Buffer)
  365. IDirectSoundBuffer_Release(self->Buffer);
  366. self->Buffer = NULL;
  367. if(self->PrimaryBuffer != NULL)
  368. IDirectSoundBuffer_Release(self->PrimaryBuffer);
  369. self->PrimaryBuffer = NULL;
  370. switch(device->FmtType)
  371. {
  372. case DevFmtByte:
  373. device->FmtType = DevFmtUByte;
  374. break;
  375. case DevFmtFloat:
  376. if((device->Flags&DEVICE_SAMPLE_TYPE_REQUEST))
  377. break;
  378. /* fall-through */
  379. case DevFmtUShort:
  380. device->FmtType = DevFmtShort;
  381. break;
  382. case DevFmtUInt:
  383. device->FmtType = DevFmtInt;
  384. break;
  385. case DevFmtUByte:
  386. case DevFmtShort:
  387. case DevFmtInt:
  388. break;
  389. }
  390. hr = IDirectSound_GetSpeakerConfig(self->DS, &speakers);
  391. if(SUCCEEDED(hr))
  392. {
  393. speakers = DSSPEAKER_CONFIG(speakers);
  394. if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
  395. {
  396. if(speakers == DSSPEAKER_MONO)
  397. device->FmtChans = DevFmtMono;
  398. else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE)
  399. device->FmtChans = DevFmtStereo;
  400. else if(speakers == DSSPEAKER_QUAD)
  401. device->FmtChans = DevFmtQuad;
  402. else if(speakers == DSSPEAKER_5POINT1_SURROUND)
  403. device->FmtChans = DevFmtX51;
  404. else if(speakers == DSSPEAKER_5POINT1_BACK)
  405. device->FmtChans = DevFmtX51Rear;
  406. else if(speakers == DSSPEAKER_7POINT1 || speakers == DSSPEAKER_7POINT1_SURROUND)
  407. device->FmtChans = DevFmtX71;
  408. else
  409. ERR("Unknown system speaker config: 0x%lx\n", speakers);
  410. }
  411. device->IsHeadphones = (device->FmtChans == DevFmtStereo &&
  412. speakers == DSSPEAKER_HEADPHONE);
  413. switch(device->FmtChans)
  414. {
  415. case DevFmtMono:
  416. OutputType.dwChannelMask = SPEAKER_FRONT_CENTER;
  417. break;
  418. case DevFmtAmbi3D:
  419. device->FmtChans = DevFmtStereo;
  420. /*fall-through*/
  421. case DevFmtStereo:
  422. OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  423. SPEAKER_FRONT_RIGHT;
  424. break;
  425. case DevFmtQuad:
  426. OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  427. SPEAKER_FRONT_RIGHT |
  428. SPEAKER_BACK_LEFT |
  429. SPEAKER_BACK_RIGHT;
  430. break;
  431. case DevFmtX51:
  432. OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  433. SPEAKER_FRONT_RIGHT |
  434. SPEAKER_FRONT_CENTER |
  435. SPEAKER_LOW_FREQUENCY |
  436. SPEAKER_SIDE_LEFT |
  437. SPEAKER_SIDE_RIGHT;
  438. break;
  439. case DevFmtX51Rear:
  440. OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  441. SPEAKER_FRONT_RIGHT |
  442. SPEAKER_FRONT_CENTER |
  443. SPEAKER_LOW_FREQUENCY |
  444. SPEAKER_BACK_LEFT |
  445. SPEAKER_BACK_RIGHT;
  446. break;
  447. case DevFmtX61:
  448. OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  449. SPEAKER_FRONT_RIGHT |
  450. SPEAKER_FRONT_CENTER |
  451. SPEAKER_LOW_FREQUENCY |
  452. SPEAKER_BACK_CENTER |
  453. SPEAKER_SIDE_LEFT |
  454. SPEAKER_SIDE_RIGHT;
  455. break;
  456. case DevFmtX71:
  457. OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  458. SPEAKER_FRONT_RIGHT |
  459. SPEAKER_FRONT_CENTER |
  460. SPEAKER_LOW_FREQUENCY |
  461. SPEAKER_BACK_LEFT |
  462. SPEAKER_BACK_RIGHT |
  463. SPEAKER_SIDE_LEFT |
  464. SPEAKER_SIDE_RIGHT;
  465. break;
  466. }
  467. retry_open:
  468. hr = S_OK;
  469. OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
  470. OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
  471. OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
  472. OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8;
  473. OutputType.Format.nSamplesPerSec = device->Frequency;
  474. OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign;
  475. OutputType.Format.cbSize = 0;
  476. }
  477. if(OutputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat)
  478. {
  479. OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
  480. OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
  481. OutputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
  482. if(device->FmtType == DevFmtFloat)
  483. OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
  484. else
  485. OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
  486. if(self->PrimaryBuffer)
  487. IDirectSoundBuffer_Release(self->PrimaryBuffer);
  488. self->PrimaryBuffer = NULL;
  489. }
  490. else
  491. {
  492. if(SUCCEEDED(hr) && !self->PrimaryBuffer)
  493. {
  494. memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
  495. DSBDescription.dwSize=sizeof(DSBUFFERDESC);
  496. DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER;
  497. hr = IDirectSound_CreateSoundBuffer(self->DS, &DSBDescription, &self->PrimaryBuffer, NULL);
  498. }
  499. if(SUCCEEDED(hr))
  500. hr = IDirectSoundBuffer_SetFormat(self->PrimaryBuffer,&OutputType.Format);
  501. }
  502. if(SUCCEEDED(hr))
  503. {
  504. if(device->NumUpdates > MAX_UPDATES)
  505. {
  506. device->UpdateSize = (device->UpdateSize*device->NumUpdates +
  507. MAX_UPDATES-1) / MAX_UPDATES;
  508. device->NumUpdates = MAX_UPDATES;
  509. }
  510. memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
  511. DSBDescription.dwSize=sizeof(DSBUFFERDESC);
  512. DSBDescription.dwFlags=DSBCAPS_CTRLPOSITIONNOTIFY|DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_GLOBALFOCUS;
  513. DSBDescription.dwBufferBytes=device->UpdateSize * device->NumUpdates *
  514. OutputType.Format.nBlockAlign;
  515. DSBDescription.lpwfxFormat=&OutputType.Format;
  516. hr = IDirectSound_CreateSoundBuffer(self->DS, &DSBDescription, &self->Buffer, NULL);
  517. if(FAILED(hr) && device->FmtType == DevFmtFloat)
  518. {
  519. device->FmtType = DevFmtShort;
  520. goto retry_open;
  521. }
  522. }
  523. if(SUCCEEDED(hr))
  524. {
  525. hr = IDirectSoundBuffer_QueryInterface(self->Buffer, &IID_IDirectSoundNotify, (void**)&self->Notifies);
  526. if(SUCCEEDED(hr))
  527. {
  528. DSBPOSITIONNOTIFY notifies[MAX_UPDATES];
  529. ALuint i;
  530. for(i = 0;i < device->NumUpdates;++i)
  531. {
  532. notifies[i].dwOffset = i * device->UpdateSize *
  533. OutputType.Format.nBlockAlign;
  534. notifies[i].hEventNotify = self->NotifyEvent;
  535. }
  536. if(IDirectSoundNotify_SetNotificationPositions(self->Notifies, device->NumUpdates, notifies) != DS_OK)
  537. hr = E_FAIL;
  538. }
  539. }
  540. if(FAILED(hr))
  541. {
  542. if(self->Notifies != NULL)
  543. IDirectSoundNotify_Release(self->Notifies);
  544. self->Notifies = NULL;
  545. if(self->Buffer != NULL)
  546. IDirectSoundBuffer_Release(self->Buffer);
  547. self->Buffer = NULL;
  548. if(self->PrimaryBuffer != NULL)
  549. IDirectSoundBuffer_Release(self->PrimaryBuffer);
  550. self->PrimaryBuffer = NULL;
  551. return ALC_FALSE;
  552. }
  553. ResetEvent(self->NotifyEvent);
  554. SetDefaultWFXChannelOrder(device);
  555. return ALC_TRUE;
  556. }
  557. static ALCboolean ALCdsoundPlayback_start(ALCdsoundPlayback *self)
  558. {
  559. ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release);
  560. if(althrd_create(&self->thread, ALCdsoundPlayback_mixerProc, self) != althrd_success)
  561. return ALC_FALSE;
  562. return ALC_TRUE;
  563. }
  564. static void ALCdsoundPlayback_stop(ALCdsoundPlayback *self)
  565. {
  566. int res;
  567. if(ATOMIC_EXCHANGE(&self->killNow, AL_TRUE, almemory_order_acq_rel))
  568. return;
  569. althrd_join(self->thread, &res);
  570. IDirectSoundBuffer_Stop(self->Buffer);
  571. }
  572. typedef struct ALCdsoundCapture {
  573. DERIVE_FROM_TYPE(ALCbackend);
  574. IDirectSoundCapture *DSC;
  575. IDirectSoundCaptureBuffer *DSCbuffer;
  576. DWORD BufferBytes;
  577. DWORD Cursor;
  578. ll_ringbuffer_t *Ring;
  579. } ALCdsoundCapture;
  580. static void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device);
  581. static void ALCdsoundCapture_Destruct(ALCdsoundCapture *self);
  582. static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *name);
  583. static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, ALCboolean, reset)
  584. static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self);
  585. static void ALCdsoundCapture_stop(ALCdsoundCapture *self);
  586. static ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples);
  587. static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self);
  588. static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, ClockLatency, getClockLatency)
  589. static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, void, lock)
  590. static DECLARE_FORWARD(ALCdsoundCapture, ALCbackend, void, unlock)
  591. DECLARE_DEFAULT_ALLOCATORS(ALCdsoundCapture)
  592. DEFINE_ALCBACKEND_VTABLE(ALCdsoundCapture);
  593. static void ALCdsoundCapture_Construct(ALCdsoundCapture *self, ALCdevice *device)
  594. {
  595. ALCbackend_Construct(STATIC_CAST(ALCbackend, self), device);
  596. SET_VTABLE2(ALCdsoundCapture, ALCbackend, self);
  597. self->DSC = NULL;
  598. self->DSCbuffer = NULL;
  599. self->Ring = NULL;
  600. }
  601. static void ALCdsoundCapture_Destruct(ALCdsoundCapture *self)
  602. {
  603. ll_ringbuffer_free(self->Ring);
  604. self->Ring = NULL;
  605. if(self->DSCbuffer != NULL)
  606. {
  607. IDirectSoundCaptureBuffer_Stop(self->DSCbuffer);
  608. IDirectSoundCaptureBuffer_Release(self->DSCbuffer);
  609. self->DSCbuffer = NULL;
  610. }
  611. if(self->DSC)
  612. IDirectSoundCapture_Release(self->DSC);
  613. self->DSC = NULL;
  614. ALCbackend_Destruct(STATIC_CAST(ALCbackend, self));
  615. }
  616. static ALCenum ALCdsoundCapture_open(ALCdsoundCapture *self, const ALCchar *deviceName)
  617. {
  618. ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
  619. WAVEFORMATEXTENSIBLE InputType;
  620. DSCBUFFERDESC DSCBDescription;
  621. const GUID *guid = NULL;
  622. HRESULT hr, hrcom;
  623. ALuint samples;
  624. if(VECTOR_SIZE(CaptureDevices) == 0)
  625. {
  626. /* Initialize COM to prevent name truncation */
  627. hrcom = CoInitialize(NULL);
  628. hr = DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices);
  629. if(FAILED(hr))
  630. ERR("Error enumerating DirectSound devices (0x%lx)!\n", hr);
  631. if(SUCCEEDED(hrcom))
  632. CoUninitialize();
  633. }
  634. if(!deviceName && VECTOR_SIZE(CaptureDevices) > 0)
  635. {
  636. deviceName = alstr_get_cstr(VECTOR_FRONT(CaptureDevices).name);
  637. guid = &VECTOR_FRONT(CaptureDevices).guid;
  638. }
  639. else
  640. {
  641. const DevMap *iter;
  642. #define MATCH_NAME(i) (alstr_cmp_cstr((i)->name, deviceName) == 0)
  643. VECTOR_FIND_IF(iter, const DevMap, CaptureDevices, MATCH_NAME);
  644. #undef MATCH_NAME
  645. if(iter == VECTOR_END(CaptureDevices))
  646. return ALC_INVALID_VALUE;
  647. guid = &iter->guid;
  648. }
  649. switch(device->FmtType)
  650. {
  651. case DevFmtByte:
  652. case DevFmtUShort:
  653. case DevFmtUInt:
  654. WARN("%s capture samples not supported\n", DevFmtTypeString(device->FmtType));
  655. return ALC_INVALID_ENUM;
  656. case DevFmtUByte:
  657. case DevFmtShort:
  658. case DevFmtInt:
  659. case DevFmtFloat:
  660. break;
  661. }
  662. memset(&InputType, 0, sizeof(InputType));
  663. switch(device->FmtChans)
  664. {
  665. case DevFmtMono:
  666. InputType.dwChannelMask = SPEAKER_FRONT_CENTER;
  667. break;
  668. case DevFmtStereo:
  669. InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  670. SPEAKER_FRONT_RIGHT;
  671. break;
  672. case DevFmtQuad:
  673. InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  674. SPEAKER_FRONT_RIGHT |
  675. SPEAKER_BACK_LEFT |
  676. SPEAKER_BACK_RIGHT;
  677. break;
  678. case DevFmtX51:
  679. InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  680. SPEAKER_FRONT_RIGHT |
  681. SPEAKER_FRONT_CENTER |
  682. SPEAKER_LOW_FREQUENCY |
  683. SPEAKER_SIDE_LEFT |
  684. SPEAKER_SIDE_RIGHT;
  685. break;
  686. case DevFmtX51Rear:
  687. InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  688. SPEAKER_FRONT_RIGHT |
  689. SPEAKER_FRONT_CENTER |
  690. SPEAKER_LOW_FREQUENCY |
  691. SPEAKER_BACK_LEFT |
  692. SPEAKER_BACK_RIGHT;
  693. break;
  694. case DevFmtX61:
  695. InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  696. SPEAKER_FRONT_RIGHT |
  697. SPEAKER_FRONT_CENTER |
  698. SPEAKER_LOW_FREQUENCY |
  699. SPEAKER_BACK_CENTER |
  700. SPEAKER_SIDE_LEFT |
  701. SPEAKER_SIDE_RIGHT;
  702. break;
  703. case DevFmtX71:
  704. InputType.dwChannelMask = SPEAKER_FRONT_LEFT |
  705. SPEAKER_FRONT_RIGHT |
  706. SPEAKER_FRONT_CENTER |
  707. SPEAKER_LOW_FREQUENCY |
  708. SPEAKER_BACK_LEFT |
  709. SPEAKER_BACK_RIGHT |
  710. SPEAKER_SIDE_LEFT |
  711. SPEAKER_SIDE_RIGHT;
  712. break;
  713. case DevFmtAmbi3D:
  714. WARN("%s capture not supported\n", DevFmtChannelsString(device->FmtChans));
  715. return ALC_INVALID_ENUM;
  716. }
  717. InputType.Format.wFormatTag = WAVE_FORMAT_PCM;
  718. InputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder);
  719. InputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
  720. InputType.Format.nBlockAlign = InputType.Format.nChannels*InputType.Format.wBitsPerSample/8;
  721. InputType.Format.nSamplesPerSec = device->Frequency;
  722. InputType.Format.nAvgBytesPerSec = InputType.Format.nSamplesPerSec*InputType.Format.nBlockAlign;
  723. InputType.Format.cbSize = 0;
  724. InputType.Samples.wValidBitsPerSample = InputType.Format.wBitsPerSample;
  725. if(device->FmtType == DevFmtFloat)
  726. InputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
  727. else
  728. InputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
  729. if(InputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat)
  730. {
  731. InputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
  732. InputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
  733. }
  734. samples = device->UpdateSize * device->NumUpdates;
  735. samples = maxu(samples, 100 * device->Frequency / 1000);
  736. memset(&DSCBDescription, 0, sizeof(DSCBUFFERDESC));
  737. DSCBDescription.dwSize = sizeof(DSCBUFFERDESC);
  738. DSCBDescription.dwFlags = 0;
  739. DSCBDescription.dwBufferBytes = samples * InputType.Format.nBlockAlign;
  740. DSCBDescription.lpwfxFormat = &InputType.Format;
  741. //DirectSoundCapture Init code
  742. hr = DirectSoundCaptureCreate(guid, &self->DSC, NULL);
  743. if(SUCCEEDED(hr))
  744. hr = IDirectSoundCapture_CreateCaptureBuffer(self->DSC, &DSCBDescription, &self->DSCbuffer, NULL);
  745. if(SUCCEEDED(hr))
  746. {
  747. self->Ring = ll_ringbuffer_create(device->UpdateSize*device->NumUpdates,
  748. InputType.Format.nBlockAlign, false);
  749. if(self->Ring == NULL)
  750. hr = DSERR_OUTOFMEMORY;
  751. }
  752. if(FAILED(hr))
  753. {
  754. ERR("Device init failed: 0x%08lx\n", hr);
  755. ll_ringbuffer_free(self->Ring);
  756. self->Ring = NULL;
  757. if(self->DSCbuffer != NULL)
  758. IDirectSoundCaptureBuffer_Release(self->DSCbuffer);
  759. self->DSCbuffer = NULL;
  760. if(self->DSC)
  761. IDirectSoundCapture_Release(self->DSC);
  762. self->DSC = NULL;
  763. return ALC_INVALID_VALUE;
  764. }
  765. self->BufferBytes = DSCBDescription.dwBufferBytes;
  766. SetDefaultWFXChannelOrder(device);
  767. alstr_copy_cstr(&device->DeviceName, deviceName);
  768. return ALC_NO_ERROR;
  769. }
  770. static ALCboolean ALCdsoundCapture_start(ALCdsoundCapture *self)
  771. {
  772. HRESULT hr;
  773. hr = IDirectSoundCaptureBuffer_Start(self->DSCbuffer, DSCBSTART_LOOPING);
  774. if(FAILED(hr))
  775. {
  776. ERR("start failed: 0x%08lx\n", hr);
  777. aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice,
  778. "Failure starting capture: 0x%lx", hr);
  779. return ALC_FALSE;
  780. }
  781. return ALC_TRUE;
  782. }
  783. static void ALCdsoundCapture_stop(ALCdsoundCapture *self)
  784. {
  785. HRESULT hr;
  786. hr = IDirectSoundCaptureBuffer_Stop(self->DSCbuffer);
  787. if(FAILED(hr))
  788. {
  789. ERR("stop failed: 0x%08lx\n", hr);
  790. aluHandleDisconnect(STATIC_CAST(ALCbackend, self)->mDevice,
  791. "Failure stopping capture: 0x%lx", hr);
  792. }
  793. }
  794. static ALCenum ALCdsoundCapture_captureSamples(ALCdsoundCapture *self, ALCvoid *buffer, ALCuint samples)
  795. {
  796. ll_ringbuffer_read(self->Ring, buffer, samples);
  797. return ALC_NO_ERROR;
  798. }
  799. static ALCuint ALCdsoundCapture_availableSamples(ALCdsoundCapture *self)
  800. {
  801. ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice;
  802. DWORD ReadCursor, LastCursor, BufferBytes, NumBytes;
  803. void *ReadPtr1, *ReadPtr2;
  804. DWORD ReadCnt1, ReadCnt2;
  805. DWORD FrameSize;
  806. HRESULT hr;
  807. if(!ATOMIC_LOAD(&device->Connected, almemory_order_acquire))
  808. goto done;
  809. FrameSize = FrameSizeFromDevFmt(device->FmtChans, device->FmtType, device->AmbiOrder);
  810. BufferBytes = self->BufferBytes;
  811. LastCursor = self->Cursor;
  812. hr = IDirectSoundCaptureBuffer_GetCurrentPosition(self->DSCbuffer, NULL, &ReadCursor);
  813. if(SUCCEEDED(hr))
  814. {
  815. NumBytes = (ReadCursor-LastCursor + BufferBytes) % BufferBytes;
  816. if(NumBytes == 0)
  817. goto done;
  818. hr = IDirectSoundCaptureBuffer_Lock(self->DSCbuffer, LastCursor, NumBytes,
  819. &ReadPtr1, &ReadCnt1,
  820. &ReadPtr2, &ReadCnt2, 0);
  821. }
  822. if(SUCCEEDED(hr))
  823. {
  824. ll_ringbuffer_write(self->Ring, ReadPtr1, ReadCnt1/FrameSize);
  825. if(ReadPtr2 != NULL)
  826. ll_ringbuffer_write(self->Ring, ReadPtr2, ReadCnt2/FrameSize);
  827. hr = IDirectSoundCaptureBuffer_Unlock(self->DSCbuffer,
  828. ReadPtr1, ReadCnt1,
  829. ReadPtr2, ReadCnt2);
  830. self->Cursor = (LastCursor+ReadCnt1+ReadCnt2) % BufferBytes;
  831. }
  832. if(FAILED(hr))
  833. {
  834. ERR("update failed: 0x%08lx\n", hr);
  835. aluHandleDisconnect(device, "Failure retrieving capture data: 0x%lx", hr);
  836. }
  837. done:
  838. return (ALCuint)ll_ringbuffer_read_space(self->Ring);
  839. }
  840. static inline void AppendAllDevicesList2(const DevMap *entry)
  841. { AppendAllDevicesList(alstr_get_cstr(entry->name)); }
  842. static inline void AppendCaptureDeviceList2(const DevMap *entry)
  843. { AppendCaptureDeviceList(alstr_get_cstr(entry->name)); }
  844. typedef struct ALCdsoundBackendFactory {
  845. DERIVE_FROM_TYPE(ALCbackendFactory);
  846. } ALCdsoundBackendFactory;
  847. #define ALCDSOUNDBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCdsoundBackendFactory, ALCbackendFactory) } }
  848. ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void);
  849. static ALCboolean ALCdsoundBackendFactory_init(ALCdsoundBackendFactory *self);
  850. static void ALCdsoundBackendFactory_deinit(ALCdsoundBackendFactory *self);
  851. static ALCboolean ALCdsoundBackendFactory_querySupport(ALCdsoundBackendFactory *self, ALCbackend_Type type);
  852. static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory *self, enum DevProbe type);
  853. static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
  854. DEFINE_ALCBACKENDFACTORY_VTABLE(ALCdsoundBackendFactory);
  855. ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void)
  856. {
  857. static ALCdsoundBackendFactory factory = ALCDSOUNDBACKENDFACTORY_INITIALIZER;
  858. return STATIC_CAST(ALCbackendFactory, &factory);
  859. }
  860. static ALCboolean ALCdsoundBackendFactory_init(ALCdsoundBackendFactory* UNUSED(self))
  861. {
  862. VECTOR_INIT(PlaybackDevices);
  863. VECTOR_INIT(CaptureDevices);
  864. if(!DSoundLoad())
  865. return ALC_FALSE;
  866. return ALC_TRUE;
  867. }
  868. static void ALCdsoundBackendFactory_deinit(ALCdsoundBackendFactory* UNUSED(self))
  869. {
  870. clear_devlist(&PlaybackDevices);
  871. VECTOR_DEINIT(PlaybackDevices);
  872. clear_devlist(&CaptureDevices);
  873. VECTOR_DEINIT(CaptureDevices);
  874. #ifdef HAVE_DYNLOAD
  875. if(ds_handle)
  876. CloseLib(ds_handle);
  877. ds_handle = NULL;
  878. #endif
  879. }
  880. static ALCboolean ALCdsoundBackendFactory_querySupport(ALCdsoundBackendFactory* UNUSED(self), ALCbackend_Type type)
  881. {
  882. if(type == ALCbackend_Playback || type == ALCbackend_Capture)
  883. return ALC_TRUE;
  884. return ALC_FALSE;
  885. }
  886. static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory* UNUSED(self), enum DevProbe type)
  887. {
  888. HRESULT hr, hrcom;
  889. /* Initialize COM to prevent name truncation */
  890. hrcom = CoInitialize(NULL);
  891. switch(type)
  892. {
  893. case ALL_DEVICE_PROBE:
  894. clear_devlist(&PlaybackDevices);
  895. hr = DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices);
  896. if(FAILED(hr))
  897. ERR("Error enumerating DirectSound playback devices (0x%lx)!\n", hr);
  898. VECTOR_FOR_EACH(const DevMap, PlaybackDevices, AppendAllDevicesList2);
  899. break;
  900. case CAPTURE_DEVICE_PROBE:
  901. clear_devlist(&CaptureDevices);
  902. hr = DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices);
  903. if(FAILED(hr))
  904. ERR("Error enumerating DirectSound capture devices (0x%lx)!\n", hr);
  905. VECTOR_FOR_EACH(const DevMap, CaptureDevices, AppendCaptureDeviceList2);
  906. break;
  907. }
  908. if(SUCCEEDED(hrcom))
  909. CoUninitialize();
  910. }
  911. static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
  912. {
  913. if(type == ALCbackend_Playback)
  914. {
  915. ALCdsoundPlayback *backend;
  916. NEW_OBJ(backend, ALCdsoundPlayback)(device);
  917. if(!backend) return NULL;
  918. return STATIC_CAST(ALCbackend, backend);
  919. }
  920. if(type == ALCbackend_Capture)
  921. {
  922. ALCdsoundCapture *backend;
  923. NEW_OBJ(backend, ALCdsoundCapture)(device);
  924. if(!backend) return NULL;
  925. return STATIC_CAST(ALCbackend, backend);
  926. }
  927. return NULL;
  928. }