Use logging macros in the dsound backend
[openal-soft/android.git] / Alc / dsound.c
blobbbf552dfd8969640584f0bf5b7752a785d7bc3f1
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.
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.
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
21 #include "config.h"
23 #define _WIN32_WINNT 0x0500
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <memory.h>
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
36 #include "alMain.h"
37 #include "AL/al.h"
38 #include "AL/alc.h"
40 #ifndef DSSPEAKER_5POINT1
41 #define DSSPEAKER_5POINT1 6
42 #endif
43 #ifndef DSSPEAKER_7POINT1
44 #define DSSPEAKER_7POINT1 7
45 #endif
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);
51 static void *ds_handle;
52 static HRESULT (WINAPI *pDirectSoundCreate)(LPCGUID pcGuidDevice, LPDIRECTSOUND *ppDS, LPUNKNOWN pUnkOuter);
53 static HRESULT (WINAPI *pDirectSoundEnumerateA)(LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext);
55 #define DirectSoundCreate pDirectSoundCreate
56 #define DirectSoundEnumerateA pDirectSoundEnumerateA
59 typedef struct {
60 // DirectSound Playback Device
61 LPDIRECTSOUND lpDS;
62 LPDIRECTSOUNDBUFFER DSpbuffer;
63 LPDIRECTSOUNDBUFFER DSsbuffer;
65 volatile int killNow;
66 ALvoid *thread;
67 } DSoundData;
70 typedef struct {
71 ALCchar *name;
72 GUID guid;
73 } DevMap;
75 static const ALCchar dsDevice[] = "DirectSound Default";
76 static DevMap *DeviceList;
77 static ALuint NumDevices;
80 static void *DSoundLoad(void)
82 if(!ds_handle)
84 ALboolean failed = AL_FALSE;
86 ds_handle = LoadLibraryA("dsound.dll");
87 if(ds_handle == NULL)
89 ERROR("Failed to load dsound.dll\n");
90 return NULL;
93 #define LOAD_FUNC(x) do { \
94 if((p##x = (void*)GetProcAddress((HMODULE)ds_handle, #x)) == NULL) { \
95 ERROR("Could not load %s from dsound.dll\n", #x); \
96 failed = AL_TRUE; \
97 } \
98 } while(0)
99 LOAD_FUNC(DirectSoundCreate);
100 LOAD_FUNC(DirectSoundEnumerateA);
101 #undef LOAD_FUNC
103 if(failed)
105 FreeLibrary(ds_handle);
106 ds_handle = NULL;
109 return ds_handle;
113 static BOOL CALLBACK DSoundEnumDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
115 char str[1024];
116 void *temp;
117 int count;
118 ALuint i;
120 (void)data;
121 (void)drvname;
123 if(NumDevices == 0)
125 temp = realloc(DeviceList, sizeof(DevMap) * (NumDevices+1));
126 if(temp)
128 DeviceList = temp;
129 DeviceList[NumDevices].name = strdup(dsDevice);
130 DeviceList[NumDevices].guid = GUID_NULL;
131 NumDevices++;
135 if(!guid)
136 return TRUE;
138 count = 0;
139 do {
140 if(count == 0)
141 snprintf(str, sizeof(str), "%s via DirectSound", desc);
142 else
143 snprintf(str, sizeof(str), "%s #%d via DirectSound", desc, count+1);
144 count++;
146 for(i = 0;i < NumDevices;i++)
148 if(strcmp(str, DeviceList[i].name) == 0)
149 break;
151 } while(i != NumDevices);
153 temp = realloc(DeviceList, sizeof(DevMap) * (NumDevices+1));
154 if(temp)
156 DeviceList = temp;
157 DeviceList[NumDevices].name = strdup(str);
158 DeviceList[NumDevices].guid = *guid;
159 NumDevices++;
162 return TRUE;
166 static ALuint DSoundProc(ALvoid *ptr)
168 ALCdevice *pDevice = (ALCdevice*)ptr;
169 DSoundData *pData = (DSoundData*)pDevice->ExtraData;
170 DSBCAPS DSBCaps;
171 DWORD LastCursor = 0;
172 DWORD PlayCursor;
173 VOID *WritePtr1, *WritePtr2;
174 DWORD WriteCnt1, WriteCnt2;
175 BOOL Playing = FALSE;
176 DWORD FrameSize;
177 DWORD FragSize;
178 DWORD avail;
179 HRESULT err;
181 SetRTPriority();
183 memset(&DSBCaps, 0, sizeof(DSBCaps));
184 DSBCaps.dwSize = sizeof(DSBCaps);
185 err = IDirectSoundBuffer_GetCaps(pData->DSsbuffer, &DSBCaps);
186 if(FAILED(err))
188 ERROR("Failed to get buffer caps: 0x%lx\n", err);
189 aluHandleDisconnect(pDevice);
190 return 1;
193 FrameSize = FrameSizeFromDevFmt(pDevice->FmtChans, pDevice->FmtType);
194 FragSize = pDevice->UpdateSize * FrameSize;
196 IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &LastCursor, NULL);
197 while(!pData->killNow)
199 // Get current play and write cursors
200 IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL);
201 avail = (PlayCursor-LastCursor+DSBCaps.dwBufferBytes) % DSBCaps.dwBufferBytes;
203 if(avail < FragSize)
205 if(!Playing)
207 err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING);
208 if(FAILED(err))
210 ERROR("Failed to play buffer: 0x%lx\n", err);
211 aluHandleDisconnect(pDevice);
212 return 1;
214 Playing = TRUE;
216 Sleep(1);
217 continue;
219 avail -= avail%FragSize;
221 // Lock output buffer
222 WriteCnt1 = 0;
223 WriteCnt2 = 0;
224 err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
226 // If the buffer is lost, restore it and lock
227 if(err == DSERR_BUFFERLOST)
229 WARN("Buffer lost, restoring...\n");
230 err = IDirectSoundBuffer_Restore(pData->DSsbuffer);
231 if(SUCCEEDED(err))
233 Playing = FALSE;
234 LastCursor = 0;
235 err = IDirectSoundBuffer_Lock(pData->DSsbuffer, 0, DSBCaps.dwBufferBytes, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
239 // Successfully locked the output buffer
240 if(SUCCEEDED(err))
242 // If we have an active context, mix data directly into output buffer otherwise fill with silence
243 aluMixData(pDevice, WritePtr1, WriteCnt1/FrameSize);
244 aluMixData(pDevice, WritePtr2, WriteCnt2/FrameSize);
246 // Unlock output buffer only when successfully locked
247 IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
249 else
251 ERROR("Buffer lock error: %#lx\n", err);
252 aluHandleDisconnect(pDevice);
253 return 1;
256 // Update old write cursor location
257 LastCursor += WriteCnt1+WriteCnt2;
258 LastCursor %= DSBCaps.dwBufferBytes;
261 return 0;
264 static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
266 DSoundData *pData = NULL;
267 LPGUID guid = NULL;
268 HRESULT hr;
270 if(!DSoundLoad())
271 return ALC_FALSE;
273 if(!deviceName)
274 deviceName = dsDevice;
275 else if(strcmp(deviceName, dsDevice) != 0)
277 ALuint i;
279 if(!DeviceList)
281 hr = DirectSoundEnumerateA(DSoundEnumDevices, NULL);
282 if(FAILED(hr))
283 ERROR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
286 for(i = 0;i < NumDevices;i++)
288 if(strcmp(deviceName, DeviceList[i].name) == 0)
290 if(i > 0)
291 guid = &DeviceList[i].guid;
292 break;
295 if(i == NumDevices)
296 return ALC_FALSE;
299 //Initialise requested device
300 pData = calloc(1, sizeof(DSoundData));
301 if(!pData)
303 alcSetError(device, ALC_OUT_OF_MEMORY);
304 return ALC_FALSE;
307 //DirectSound Init code
308 hr = DirectSoundCreate(guid, &pData->lpDS, NULL);
309 if(SUCCEEDED(hr))
310 hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY);
311 if(FAILED(hr))
313 if(pData->lpDS)
314 IDirectSound_Release(pData->lpDS);
315 free(pData);
316 ERROR("Device init failed: 0x%08lx\n", hr);
317 return ALC_FALSE;
320 device->szDeviceName = strdup(deviceName);
321 device->ExtraData = pData;
322 return ALC_TRUE;
325 static void DSoundClosePlayback(ALCdevice *device)
327 DSoundData *pData = device->ExtraData;
329 IDirectSound_Release(pData->lpDS);
330 free(pData);
331 device->ExtraData = NULL;
334 static ALCboolean DSoundResetPlayback(ALCdevice *device)
336 DSoundData *pData = (DSoundData*)device->ExtraData;
337 DSBUFFERDESC DSBDescription;
338 WAVEFORMATEXTENSIBLE OutputType;
339 DWORD speakers;
340 HRESULT hr;
342 memset(&OutputType, 0, sizeof(OutputType));
344 switch(device->FmtType)
346 case DevFmtByte:
347 device->FmtType = DevFmtUByte;
348 break;
349 case DevFmtUShort:
350 device->FmtType = DevFmtShort;
351 break;
352 case DevFmtUByte:
353 case DevFmtShort:
354 case DevFmtFloat:
355 break;
358 hr = IDirectSound_GetSpeakerConfig(pData->lpDS, &speakers);
359 if(SUCCEEDED(hr))
361 if(!(device->Flags&DEVICE_CHANNELS_REQUEST))
363 speakers = DSSPEAKER_CONFIG(speakers);
364 if(speakers == DSSPEAKER_MONO)
365 device->FmtChans = DevFmtMono;
366 else if(speakers == DSSPEAKER_STEREO || speakers == DSSPEAKER_HEADPHONE)
367 device->FmtChans = DevFmtStereo;
368 else if(speakers == DSSPEAKER_QUAD)
369 device->FmtChans = DevFmtQuad;
370 else if(speakers == DSSPEAKER_5POINT1)
371 device->FmtChans = DevFmtX51;
372 else if(speakers == DSSPEAKER_7POINT1)
373 device->FmtChans = DevFmtX71;
374 else
375 ERROR("Unknown system speaker config: 0x%lx\n", speakers);
378 switch(device->FmtChans)
380 case DevFmtMono:
381 OutputType.dwChannelMask = SPEAKER_FRONT_CENTER;
382 break;
383 case DevFmtStereo:
384 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
385 SPEAKER_FRONT_RIGHT;
386 break;
387 case DevFmtQuad:
388 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
389 SPEAKER_FRONT_RIGHT |
390 SPEAKER_BACK_LEFT |
391 SPEAKER_BACK_RIGHT;
392 break;
393 case DevFmtX51:
394 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
395 SPEAKER_FRONT_RIGHT |
396 SPEAKER_FRONT_CENTER |
397 SPEAKER_LOW_FREQUENCY |
398 SPEAKER_BACK_LEFT |
399 SPEAKER_BACK_RIGHT;
400 break;
401 case DevFmtX51Side:
402 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
403 SPEAKER_FRONT_RIGHT |
404 SPEAKER_FRONT_CENTER |
405 SPEAKER_LOW_FREQUENCY |
406 SPEAKER_SIDE_LEFT |
407 SPEAKER_SIDE_RIGHT;
408 break;
409 case DevFmtX61:
410 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
411 SPEAKER_FRONT_RIGHT |
412 SPEAKER_FRONT_CENTER |
413 SPEAKER_LOW_FREQUENCY |
414 SPEAKER_BACK_CENTER |
415 SPEAKER_SIDE_LEFT |
416 SPEAKER_SIDE_RIGHT;
417 break;
418 case DevFmtX71:
419 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
420 SPEAKER_FRONT_RIGHT |
421 SPEAKER_FRONT_CENTER |
422 SPEAKER_LOW_FREQUENCY |
423 SPEAKER_BACK_LEFT |
424 SPEAKER_BACK_RIGHT |
425 SPEAKER_SIDE_LEFT |
426 SPEAKER_SIDE_RIGHT;
427 break;
430 OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
431 OutputType.Format.nChannels = ChannelsFromDevFmt(device->FmtChans);
432 OutputType.Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8;
433 OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8;
434 OutputType.Format.nSamplesPerSec = device->Frequency;
435 OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign;
436 OutputType.Format.cbSize = 0;
439 if(OutputType.Format.nChannels > 2 || device->FmtType == DevFmtFloat)
441 OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
442 OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
443 OutputType.Format.cbSize = sizeof(WAVEFORMATEXTENSIBLE) - sizeof(WAVEFORMATEX);
444 if(device->FmtType == DevFmtFloat)
445 OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT;
446 else
447 OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
449 else
451 if(SUCCEEDED(hr))
453 memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
454 DSBDescription.dwSize=sizeof(DSBUFFERDESC);
455 DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER;
456 hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSpbuffer, NULL);
458 if(SUCCEEDED(hr))
459 hr = IDirectSoundBuffer_SetFormat(pData->DSpbuffer,&OutputType.Format);
462 if(SUCCEEDED(hr))
464 memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
465 DSBDescription.dwSize=sizeof(DSBUFFERDESC);
466 DSBDescription.dwFlags=DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2;
467 DSBDescription.dwBufferBytes=device->UpdateSize * device->NumUpdates *
468 OutputType.Format.nBlockAlign;
469 DSBDescription.lpwfxFormat=&OutputType.Format;
470 hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL);
473 if(SUCCEEDED(hr))
475 SetDefaultWFXChannelOrder(device);
476 pData->thread = StartThread(DSoundProc, device);
477 if(!pData->thread)
478 hr = E_FAIL;
481 if(FAILED(hr))
483 if (pData->DSsbuffer)
484 IDirectSoundBuffer_Release(pData->DSsbuffer);
485 pData->DSsbuffer = NULL;
486 if (pData->DSpbuffer)
487 IDirectSoundBuffer_Release(pData->DSpbuffer);
488 pData->DSpbuffer = NULL;
489 return ALC_FALSE;
492 return ALC_TRUE;
495 static void DSoundStopPlayback(ALCdevice *device)
497 DSoundData *pData = device->ExtraData;
499 if(!pData->thread)
500 return;
502 pData->killNow = 1;
503 StopThread(pData->thread);
504 pData->thread = NULL;
506 pData->killNow = 0;
508 IDirectSoundBuffer_Release(pData->DSsbuffer);
509 pData->DSsbuffer = NULL;
510 if (pData->DSpbuffer)
511 IDirectSoundBuffer_Release(pData->DSpbuffer);
512 pData->DSpbuffer = NULL;
516 static ALCboolean DSoundOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName)
518 (void)pDevice;
519 (void)deviceName;
520 return ALC_FALSE;
523 static void DSoundCloseCapture(ALCdevice *pDevice)
525 (void)pDevice;
528 static void DSoundStartCapture(ALCdevice *pDevice)
530 (void)pDevice;
533 static void DSoundStopCapture(ALCdevice *pDevice)
535 (void)pDevice;
538 static void DSoundCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
540 (void)pDevice;
541 (void)pBuffer;
542 (void)lSamples;
545 static ALCuint DSoundAvailableSamples(ALCdevice *pDevice)
547 (void)pDevice;
548 return 0;
552 static const BackendFuncs DSoundFuncs = {
553 DSoundOpenPlayback,
554 DSoundClosePlayback,
555 DSoundResetPlayback,
556 DSoundStopPlayback,
557 DSoundOpenCapture,
558 DSoundCloseCapture,
559 DSoundStartCapture,
560 DSoundStopCapture,
561 DSoundCaptureSamples,
562 DSoundAvailableSamples
566 void alcDSoundInit(BackendFuncs *FuncList)
568 *FuncList = DSoundFuncs;
571 void alcDSoundDeinit(void)
573 ALuint i;
575 for(i = 0;i < NumDevices;++i)
576 free(DeviceList[i].name);
577 free(DeviceList);
578 DeviceList = NULL;
579 NumDevices = 0;
581 if(ds_handle)
582 FreeLibrary(ds_handle);
583 ds_handle = NULL;
586 void alcDSoundProbe(enum DevProbe type)
588 HRESULT hr;
589 ALuint i;
591 if(!DSoundLoad()) return;
593 switch(type)
595 case DEVICE_PROBE:
596 AppendDeviceList(dsDevice);
597 break;
599 case ALL_DEVICE_PROBE:
600 for(i = 0;i < NumDevices;++i)
601 free(DeviceList[i].name);
602 free(DeviceList);
603 DeviceList = NULL;
604 NumDevices = 0;
606 hr = DirectSoundEnumerateA(DSoundEnumDevices, NULL);
607 if(FAILED(hr))
608 ERROR("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);
609 else
611 for(i = 0;i < NumDevices;i++)
612 AppendAllDeviceList(DeviceList[i].name);
614 break;
616 case CAPTURE_DEVICE_PROBE:
617 break;