Remove explicit dependancy on ole32 and unused dxguid
[openal-soft/openbsd.git] / Alc / dsound.c
blob5313b039b05b55020c6d906bbb4067ed9e153b0c
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 INITGUID
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <memory.h>
28 #include <windows.h>
29 #include <mmsystem.h>
30 #include <mmreg.h>
31 #include <dsound.h>
33 #include "alMain.h"
34 #include "AL/al.h"
35 #include "AL/alc.h"
37 #ifndef DSSPEAKER_7POINT1
38 #define DSSPEAKER_7POINT1 7
39 #endif
41 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
43 typedef struct {
44 // DirectSound Playback Device
45 LPDIRECTSOUND lpDS;
46 LPDIRECTSOUNDBUFFER DSpbuffer;
47 LPDIRECTSOUNDBUFFER DSsbuffer;
49 int killNow;
50 ALvoid *thread;
51 } DSoundData;
54 typedef struct {
55 ALCchar *name;
56 GUID guid;
57 } DevMap;
58 static DevMap DeviceList[16];
61 static ALuint DSoundProc(ALvoid *ptr)
63 ALCdevice *pDevice = (ALCdevice*)ptr;
64 DSoundData *pData = (DSoundData*)pDevice->ExtraData;
65 DWORD LastCursor = 0;
66 DWORD PlayCursor;
67 VOID *WritePtr1, *WritePtr2;
68 DWORD WriteCnt1, WriteCnt2;
69 DWORD BufferSize;
70 DWORD avail;
71 HRESULT err;
73 BufferSize = pDevice->UpdateFreq*pDevice->FrameSize;
75 while(!pData->killNow)
77 // Get current play and write cursors
78 IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL);
79 avail = (PlayCursor-LastCursor+BufferSize) % BufferSize;
81 if(avail == 0)
83 Sleep(1);
84 continue;
87 // Lock output buffer
88 WriteCnt1 = 0;
89 WriteCnt2 = 0;
90 err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
92 // If the buffer is lost, restore it, play and lock
93 if(err == DSERR_BUFFERLOST)
95 err = IDirectSoundBuffer_Restore(pData->DSsbuffer);
96 if(SUCCEEDED(err))
97 err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING);
98 if(SUCCEEDED(err))
99 err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
102 // Successfully locked the output buffer
103 if(SUCCEEDED(err))
105 // If we have an active context, mix data directly into output buffer otherwise fill with silence
106 SuspendContext(NULL);
107 aluMixData(pDevice->Context, WritePtr1, WriteCnt1, pDevice->Format);
108 aluMixData(pDevice->Context, WritePtr2, WriteCnt2, pDevice->Format);
109 ProcessContext(NULL);
111 // Unlock output buffer only when successfully locked
112 IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
114 else
115 AL_PRINT("Buffer lock error: %#lx\n", err);
117 // Update old write cursor location
118 LastCursor += WriteCnt1+WriteCnt2;
119 LastCursor %= BufferSize;
122 return 0;
125 static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
127 DSBUFFERDESC DSBDescription;
128 DSoundData *pData = NULL;
129 WAVEFORMATEXTENSIBLE OutputType;
130 LPGUID guid = NULL;
131 DWORD speakers;
132 HRESULT hr;
134 if(deviceName)
136 int i;
137 for(i = 0;DeviceList[i].name;i++)
139 if(strcmp(deviceName, DeviceList[i].name) == 0)
141 device->szDeviceName = DeviceList[i].name;
142 if(i > 0)
143 guid = &DeviceList[i].guid;
144 break;
147 if(!DeviceList[i].name)
148 return ALC_FALSE;
150 else
151 device->szDeviceName = DeviceList[0].name;
153 memset(&OutputType, 0, sizeof(OutputType));
155 //Initialise requested device
157 pData = calloc(1, sizeof(DSoundData));
158 if(!pData)
160 SetALCError(ALC_OUT_OF_MEMORY);
161 return ALC_FALSE;
164 //DirectSound Init code
165 hr = DirectSoundCreate(guid, &pData->lpDS, NULL);
166 if(SUCCEEDED(hr))
167 hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY);
169 if(SUCCEEDED(hr))
170 hr = IDirectSound_GetSpeakerConfig(pData->lpDS, &speakers);
171 if(SUCCEEDED(hr))
173 speakers = DSSPEAKER_CONFIG(speakers);
174 if(speakers == DSSPEAKER_MONO)
176 if(aluBytesFromFormat(device->Format) == 1)
177 device->Format = AL_FORMAT_MONO8;
178 else
179 device->Format = AL_FORMAT_MONO16;
181 else if(speakers == DSSPEAKER_STEREO)
183 if(aluBytesFromFormat(device->Format) == 1)
184 device->Format = AL_FORMAT_STEREO8;
185 else
186 device->Format = AL_FORMAT_STEREO16;
188 else if(speakers == DSSPEAKER_QUAD)
190 if(aluBytesFromFormat(device->Format) == 1)
191 device->Format = AL_FORMAT_QUAD8;
192 else
193 device->Format = AL_FORMAT_QUAD16;
194 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
195 SPEAKER_FRONT_RIGHT |
196 SPEAKER_BACK_LEFT |
197 SPEAKER_BACK_RIGHT;
199 else if(speakers == DSSPEAKER_5POINT1)
201 if(aluBytesFromFormat(device->Format) == 1)
202 device->Format = AL_FORMAT_51CHN8;
203 else
204 device->Format = AL_FORMAT_51CHN16;
205 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
206 SPEAKER_FRONT_RIGHT |
207 SPEAKER_FRONT_CENTER |
208 SPEAKER_LOW_FREQUENCY |
209 SPEAKER_BACK_LEFT |
210 SPEAKER_BACK_RIGHT;
212 else if(speakers == DSSPEAKER_7POINT1)
214 if(aluBytesFromFormat(device->Format) == 1)
215 device->Format = AL_FORMAT_71CHN8;
216 else
217 device->Format = AL_FORMAT_71CHN16;
218 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
219 SPEAKER_FRONT_RIGHT |
220 SPEAKER_FRONT_CENTER |
221 SPEAKER_LOW_FREQUENCY |
222 SPEAKER_BACK_LEFT |
223 SPEAKER_BACK_RIGHT |
224 SPEAKER_SIDE_LEFT |
225 SPEAKER_SIDE_RIGHT;
227 device->FrameSize = aluBytesFromFormat(device->Format) *
228 aluChannelsFromFormat(device->Format);
230 OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
231 OutputType.Format.nChannels = aluChannelsFromFormat(device->Format);
232 OutputType.Format.wBitsPerSample = aluBytesFromFormat(device->Format) * 8;
233 OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8;
234 OutputType.Format.nSamplesPerSec = device->Frequency;
235 OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign;
236 OutputType.Format.cbSize = 0;
239 if(OutputType.Format.nChannels > 2)
241 OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
242 OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
243 OutputType.Format.cbSize = 22;
244 OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
246 else
248 if(SUCCEEDED(hr))
250 memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
251 DSBDescription.dwSize=sizeof(DSBUFFERDESC);
252 DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER;
253 hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSpbuffer, NULL);
255 if(SUCCEEDED(hr))
256 hr = IDirectSoundBuffer_SetFormat(pData->DSpbuffer,&OutputType.Format);
259 if(SUCCEEDED(hr))
261 memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
262 DSBDescription.dwSize=sizeof(DSBUFFERDESC);
263 DSBDescription.dwFlags=DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2;
264 DSBDescription.dwBufferBytes=device->UpdateFreq * device->FrameSize;
265 DSBDescription.lpwfxFormat=&OutputType.Format;
266 hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL);
269 if(SUCCEEDED(hr))
270 hr = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING);
272 device->ExtraData = pData;
273 pData->thread = StartThread(DSoundProc, device);
274 if(!pData->thread)
275 hr = E_FAIL;
277 if(FAILED(hr))
279 if (pData->DSsbuffer)
280 IDirectSoundBuffer_Release(pData->DSsbuffer);
281 if (pData->DSpbuffer)
282 IDirectSoundBuffer_Release(pData->DSpbuffer);
283 if (pData->lpDS)
284 IDirectSound_Release(pData->lpDS);
286 free(pData);
287 return ALC_FALSE;
290 return ALC_TRUE;
293 static void DSoundClosePlayback(ALCdevice *device)
295 DSoundData *pData = device->ExtraData;
297 pData->killNow = 1;
298 StopThread(pData->thread);
300 IDirectSoundBuffer_Release(pData->DSsbuffer);
301 if (pData->DSpbuffer)
302 IDirectSoundBuffer_Release(pData->DSpbuffer);
303 IDirectSound_Release(pData->lpDS);
305 free(pData);
306 device->ExtraData = NULL;
310 static ALCboolean DSoundOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize)
312 (void)pDevice;
313 (void)deviceName;
314 (void)frequency;
315 (void)format;
316 (void)SampleSize;
317 return ALC_FALSE;
320 static void DSoundCloseCapture(ALCdevice *pDevice)
322 (void)pDevice;
325 static void DSoundStartCapture(ALCdevice *pDevice)
327 (void)pDevice;
330 static void DSoundStopCapture(ALCdevice *pDevice)
332 (void)pDevice;
335 static void DSoundCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
337 (void)pDevice;
338 (void)pBuffer;
339 (void)lSamples;
342 static ALCuint DSoundAvailableSamples(ALCdevice *pDevice)
344 (void)pDevice;
345 return 0;
349 BackendFuncs DSoundFuncs = {
350 DSoundOpenPlayback,
351 DSoundClosePlayback,
352 DSoundOpenCapture,
353 DSoundCloseCapture,
354 DSoundStartCapture,
355 DSoundStopCapture,
356 DSoundCaptureSamples,
357 DSoundAvailableSamples
360 static BOOL CALLBACK DSoundEnumDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
362 static size_t i = 1;
363 (void)drvname;
364 (void)data;
366 if(guid)
368 char str[128];
369 snprintf(str, sizeof(str), "DirectSound Software on %s", desc);
370 DeviceList[i].name = AppendAllDeviceList(str);
371 DeviceList[i].guid = *guid;
372 i++;
374 else
375 DeviceList[0].name = AppendDeviceList("DirectSound Software");
377 return TRUE;
380 void alcDSoundInit(BackendFuncs *FuncList)
382 HRESULT hr;
384 *FuncList = DSoundFuncs;
386 hr = DirectSoundEnumerate(DSoundEnumDevices, NULL);
387 if(FAILED(hr))
388 AL_PRINT("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);