Mercurial > audio-send
comparison Alc/backends/dsound.c @ 0:f9476ff7637e
initial forking of open-al to create multiple listeners
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Tue, 25 Oct 2011 13:02:31 -0700 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:f9476ff7637e |
---|---|
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 | |
21 #include "config.h" | |
22 | |
23 #define _WIN32_WINNT 0x0500 | |
24 #include <stdlib.h> | |
25 #include <stdio.h> | |
26 #include <memory.h> | |
27 | |
28 #include <dsound.h> | |
29 #include <cguid.h> | |
30 #include <mmreg.h> | |
31 #ifndef _WAVEFORMATEXTENSIBLE_ | |
32 #include <ks.h> | |
33 #include <ksmedia.h> | |
34 #endif | |
35 | |
36 #include "alMain.h" | |
37 #include "AL/al.h" | |
38 #include "AL/alc.h" | |
39 | |
40 #ifndef DSSPEAKER_5POINT1 | |
41 #define DSSPEAKER_5POINT1 6 | |
42 #endif | |
43 #ifndef DSSPEAKER_7POINT1 | |
44 #define DSSPEAKER_7POINT1 7 | |
45 #endif | |
46 | |
47 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); | |
48 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, 0x00000003, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71); | |
49 | |
50 | |
51 static HMODULE ds_handle; | |
52 static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID pcGuidDevice, IDirectSound **ppDS, IUnknown *pUnkOuter); | |
53 static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, void *pContext); | |
54 | |
55 #define DirectSoundCreate pDirectSoundCreate | |
56 #define DirectSoundEnumerateA pDirectSoundEnumerateA | |
57 | |
58 | |
59 typedef struct { | |
60 // DirectSound Playback Device | |
61 IDirectSound *lpDS; | |
62 IDirectSoundBuffer *DSpbuffer; | |
63 IDirectSoundBuffer *DSsbuffer; | |
64 IDirectSoundNotify *DSnotify; | |
65 HANDLE hNotifyEvent; | |
66 | |
67 volatile int killNow; | |
68 ALvoid *thread; | |
69 } DSoundData; | |
70 | |
71 | |
72 typedef struct { | |
73 ALCchar *name; | |
74 GUID guid; | |
75 } DevMap; | |
76 | |
77 static const ALCchar dsDevice[] = "DirectSound Default"; | |
78 static DevMap *DeviceList; | |
79 static ALuint NumDevices; | |
80 | |
81 #define MAX_UPDATES 128 | |
82 | |
83 static ALCboolean DSoundLoad(void) | |
84 { | |
85 ALCboolean ok = ALC_TRUE; | |
86 if(!ds_handle) | |
87 { | |
88 ds_handle = LoadLibraryA("dsound.dll"); | |
89 if(ds_handle == NULL) | |
90 { | |
91 ERR("Failed to load dsound.dll\n"); | |
92 return ALC_FALSE; | |
93 } | |
94 | |
95 #define LOAD_FUNC(x) do { \ | |
96 if((p##x = (void*)GetProcAddress(ds_handle, #x)) == NULL) { \ | |
97 ERR("Could not load %s from dsound.dll\n", #x); \ | |
98 ok = ALC_FALSE; \ | |
99 } \ | |
100 } while(0) | |
101 LOAD_FUNC(DirectSoundCreate); | |
102 LOAD_FUNC(DirectSoundEnumerateA); | |
103 #undef LOAD_FUNC | |
104 | |
105 if(!ok) | |
106 { | |
107 FreeLibrary(ds_handle); | |
108 ds_handle = NULL; | |
109 } | |
110 } | |
111 return ok; | |
112 } | |
113 | |
114 | |
115 static BOOL CALLBACK DSoundEnumDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data) | |
116 { | |
117 char str[1024]; | |
118 void *temp; | |
119 int count; | |
120 ALuint i; | |
121 | |
122 (void)data; | |
123 (void)drvname; | |
124 | |
125 if(!guid) | |
126 return TRUE; | |
127 | |
128 count = 0; | |
129 do { | |
130 if(count == 0) | |
131 snprintf(str, sizeof(str), "%s", desc); | |
132 else | |
133 snprintf(str, sizeof(str), "%s #%d", desc, count+1); | |
134 count++; | |
135 | |
136 for(i = 0;i < NumDevices;i++) | |
137 { | |
138 if(strcmp(str, DeviceList[i].name) == 0) | |
139 break; | |
140 } | |
141 } while(i != NumDevices); | |
142 | |
143 temp = realloc(DeviceList, sizeof(DevMap) * (NumDevices+1)); | |
144 if(temp) | |
145 { | |
146 DeviceList = temp; | |
147 DeviceList[NumDevices].name = strdup(str); | |
148 DeviceList[NumDevices].guid = *guid; | |
149 NumDevices++; | |
150 } | |
151 | |
152 return TRUE; | |
153 } | |
154 | |
155 | |
156 static ALuint DSoundProc(ALvoid *ptr) | |
157 { | |
158 ALCdevice *pDevice = (ALCdevice*)ptr; | |
159 DSoundData *pData = (DSoundData*)pDevice->ExtraData; | |
160 DSBCAPS DSBCaps; | |
161 DWORD LastCursor = 0; | |
162 DWORD PlayCursor; | |
163 VOID *WritePtr1, *WritePtr2; | |
164 DWORD WriteCnt1, WriteCnt2; | |
165 BOOL Playing = FALSE; | |
166 DWORD FrameSize; | |
167 DWORD FragSize; | |
168 DWORD avail; | |
169 HRESULT err; | |
170 | |
171 SetRTPriority(); | |
172 | |
173 memset(&DSBCaps, 0, sizeof(DSBCaps)); | |
174 DSBCaps.dwSize = sizeof(DSBCaps); | |
175 err = IDirectSoundBuffer_GetCaps(pData->DSsbuffer, &DSBCaps); | |
176 if(FAILED(err)) | |
177 { | |
178 ERR("Failed to get buffer caps: 0x%lx\n", err); | |
179 aluHandleDisconnect(pDevice); | |
180 return 1; | |
181 } | |
182 | |
183 FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType); | |
184 FragSize = pDevice->UpdateSize * FrameSize; | |
185 | |
186 IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &LastCursor, NULL); | |
187 while(!pData->killNow) | |
188 { | |
189 // Get current play cursor | |
190 IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL); | |
191 avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes; | |
192 | |
193 if(avail < FragSize) | |
194 { | |
195 if(!Playing) | |
196 { | |
197 err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING); | |
198 if(FAILED(err)) | |
199 { | |
200 ERR("Failed to play buffer: 0x%lx\n", err); | |
201 aluHandleDisconnect(pDevice); | |
202 return 1; | |
203 } | |
204 Playing = TRUE; | |
205 } | |
206 | |
207 avail = WaitForSingleObjectEx(pData->hNotifyEvent, 2000, FALSE); | |
208 if(avail != WAIT_OBJECT_0) | |
209 ERR("WaitForSingleObjectEx error: 0x%lx\n", avail); | |
210 continue; | |
211 } | |
212 avail -= avail%FragSize; | |
213 | |
214 // Lock output buffer | |
215 WriteCnt1 = 0; | |
216 WriteCnt2 = 0; | |
217 err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); | |
218 | |
219 // If the buffer is lost, restore it and lock | |
220 if(err == DSERR_BUFFERLOST) | |
221 { | |
222 WARN("Buffer lost, restoring...\n"); | |
223 err = IDirectSoundBuffer_Restore(pData->DSsbuffer); | |
224 if(SUCCEEDED(err)) | |
225 { | |
226 Playing = FALSE; | |
227 LastCursor = 0; | |
228 err = IDirectSoundBuffer_Lock(pData->DSsbuffer, 0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0); | |
229 } | |
230 } | |
231 | |
232 // Successfully locked the output buffer | |
233 if(SUCCEEDED(err)) | |
234 { | |
235 // If we have an active context, mix data directly into output buffer otherwise fill with silence | |
236 aluMixData(pDevice, WritePtr1, WriteCnt1/FrameSize); | |
237 aluMixData(pDevice, WritePtr2, WriteCnt2/FrameSize); | |
238 | |
239 // Unlock output buffer only when successfully locked | |
240 IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2); | |
241 } | |
242 else | |
243 { | |
244 ERR("Buffer lock error: %#lx\n", err); | |
245 aluHandleDisconnect(pDevice); | |
246 return 1; | |
247 } | |
248 | |
249 // Update old write cursor location | |
250 LastCursor += WriteCnt1+WriteCnt2; | |
251 LastCursor %= DSBCaps.dwBufferBytes; | |
252 } | |
253 | |
254 return 0; | |
255 } | |
256 | |
257 static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName) | |
258 { | |
259 DSoundData *pData = NULL; | |
260 LPGUID guid = NULL; | |
261 HRESULT hr; | |
262 | |
263 if(!deviceName) | |
264 deviceName = dsDevice; | |
265 else if(strcmp(deviceName, dsDevice) != 0) | |
266 { | |
267 ALuint i; | |
268 | |
269 if(!DeviceList) | |
270 { | |
271 hr = DirectSoundEnumerateA(DSoundEnumDevices, NULL); | |
272 if(FAILED(hr)) | |
273 ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr); | |
274 } | |
275 | |
276 for(i = 0;i < NumDevices;i++) | |
277 { | |
278 if(strcmp(deviceName, DeviceList[i].name) == 0) | |
279 { | |
280 guid = &DeviceList[i].guid; | |
281 break; | |
282 } | |
283 } | |
284 if(i == NumDevices) | |
285 return ALC_FALSE; | |
286 } | |
287 | |
288 //Initialise requested device | |
289 pData = calloc(1, sizeof(DSoundData)); | |
290 if(!pData) | |
291 { | |
292 alcSetError(device, ALC_OUT_OF_MEMORY); | |
293 return ALC_FALSE; | |
294 } | |
295 | |
296 hr = DS_OK; | |
297 pData->hNotifyEvent = CreateEvent(NULL, FALSE, FALSE, NULL); | |
298 if(pData->hNotifyEvent == NULL) | |
299 hr = E_FAIL; | |
300 | |
301 //DirectSound Init code | |
302 if(SUCCEEDED(hr)) | |
303 hr = DirectSoundCreate(guid, &pData->lpDS, NULL); | |
304 if(SUCCEEDED(hr)) | |
305 hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY); | |
306 if(FAILED(hr)) | |
307 { | |
308 if(pData->lpDS) | |
309 IDirectSound_Release(pData->lpDS); | |
310 if(pData->hNotifyEvent) | |
311 CloseHandle(pData->hNotifyEvent); | |
312 free(pData); | |
313 ERR("Device init failed: 0x%08lx\n", hr); | |
314 return ALC_FALSE; | |
315 } | |
316 | |
317 device->szDeviceName = strdup(deviceName); | |
318 device->ExtraData = pData; | |
319 return ALC_TRUE; | |
320 } | |
321 | |
322 static void DSoundClosePlayback(ALCdevice *device) | |
323 { | |
324 DSoundData *pData = device->ExtraData; | |
325 | |
326 IDirectSound_Release(pData->lpDS); | |
327 CloseHandle(pData->hNotifyEvent); | |
328 free(pData); | |
329 device->ExtraData = NULL; | |
330 } | |
331 | |
332 static ALCboolean DSoundResetPlayback(ALCdevice *device) | |
333 { | |
334 DSoundData *pData = (DSoundData*)device->ExtraData; | |
335 DSBUFFERDESC DSBDescription; | |
336 WAVEFORMATEXTENSIBLE OutputType; | |
337 DWORD speakers; | |
338 HRESULT hr; | |
339 | |
340 memset(&OutputType, 0, sizeof(OutputType)); | |
341 | |
342 switch(device->FmtType) | |
343 { | |
344 case DevFmtByte: | |
345 device->FmtType = DevFmtUByte; | |
346 break; | |
347 case DevFmtUShort: | |
348 device->FmtType = DevFmtShort; | |
349 break; | |
350 case DevFmtUByte: | |
351 case DevFmtShort: | |
352 case DevFmtFloat: | |
353 break; | |
354 } | |
355 | |
356 hr = IDirectSound_GetSpeakerConfig(pData->lpDS, &speakers); | |
357 if(SUCCEEDED(hr)) | |
358 { | |
359 if(!(device->Flags&DEVICE_CHANNELS_REQUEST)) | |
360 { | |
361 speakers = DSSPEAKER_CONFIG(speakers); | |
362 if(speakers == DSSPEAKER_MONO) | |
363 device->FmtChans = DevFmtMono; | |
364 else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE) | |
365 device->FmtChans = DevFmtStereo; | |
366 else if(speakers == DSSPEAKER_QUAD) | |
367 device->FmtChans = DevFmtQuad; | |
368 else if(speakers == DSSPEAKER_5POINT1) | |
369 device->FmtChans = DevFmtX51; | |
370 else if(speakers == DSSPEAKER_7POINT1) | |
371 device->FmtChans = DevFmtX71; | |
372 else | |
373 ERR("Unknown system speaker config: 0x%lx\n", speakers); | |
374 } | |
375 | |
376 switch(device->FmtChans) | |
377 { | |
378 case DevFmtMono: | |
379 OutputType.dwChannelMask = SPEAKER_FRONT_CENTER; | |
380 break; | |
381 case DevFmtStereo: | |
382 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | | |
383 SPEAKER_FRONT_RIGHT; | |
384 break; | |
385 case DevFmtQuad: | |
386 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | | |
387 SPEAKER_FRONT_RIGHT | | |
388 SPEAKER_BACK_LEFT | | |
389 SPEAKER_BACK_RIGHT; | |
390 break; | |
391 case DevFmtX51: | |
392 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | | |
393 SPEAKER_FRONT_RIGHT | | |
394 SPEAKER_FRONT_CENTER | | |
395 SPEAKER_LOW_FREQUENCY | | |
396 SPEAKER_BACK_LEFT | | |
397 SPEAKER_BACK_RIGHT; | |
398 break; | |
399 case DevFmtX51Side: | |
400 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | | |
401 SPEAKER_FRONT_RIGHT | | |
402 SPEAKER_FRONT_CENTER | | |
403 SPEAKER_LOW_FREQUENCY | | |
404 SPEAKER_SIDE_LEFT | | |
405 SPEAKER_SIDE_RIGHT; | |
406 break; | |
407 case DevFmtX61: | |
408 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT | | |
409 SPEAKER_FRONT_RIGHT | | |
410 SPEAKER_FRONT_CENTER | | |
411 SPEAKER_LOW_FREQUENCY | | |
412 SPEAKER_BACK_CENTER | | |
413 SPEAKER_SIDE_LEFT | | |
414 SPEAKER_SIDE_RIGHT; | |
415 break; | |
416 case DevFmtX71: | |
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 SPEAKER_SIDE_LEFT | | |
424 SPEAKER_SIDE_RIGHT; | |
425 break; | |
426 } | |
427 | |
428 OutputType.Format.wFormatTag = WAVE_FORMAT_PCM; | |
429 OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans); | |
430 OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; | |
431 OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8; | |
432 OutputType.Format.nSamplesPerSec = device->Frequency; | |
433 OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign; | |
434 OutputType.Format.cbSize = 0; | |
435 } | |
436 | |
437 if(OutputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat) | |
438 { | |
439 OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; | |
440 OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample; | |
441 OutputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX); | |
442 if(device->FmtType == DevFmtFloat) | |
443 OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; | |
444 else | |
445 OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM; | |
446 } | |
447 else | |
448 { | |
449 if(SUCCEEDED(hr)) | |
450 { | |
451 memset(&DSBDescription,0,sizeof(DSBUFFERDESC)); | |
452 DSBDescription.dwSize=sizeof(DSBUFFERDESC); | |
453 DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER; | |
454 hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSpbuffer, NULL); | |
455 } | |
456 if(SUCCEEDED(hr)) | |
457 hr = IDirectSoundBuffer_SetFormat(pData->DSpbuffer,&OutputType.Format); | |
458 } | |
459 | |
460 if(SUCCEEDED(hr)) | |
461 { | |
462 if(device->NumUpdates > MAX_UPDATES) | |
463 { | |
464 device->UpdateSize = (device->UpdateSize*device->NumUpdates + | |
465 MAX_UPDATES-1) / MAX_UPDATES; | |
466 device->NumUpdates = MAX_UPDATES; | |
467 } | |
468 | |
469 memset(&DSBDescription,0,sizeof(DSBUFFERDESC)); | |
470 DSBDescription.dwSize=sizeof(DSBUFFERDESC); | |
471 DSBDescription.dwFlags=DSBCAPS_CTRLPOSITIONNOTIFY|DSBCAPS_GETCURRENTPOSITION2|DSBCAPS_GLOBALFOCUS; | |
472 DSBDescription.dwBufferBytes=device->UpdateSize * device->NumUpdates * | |
473 OutputType.Format.nBlockAlign; | |
474 DSBDescription.lpwfxFormat=&OutputType.Format; | |
475 hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL); | |
476 } | |
477 | |
478 if(SUCCEEDED(hr)) | |
479 { | |
480 hr = IDirectSoundBuffer_QueryInterface(pData->DSsbuffer, &IID_IDirectSoundNotify, (LPVOID *)&pData->DSnotify); | |
481 if(SUCCEEDED(hr)) | |
482 { | |
483 DSBPOSITIONNOTIFY notifies[MAX_UPDATES]; | |
484 ALuint i; | |
485 | |
486 for(i = 0;i < device->NumUpdates;++i) | |
487 { | |
488 notifies[i].dwOffset = i * device->UpdateSize * | |
489 OutputType.Format.nBlockAlign; | |
490 notifies[i].hEventNotify = pData->hNotifyEvent; | |
491 } | |
492 if(IDirectSoundNotify_SetNotificationPositions(pData->DSnotify, device->NumUpdates, notifies) != DS_OK) | |
493 hr = E_FAIL; | |
494 } | |
495 } | |
496 | |
497 if(SUCCEEDED(hr)) | |
498 { | |
499 ResetEvent(pData->hNotifyEvent); | |
500 SetDefaultWFXChannelOrder(device); | |
501 pData->thread = StartThread(DSoundProc, device); | |
502 if(pData->thread == NULL) | |
503 hr = E_FAIL; | |
504 } | |
505 | |
506 if(FAILED(hr)) | |
507 { | |
508 if(pData->DSnotify != NULL) | |
509 IDirectSoundNotify_Release(pData->DSnotify); | |
510 pData->DSnotify = NULL; | |
511 if(pData->DSsbuffer != NULL) | |
512 IDirectSoundBuffer_Release(pData->DSsbuffer); | |
513 pData->DSsbuffer = NULL; | |
514 if(pData->DSpbuffer != NULL) | |
515 IDirectSoundBuffer_Release(pData->DSpbuffer); | |
516 pData->DSpbuffer = NULL; | |
517 return ALC_FALSE; | |
518 } | |
519 | |
520 return ALC_TRUE; | |
521 } | |
522 | |
523 static void DSoundStopPlayback(ALCdevice *device) | |
524 { | |
525 DSoundData *pData = device->ExtraData; | |
526 | |
527 if(!pData->thread) | |
528 return; | |
529 | |
530 pData->killNow = 1; | |
531 StopThread(pData->thread); | |
532 pData->thread = NULL; | |
533 | |
534 pData->killNow = 0; | |
535 | |
536 IDirectSoundNotify_Release(pData->DSnotify); | |
537 pData->DSnotify = NULL; | |
538 IDirectSoundBuffer_Release(pData->DSsbuffer); | |
539 pData->DSsbuffer = NULL; | |
540 if(pData->DSpbuffer != NULL) | |
541 IDirectSoundBuffer_Release(pData->DSpbuffer); | |
542 pData->DSpbuffer = NULL; | |
543 } | |
544 | |
545 | |
546 static const BackendFuncs DSoundFuncs = { | |
547 DSoundOpenPlayback, | |
548 DSoundClosePlayback, | |
549 DSoundResetPlayback, | |
550 DSoundStopPlayback, | |
551 NULL, | |
552 NULL, | |
553 NULL, | |
554 NULL, | |
555 NULL, | |
556 NULL | |
557 }; | |
558 | |
559 | |
560 ALCboolean alcDSoundInit(BackendFuncs *FuncList) | |
561 { | |
562 if(!DSoundLoad()) | |
563 return ALC_FALSE; | |
564 *FuncList = DSoundFuncs; | |
565 return ALC_TRUE; | |
566 } | |
567 | |
568 void alcDSoundDeinit(void) | |
569 { | |
570 ALuint i; | |
571 | |
572 for(i = 0;i < NumDevices;++i) | |
573 free(DeviceList[i].name); | |
574 free(DeviceList); | |
575 DeviceList = NULL; | |
576 NumDevices = 0; | |
577 | |
578 if(ds_handle) | |
579 FreeLibrary(ds_handle); | |
580 ds_handle = NULL; | |
581 } | |
582 | |
583 void alcDSoundProbe(enum DevProbe type) | |
584 { | |
585 HRESULT hr; | |
586 ALuint i; | |
587 | |
588 switch(type) | |
589 { | |
590 case DEVICE_PROBE: | |
591 AppendDeviceList(dsDevice); | |
592 break; | |
593 | |
594 case ALL_DEVICE_PROBE: | |
595 for(i = 0;i < NumDevices;++i) | |
596 free(DeviceList[i].name); | |
597 free(DeviceList); | |
598 DeviceList = NULL; | |
599 NumDevices = 0; | |
600 | |
601 hr = DirectSoundEnumerateA(DSoundEnumDevices, NULL); | |
602 if(FAILED(hr)) | |
603 ERR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr); | |
604 else | |
605 { | |
606 for(i = 0;i < NumDevices;i++) | |
607 AppendAllDeviceList(DeviceList[i].name); | |
608 } | |
609 break; | |
610 | |
611 case CAPTURE_DEVICE_PROBE: | |
612 break; | |
613 } | |
614 } |