From 8b26e95f9128d1df3f03a1d7e6dbf906a33d885a Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 13 Sep 2023 10:11:23 -0400 Subject: [PATCH] audio: Change SDL_AudioStreamCallback Now it offers the total requested bytes in addition to the amount immediately needed (and immediately needed might be zero if the stream already has enough queued to satisfy the request. --- include/SDL3/SDL_audio.h | 17 +++++++++++++---- src/audio/SDL_audiocvt.c | 14 ++++++-------- test/testaudiostreamdynamicresample.c | 2 +- test/testsurround.c | 2 +- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/include/SDL3/SDL_audio.h b/include/SDL3/SDL_audio.h index 84894ceba..dcbb71154 100644 --- a/include/SDL3/SDL_audio.h +++ b/include/SDL3/SDL_audio.h @@ -954,13 +954,22 @@ extern DECLSPEC int SDLCALL SDL_UnlockAudioStream(SDL_AudioStream *stream); * before your callback is called, so your callback does not need to * manage the lock explicitly. * + * Two values are offered here: one is the amount of additional data needed + * to satisfy the immediate request (which might be zero if the stream + * already has enough data queued) and the other is the total amount + * being requested. In a Get call triggering a Put callback, these + * values can be different. In a Put call triggering a Get callback, + * these values are always the same. + * + * Byte counts might be slightly overestimated due to buffering or + * resampling, and may change from call to call. + * * \param stream The SDL audio stream associated with this callback. - * \param approx_amount The _approximate_ amount of data, in bytes, that is requested or available. - * This might be slightly overestimated due to buffering or - * resampling, and may change from call to call. + * \param additional The amount of data, in bytes, that is needed right now + * \param total_amount The total amount of data requested, in bytes, that is requested or available. * \param userdata An opaque pointer provided by the app for their personal use. */ -typedef void (SDLCALL *SDL_AudioStreamCallback)(void *userdata, SDL_AudioStream *stream, int approx_amount); +typedef void (SDLCALL *SDL_AudioStreamCallback)(void *userdata, SDL_AudioStream *stream, int additional_amount, int total_amount); /** * Set a callback that runs when data is requested from an audio stream. diff --git a/src/audio/SDL_audiocvt.c b/src/audio/SDL_audiocvt.c index 70a405b15..dc521f134 100644 --- a/src/audio/SDL_audiocvt.c +++ b/src/audio/SDL_audiocvt.c @@ -1342,9 +1342,7 @@ int SDL_PutAudioStreamData(SDL_AudioStream *stream, const void *buf, int len) if ((retval == 0) && stream->put_callback) { const int newavail = SDL_GetAudioStreamAvailable(stream) - prev_available; - if (newavail > 0) { // don't call the callback if we can't actually offer new data (still filling future buffer, only added 1 frame but downsampling needs more to produce new sound, etc). - stream->put_callback(stream->put_callback_userdata, stream, newavail); - } + stream->put_callback(stream->put_callback_userdata, stream, newavail, newavail); } SDL_UnlockMutex(stream->lock); @@ -1647,7 +1645,8 @@ int SDL_GetAudioStreamData(SDL_AudioStream *stream, void *voidbuf, int len) // give the callback a chance to fill in more stream data if it wants. if (stream->get_callback) { - Sint64 approx_request = len / dst_frame_size; // start with sample frames desired + Sint64 total_request = len / dst_frame_size; // start with sample frames desired + Sint64 approx_request = total_request; const Sint64 available_frames = GetAudioStreamAvailableFrames(stream); approx_request -= SDL_min(available_frames, approx_request); @@ -1655,14 +1654,13 @@ int SDL_GetAudioStreamData(SDL_AudioStream *stream, void *voidbuf, int len) const Sint64 resample_rate = GetStreamResampleRate(stream, stream->src_spec.freq); if (resample_rate) { + total_request = GetResamplerNeededInputFrames((int) total_request, resample_rate, 0); approx_request = GetResamplerNeededInputFrames((int) approx_request, resample_rate, 0); } + total_request *= SDL_AUDIO_FRAMESIZE(stream->src_spec); // convert sample frames to bytes. approx_request *= SDL_AUDIO_FRAMESIZE(stream->src_spec); // convert sample frames to bytes. - - if (approx_request > 0) { // don't call the callback if we can satisfy this request with existing data. - stream->get_callback(stream->get_callback_userdata, stream, (int) SDL_min(approx_request, SDL_INT_MAX)); - } + stream->get_callback(stream->get_callback_userdata, stream, (int) SDL_min(approx_request, SDL_INT_MAX), (int) SDL_min(total_request, SDL_INT_MAX)); } const int chunk_size = 4096; diff --git a/test/testaudiostreamdynamicresample.c b/test/testaudiostreamdynamicresample.c index 15d6dec27..7e9e09211 100644 --- a/test/testaudiostreamdynamicresample.c +++ b/test/testaudiostreamdynamicresample.c @@ -356,7 +356,7 @@ static void loop(void) } } -static void SDLCALL our_get_callback(void *userdata, SDL_AudioStream *strm, int approx_amount) +static void SDLCALL our_get_callback(void *userdata, SDL_AudioStream *strm, int approx_amount, int total_amount) { last_get_callback = SDL_GetTicks(); last_get_amount = approx_amount; diff --git a/test/testsurround.c b/test/testsurround.c index 001952ea1..551f316b9 100644 --- a/test/testsurround.c +++ b/test/testsurround.c @@ -96,7 +96,7 @@ static SDL_bool is_lfe_channel(int channel_index, int channel_count) return (channel_count == 3 && channel_index == 2) || (channel_count >= 6 && channel_index == 3); } -static void SDLCALL fill_buffer(void *userdata, SDL_AudioStream *stream, int len) +static void SDLCALL fill_buffer(void *userdata, SDL_AudioStream *stream, int len, int totallen) { const int samples = len / sizeof(Sint16); Sint16 *buffer = NULL;