SDL: Add SDL_PlayAudioDevice() to play audio. Remove pause_on param from SDL_PauseAudioDevice()

From 93e2903ac550b9f0ac034af4174658c1f5ffbc04 Mon Sep 17 00:00:00 2001
From: Sylvain <[EMAIL REDACTED]>
Date: Fri, 6 Jan 2023 13:59:45 +0100
Subject: [PATCH] Add SDL_PlayAudioDevice() to play audio. Remove pause_on
 param from SDL_PauseAudioDevice()

---
 WhatsNew.txt                      |  1 +
 docs/README-migration.md          |  2 ++
 include/SDL3/SDL_audio.h          | 40 +++++++++++++++++++++----------
 src/audio/SDL_audio.c             | 14 +++++++++--
 src/dynapi/SDL_dynapi.sym         |  1 +
 src/dynapi/SDL_dynapi_overrides.h |  1 +
 src/dynapi/SDL_dynapi_procs.h     |  3 ++-
 test/loopwave.c                   |  2 +-
 test/loopwavequeue.c              |  2 +-
 test/testaudiocapture.c           | 12 +++++-----
 test/testaudiohotplug.c           |  2 +-
 test/testautomation_audio.c       | 14 +++++++----
 test/testmultiaudio.c             | 10 ++++----
 test/testsurround.c               |  2 +-
 14 files changed, 72 insertions(+), 34 deletions(-)

diff --git a/WhatsNew.txt b/WhatsNew.txt
index 56172f41ba20..f6458552a292 100644
--- a/WhatsNew.txt
+++ b/WhatsNew.txt
@@ -21,3 +21,4 @@ General:
 * The timestamp member of the SDL_Event structure is now in nanoseconds, filled in with the time the event was generated, or the time it was queued if that's not available
 * Added SDL_modf() and SDL_modff() to separate the whole and fractional portions of a floating point number
 * Added SDL_GetRenderVSync() to get vsync of the given renderer
+* Added SDL_PlayAudioDevice() to start audio playback
diff --git a/docs/README-migration.md b/docs/README-migration.md
index 2c413d3813a2..a18478eecb3a 100644
--- a/docs/README-migration.md
+++ b/docs/README-migration.md
@@ -47,6 +47,8 @@ The vi format comments have been removed from source code. Vim users can use the
 
 SDL_AudioInit() and SDL_AudioQuit() have been removed. Instead you can call SDL_InitSubSytem() and SDL_QuitSubSytem() with SDL_INIT_AUDIO, which will properly refcount the subsystems. You can choose a specific audio driver using SDL_AUDIO_DRIVER hint.
 
+SDL_PauseAudioDevice() is only used to pause audio playback. Use SDL_PlayAudioDevice() to start playing audio.
+
 SDL_FreeWAV has been removed and calls can be replaced with SDL_free.
 
 The following functions have been renamed:
diff --git a/include/SDL3/SDL_audio.h b/include/SDL3/SDL_audio.h
index cd4260c36b2b..bef22bc0f02c 100644
--- a/include/SDL3/SDL_audio.h
+++ b/include/SDL3/SDL_audio.h
@@ -466,7 +466,7 @@ extern DECLSPEC int SDLCALL SDL_GetDefaultAudioInfo(char **name,
  * diskaudio driver.
  *
  * An opened audio device starts out paused, and should be enabled for playing
- * by calling SDL_PauseAudioDevice(devid, 0) when you are ready for your audio
+ * by calling SDL_PlayAudioDevice(devid) when you are ready for your audio
  * callback function to be called. Since the audio driver may modify the
  * requested size of the audio buffer, you should allocate any local mixing
  * buffers after you open the audio device.
@@ -554,6 +554,7 @@ extern DECLSPEC int SDLCALL SDL_GetDefaultAudioInfo(char **name,
  * \sa SDL_CloseAudioDevice
  * \sa SDL_GetAudioDeviceName
  * \sa SDL_LockAudioDevice
+ * \sa SDL_PlayAudioDevice
  * \sa SDL_PauseAudioDevice
  * \sa SDL_UnlockAudioDevice
  */
@@ -588,41 +589,56 @@ typedef enum
  *
  * \since This function is available since SDL 3.0.0.
  *
+ * \sa SDL_PlayAudioDevice
  * \sa SDL_PauseAudioDevice
  */
 extern DECLSPEC SDL_AudioStatus SDLCALL SDL_GetAudioDeviceStatus(SDL_AudioDeviceID dev);
 /* @} *//* Audio State */
 
 /**
- * Use this function to pause and unpause audio playback on a specified
- * device.
+ * Use this function to play audio on a specified device.
  *
- * This function pauses and unpauses the audio callback processing for a given
- * device. Newly-opened audio devices start in the paused state, so you must
- * call this function with **pause_on**=0 after opening the specified audio
+ * Newly-opened audio devices start in the paused state, so you must
+ * call this function after opening the specified audio
  * device to start playing sound. This allows you to safely initialize data
  * for your callback function after opening the audio device. Silence will be
  * written to the audio device while paused, and the audio callback is
  * guaranteed to not be called. Pausing one device does not prevent other
  * unpaused devices from running their callbacks.
  *
- * Pausing state does not stack; even if you pause a device several times, a
- * single unpause will start the device playing again, and vice versa. This is
- * different from how SDL_LockAudioDevice() works.
+ * \param dev a device opened by SDL_OpenAudioDevice()
+ *
+ * \since This function is available since SDL 3.0.0.
+ *
+ * \sa SDL_LockAudioDevice
+ * \sa SDL_PauseAudioDevice
+ */
+extern DECLSPEC void SDLCALL SDL_PlayAudioDevice(SDL_AudioDeviceID dev);
+
+
+
+/**
+ * Use this function to pause audio playback on a specified device.
+ *
+ * This function pauses the audio callback processing for a given
+ * device.  Silence will be written to the audio device while paused, and
+ * the audio callback is guaranteed to not be called.
+ * Pausing one device does not prevent other unpaused devices from running
+ * their callbacks.
  *
  * If you just need to protect a few variables from race conditions vs your
  * callback, you shouldn't pause the audio device, as it will lead to dropouts
  * in the audio playback. Instead, you should use SDL_LockAudioDevice().
  *
  * \param dev a device opened by SDL_OpenAudioDevice()
- * \param pause_on non-zero to pause, 0 to unpause
  *
  * \since This function is available since SDL 3.0.0.
  *
  * \sa SDL_LockAudioDevice
+ * \sa SDL_PlayAudioDevice
  */
-extern DECLSPEC void SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID dev,
-                                                  int pause_on);
+extern DECLSPEC void SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID dev);
+
 
 /**
  * Load the audio data of a WAVE file into memory.
diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c
index 39232ae6814e..d6a23b9a9d68 100644
--- a/src/audio/SDL_audio.c
+++ b/src/audio/SDL_audio.c
@@ -1516,12 +1516,22 @@ SDL_GetAudioDeviceStatus(SDL_AudioDeviceID devid)
     return status;
 }
 
-void SDL_PauseAudioDevice(SDL_AudioDeviceID devid, int pause_on)
+void SDL_PauseAudioDevice(SDL_AudioDeviceID devid)
 {
     SDL_AudioDevice *device = get_audio_device(devid);
     if (device) {
         current_audio.impl.LockDevice(device);
-        SDL_AtomicSet(&device->paused, pause_on ? 1 : 0);
+        SDL_AtomicSet(&device->paused, 1);
+        current_audio.impl.UnlockDevice(device);
+    }
+}
+
+void SDL_PlayAudioDevice(SDL_AudioDeviceID devid)
+{
+    SDL_AudioDevice *device = get_audio_device(devid);
+    if (device) {
+        current_audio.impl.LockDevice(device);
+        SDL_AtomicSet(&device->paused, 0);
         current_audio.impl.UnlockDevice(device);
     }
 }
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index ba9584811533..fe547ae87fda 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -842,6 +842,7 @@ SDL3_0.0.0 {
     SDL_modf;
     SDL_modff;
     SDL_GetRenderVSync;
+    SDL_PlayAudioDevice;
     # extra symbols go here (don't modify this line)
   local: *;
 };
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 71e0719008f2..f36fb3cc2e47 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -870,3 +870,4 @@
 #define SDL_modf SDL_modf_REAL
 #define SDL_modff SDL_modff_REAL
 #define SDL_GetRenderVSync SDL_GetRenderVSync_REAL
+#define SDL_PlayAudioDevice SDL_PlayAudioDevice_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index fb7c9f3d35cc..9401e94ae560 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -576,7 +576,7 @@ SDL_DYNAPI_PROC(SDL_Gamepad*,SDL_OpenGamepad,(SDL_JoystickID a),(a),return)
 SDL_DYNAPI_PROC(SDL_Joystick*,SDL_OpenJoystick,(SDL_JoystickID a),(a),return)
 SDL_DYNAPI_PROC(SDL_Sensor*,SDL_OpenSensor,(SDL_SensorID a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_OpenURL,(const char *a),(a),return)
-SDL_DYNAPI_PROC(void,SDL_PauseAudioDevice,(SDL_AudioDeviceID a, int b),(a,b),)
+SDL_DYNAPI_PROC(void,SDL_PauseAudioDevice,(SDL_AudioDeviceID a),(a),)
 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(int,SDL_PollEvent,(SDL_Event *a),(a),return)
 SDL_DYNAPI_PROC(int,SDL_PremultiplyAlpha,(int a, int b, Uint32 c, const void *d, int e, Uint32 f, void *g, int h),(a,b,c,d,e,f,g,h),return)
@@ -915,3 +915,4 @@ SDL_DYNAPI_PROC(wchar_t*,SDL_wcsstr,(const wchar_t *a, const wchar_t *b),(a,b),r
 SDL_DYNAPI_PROC(double,SDL_modf,(double a, double *b),(a,b),return)
 SDL_DYNAPI_PROC(float,SDL_modff,(float a, float *b),(a,b),return)
 SDL_DYNAPI_PROC(int,SDL_GetRenderVSync,(SDL_Renderer *a, int *b),(a,b),return)
+SDL_DYNAPI_PROC(void,SDL_PlayAudioDevice,(SDL_AudioDeviceID a),(a),)
diff --git a/test/loopwave.c b/test/loopwave.c
index a4d05e04dbd0..ab84def177e9 100644
--- a/test/loopwave.c
+++ b/test/loopwave.c
@@ -64,7 +64,7 @@ open_audio()
     }
 
     /* Let the audio run */
-    SDL_PauseAudioDevice(device, SDL_FALSE);
+    SDL_PlayAudioDevice(device);
 }
 
 #ifndef __EMSCRIPTEN__
diff --git a/test/loopwavequeue.c b/test/loopwavequeue.c
index 6c1c6a475d41..ea63e3f8f3ff 100644
--- a/test/loopwavequeue.c
+++ b/test/loopwavequeue.c
@@ -123,7 +123,7 @@ int main(int argc, char *argv[])
     /*static x[99999]; SDL_QueueAudio(1, x, sizeof (x));*/
 
     /* Let the audio run */
-    SDL_PauseAudioDevice(g_audio_id, 0);
+    SDL_PlayAudioDevice(g_audio_id);
 
     done = 0;
 
diff --git a/test/testaudiocapture.c b/test/testaudiocapture.c
index 3f6b12717b87..90d3279311bc 100644
--- a/test/testaudiocapture.c
+++ b/test/testaudiocapture.c
@@ -40,13 +40,13 @@ loop()
             }
         } else if (e.type == SDL_MOUSEBUTTONDOWN) {
             if (e.button.button == 1) {
-                SDL_PauseAudioDevice(devid_out, SDL_TRUE);
-                SDL_PauseAudioDevice(devid_in, SDL_FALSE);
+                SDL_PauseAudioDevice(devid_out);
+                SDL_PlayAudioDevice(devid_in);
             }
         } else if (e.type == SDL_MOUSEBUTTONUP) {
             if (e.button.button == 1) {
-                SDL_PauseAudioDevice(devid_in, SDL_TRUE);
-                SDL_PauseAudioDevice(devid_out, SDL_FALSE);
+                SDL_PauseAudioDevice(devid_in);
+                SDL_PlayAudioDevice(devid_out);
             }
         }
     }
@@ -62,9 +62,9 @@ loop()
     if (please_quit) {
         /* stop playing back, quit. */
         SDL_Log("Shutting down.\n");
-        SDL_PauseAudioDevice(devid_in, 1);
+        SDL_PauseAudioDevice(devid_in);
         SDL_CloseAudioDevice(devid_in);
-        SDL_PauseAudioDevice(devid_out, 1);
+        SDL_PauseAudioDevice(devid_out);
         SDL_CloseAudioDevice(devid_out);
         SDL_DestroyRenderer(renderer);
         SDL_DestroyWindow(window);
diff --git a/test/testaudiohotplug.c b/test/testaudiohotplug.c
index 085dbb030014..01386c47693a 100644
--- a/test/testaudiohotplug.c
+++ b/test/testaudiohotplug.c
@@ -110,7 +110,7 @@ iteration()
                     SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open '%s': %s\n", name, SDL_GetError());
                 } else {
                     SDL_Log("Opened '%s' as %u\n", name, (unsigned int)dev);
-                    SDL_PauseAudioDevice(dev, 0);
+                    SDL_PlayAudioDevice(dev);
                 }
             }
         } else if (e.type == SDL_AUDIODEVICEREMOVED) {
diff --git a/test/testautomation_audio.c b/test/testautomation_audio.c
index c6d3df318f95..500b366ec458 100644
--- a/test/testautomation_audio.c
+++ b/test/testautomation_audio.c
@@ -224,6 +224,7 @@ int audio_initOpenCloseQuitAudio()
  * \brief Pause and unpause audio
  *
  * \sa https://wiki.libsdl.org/SDL_PauseAudioDevice
+ * \sa https://wiki.libsdl.org/SDL_PlayAudioDevice
  */
 int audio_pauseUnpauseAudio()
 {
@@ -298,8 +299,8 @@ int audio_pauseUnpauseAudio()
                 /* Un-pause audio to start playing (maybe multiple times) */
                 pause_on = 0;
                 for (k = 0; k <= j; k++) {
-                    SDL_PauseAudioDevice(g_audio_id, pause_on);
-                    SDLTest_AssertPass("Call to SDL_PauseAudioDevice(g_audio_id, %d), call %d", pause_on, k + 1);
+                    SDL_PlayAudioDevice(g_audio_id);
+                    SDLTest_AssertPass("Call to SDL_PlayAudioDevice(g_audio_id), call %d", k + 1);
                 }
 
                 /* Wait for callback */
@@ -314,8 +315,13 @@ int audio_pauseUnpauseAudio()
                 /* Pause audio to stop playing (maybe multiple times) */
                 for (k = 0; k <= j; k++) {
                     pause_on = (k == 0) ? 1 : SDLTest_RandomIntegerInRange(99, 9999);
-                    SDL_PauseAudioDevice(g_audio_id, pause_on);
-                    SDLTest_AssertPass("Call to SDL_PauseAudioDevice(g_audio_id, %d), call %d", pause_on, k + 1);
+                    if (pause_on) {
+                        SDL_PauseAudioDevice(g_audio_id);
+                        SDLTest_AssertPass("Call to SDL_PauseAudioDevice(g_audio_id), call %d", k + 1);
+                    } else {
+                        SDL_PlayAudioDevice(g_audio_id);
+                        SDLTest_AssertPass("Call to SDL_PlayAudioDevice(g_audio_id), call %d", k + 1);
+                    }
                 }
 
                 /* Ensure callback is not called again */
diff --git a/test/testmultiaudio.c b/test/testmultiaudio.c
index 1e6ad500f53f..d3dbb36c3327 100644
--- a/test/testmultiaudio.c
+++ b/test/testmultiaudio.c
@@ -60,7 +60,7 @@ void loop()
 #ifdef __EMSCRIPTEN__
         emscripten_cancel_main_loop();
 #endif
-        SDL_PauseAudioDevice(cbd[0].dev, 1);
+        SDL_PauseAudioDevice(cbd[0].dev);
         SDL_CloseAudioDevice(cbd[0].dev);
         SDL_free(sound);
         SDL_Quit();
@@ -98,7 +98,7 @@ test_multi_audio(int devcount)
         if (cbd[0].dev == 0) {
             SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Open device failed: %s\n", SDL_GetError());
         } else {
-            SDL_PauseAudioDevice(cbd[0].dev, 0);
+            SDL_PlayAudioDevice(cbd[0].dev);
 #ifdef __EMSCRIPTEN__
             emscripten_set_main_loop(loop, 0, 1);
 #else
@@ -110,7 +110,7 @@ test_multi_audio(int devcount)
 #endif
                 SDL_Delay(100);
             }
-            SDL_PauseAudioDevice(cbd[0].dev, 1);
+            SDL_PauseAudioDevice(cbd[0].dev);
 #endif
             SDL_Log("done.\n");
             SDL_CloseAudioDevice(cbd[0].dev);
@@ -131,7 +131,7 @@ test_multi_audio(int devcount)
 
     for (i = 0; i < devcount; i++) {
         if (cbd[i].dev) {
-            SDL_PauseAudioDevice(cbd[i].dev, 0);
+            SDL_PlayAudioDevice(cbd[i].dev);
         }
     }
 
@@ -154,7 +154,7 @@ test_multi_audio(int devcount)
 #ifndef __EMSCRIPTEN__
     for (i = 0; i < devcount; i++) {
         if (cbd[i].dev) {
-            SDL_PauseAudioDevice(cbd[i].dev, 1);
+            SDL_PauseAudioDevice(cbd[i].dev);
             SDL_CloseAudioDevice(cbd[i].dev);
         }
     }
diff --git a/test/testsurround.c b/test/testsurround.c
index 7241a15cb57a..051e156a1b09 100644
--- a/test/testsurround.c
+++ b/test/testsurround.c
@@ -179,7 +179,7 @@ int main(int argc, char *argv[])
         total_channels = spec.channels;
         active_channel = 0;
 
-        SDL_PauseAudioDevice(dev, 0);
+        SDL_PlayAudioDevice(dev);
 
         for (j = 0; j < total_channels; j++) {
             int sine_freq = is_lfe_channel(j, total_channels) ? LFE_SINE_FREQ_HZ : SINE_FREQ_HZ;