Remove unneeded headers
[openal-soft.git] / Alc / dsound.c
blob34f6d538c9791ff41b2fea5bfb99dbedc0fdd291
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 <dsound.h>
29 #include <mmreg.h>
31 #include "alMain.h"
32 #include "AL/al.h"
33 #include "AL/alc.h"
35 #ifndef DSSPEAKER_7POINT1
36 #define DSSPEAKER_7POINT1 7
37 #endif
39 DEFINE_GUID(KSDATAFORMAT_SUBTYPE_PCM, 0x00000001, 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71);
41 // Since DSound doesn't report the fragment size, just assume 4 fragments
42 #define DS_FRAGS 4
44 typedef struct {
45 // DirectSound Playback Device
46 LPDIRECTSOUND lpDS;
47 LPDIRECTSOUNDBUFFER DSpbuffer;
48 LPDIRECTSOUNDBUFFER DSsbuffer;
50 int killNow;
51 ALvoid *thread;
52 } DSoundData;
55 typedef struct {
56 ALCchar *name;
57 GUID guid;
58 } DevMap;
59 static DevMap DeviceList[16];
62 static ALuint DSoundProc(ALvoid *ptr)
64 ALCdevice *pDevice = (ALCdevice*)ptr;
65 DSoundData *pData = (DSoundData*)pDevice->ExtraData;
66 DWORD LastCursor = 0;
67 DWORD PlayCursor;
68 VOID *WritePtr1, *WritePtr2;
69 DWORD WriteCnt1, WriteCnt2;
70 DWORD BufferSize;
71 DWORD avail;
72 HRESULT err;
74 BufferSize = pDevice->UpdateSize*DS_FRAGS*pDevice->FrameSize;
76 while(!pData->killNow)
78 // Get current play and write cursors
79 IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL);
80 avail = (PlayCursor-LastCursor+BufferSize) % BufferSize;
82 if(avail == 0)
84 Sleep(1);
85 continue;
88 // Lock output buffer
89 WriteCnt1 = 0;
90 WriteCnt2 = 0;
91 err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
93 // If the buffer is lost, restore it, play and lock
94 if(err == DSERR_BUFFERLOST)
96 err = IDirectSoundBuffer_Restore(pData->DSsbuffer);
97 if(SUCCEEDED(err))
98 err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING);
99 if(SUCCEEDED(err))
100 err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
103 // Successfully locked the output buffer
104 if(SUCCEEDED(err))
106 // If we have an active context, mix data directly into output buffer otherwise fill with silence
107 SuspendContext(NULL);
108 aluMixData(pDevice->Context, WritePtr1, WriteCnt1, pDevice->Format);
109 aluMixData(pDevice->Context, WritePtr2, WriteCnt2, pDevice->Format);
110 ProcessContext(NULL);
112 // Unlock output buffer only when successfully locked
113 IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
115 else
116 AL_PRINT("Buffer lock error: %#lx\n", err);
118 // Update old write cursor location
119 LastCursor += WriteCnt1+WriteCnt2;
120 LastCursor %= BufferSize;
123 return 0;
126 static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
128 DSBUFFERDESC DSBDescription;
129 DSoundData *pData = NULL;
130 WAVEFORMATEXTENSIBLE OutputType;
131 LPGUID guid = NULL;
132 DWORD speakers;
133 HRESULT hr;
135 if(deviceName)
137 int i;
138 for(i = 0;DeviceList[i].name;i++)
140 if(strcmp(deviceName, DeviceList[i].name) == 0)
142 device->szDeviceName = DeviceList[i].name;
143 if(i > 0)
144 guid = &DeviceList[i].guid;
145 break;
148 if(!DeviceList[i].name)
149 return ALC_FALSE;
151 else
152 device->szDeviceName = DeviceList[0].name;
154 memset(&OutputType, 0, sizeof(OutputType));
156 //Initialise requested device
158 pData = calloc(1, sizeof(DSoundData));
159 if(!pData)
161 SetALCError(ALC_OUT_OF_MEMORY);
162 return ALC_FALSE;
165 //DirectSound Init code
166 hr = DirectSoundCreate(guid, &pData->lpDS, NULL);
167 if(SUCCEEDED(hr))
168 hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY);
170 if(SUCCEEDED(hr))
171 hr = IDirectSound_GetSpeakerConfig(pData->lpDS, &speakers);
172 if(SUCCEEDED(hr))
174 speakers = DSSPEAKER_CONFIG(speakers);
175 if(speakers == DSSPEAKER_MONO)
177 if(aluBytesFromFormat(device->Format) == 1)
178 device->Format = AL_FORMAT_MONO8;
179 else
180 device->Format = AL_FORMAT_MONO16;
182 else if(speakers == DSSPEAKER_STEREO)
184 if(aluBytesFromFormat(device->Format) == 1)
185 device->Format = AL_FORMAT_STEREO8;
186 else
187 device->Format = AL_FORMAT_STEREO16;
189 else if(speakers == DSSPEAKER_QUAD)
191 if(aluBytesFromFormat(device->Format) == 1)
192 device->Format = AL_FORMAT_QUAD8;
193 else
194 device->Format = AL_FORMAT_QUAD16;
195 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
196 SPEAKER_FRONT_RIGHT |
197 SPEAKER_BACK_LEFT |
198 SPEAKER_BACK_RIGHT;
200 else if(speakers == DSSPEAKER_5POINT1)
202 if(aluBytesFromFormat(device->Format) == 1)
203 device->Format = AL_FORMAT_51CHN8;
204 else
205 device->Format = AL_FORMAT_51CHN16;
206 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
207 SPEAKER_FRONT_RIGHT |
208 SPEAKER_FRONT_CENTER |
209 SPEAKER_LOW_FREQUENCY |
210 SPEAKER_BACK_LEFT |
211 SPEAKER_BACK_RIGHT;
213 else if(speakers == DSSPEAKER_7POINT1)
215 if(aluBytesFromFormat(device->Format) == 1)
216 device->Format = AL_FORMAT_71CHN8;
217 else
218 device->Format = AL_FORMAT_71CHN16;
219 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
220 SPEAKER_FRONT_RIGHT |
221 SPEAKER_FRONT_CENTER |
222 SPEAKER_LOW_FREQUENCY |
223 SPEAKER_BACK_LEFT |
224 SPEAKER_BACK_RIGHT |
225 SPEAKER_SIDE_LEFT |
226 SPEAKER_SIDE_RIGHT;
228 device->FrameSize = aluBytesFromFormat(device->Format) *
229 aluChannelsFromFormat(device->Format);
231 OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
232 OutputType.Format.nChannels = aluChannelsFromFormat(device->Format);
233 OutputType.Format.wBitsPerSample = aluBytesFromFormat(device->Format) * 8;
234 OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8;
235 OutputType.Format.nSamplesPerSec = device->Frequency;
236 OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign;
237 OutputType.Format.cbSize = 0;
239 device->UpdateSize /= DS_FRAGS;
242 if(OutputType.Format.nChannels > 2)
244 OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
245 OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
246 OutputType.Format.cbSize = 22;
247 OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
249 else
251 if(SUCCEEDED(hr))
253 memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
254 DSBDescription.dwSize=sizeof(DSBUFFERDESC);
255 DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER;
256 hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSpbuffer, NULL);
258 if(SUCCEEDED(hr))
259 hr = IDirectSoundBuffer_SetFormat(pData->DSpbuffer,&OutputType.Format);
262 if(SUCCEEDED(hr))
264 memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
265 DSBDescription.dwSize=sizeof(DSBUFFERDESC);
266 DSBDescription.dwFlags=DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2;
267 DSBDescription.dwBufferBytes=device->UpdateSize * DS_FRAGS * device->FrameSize;
268 DSBDescription.lpwfxFormat=&OutputType.Format;
269 hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL);
272 if(SUCCEEDED(hr))
273 hr = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING);
275 device->ExtraData = pData;
276 pData->thread = StartThread(DSoundProc, device);
277 if(!pData->thread)
278 hr = E_FAIL;
280 if(FAILED(hr))
282 if (pData->DSsbuffer)
283 IDirectSoundBuffer_Release(pData->DSsbuffer);
284 if (pData->DSpbuffer)
285 IDirectSoundBuffer_Release(pData->DSpbuffer);
286 if (pData->lpDS)
287 IDirectSound_Release(pData->lpDS);
289 free(pData);
290 return ALC_FALSE;
293 return ALC_TRUE;
296 static void DSoundClosePlayback(ALCdevice *device)
298 DSoundData *pData = device->ExtraData;
300 pData->killNow = 1;
301 StopThread(pData->thread);
303 IDirectSoundBuffer_Release(pData->DSsbuffer);
304 if (pData->DSpbuffer)
305 IDirectSoundBuffer_Release(pData->DSpbuffer);
306 IDirectSound_Release(pData->lpDS);
308 free(pData);
309 device->ExtraData = NULL;
313 static ALCboolean DSoundOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize)
315 (void)pDevice;
316 (void)deviceName;
317 (void)frequency;
318 (void)format;
319 (void)SampleSize;
320 return ALC_FALSE;
323 static void DSoundCloseCapture(ALCdevice *pDevice)
325 (void)pDevice;
328 static void DSoundStartCapture(ALCdevice *pDevice)
330 (void)pDevice;
333 static void DSoundStopCapture(ALCdevice *pDevice)
335 (void)pDevice;
338 static void DSoundCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
340 (void)pDevice;
341 (void)pBuffer;
342 (void)lSamples;
345 static ALCuint DSoundAvailableSamples(ALCdevice *pDevice)
347 (void)pDevice;
348 return 0;
352 BackendFuncs DSoundFuncs = {
353 DSoundOpenPlayback,
354 DSoundClosePlayback,
355 DSoundOpenCapture,
356 DSoundCloseCapture,
357 DSoundStartCapture,
358 DSoundStopCapture,
359 DSoundCaptureSamples,
360 DSoundAvailableSamples
363 static BOOL CALLBACK DSoundEnumDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
365 static size_t i = 1;
366 (void)drvname;
367 (void)data;
369 if(guid)
371 char str[128];
372 snprintf(str, sizeof(str), "DirectSound Software on %s", desc);
373 DeviceList[i].name = AppendAllDeviceList(str);
374 DeviceList[i].guid = *guid;
375 i++;
377 else
378 DeviceList[0].name = AppendDeviceList("DirectSound Software");
380 return TRUE;
383 void alcDSoundInit(BackendFuncs *FuncList)
385 HRESULT hr;
387 *FuncList = DSoundFuncs;
389 hr = DirectSoundEnumerate(DSoundEnumDevices, NULL);
390 if(FAILED(hr))
391 AL_PRINT("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);