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