From 45586e83da5981bceefbcf0520e49208b4779311 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Via=C4=8Das=C5=82a=C5=AD?= <viachaslavic@outlook.com>
Date: Mon, 3 Feb 2025 06:30:02 +0300
Subject: [PATCH] (PipeWire) Pass the new_rate to the audio driver (#17508)

Set the supported sample rate after initialization.
Also a few minor fixes.
---
 audio/common/pipewire.c             | 11 ++++-----
 audio/common/pipewire.h             |  2 +-
 audio/drivers/pipewire.c            | 33 ++++++++++++-------------
 audio/drivers_microphone/pipewire.c | 38 +++++++++++++----------------
 4 files changed, 39 insertions(+), 45 deletions(-)

diff --git a/audio/common/pipewire.c b/audio/common/pipewire.c
index 2f64656e62..e931254f52 100644
--- a/audio/common/pipewire.c
+++ b/audio/common/pipewire.c
@@ -203,20 +203,19 @@ void pipewire_core_deinit(pipewire_core_t *pw)
       pw_thread_loop_stop(pw->thread_loop);
 
    if (pw->registry)
+   {
+      spa_hook_remove(&pw->registry_listener);
       pw_proxy_destroy((struct pw_proxy*)pw->registry);
+   }
 
    if (pw->core)
    {
       spa_hook_remove(&pw->core_listener);
-      spa_zero(pw->core_listener);
       pw_core_disconnect(pw->core);
    }
 
-   if (pw->ctx)
-      pw_context_destroy(pw->ctx);
-
-   if (pw->thread_loop)
-      pw_thread_loop_destroy(pw->thread_loop);
+   spa_clear_ptr(pw->ctx, pw_context_destroy);
+   spa_clear_ptr(pw->thread_loop, pw_thread_loop_destroy);
 
    if (pw->devicelist)
       string_list_free(pw->devicelist);
diff --git a/audio/common/pipewire.h b/audio/common/pipewire.h
index cb69c3c5a4..ee57ffb22f 100644
--- a/audio/common/pipewire.h
+++ b/audio/common/pipewire.h
@@ -33,7 +33,7 @@
 #define PW_RARCH_MEDIA_TYPE_VIDEO          "Video"
 #define PW_RARCH_MEDIA_TYPE_MIDI           "Midi"
 #define PW_RARCH_MEDIA_CATEGORY_PLAYBACK   "Playback"
-#define PW_RARCH_MEDIA_CATEGORY_RECORD	    "Capture"
+#define PW_RARCH_MEDIA_CATEGORY_RECORD     "Capture"
 #define PW_RARCH_MEDIA_ROLE                "Game"
 
 typedef struct pipewire_core
diff --git a/audio/drivers/pipewire.c b/audio/drivers/pipewire.c
index 00b51c77b2..e35548d736 100644
--- a/audio/drivers/pipewire.c
+++ b/audio/drivers/pipewire.c
@@ -61,6 +61,7 @@ static void playback_process_cb(void *data)
    uint32_t req, idx, n_bytes;
    int32_t avail;
 
+   retro_assert(audio);
    retro_assert(audio->stream);
 
    if ((b = pw_stream_dequeue_buffer(audio->stream)) == NULL)
@@ -132,26 +133,22 @@ static void registry_event_global(void *data, uint32_t id,
    union string_list_elem_attr attr;
    const struct spa_dict_item *item;
    pipewire_core_t              *pw = (pipewire_core_t*)data;
-   const char                *media = NULL;
    const char                 *sink = NULL;
 
-   if (spa_streq(type, PW_TYPE_INTERFACE_Node))
+   if (spa_streq(type, PW_TYPE_INTERFACE_Node)
+      && spa_streq("Audio/Sink", spa_dict_lookup(props, PW_KEY_MEDIA_CLASS)))
    {
-      media = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS);
-      if (media && spa_streq(media, "Audio/Sink"))
+      sink = spa_dict_lookup(props, PW_KEY_NODE_NAME);
+      if (sink && pw->devicelist)
       {
-         sink = spa_dict_lookup(props, PW_KEY_NODE_NAME);
-         if (sink && pw->devicelist)
-         {
-            attr.i = id;
-            string_list_append(pw->devicelist, sink, attr);
-            RARCH_LOG("[Audio] [PipeWire]: Found Sink Node: %s\n", sink);
-         }
-
-         RARCH_DBG("[Audio] [PipeWire]: Object: id:%u Type:%s/%d\n", id, type, version);
-         spa_dict_for_each(item, props)
-            RARCH_DBG("[Audio] [PipeWire]: \t\t%s: \"%s\"\n", item->key, item->value);
+         attr.i = id;
+         string_list_append(pw->devicelist, sink, attr);
+         RARCH_LOG("[Audio] [PipeWire]: Found Sink Node: %s\n", sink);
       }
+
+      RARCH_DBG("[Audio] [PipeWire]: Object: id:%u Type:%s/%d\n", id, type, version);
+      spa_dict_for_each(item, props)
+         RARCH_DBG("[Audio] [PipeWire]: \t\t%s: \"%s\"\n", item->key, item->value);
    }
 }
 
@@ -225,15 +222,17 @@ static void *pipewire_init(const char *device, unsigned rate,
                            PW_STREAM_FLAG_MAP_BUFFERS |
                            PW_STREAM_FLAG_RT_PROCESS,
                            params, 1);
-
    if (res < 0)
       goto unlock_error;
 
    audio->highwater_mark = MIN(RINGBUFFER_SIZE,
                                latency * (uint64_t)rate / 1000 * audio->frame_size);
 
+   pw_thread_loop_wait(audio->pw->thread_loop);
    pw_thread_loop_unlock(audio->pw->thread_loop);
 
+   *new_rate = audio->info.rate;
+
    return audio;
 
 unlock_error:
@@ -384,7 +383,7 @@ static void pipewire_free(void *data)
    pipewire_audio_t *audio = (pipewire_audio_t*)data;
 
    if (!audio)
-      return pw_deinit();
+      return;
 
    if (audio->stream)
    {
diff --git a/audio/drivers_microphone/pipewire.c b/audio/drivers_microphone/pipewire.c
index 68b7bd7168..c6d2867905 100644
--- a/audio/drivers_microphone/pipewire.c
+++ b/audio/drivers_microphone/pipewire.c
@@ -72,7 +72,8 @@ static void capture_process_cb(void *data)
    uint32_t idx, offs, n_bytes;
    pipewire_microphone_t *mic = (pipewire_microphone_t*)data;
 
-   assert(mic->stream);
+   retro_assert(mic);
+   retro_assert(mic->stream);
 
    if (!(b = pw_stream_dequeue_buffer(mic->stream)))
    {
@@ -120,28 +121,25 @@ static void registry_event_global(void *data, uint32_t id,
    union string_list_elem_attr attr;
    const struct spa_dict_item *item;
    pipewire_core_t              *pw = (pipewire_core_t*)data;
-   const char                *media = NULL;
    const char                 *sink = NULL;
 
    if (!pw)
       return;
 
-   if (spa_streq(type, PW_TYPE_INTERFACE_Node))
+   if (   spa_streq(type, PW_TYPE_INTERFACE_Node)
+       && spa_streq("Audio/Source", spa_dict_lookup(props, PW_KEY_MEDIA_CLASS)))
    {
-      media = spa_dict_lookup(props, PW_KEY_MEDIA_CLASS);
-      if (media && spa_streq(media, "Audio/Source"))
+      sink = spa_dict_lookup(props, PW_KEY_NODE_NAME);
+      if (sink && pw->devicelist)
       {
-         if ((sink = spa_dict_lookup(props, PW_KEY_NODE_NAME)) != NULL)
-         {
-            attr.i = id;
-            string_list_append(pw->devicelist, sink, attr);
-            RARCH_LOG("[Microphone] [PipeWire]: Found Source Node: %s\n", sink);
-         }
-
-         RARCH_DBG("[Microphone] [PipeWire]: Object: id:%u Type:%s/%d\n", id, type, version);
-         spa_dict_for_each(item, props)
-            RARCH_DBG("[Microphone] [PipeWire]: \t\t%s: \"%s\"\n", item->key, item->value);
+         attr.i = id;
+         string_list_append(pw->devicelist, sink, attr);
+         RARCH_LOG("[Microphone] [PipeWire]: Found Source Node: %s\n", sink);
       }
+
+      RARCH_DBG("[Microphone] [PipeWire]: Object: id:%u Type:%s/%d\n", id, type, version);
+      spa_dict_for_each(item, props)
+         RARCH_DBG("[Microphone] [PipeWire]: \t\t%s: \"%s\"\n", item->key, item->value);
    }
 }
 
@@ -285,14 +283,12 @@ static void *pipewire_microphone_open_mic(void *driver_context,
    struct pw_properties *props = NULL;
    const char           *error = NULL;
    struct spa_pod_builder    b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
-   pipewire_microphone_t   *mic = calloc(1, sizeof(pipewire_microphone_t));
+   pipewire_microphone_t   *mic = NULL;
 
-   retro_assert(driver_context);
-
-   if (!mic)
+   if (!driver_context || (mic = calloc(1, sizeof(pipewire_microphone_t))) == NULL)
       goto error;
 
-   mic->pw       = (pipewire_core_t*)driver_context;
+   mic->pw = (pipewire_core_t*)driver_context;
 
    pw_thread_loop_lock(mic->pw->thread_loop);
 
@@ -393,7 +389,7 @@ static bool pipewire_microphone_stop_mic(void *driver_context, void *mic_context
       return false;
 
    if (pw_stream_get_state(mic->stream, &error) == PW_STREAM_STATE_STREAMING)
-     res =  pipewire_stream_set_active(pw->thread_loop, mic->stream, false);
+      res = pipewire_stream_set_active(pw->thread_loop, mic->stream, false);
    else
       /* For other states we assume that the stream is inactive */
       res = true;