dsound.c 37 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079
  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. typedef struct ALCdsoundBackendFactory {
  841. DERIVE_FROM_TYPE(ALCbackendFactory);
  842. } ALCdsoundBackendFactory;
  843. #define ALCDSOUNDBACKENDFACTORY_INITIALIZER { { GET_VTABLE2(ALCdsoundBackendFactory, ALCbackendFactory) } }
  844. ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void);
  845. static ALCboolean ALCdsoundBackendFactory_init(ALCdsoundBackendFactory *self);
  846. static void ALCdsoundBackendFactory_deinit(ALCdsoundBackendFactory *self);
  847. static ALCboolean ALCdsoundBackendFactory_querySupport(ALCdsoundBackendFactory *self, ALCbackend_Type type);
  848. static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory *self, enum DevProbe type, al_string *outnames);
  849. static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory *self, ALCdevice *device, ALCbackend_Type type);
  850. DEFINE_ALCBACKENDFACTORY_VTABLE(ALCdsoundBackendFactory);
  851. ALCbackendFactory *ALCdsoundBackendFactory_getFactory(void)
  852. {
  853. static ALCdsoundBackendFactory factory = ALCDSOUNDBACKENDFACTORY_INITIALIZER;
  854. return STATIC_CAST(ALCbackendFactory, &factory);
  855. }
  856. static ALCboolean ALCdsoundBackendFactory_init(ALCdsoundBackendFactory* UNUSED(self))
  857. {
  858. VECTOR_INIT(PlaybackDevices);
  859. VECTOR_INIT(CaptureDevices);
  860. if(!DSoundLoad())
  861. return ALC_FALSE;
  862. return ALC_TRUE;
  863. }
  864. static void ALCdsoundBackendFactory_deinit(ALCdsoundBackendFactory* UNUSED(self))
  865. {
  866. clear_devlist(&PlaybackDevices);
  867. VECTOR_DEINIT(PlaybackDevices);
  868. clear_devlist(&CaptureDevices);
  869. VECTOR_DEINIT(CaptureDevices);
  870. #ifdef HAVE_DYNLOAD
  871. if(ds_handle)
  872. CloseLib(ds_handle);
  873. ds_handle = NULL;
  874. #endif
  875. }
  876. static ALCboolean ALCdsoundBackendFactory_querySupport(ALCdsoundBackendFactory* UNUSED(self), ALCbackend_Type type)
  877. {
  878. if(type == ALCbackend_Playback || type == ALCbackend_Capture)
  879. return ALC_TRUE;
  880. return ALC_FALSE;
  881. }
  882. static void ALCdsoundBackendFactory_probe(ALCdsoundBackendFactory* UNUSED(self), enum DevProbe type, al_string *outnames)
  883. {
  884. HRESULT hr, hrcom;
  885. /* Initialize COM to prevent name truncation */
  886. hrcom = CoInitialize(NULL);
  887. switch(type)
  888. {
  889. #define APPEND_OUTNAME(e) do { \
  890. if(!alstr_empty((e)->name)) \
  891. alstr_append_range(outnames, VECTOR_BEGIN((e)->name), \
  892. VECTOR_END((e)->name)+1); \
  893. } while(0)
  894. case ALL_DEVICE_PROBE:
  895. clear_devlist(&PlaybackDevices);
  896. hr = DirectSoundEnumerateW(DSoundEnumDevices, &PlaybackDevices);
  897. if(FAILED(hr))
  898. ERR("Error enumerating DirectSound playback devices (0x%lx)!\n", hr);
  899. VECTOR_FOR_EACH(const DevMap, PlaybackDevices, APPEND_OUTNAME);
  900. break;
  901. case CAPTURE_DEVICE_PROBE:
  902. clear_devlist(&CaptureDevices);
  903. hr = DirectSoundCaptureEnumerateW(DSoundEnumDevices, &CaptureDevices);
  904. if(FAILED(hr))
  905. ERR("Error enumerating DirectSound capture devices (0x%lx)!\n", hr);
  906. VECTOR_FOR_EACH(const DevMap, CaptureDevices, APPEND_OUTNAME);
  907. break;
  908. #undef APPEND_OUTNAME
  909. }
  910. if(SUCCEEDED(hrcom))
  911. CoUninitialize();
  912. }
  913. static ALCbackend* ALCdsoundBackendFactory_createBackend(ALCdsoundBackendFactory* UNUSED(self), ALCdevice *device, ALCbackend_Type type)
  914. {
  915. if(type == ALCbackend_Playback)
  916. {
  917. ALCdsoundPlayback *backend;
  918. NEW_OBJ(backend, ALCdsoundPlayback)(device);
  919. if(!backend) return NULL;
  920. return STATIC_CAST(ALCbackend, backend);
  921. }
  922. if(type == ALCbackend_Capture)
  923. {
  924. ALCdsoundCapture *backend;
  925. NEW_OBJ(backend, ALCdsoundCapture)(device);
  926. if(!backend) return NULL;
  927. return STATIC_CAST(ALCbackend, backend);
  928. }
  929. return NULL;
  930. }