Atlas - SDL_directsound.c
Home / ext / SDL / src / audio / directsound Lines: 2 | Size: 24463 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#ifdef SDL_AUDIO_DRIVER_DSOUND 24 25#include "../SDL_sysaudio.h" 26#include "SDL_directsound.h" 27#include <mmreg.h> 28#ifdef HAVE_MMDEVICEAPI_H 29#include "../../core/windows/SDL_immdevice.h" 30#endif 31 32#ifndef WAVE_FORMAT_IEEE_FLOAT 33#define WAVE_FORMAT_IEEE_FLOAT 0x0003 34#endif 35 36// For Vista+, we can enumerate DSound devices with IMMDevice 37#ifdef HAVE_MMDEVICEAPI_H 38static bool SupportsIMMDevice = false; 39#endif 40 41// DirectX function pointers for audio 42static SDL_SharedObject *DSoundDLL = NULL; 43typedef HRESULT (WINAPI *pfnDirectSoundCreate8)(LPGUID, LPDIRECTSOUND *, LPUNKNOWN); 44typedef HRESULT (WINAPI *pfnDirectSoundEnumerateW)(LPDSENUMCALLBACKW, LPVOID); 45typedef HRESULT (WINAPI *pfnDirectSoundCaptureCreate8)(LPCGUID, LPDIRECTSOUNDCAPTURE8 *, LPUNKNOWN); 46typedef HRESULT (WINAPI *pfnDirectSoundCaptureEnumerateW)(LPDSENUMCALLBACKW, LPVOID); 47typedef HRESULT (WINAPI *pfnGetDeviceID)(LPCGUID, LPGUID); 48static pfnDirectSoundCreate8 pDirectSoundCreate8 = NULL; 49static pfnDirectSoundEnumerateW pDirectSoundEnumerateW = NULL; 50static pfnDirectSoundCaptureCreate8 pDirectSoundCaptureCreate8 = NULL; 51static pfnDirectSoundCaptureEnumerateW pDirectSoundCaptureEnumerateW = NULL; 52static pfnGetDeviceID pGetDeviceID = NULL; 53 54#include <initguid.h> 55DEFINE_GUID(SDL_DSDEVID_DefaultPlayback, 0xdef00000, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); 56DEFINE_GUID(SDL_DSDEVID_DefaultCapture, 0xdef00001, 0x9c6d, 0x47ed, 0xaa, 0xf1, 0x4d, 0xda, 0x8f, 0x2b, 0x5c, 0x03); 57 58static const GUID SDL_KSDATAFORMAT_SUBTYPE_PCM = { 0x00000001, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } }; 59static const GUID SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT = { 0x00000003, 0x0000, 0x0010, { 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 } }; 60 61static void DSOUND_Unload(void) 62{ 63 pDirectSoundCreate8 = NULL; 64 pDirectSoundEnumerateW = NULL; 65 pDirectSoundCaptureCreate8 = NULL; 66 pDirectSoundCaptureEnumerateW = NULL; 67 pGetDeviceID = NULL; 68 69 if (DSoundDLL) { 70 SDL_UnloadObject(DSoundDLL); 71 DSoundDLL = NULL; 72 } 73} 74 75static bool DSOUND_Load(void) 76{ 77 bool loaded = false; 78 79 DSOUND_Unload(); 80 81 DSoundDLL = SDL_LoadObject("DSOUND.DLL"); 82 if (!DSoundDLL) { 83 SDL_SetError("DirectSound: failed to load DSOUND.DLL"); 84 } else { 85// Now make sure we have DirectX 8 or better... 86#define DSOUNDLOAD(f) \ 87 { \ 88 p##f = (pfn##f)SDL_LoadFunction(DSoundDLL, #f); \ 89 if (!p##f) \ 90 loaded = false; \ 91 } 92 loaded = true; // will reset if necessary. 93 DSOUNDLOAD(DirectSoundCreate8); 94 DSOUNDLOAD(DirectSoundEnumerateW); 95 DSOUNDLOAD(DirectSoundCaptureCreate8); 96 DSOUNDLOAD(DirectSoundCaptureEnumerateW); 97 DSOUNDLOAD(GetDeviceID); 98#undef DSOUNDLOAD 99 100 if (!loaded) { 101 SDL_SetError("DirectSound: System doesn't appear to have DX8."); 102 } 103 } 104 105 if (!loaded) { 106 DSOUND_Unload(); 107 } 108 109 return loaded; 110} 111 112static bool SetDSerror(const char *function, int code) 113{ 114 const char *error; 115 116 switch (code) { 117 case E_NOINTERFACE: 118 error = "Unsupported interface -- Is DirectX 8.0 or later installed?"; 119 break; 120 case DSERR_ALLOCATED: 121 error = "Audio device in use"; 122 break; 123 case DSERR_BADFORMAT: 124 error = "Unsupported audio format"; 125 break; 126 case DSERR_BUFFERLOST: 127 error = "Mixing buffer was lost"; 128 break; 129 case DSERR_CONTROLUNAVAIL: 130 error = "Control requested is not available"; 131 break; 132 case DSERR_INVALIDCALL: 133 error = "Invalid call for the current state"; 134 break; 135 case DSERR_INVALIDPARAM: 136 error = "Invalid parameter"; 137 break; 138 case DSERR_NODRIVER: 139 error = "No audio device found"; 140 break; 141 case DSERR_OUTOFMEMORY: 142 error = "Out of memory"; 143 break; 144 case DSERR_PRIOLEVELNEEDED: 145 error = "Caller doesn't have priority"; 146 break; 147 case DSERR_UNSUPPORTED: 148 error = "Function not supported"; 149 break; 150 default: 151 error = "Unknown DirectSound error"; 152 break; 153 } 154 155 return SDL_SetError("%s: %s (0x%x)", function, error, code); 156} 157 158static void DSOUND_FreeDeviceHandle(SDL_AudioDevice *device) 159{ 160#ifdef HAVE_MMDEVICEAPI_H 161 if (SupportsIMMDevice) { 162 SDL_IMMDevice_FreeDeviceHandle(device); 163 } else 164#endif 165 { 166 SDL_free(device->handle); 167 } 168} 169 170// FindAllDevs is presumably only used on WinXP; Vista and later can use IMMDevice for better results. 171typedef struct FindAllDevsData 172{ 173 bool recording; 174 SDL_AudioDevice **default_device; 175 LPCGUID default_device_guid; 176} FindAllDevsData; 177 178static BOOL CALLBACK FindAllDevs(LPGUID guid, LPCWSTR desc, LPCWSTR module, LPVOID userdata) 179{ 180 FindAllDevsData *data = (FindAllDevsData *) userdata; 181 if (guid != NULL) { // skip default device 182 char *str = WIN_LookupAudioDeviceName(desc, guid); 183 if (str) { 184 LPGUID cpyguid = (LPGUID)SDL_malloc(sizeof(GUID)); 185 if (cpyguid) { 186 SDL_copyp(cpyguid, guid); 187 188 /* Note that spec is NULL, because we are required to connect to the 189 * device before getting the channel mask and output format, making 190 * this information inaccessible at enumeration time 191 */ 192 SDL_AudioDevice *device = SDL_AddAudioDevice(data->recording, str, NULL, cpyguid); 193 if (device && data->default_device && data->default_device_guid) { 194 if (SDL_memcmp(cpyguid, data->default_device_guid, sizeof (GUID)) == 0) { 195 *data->default_device = device; 196 } 197 } 198 } 199 SDL_free(str); // SDL_AddAudioDevice() makes a copy of this string. 200 } 201 } 202 return TRUE; // keep enumerating. 203} 204 205static void DSOUND_DetectDevices(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording) 206{ 207#ifdef HAVE_MMDEVICEAPI_H 208 if (SupportsIMMDevice) { 209 SDL_IMMDevice_EnumerateEndpoints(default_playback, default_recording, SDL_AUDIO_UNKNOWN, false); 210 } else 211#endif 212 { 213 // Without IMMDevice, you can enumerate devices and figure out the default devices, 214 // but you won't get device hotplug or default device change notifications. But this is 215 // only for WinXP; Windows Vista and later should be using IMMDevice. 216 FindAllDevsData data; 217 GUID guid; 218 219 data.recording = true; 220 data.default_device = default_recording; 221 data.default_device_guid = (pGetDeviceID(&SDL_DSDEVID_DefaultCapture, &guid) == DS_OK) ? &guid : NULL; 222 pDirectSoundCaptureEnumerateW(FindAllDevs, &data); 223 224 data.recording = false; 225 data.default_device = default_playback; 226 data.default_device_guid = (pGetDeviceID(&SDL_DSDEVID_DefaultPlayback, &guid) == DS_OK) ? &guid : NULL; 227 pDirectSoundEnumerateW(FindAllDevs, &data); 228 } 229 230} 231 232static bool DSOUND_WaitDevice(SDL_AudioDevice *device) 233{ 234 /* Semi-busy wait, since we have no way of getting play notification 235 on a primary mixing buffer located in hardware (DirectX 5.0) 236 */ 237 while (!SDL_GetAtomicInt(&device->shutdown)) { 238 DWORD status = 0; 239 DWORD cursor = 0; 240 DWORD junk = 0; 241 HRESULT result = DS_OK; 242 243 // Try to restore a lost sound buffer 244 IDirectSoundBuffer_GetStatus(device->hidden->mixbuf, &status); 245 if (status & DSBSTATUS_BUFFERLOST) { 246 IDirectSoundBuffer_Restore(device->hidden->mixbuf); 247 } else if (!(status & DSBSTATUS_PLAYING)) { 248 result = IDirectSoundBuffer_Play(device->hidden->mixbuf, 0, 0, DSBPLAY_LOOPING); 249 } else { 250 // Find out where we are playing 251 result = IDirectSoundBuffer_GetCurrentPosition(device->hidden->mixbuf, &junk, &cursor); 252 if ((result == DS_OK) && ((cursor / device->buffer_size) != device->hidden->lastchunk)) { 253 break; // ready for next chunk! 254 } 255 } 256 257 if ((result != DS_OK) && (result != DSERR_BUFFERLOST)) { 258 return false; 259 } 260 261 SDL_Delay(1); // not ready yet; sleep a bit. 262 } 263 264 return true; 265} 266 267static bool DSOUND_PlayDevice(SDL_AudioDevice *device, const Uint8 *buffer, int buflen) 268{ 269 // Unlock the buffer, allowing it to play 270 SDL_assert(buflen == device->buffer_size); 271 if (IDirectSoundBuffer_Unlock(device->hidden->mixbuf, (LPVOID) buffer, buflen, NULL, 0) != DS_OK) { 272 return false; 273 } 274 return true; 275} 276 277static Uint8 *DSOUND_GetDeviceBuf(SDL_AudioDevice *device, int *buffer_size) 278{ 279 DWORD cursor = 0; 280 DWORD junk = 0; 281 HRESULT result = DS_OK; 282 283 SDL_assert(*buffer_size == device->buffer_size); 284 285 // Figure out which blocks to fill next 286 device->hidden->locked_buf = NULL; 287 result = IDirectSoundBuffer_GetCurrentPosition(device->hidden->mixbuf, 288 &junk, &cursor); 289 if (result == DSERR_BUFFERLOST) { 290 IDirectSoundBuffer_Restore(device->hidden->mixbuf); 291 result = IDirectSoundBuffer_GetCurrentPosition(device->hidden->mixbuf, 292 &junk, &cursor); 293 } 294 if (result != DS_OK) { 295 SetDSerror("DirectSound GetCurrentPosition", result); 296 return NULL; 297 } 298 cursor /= device->buffer_size; 299#ifdef DEBUG_SOUND 300 // Detect audio dropouts 301 { 302 DWORD spot = cursor; 303 if (spot < device->hidden->lastchunk) { 304 spot += device->hidden->num_buffers; 305 } 306 if (spot > device->hidden->lastchunk + 1) { 307 fprintf(stderr, "Audio dropout, missed %d fragments\n", 308 (spot - (device->hidden->lastchunk + 1))); 309 } 310 } 311#endif 312 device->hidden->lastchunk = cursor; 313 cursor = (cursor + 1) % device->hidden->num_buffers; 314 cursor *= device->buffer_size; 315 316 // Lock the audio buffer 317 DWORD rawlen = 0; 318 result = IDirectSoundBuffer_Lock(device->hidden->mixbuf, cursor, 319 device->buffer_size, 320 (LPVOID *)&device->hidden->locked_buf, 321 &rawlen, NULL, &junk, 0); 322 if (result == DSERR_BUFFERLOST) { 323 IDirectSoundBuffer_Restore(device->hidden->mixbuf); 324 result = IDirectSoundBuffer_Lock(device->hidden->mixbuf, cursor, 325 device->buffer_size, 326 (LPVOID *)&device->hidden->locked_buf, &rawlen, NULL, 327 &junk, 0); 328 } 329 if (result != DS_OK) { 330 SetDSerror("DirectSound Lock", result); 331 return NULL; 332 } 333 return device->hidden->locked_buf; 334} 335 336static bool DSOUND_WaitRecordingDevice(SDL_AudioDevice *device) 337{ 338 struct SDL_PrivateAudioData *h = device->hidden; 339 while (!SDL_GetAtomicInt(&device->shutdown)) { 340 DWORD junk, cursor; 341 if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) != DS_OK) { 342 return false; 343 } else if ((cursor / device->buffer_size) != h->lastchunk) { 344 break; 345 } 346 SDL_Delay(1); 347 } 348 349 return true; 350} 351 352static int DSOUND_RecordDevice(SDL_AudioDevice *device, void *buffer, int buflen) 353{ 354 struct SDL_PrivateAudioData *h = device->hidden; 355 DWORD ptr1len, ptr2len; 356 VOID *ptr1, *ptr2; 357 358 SDL_assert(buflen == device->buffer_size); 359 360 if (IDirectSoundCaptureBuffer_Lock(h->capturebuf, h->lastchunk * buflen, buflen, &ptr1, &ptr1len, &ptr2, &ptr2len, 0) != DS_OK) { 361 return -1; 362 } 363 364 SDL_assert(ptr1len == (DWORD)buflen); 365 SDL_assert(ptr2 == NULL); 366 SDL_assert(ptr2len == 0); 367 368 SDL_memcpy(buffer, ptr1, ptr1len); 369 370 if (IDirectSoundCaptureBuffer_Unlock(h->capturebuf, ptr1, ptr1len, ptr2, ptr2len) != DS_OK) { 371 return -1; 372 } 373 374 h->lastchunk = (h->lastchunk + 1) % h->num_buffers; 375 376 return (int) ptr1len; 377} 378 379static void DSOUND_FlushRecording(SDL_AudioDevice *device) 380{ 381 struct SDL_PrivateAudioData *h = device->hidden; 382 DWORD junk, cursor; 383 if (IDirectSoundCaptureBuffer_GetCurrentPosition(h->capturebuf, &junk, &cursor) == DS_OK) { 384 h->lastchunk = cursor / device->buffer_size; 385 } 386} 387 388static void DSOUND_CloseDevice(SDL_AudioDevice *device) 389{ 390 if (device->hidden) { 391 if (device->hidden->mixbuf) { 392 IDirectSoundBuffer_Stop(device->hidden->mixbuf); 393 IDirectSoundBuffer_Release(device->hidden->mixbuf); 394 } 395 if (device->hidden->sound) { 396 IDirectSound_Release(device->hidden->sound); 397 } 398 if (device->hidden->capturebuf) { 399 IDirectSoundCaptureBuffer_Stop(device->hidden->capturebuf); 400 IDirectSoundCaptureBuffer_Release(device->hidden->capturebuf); 401 } 402 if (device->hidden->capture) { 403 IDirectSoundCapture_Release(device->hidden->capture); 404 } 405 SDL_free(device->hidden); 406 device->hidden = NULL; 407 } 408} 409 410/* This function tries to create a secondary audio buffer, and returns the 411 number of audio chunks available in the created buffer. This is for 412 playback devices, not recording. 413*/ 414static bool CreateSecondary(SDL_AudioDevice *device, const DWORD bufsize, WAVEFORMATEX *wfmt) 415{ 416 LPDIRECTSOUND sndObj = device->hidden->sound; 417 LPDIRECTSOUNDBUFFER *sndbuf = &device->hidden->mixbuf; 418 HRESULT result = DS_OK; 419 DSBUFFERDESC format; 420 LPVOID pvAudioPtr1, pvAudioPtr2; 421 DWORD dwAudioBytes1, dwAudioBytes2; 422 423 // Try to create the secondary buffer 424 SDL_zero(format); 425 format.dwSize = sizeof(format); 426 format.dwFlags = DSBCAPS_GETCURRENTPOSITION2; 427 format.dwFlags |= DSBCAPS_GLOBALFOCUS; 428 format.dwBufferBytes = bufsize; 429 format.lpwfxFormat = wfmt; 430 result = IDirectSound_CreateSoundBuffer(sndObj, &format, sndbuf, NULL); 431 if (result != DS_OK) { 432 return SetDSerror("DirectSound CreateSoundBuffer", result); 433 } 434 IDirectSoundBuffer_SetFormat(*sndbuf, wfmt); 435 436 // Silence the initial audio buffer 437 result = IDirectSoundBuffer_Lock(*sndbuf, 0, format.dwBufferBytes, 438 (LPVOID *)&pvAudioPtr1, &dwAudioBytes1, 439 (LPVOID *)&pvAudioPtr2, &dwAudioBytes2, 440 DSBLOCK_ENTIREBUFFER); 441 if (result == DS_OK) { 442 SDL_memset(pvAudioPtr1, device->silence_value, dwAudioBytes1); 443 IDirectSoundBuffer_Unlock(*sndbuf, 444 (LPVOID)pvAudioPtr1, dwAudioBytes1, 445 (LPVOID)pvAudioPtr2, dwAudioBytes2); 446 } 447 448 return true; // We're ready to go 449} 450 451/* This function tries to create a capture buffer, and returns the 452 number of audio chunks available in the created buffer. This is for 453 recording devices, not playback. 454*/ 455static bool CreateCaptureBuffer(SDL_AudioDevice *device, const DWORD bufsize, WAVEFORMATEX *wfmt) 456{ 457 LPDIRECTSOUNDCAPTURE capture = device->hidden->capture; 458 LPDIRECTSOUNDCAPTUREBUFFER *capturebuf = &device->hidden->capturebuf; 459 DSCBUFFERDESC format; 460 HRESULT result; 461 462 SDL_zero(format); 463 format.dwSize = sizeof(format); 464 format.dwFlags = DSCBCAPS_WAVEMAPPED; 465 format.dwBufferBytes = bufsize; 466 format.lpwfxFormat = wfmt; 467 468 result = IDirectSoundCapture_CreateCaptureBuffer(capture, &format, capturebuf, NULL); 469 if (result != DS_OK) { 470 return SetDSerror("DirectSound CreateCaptureBuffer", result); 471 } 472 473 result = IDirectSoundCaptureBuffer_Start(*capturebuf, DSCBSTART_LOOPING); 474 if (result != DS_OK) { 475 IDirectSoundCaptureBuffer_Release(*capturebuf); 476 return SetDSerror("DirectSound Start", result); 477 } 478 479#if 0 480 // presumably this starts at zero, but just in case... 481 result = IDirectSoundCaptureBuffer_GetCurrentPosition(*capturebuf, &junk, &cursor); 482 if (result != DS_OK) { 483 IDirectSoundCaptureBuffer_Stop(*capturebuf); 484 IDirectSoundCaptureBuffer_Release(*capturebuf); 485 return SetDSerror("DirectSound GetCurrentPosition", result); 486 } 487 488 device->hidden->lastchunk = cursor / device->buffer_size; 489#endif 490 491 return true; 492} 493 494static bool DSOUND_OpenDevice(SDL_AudioDevice *device) 495{ 496 // Initialize all variables that we clean on shutdown 497 device->hidden = (struct SDL_PrivateAudioData *)SDL_calloc(1, sizeof(*device->hidden)); 498 if (!device->hidden) { 499 return false; 500 } 501 502 // Open the audio device 503 LPGUID guid; 504#ifdef HAVE_MMDEVICEAPI_H 505 if (SupportsIMMDevice) { 506 guid = SDL_IMMDevice_GetDirectSoundGUID(device); 507 } else 508#endif 509 { 510 guid = (LPGUID) device->handle; 511 } 512 513 SDL_assert(guid != NULL); 514 515 HRESULT result; 516 if (device->recording) { 517 result = pDirectSoundCaptureCreate8(guid, &device->hidden->capture, NULL); 518 if (result != DS_OK) { 519 return SetDSerror("DirectSoundCaptureCreate8", result); 520 } 521 } else { 522 result = pDirectSoundCreate8(guid, &device->hidden->sound, NULL); 523 if (result != DS_OK) { 524 return SetDSerror("DirectSoundCreate8", result); 525 } 526 result = IDirectSound_SetCooperativeLevel(device->hidden->sound, 527 GetDesktopWindow(), 528 DSSCL_NORMAL); 529 if (result != DS_OK) { 530 return SetDSerror("DirectSound SetCooperativeLevel", result); 531 } 532 } 533 534 const DWORD numchunks = 8; 535 DWORD bufsize; 536 bool tried_format = false; 537 SDL_AudioFormat test_format; 538 const SDL_AudioFormat *closefmts = SDL_ClosestAudioFormats(device->spec.format); 539 while ((test_format = *(closefmts++)) != 0) { 540 switch (test_format) { 541 case SDL_AUDIO_U8: 542 case SDL_AUDIO_S16: 543 case SDL_AUDIO_S32: 544 case SDL_AUDIO_F32: 545 tried_format = true; 546 547 device->spec.format = test_format; 548 549 // Update the fragment size as size in bytes 550 SDL_UpdatedAudioDeviceFormat(device); 551 552 bufsize = numchunks * device->buffer_size; 553 if ((bufsize < DSBSIZE_MIN) || (bufsize > DSBSIZE_MAX)) { 554 SDL_SetError("Sound buffer size must be between %d and %d", 555 (int)((DSBSIZE_MIN < numchunks) ? 1 : DSBSIZE_MIN / numchunks), 556 (int)(DSBSIZE_MAX / numchunks)); 557 } else { 558 WAVEFORMATEXTENSIBLE wfmt; 559 SDL_zero(wfmt); 560 if (device->spec.channels > 2) { 561 wfmt.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; 562 wfmt.Format.cbSize = sizeof(wfmt) - sizeof(WAVEFORMATEX); 563 564 if (SDL_AUDIO_ISFLOAT(device->spec.format)) { 565 SDL_memcpy(&wfmt.SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_IEEE_FLOAT, sizeof(GUID)); 566 } else { 567 SDL_memcpy(&wfmt.SubFormat, &SDL_KSDATAFORMAT_SUBTYPE_PCM, sizeof(GUID)); 568 } 569 wfmt.Samples.wValidBitsPerSample = SDL_AUDIO_BITSIZE(device->spec.format); 570 571 switch (device->spec.channels) { 572 case 3: // 3.0 (or 2.1) 573 wfmt.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER; 574 break; 575 case 4: // 4.0 576 wfmt.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; 577 break; 578 case 5: // 5.0 (or 4.1) 579 wfmt.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; 580 break; 581 case 6: // 5.1 582 wfmt.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT; 583 break; 584 case 7: // 6.1 585 wfmt.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_BACK_CENTER; 586 break; 587 case 8: // 7.1 588 wfmt.dwChannelMask = SPEAKER_FRONT_LEFT | SPEAKER_FRONT_RIGHT | SPEAKER_FRONT_CENTER | SPEAKER_LOW_FREQUENCY | SPEAKER_BACK_LEFT | SPEAKER_BACK_RIGHT | SPEAKER_SIDE_LEFT | SPEAKER_SIDE_RIGHT; 589 break; 590 default: 591 SDL_assert(!"Unsupported channel count!"); 592 break; 593 } 594 } else if (SDL_AUDIO_ISFLOAT(device->spec.format)) { 595 wfmt.Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; 596 } else { 597 wfmt.Format.wFormatTag = WAVE_FORMAT_PCM; 598 } 599 600 wfmt.Format.wBitsPerSample = SDL_AUDIO_BITSIZE(device->spec.format); 601 wfmt.Format.nChannels = (WORD)device->spec.channels; 602 wfmt.Format.nSamplesPerSec = device->spec.freq; 603 wfmt.Format.nBlockAlign = wfmt.Format.nChannels * (wfmt.Format.wBitsPerSample / 8); 604 wfmt.Format.nAvgBytesPerSec = wfmt.Format.nSamplesPerSec * wfmt.Format.nBlockAlign; 605 606 const bool rc = device->recording ? CreateCaptureBuffer(device, bufsize, (WAVEFORMATEX *)&wfmt) : CreateSecondary(device, bufsize, (WAVEFORMATEX *)&wfmt); 607 if (rc) { 608 device->hidden->num_buffers = numchunks; 609 break; 610 } 611 } 612 continue; 613 default: 614 continue; 615 } 616 break; 617 } 618 619 if (!test_format) { 620 if (tried_format) { 621 return false; // CreateSecondary() should have called SDL_SetError(). 622 } 623 return SDL_SetError("%s: Unsupported audio format", "directsound"); 624 } 625 626 // Playback buffers will auto-start playing in DSOUND_WaitDevice() 627 628 return true; // good to go. 629} 630 631static void DSOUND_DeinitializeStart(void) 632{ 633#ifdef HAVE_MMDEVICEAPI_H 634 if (SupportsIMMDevice) { 635 SDL_IMMDevice_Quit(); 636 } 637#endif 638} 639 640static void DSOUND_Deinitialize(void) 641{ 642 DSOUND_Unload(); 643#ifdef HAVE_MMDEVICEAPI_H 644 SupportsIMMDevice = false; 645#endif 646} 647 648static bool DSOUND_Init(SDL_AudioDriverImpl *impl) 649{ 650 if (!DSOUND_Load()) { 651 return false; 652 } 653 654#ifdef HAVE_MMDEVICEAPI_H 655 SupportsIMMDevice = SDL_IMMDevice_Init(NULL); 656#endif 657 658 impl->DetectDevices = DSOUND_DetectDevices; 659 impl->OpenDevice = DSOUND_OpenDevice; 660 impl->PlayDevice = DSOUND_PlayDevice; 661 impl->WaitDevice = DSOUND_WaitDevice; 662 impl->GetDeviceBuf = DSOUND_GetDeviceBuf; 663 impl->WaitRecordingDevice = DSOUND_WaitRecordingDevice; 664 impl->RecordDevice = DSOUND_RecordDevice; 665 impl->FlushRecording = DSOUND_FlushRecording; 666 impl->CloseDevice = DSOUND_CloseDevice; 667 impl->FreeDeviceHandle = DSOUND_FreeDeviceHandle; 668 impl->DeinitializeStart = DSOUND_DeinitializeStart; 669 impl->Deinitialize = DSOUND_Deinitialize; 670 671 impl->HasRecordingSupport = true; 672 673 return true; 674} 675 676AudioBootStrap DSOUND_bootstrap = { 677 "directsound", "DirectSound", DSOUND_Init, false, false 678}; 679 680#endif // SDL_AUDIO_DRIVER_DSOUND 681[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.