diff --git a/include/SDL3/SDL_audio.h b/include/SDL3/SDL_audio.h index dcbb71154f..b870d07712 100644 --- a/include/SDL3/SDL_audio.h +++ b/include/SDL3/SDL_audio.h @@ -327,8 +327,20 @@ extern DECLSPEC char *SDLCALL SDL_GetAudioDeviceName(SDL_AudioDeviceID devid); * reasonable recommendation before opening the system-recommended default * device. * + * You can also use this to request the current device buffer size. This is + * specified in sample frames and represents the amount of data SDL will + * feed to the physical hardware in each chunk. This can be converted to + * milliseconds of audio with the following equation: + * + * `ms = (int) ((((Sint64) frames) * 1000) / spec.freq);` + * + * Buffer size is only important if you need low-level control over the audio + * playback timing. Most apps do not need this. + * * \param devid the instance ID of the device to query. * \param spec On return, will be filled with device details. + * \param sample_frames Pointer to store device buffer size, in sample frames. + * Can be NULL. * \returns 0 on success or a negative error code on failure; call * SDL_GetError() for more information. * @@ -336,7 +348,7 @@ extern DECLSPEC char *SDLCALL SDL_GetAudioDeviceName(SDL_AudioDeviceID devid); * * \since This function is available since SDL 3.0.0. */ -extern DECLSPEC int SDLCALL SDL_GetAudioDeviceFormat(SDL_AudioDeviceID devid, SDL_AudioSpec *spec); +extern DECLSPEC int SDLCALL SDL_GetAudioDeviceFormat(SDL_AudioDeviceID devid, SDL_AudioSpec *spec, int *sample_frames); /** diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index c994a1b8f4..6dfd8b7de9 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -116,6 +116,30 @@ const char *SDL_GetCurrentAudioDriver(void) return current_audio.name; } +static int GetDefaultSampleFramesFromFreq(const int freq) +{ + const char *hint = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES); + if (hint) { + const int val = SDL_atoi(hint); + if (val > 0) { + return val; + } + } + + if (freq <= 11025) { + return 512; + } else if (freq <= 22050) { + return 1024; + } else if (freq <= 48000) { + return 2048; + } else if (freq <= 96000) { + return 4096; + } + + return 8192; // shrug +} + + // device management and hotplug... @@ -238,6 +262,7 @@ static SDL_AudioDevice *CreatePhysicalAudioDevice(const char *name, SDL_bool isc device->iscapture = iscapture; SDL_memcpy(&device->spec, spec, sizeof (SDL_AudioSpec)); SDL_memcpy(&device->default_spec, spec, sizeof (SDL_AudioSpec)); + device->sample_frames = GetDefaultSampleFramesFromFreq(device->spec.freq); device->silence_value = SDL_GetSilenceValueForFormat(device->spec.format); device->handle = handle; device->prev = NULL; @@ -1112,7 +1137,7 @@ char *SDL_GetAudioDeviceName(SDL_AudioDeviceID devid) return retval; } -int SDL_GetAudioDeviceFormat(SDL_AudioDeviceID devid, SDL_AudioSpec *spec) +int SDL_GetAudioDeviceFormat(SDL_AudioDeviceID devid, SDL_AudioSpec *spec, int *sample_frames) { if (!spec) { return SDL_InvalidParamError("spec"); @@ -1137,6 +1162,9 @@ int SDL_GetAudioDeviceFormat(SDL_AudioDeviceID devid, SDL_AudioSpec *spec) } SDL_memcpy(spec, &device->spec, sizeof (SDL_AudioSpec)); + if (sample_frames) { + *sample_frames = device->sample_frames; + } SDL_UnlockMutex(device->lock); return 0; @@ -1246,29 +1274,6 @@ static void PrepareAudioFormat(SDL_bool iscapture, SDL_AudioSpec *spec) } } -static int GetDefaultSampleFramesFromFreq(const int freq) -{ - const char *hint = SDL_GetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES); - if (hint) { - const int val = SDL_atoi(hint); - if (val > 0) { - return val; - } - } - - if (freq <= 11025) { - return 512; - } else if (freq <= 22050) { - return 1024; - } else if (freq <= 48000) { - return 2048; - } else if (freq <= 96000) { - return 4096; - } - - return 8192; // shrug -} - void SDL_UpdatedAudioDeviceFormat(SDL_AudioDevice *device) { device->silence_value = SDL_GetSilenceValueForFormat(device->spec.format); diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index ce7170667d..71eba0275e 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -926,7 +926,7 @@ SDL_DYNAPI_PROC(const char*,SDL_GetCurrentAudioDriver,(void),(),return) SDL_DYNAPI_PROC(SDL_AudioDeviceID*,SDL_GetAudioOutputDevices,(int *a),(a),return) SDL_DYNAPI_PROC(SDL_AudioDeviceID*,SDL_GetAudioCaptureDevices,(int *a),(a),return) SDL_DYNAPI_PROC(char*,SDL_GetAudioDeviceName,(SDL_AudioDeviceID a),(a),return) -SDL_DYNAPI_PROC(int,SDL_GetAudioDeviceFormat,(SDL_AudioDeviceID a, SDL_AudioSpec *b),(a,b),return) +SDL_DYNAPI_PROC(int,SDL_GetAudioDeviceFormat,(SDL_AudioDeviceID a, SDL_AudioSpec *b, int *c),(a,b,c),return) SDL_DYNAPI_PROC(SDL_AudioDeviceID,SDL_OpenAudioDevice,(SDL_AudioDeviceID a, const SDL_AudioSpec *b),(a,b),return) SDL_DYNAPI_PROC(void,SDL_CloseAudioDevice,(SDL_AudioDeviceID a),(a),) SDL_DYNAPI_PROC(int,SDL_BindAudioStreams,(SDL_AudioDeviceID a, SDL_AudioStream **b, int c),(a,b,c),return) diff --git a/test/testaudio.c b/test/testaudio.c index 628c1ec9d5..bd15838311 100644 --- a/test/testaudio.c +++ b/test/testaudio.c @@ -765,9 +765,10 @@ static void DeviceThing_ondrag(Thing *thing, int button, float x, float y) static void SetLogicalDeviceTitlebar(Thing *thing) { SDL_AudioSpec *spec = &thing->data.logdev.spec; - SDL_GetAudioDeviceFormat(thing->data.logdev.devid, spec); + int frames = 0; + SDL_GetAudioDeviceFormat(thing->data.logdev.devid, spec, &frames); SDL_free(thing->titlebar); - SDL_asprintf(&thing->titlebar, "Logical device #%u (%s, %s, %s, %uHz)", (unsigned int) thing->data.logdev.devid, thing->data.logdev.iscapture ? "CAPTURE" : "OUTPUT", AudioFmtToString(spec->format), AudioChansToStr(spec->channels), (unsigned int) spec->freq); + SDL_asprintf(&thing->titlebar, "Logical device #%u (%s, %s, %s, %uHz, %d frames)", (unsigned int) thing->data.logdev.devid, thing->data.logdev.iscapture ? "CAPTURE" : "OUTPUT", AudioFmtToString(spec->format), AudioChansToStr(spec->channels), (unsigned int) spec->freq, frames); } static void LogicalDeviceThing_ondrop(Thing *thing, int button, float x, float y) @@ -938,15 +939,16 @@ static Thing *CreateLogicalDeviceThing(Thing *parent, const SDL_AudioDeviceID wh static void SetPhysicalDeviceTitlebar(Thing *thing) { + int frames = 0; SDL_AudioSpec *spec = &thing->data.physdev.spec; - SDL_GetAudioDeviceFormat(thing->data.physdev.devid, spec); + SDL_GetAudioDeviceFormat(thing->data.physdev.devid, spec, &frames); SDL_free(thing->titlebar); if (thing->data.physdev.devid == SDL_AUDIO_DEVICE_DEFAULT_CAPTURE) { - SDL_asprintf(&thing->titlebar, "Default system device (CAPTURE, %s, %s, %uHz)", AudioFmtToString(spec->format), AudioChansToStr(spec->channels), (unsigned int) spec->freq); + SDL_asprintf(&thing->titlebar, "Default system device (CAPTURE, %s, %s, %uHz, %d frames)", AudioFmtToString(spec->format), AudioChansToStr(spec->channels), (unsigned int) spec->freq, frames); } else if (thing->data.physdev.devid == SDL_AUDIO_DEVICE_DEFAULT_OUTPUT) { - SDL_asprintf(&thing->titlebar, "Default system device (OUTPUT, %s, %s, %uHz)", AudioFmtToString(spec->format), AudioChansToStr(spec->channels), (unsigned int) spec->freq); + SDL_asprintf(&thing->titlebar, "Default system device (OUTPUT, %s, %s, %uHz, %d frames)", AudioFmtToString(spec->format), AudioChansToStr(spec->channels), (unsigned int) spec->freq, frames); } else { - SDL_asprintf(&thing->titlebar, "Physical device #%u (%s, \"%s\", %s, %s, %uHz)", (unsigned int) thing->data.physdev.devid, thing->data.physdev.iscapture ? "CAPTURE" : "OUTPUT", thing->data.physdev.name, AudioFmtToString(spec->format), AudioChansToStr(spec->channels), (unsigned int) spec->freq); + SDL_asprintf(&thing->titlebar, "Physical device #%u (%s, \"%s\", %s, %s, %uHz, %d frames)", (unsigned int) thing->data.physdev.devid, thing->data.physdev.iscapture ? "CAPTURE" : "OUTPUT", thing->data.physdev.name, AudioFmtToString(spec->format), AudioChansToStr(spec->channels), (unsigned int) spec->freq, frames); } } diff --git a/test/testaudiocapture.c b/test/testaudiocapture.c index ec7659df2e..efc4be1010 100644 --- a/test/testaudiocapture.c +++ b/test/testaudiocapture.c @@ -179,7 +179,7 @@ int main(int argc, char **argv) exit(1); } SDL_PauseAudioDevice(device); - SDL_GetAudioDeviceFormat(device, &outspec); + SDL_GetAudioDeviceFormat(device, &outspec, NULL); stream_out = SDL_CreateAudioStream(&outspec, &outspec); if (!stream_out) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create an audio stream for playback: %s!\n", SDL_GetError()); @@ -203,7 +203,7 @@ int main(int argc, char **argv) exit(1); } SDL_PauseAudioDevice(device); - SDL_GetAudioDeviceFormat(device, &inspec); + SDL_GetAudioDeviceFormat(device, &inspec, NULL); stream_in = SDL_CreateAudioStream(&inspec, &inspec); if (!stream_in) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't create an audio stream for capture: %s!\n", SDL_GetError()); diff --git a/test/testaudioinfo.c b/test/testaudioinfo.c index 636d4aaf7b..8034f5623c 100644 --- a/test/testaudioinfo.c +++ b/test/testaudioinfo.c @@ -19,6 +19,7 @@ print_devices(SDL_bool iscapture) SDL_AudioSpec spec; const char *typestr = ((iscapture) ? "capture" : "output"); int n = 0; + int frames; SDL_AudioDeviceID *devices = iscapture ? SDL_GetAudioCaptureDevices(&n) : SDL_GetAudioOutputDevices(&n); if (devices == NULL) { @@ -37,10 +38,11 @@ print_devices(SDL_bool iscapture) SDL_Log(" %d Error: %s\n", i, SDL_GetError()); } - if (SDL_GetAudioDeviceFormat(devices[i], &spec) == 0) { + if (SDL_GetAudioDeviceFormat(devices[i], &spec, &frames) == 0) { SDL_Log(" Sample Rate: %d\n", spec.freq); SDL_Log(" Channels: %d\n", spec.channels); SDL_Log(" SDL_AudioFormat: %X\n", spec.format); + SDL_Log(" Buffer Size: %d frames\n", frames); } } SDL_Log("\n"); @@ -53,6 +55,7 @@ int main(int argc, char **argv) SDL_AudioSpec spec; int i; int n; + int frames; SDLTest_CommonState *state; /* Initialize test framework */ @@ -92,22 +95,24 @@ int main(int argc, char **argv) print_devices(SDL_FALSE); print_devices(SDL_TRUE); - if (SDL_GetAudioDeviceFormat(SDL_AUDIO_DEVICE_DEFAULT_OUTPUT, &spec) < 0) { + if (SDL_GetAudioDeviceFormat(SDL_AUDIO_DEVICE_DEFAULT_OUTPUT, &spec, &frames) < 0) { SDL_Log("Error when calling SDL_GetAudioDeviceFormat(default output): %s\n", SDL_GetError()); } else { SDL_Log("Default Output Device:\n"); SDL_Log("Sample Rate: %d\n", spec.freq); SDL_Log("Channels: %d\n", spec.channels); SDL_Log("SDL_AudioFormat: %X\n", spec.format); + SDL_Log("Buffer Size: %d frames\n", frames); } - if (SDL_GetAudioDeviceFormat(SDL_AUDIO_DEVICE_DEFAULT_CAPTURE, &spec) < 0) { + if (SDL_GetAudioDeviceFormat(SDL_AUDIO_DEVICE_DEFAULT_CAPTURE, &spec, &frames) < 0) { SDL_Log("Error when calling SDL_GetAudioDeviceFormat(default capture): %s\n", SDL_GetError()); } else { SDL_Log("Default Capture Device:\n"); SDL_Log("Sample Rate: %d\n", spec.freq); SDL_Log("Channels: %d\n", spec.channels); SDL_Log("SDL_AudioFormat: %X\n", spec.format); + SDL_Log("Buffer Size: %d frames\n", frames); } SDL_Quit(); diff --git a/test/testsurround.c b/test/testsurround.c index 551f316b9d..1edd1faf69 100644 --- a/test/testsurround.c +++ b/test/testsurround.c @@ -197,7 +197,7 @@ int main(int argc, char *argv[]) SDL_Log("Testing audio device: %s\n", devname); SDL_free(devname); - if (SDL_GetAudioDeviceFormat(devices[i], &spec) != 0) { + if (SDL_GetAudioDeviceFormat(devices[i], &spec, NULL) != 0) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "SDL_GetAudioDeviceFormat() failed: %s\n", SDL_GetError()); continue; }