Remove FrameSize struct member
[openal-soft.git] / Alc / dsound.c
blob6dc87057aa5c9804a3701ea68052666de6ba033f
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 *
75 aluBytesFromFormat(pDevice->Format) *
76 aluChannelsFromFormat(pDevice->Format);
78 while(!pData->killNow)
80 // Get current play and write cursors
81 IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL);
82 avail = (PlayCursor-LastCursor+BufferSize) % BufferSize;
84 if(avail == 0)
86 Sleep(1);
87 continue;
90 // Lock output buffer
91 WriteCnt1 = 0;
92 WriteCnt2 = 0;
93 err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
95 // If the buffer is lost, restore it, play and lock
96 if(err == DSERR_BUFFERLOST)
98 err = IDirectSoundBuffer_Restore(pData->DSsbuffer);
99 if(SUCCEEDED(err))
100 err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING);
101 if(SUCCEEDED(err))
102 err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr1, &WriteCnt1, &WritePtr2, &WriteCnt2, 0);
105 // Successfully locked the output buffer
106 if(SUCCEEDED(err))
108 // If we have an active context, mix data directly into output buffer otherwise fill with silence
109 SuspendContext(NULL);
110 aluMixData(pDevice->Context, WritePtr1, WriteCnt1, pDevice->Format);
111 aluMixData(pDevice->Context, WritePtr2, WriteCnt2, pDevice->Format);
112 ProcessContext(NULL);
114 // Unlock output buffer only when successfully locked
115 IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr1, WriteCnt1, WritePtr2, WriteCnt2);
117 else
118 AL_PRINT("Buffer lock error: %#lx\n", err);
120 // Update old write cursor location
121 LastCursor += WriteCnt1+WriteCnt2;
122 LastCursor %= BufferSize;
125 return 0;
128 static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName)
130 DSBUFFERDESC DSBDescription;
131 DSoundData *pData = NULL;
132 WAVEFORMATEXTENSIBLE OutputType;
133 DWORD frameSize = 0;
134 LPGUID guid = NULL;
135 DWORD speakers;
136 HRESULT hr;
138 if(deviceName)
140 int i;
141 for(i = 0;DeviceList[i].name;i++)
143 if(strcmp(deviceName, DeviceList[i].name) == 0)
145 device->szDeviceName = DeviceList[i].name;
146 if(i > 0)
147 guid = &DeviceList[i].guid;
148 break;
151 if(!DeviceList[i].name)
152 return ALC_FALSE;
154 else
155 device->szDeviceName = DeviceList[0].name;
157 memset(&OutputType, 0, sizeof(OutputType));
159 //Initialise requested device
161 pData = calloc(1, sizeof(DSoundData));
162 if(!pData)
164 SetALCError(ALC_OUT_OF_MEMORY);
165 return ALC_FALSE;
168 //DirectSound Init code
169 hr = DirectSoundCreate(guid, &pData->lpDS, NULL);
170 if(SUCCEEDED(hr))
171 hr = IDirectSound_SetCooperativeLevel(pData->lpDS, GetForegroundWindow(), DSSCL_PRIORITY);
173 if(SUCCEEDED(hr))
174 hr = IDirectSound_GetSpeakerConfig(pData->lpDS, &speakers);
175 if(SUCCEEDED(hr))
177 speakers = DSSPEAKER_CONFIG(speakers);
178 if(speakers == DSSPEAKER_MONO)
180 if(aluBytesFromFormat(device->Format) == 1)
181 device->Format = AL_FORMAT_MONO8;
182 else
183 device->Format = AL_FORMAT_MONO16;
185 else if(speakers == DSSPEAKER_STEREO)
187 if(aluBytesFromFormat(device->Format) == 1)
188 device->Format = AL_FORMAT_STEREO8;
189 else
190 device->Format = AL_FORMAT_STEREO16;
192 else if(speakers == DSSPEAKER_QUAD)
194 if(aluBytesFromFormat(device->Format) == 1)
195 device->Format = AL_FORMAT_QUAD8;
196 else
197 device->Format = AL_FORMAT_QUAD16;
198 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
199 SPEAKER_FRONT_RIGHT |
200 SPEAKER_BACK_LEFT |
201 SPEAKER_BACK_RIGHT;
203 else if(speakers == DSSPEAKER_5POINT1)
205 if(aluBytesFromFormat(device->Format) == 1)
206 device->Format = AL_FORMAT_51CHN8;
207 else
208 device->Format = AL_FORMAT_51CHN16;
209 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
210 SPEAKER_FRONT_RIGHT |
211 SPEAKER_FRONT_CENTER |
212 SPEAKER_LOW_FREQUENCY |
213 SPEAKER_BACK_LEFT |
214 SPEAKER_BACK_RIGHT;
216 else if(speakers == DSSPEAKER_7POINT1)
218 if(aluBytesFromFormat(device->Format) == 1)
219 device->Format = AL_FORMAT_71CHN8;
220 else
221 device->Format = AL_FORMAT_71CHN16;
222 OutputType.dwChannelMask = SPEAKER_FRONT_LEFT |
223 SPEAKER_FRONT_RIGHT |
224 SPEAKER_FRONT_CENTER |
225 SPEAKER_LOW_FREQUENCY |
226 SPEAKER_BACK_LEFT |
227 SPEAKER_BACK_RIGHT |
228 SPEAKER_SIDE_LEFT |
229 SPEAKER_SIDE_RIGHT;
231 frameSize = aluBytesFromFormat(device->Format) *
232 aluChannelsFromFormat(device->Format);
234 OutputType.Format.wFormatTag = WAVE_FORMAT_PCM;
235 OutputType.Format.nChannels = aluChannelsFromFormat(device->Format);
236 OutputType.Format.wBitsPerSample = aluBytesFromFormat(device->Format) * 8;
237 OutputType.Format.nBlockAlign = OutputType.Format.nChannels*OutputType.Format.wBitsPerSample/8;
238 OutputType.Format.nSamplesPerSec = device->Frequency;
239 OutputType.Format.nAvgBytesPerSec = OutputType.Format.nSamplesPerSec*OutputType.Format.nBlockAlign;
240 OutputType.Format.cbSize = 0;
242 device->UpdateSize /= DS_FRAGS;
245 if(OutputType.Format.nChannels > 2)
247 OutputType.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE;
248 OutputType.Samples.wValidBitsPerSample = OutputType.Format.wBitsPerSample;
249 OutputType.Format.cbSize = 22;
250 OutputType.SubFormat = KSDATAFORMAT_SUBTYPE_PCM;
252 else
254 if(SUCCEEDED(hr))
256 memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
257 DSBDescription.dwSize=sizeof(DSBUFFERDESC);
258 DSBDescription.dwFlags=DSBCAPS_PRIMARYBUFFER;
259 hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSpbuffer, NULL);
261 if(SUCCEEDED(hr))
262 hr = IDirectSoundBuffer_SetFormat(pData->DSpbuffer,&OutputType.Format);
265 if(SUCCEEDED(hr))
267 memset(&DSBDescription,0,sizeof(DSBUFFERDESC));
268 DSBDescription.dwSize=sizeof(DSBUFFERDESC);
269 DSBDescription.dwFlags=DSBCAPS_GLOBALFOCUS|DSBCAPS_GETCURRENTPOSITION2;
270 DSBDescription.dwBufferBytes=device->UpdateSize * DS_FRAGS * frameSize;
271 DSBDescription.lpwfxFormat=&OutputType.Format;
272 hr = IDirectSound_CreateSoundBuffer(pData->lpDS, &DSBDescription, &pData->DSsbuffer, NULL);
275 if(SUCCEEDED(hr))
276 hr = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING);
278 device->ExtraData = pData;
279 pData->thread = StartThread(DSoundProc, device);
280 if(!pData->thread)
281 hr = E_FAIL;
283 if(FAILED(hr))
285 if (pData->DSsbuffer)
286 IDirectSoundBuffer_Release(pData->DSsbuffer);
287 if (pData->DSpbuffer)
288 IDirectSoundBuffer_Release(pData->DSpbuffer);
289 if (pData->lpDS)
290 IDirectSound_Release(pData->lpDS);
292 free(pData);
293 return ALC_FALSE;
296 return ALC_TRUE;
299 static void DSoundClosePlayback(ALCdevice *device)
301 DSoundData *pData = device->ExtraData;
303 pData->killNow = 1;
304 StopThread(pData->thread);
306 IDirectSoundBuffer_Release(pData->DSsbuffer);
307 if (pData->DSpbuffer)
308 IDirectSoundBuffer_Release(pData->DSpbuffer);
309 IDirectSound_Release(pData->lpDS);
311 free(pData);
312 device->ExtraData = NULL;
316 static ALCboolean DSoundOpenCapture(ALCdevice *pDevice, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize)
318 (void)pDevice;
319 (void)deviceName;
320 (void)frequency;
321 (void)format;
322 (void)SampleSize;
323 return ALC_FALSE;
326 static void DSoundCloseCapture(ALCdevice *pDevice)
328 (void)pDevice;
331 static void DSoundStartCapture(ALCdevice *pDevice)
333 (void)pDevice;
336 static void DSoundStopCapture(ALCdevice *pDevice)
338 (void)pDevice;
341 static void DSoundCaptureSamples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples)
343 (void)pDevice;
344 (void)pBuffer;
345 (void)lSamples;
348 static ALCuint DSoundAvailableSamples(ALCdevice *pDevice)
350 (void)pDevice;
351 return 0;
355 BackendFuncs DSoundFuncs = {
356 DSoundOpenPlayback,
357 DSoundClosePlayback,
358 DSoundOpenCapture,
359 DSoundCloseCapture,
360 DSoundStartCapture,
361 DSoundStopCapture,
362 DSoundCaptureSamples,
363 DSoundAvailableSamples
366 static BOOL CALLBACK DSoundEnumDevices(LPGUID guid, LPCSTR desc, LPCSTR drvname, LPVOID data)
368 static size_t i = 1;
369 (void)drvname;
370 (void)data;
372 if(guid)
374 char str[128];
375 snprintf(str, sizeof(str), "DirectSound Software on %s", desc);
376 DeviceList[i].name = AppendAllDeviceList(str);
377 DeviceList[i].guid = *guid;
378 i++;
380 else
381 DeviceList[0].name = AppendDeviceList("DirectSound Software");
383 return TRUE;
386 void alcDSoundInit(BackendFuncs *FuncList)
388 HRESULT hr;
390 *FuncList = DSoundFuncs;
392 hr = DirectSoundEnumerate(DSoundEnumDevices, NULL);
393 if(FAILED(hr))
394 AL_PRINT("Error enumerating DirectSound devices (%#x)!\n", (unsigned int)hr);