annotate Alc/backends/dsound.c @ 0:f9476ff7637e

initial forking of open-al to create multiple listeners
author Robert McIntyre <rlm@mit.edu>
date Tue, 25 Oct 2011 13:02:31 -0700
parents
children
rev   line source
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 }