From 534768c7c53f44695cde49ca91fcaa4692db4322 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sun, 26 May 2024 08:10:51 -0700 Subject: [PATCH] Added SDL_PauseAudioStreamDevice() and SDL_ResumeAudioStreamDevice() --- include/SDL3/SDL_audio.h | 63 +++++++++++++++++++++++++++++++ src/audio/SDL_audio.c | 39 ++++++++++++++++--- src/dynapi/SDL_dynapi.sym | 2 + src/dynapi/SDL_dynapi_overrides.h | 2 + src/dynapi/SDL_dynapi_procs.h | 2 + 5 files changed, 102 insertions(+), 6 deletions(-) diff --git a/include/SDL3/SDL_audio.h b/include/SDL3/SDL_audio.h index 6f77585cdf..c15b5a31dc 100644 --- a/include/SDL3/SDL_audio.h +++ b/include/SDL3/SDL_audio.h @@ -1097,6 +1097,69 @@ extern SDL_DECLSPEC int SDLCALL SDL_FlushAudioStream(SDL_AudioStream *stream); */ extern SDL_DECLSPEC int SDLCALL SDL_ClearAudioStream(SDL_AudioStream *stream); +/** + * Use this function to pause audio playback on the audio device associated with an audio stream. + * + * This function pauses audio processing for a given device. Any bound audio + * streams will not progress, and no audio will be generated. Pausing one + * device does not prevent other unpaused devices from running. + * + * Pausing a device can be useful to halt all audio without unbinding all the + * audio streams. This might be useful while a game is paused, or a level is + * loading, etc. + * + * \param stream The audio stream associated with the audio device to pause + * \returns 0 on success or a negative error code on failure; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_ResumeAudioStreamDevice + */ +extern SDL_DECLSPEC int SDLCALL SDL_PauseAudioStreamDevice(SDL_AudioStream *stream); + +/** + * Use this function to unpause audio playback on the audio device associated with an audio stream. + * + * This function unpauses audio processing for a given device that has + * previously been paused. Once unpaused, any bound audio streams will begin to progress again, and audio can be generated. + * + * \param stream The audio stream associated with the audio device to resume + * \returns 0 on success or a negative error code on failure; call + * SDL_GetError() for more information. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_PauseAudioStreamDevice + */ +extern SDL_DECLSPEC int SDLCALL SDL_ResumeAudioStreamDevice(SDL_AudioStream *stream); + +/** + * Use this function to query if an audio device is paused. + * + * Unlike in SDL2, audio devices start in an _unpaused_ state, since an app + * has to bind a stream before any audio will flow. + * + * Physical devices can not be paused or unpaused, only logical devices + * created through SDL_OpenAudioDevice() can be. Physical and invalid device + * IDs will report themselves as unpaused here. + * + * \param dev a device opened by SDL_OpenAudioDevice() + * \returns SDL_TRUE if device is valid and paused, SDL_FALSE otherwise. + * + * \threadsafety It is safe to call this function from any thread. + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_PauseAudioDevice + * \sa SDL_ResumeAudioDevice + */ +extern SDL_DECLSPEC SDL_bool SDLCALL SDL_AudioDevicePaused(SDL_AudioDeviceID dev); + /** * Lock an audio stream for serialized access. * diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index b3b1bd80c1..98d6712c39 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -1947,13 +1947,20 @@ void SDL_UnbindAudioStream(SDL_AudioStream *stream) SDL_AudioDeviceID SDL_GetAudioStreamDevice(SDL_AudioStream *stream) { SDL_AudioDeviceID retval = 0; - if (stream) { - SDL_LockMutex(stream->lock); - if (stream->bound_device) { - retval = stream->bound_device->instance_id; - } - SDL_UnlockMutex(stream->lock); + + if (!stream) { + SDL_InvalidParamError("stream"); + return 0; } + + SDL_LockMutex(stream->lock); + if (stream->bound_device) { + retval = stream->bound_device->instance_id; + } else { + SDL_SetError("Audio stream not bound to an audio device"); + } + SDL_UnlockMutex(stream->lock); + return retval; } @@ -2024,6 +2031,26 @@ SDL_AudioStream *SDL_OpenAudioDeviceStream(SDL_AudioDeviceID devid, const SDL_Au return stream; } +int SDL_PauseAudioStreamDevice(SDL_AudioStream *stream) +{ + SDL_AudioDeviceID devid = SDL_GetAudioStreamDevice(stream); + if (!devid) { + return -1; + } + + return SDL_PauseAudioDevice(devid); +} + +int SDL_ResumeAudioStreamDevice(SDL_AudioStream *stream) +{ + SDL_AudioDeviceID devid = SDL_GetAudioStreamDevice(stream); + if (!devid) { + return -1; + } + + return SDL_ResumeAudioDevice(devid); +} + #define NUM_FORMATS 8 static const SDL_AudioFormat format_list[NUM_FORMATS][NUM_FORMATS + 1] = { { SDL_AUDIO_U8, SDL_AUDIO_S8, SDL_AUDIO_S16LE, SDL_AUDIO_S16BE, SDL_AUDIO_S32LE, SDL_AUDIO_S32BE, SDL_AUDIO_F32LE, SDL_AUDIO_F32BE, 0 }, diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 4b5758984e..744cd0eb7e 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -589,6 +589,7 @@ SDL3_0.0.0 { SDL_OpenUserStorage; SDL_OutOfMemory; SDL_PauseAudioDevice; + SDL_PauseAudioStreamDevice; SDL_PauseHaptic; SDL_PeepEvents; SDL_PenConnected; @@ -656,6 +657,7 @@ SDL3_0.0.0 { SDL_ResetLogPriorities; SDL_RestoreWindow; SDL_ResumeAudioDevice; + SDL_ResumeAudioStreamDevice; SDL_ResumeHaptic; SDL_RumbleGamepad; SDL_RumbleGamepadTriggers; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index d4301d0df8..2e5558159c 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -614,6 +614,7 @@ #define SDL_OpenUserStorage SDL_OpenUserStorage_REAL #define SDL_OutOfMemory SDL_OutOfMemory_REAL #define SDL_PauseAudioDevice SDL_PauseAudioDevice_REAL +#define SDL_PauseAudioStreamDevice SDL_PauseAudioStreamDevice_REAL #define SDL_PauseHaptic SDL_PauseHaptic_REAL #define SDL_PeepEvents SDL_PeepEvents_REAL #define SDL_PenConnected SDL_PenConnected_REAL @@ -681,6 +682,7 @@ #define SDL_ResetLogPriorities SDL_ResetLogPriorities_REAL #define SDL_RestoreWindow SDL_RestoreWindow_REAL #define SDL_ResumeAudioDevice SDL_ResumeAudioDevice_REAL +#define SDL_ResumeAudioStreamDevice SDL_ResumeAudioStreamDevice_REAL #define SDL_ResumeHaptic SDL_ResumeHaptic_REAL #define SDL_RumbleGamepad SDL_RumbleGamepad_REAL #define SDL_RumbleGamepadTriggers SDL_RumbleGamepadTriggers_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 1b069ff399..c78e76d58c 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -625,6 +625,7 @@ SDL_DYNAPI_PROC(int,SDL_OpenURL,(const char *a),(a),return) SDL_DYNAPI_PROC(SDL_Storage*,SDL_OpenUserStorage,(const char *a, const char *b, SDL_PropertiesID c),(a,b,c),return) SDL_DYNAPI_PROC(int,SDL_OutOfMemory,(void),(),return) SDL_DYNAPI_PROC(int,SDL_PauseAudioDevice,(SDL_AudioDeviceID a),(a),return) +SDL_DYNAPI_PROC(int,SDL_PauseAudioStreamDevice,(SDL_AudioStream *a),(a),return) SDL_DYNAPI_PROC(int,SDL_PauseHaptic,(SDL_Haptic *a),(a),return) SDL_DYNAPI_PROC(int,SDL_PeepEvents,(SDL_Event *a, int b, SDL_EventAction c, Uint32 d, Uint32 e),(a,b,c,d,e),return) SDL_DYNAPI_PROC(SDL_bool,SDL_PenConnected,(SDL_PenID a),(a),return) @@ -692,6 +693,7 @@ SDL_DYNAPI_PROC(void,SDL_ResetKeyboard,(void),(),) SDL_DYNAPI_PROC(void,SDL_ResetLogPriorities,(void),(),) SDL_DYNAPI_PROC(int,SDL_RestoreWindow,(SDL_Window *a),(a),return) SDL_DYNAPI_PROC(int,SDL_ResumeAudioDevice,(SDL_AudioDeviceID a),(a),return) +SDL_DYNAPI_PROC(int,SDL_ResumeAudioStreamDevice,(SDL_AudioStream *a),(a),return) SDL_DYNAPI_PROC(int,SDL_ResumeHaptic,(SDL_Haptic *a),(a),return) SDL_DYNAPI_PROC(int,SDL_RumbleGamepad,(SDL_Gamepad *a, Uint16 b, Uint16 c, Uint32 d),(a,b,c,d),return) SDL_DYNAPI_PROC(int,SDL_RumbleGamepadTriggers,(SDL_Gamepad *a, Uint16 b, Uint16 c, Uint32 d),(a,b,c,d),return)