From fc722f8aea13246ce7779acbb3a59681b64131a6 Mon Sep 17 00:00:00 2001 From: George Kiagiadakis Date: Thu, 11 Feb 2021 14:13:55 +0200 Subject: meta-pipewire: backport pipewire updates from master Bug-AGL: SPEC-3844 Bug-AGL: SPEC-3900 Bug-AGL: SPEC-3909 Signed-off-by: George Kiagiadakis Change-Id: I3c32d0083f31f94b49e33c3dd546515d39df7867 Reviewed-on: https://gerrit.automotivelinux.org/gerrit/c/AGL/meta-agl/+/26360 Reviewed-by: Jan-Simon Moeller Tested-by: Jan-Simon Moeller --- ...t-version-check-to-require-meson-0.47-not.patch | 30 - ...k-use-all-the-available-dest-memory-when-.patch | 33 + .../0002-arm-build-with-mno-unaligned-access.patch | 30 - ...k-release-manually-acquired-buffers-back-.patch | 52 + ...nt-new-pwaudio-src-sink-elements-based-on.patch | 1280 -------------------- ...t-always-assume-that-output-ports-are-NOT.patch | 35 - ...005-module-access-add-same-sec-label-mode.patch | 94 -- ...ll-reuse_buffers-when-resetting-the-state.patch | 30 - ...lsa-Set-period_size-depending-on-hardware.patch | 35 - ...add-warning-in-case-of-partial-read-write.patch | 80 -- ...9-alsa-adjust-delay-depending-on-hardware.patch | 64 - 11 files changed, 85 insertions(+), 1678 deletions(-) delete mode 100644 meta-pipewire/recipes-multimedia/pipewire/pipewire/0001-meson-revert-version-check-to-require-meson-0.47-not.patch create mode 100644 meta-pipewire/recipes-multimedia/pipewire/pipewire/0001-pipewiresink-use-all-the-available-dest-memory-when-.patch delete mode 100644 meta-pipewire/recipes-multimedia/pipewire/pipewire/0002-arm-build-with-mno-unaligned-access.patch create mode 100644 meta-pipewire/recipes-multimedia/pipewire/pipewire/0002-pipewiresink-release-manually-acquired-buffers-back-.patch delete mode 100644 meta-pipewire/recipes-multimedia/pipewire/pipewire/0003-gst-Implement-new-pwaudio-src-sink-elements-based-on.patch delete mode 100644 meta-pipewire/recipes-multimedia/pipewire/pipewire/0004-audioconvert-always-assume-that-output-ports-are-NOT.patch delete mode 100644 meta-pipewire/recipes-multimedia/pipewire/pipewire/0005-module-access-add-same-sec-label-mode.patch delete mode 100644 meta-pipewire/recipes-multimedia/pipewire/pipewire/0006-alsa-pcm-call-reuse_buffers-when-resetting-the-state.patch delete mode 100644 meta-pipewire/recipes-multimedia/pipewire/pipewire/0007-alsa-Set-period_size-depending-on-hardware.patch delete mode 100644 meta-pipewire/recipes-multimedia/pipewire/pipewire/0008-alsa-add-warning-in-case-of-partial-read-write.patch delete mode 100644 meta-pipewire/recipes-multimedia/pipewire/pipewire/0009-alsa-adjust-delay-depending-on-hardware.patch (limited to 'meta-pipewire/recipes-multimedia/pipewire/pipewire') diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0001-meson-revert-version-check-to-require-meson-0.47-not.patch b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0001-meson-revert-version-check-to-require-meson-0.47-not.patch deleted file mode 100644 index 4e7bb0d4f..000000000 --- a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0001-meson-revert-version-check-to-require-meson-0.47-not.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 5a249321aa84cd74e3d83bcd555c85fba3cd682d Mon Sep 17 00:00:00 2001 -From: George Kiagiadakis -Date: Sun, 22 Sep 2019 17:59:19 +0300 -Subject: [PATCH] meson: revert version check to require meson 0.47, not 0.50 - -meson 0.50 is not really needed, but there are some strange warnings -if you require an older version; in any case, AGL does not have 0.50 -yet, so let's not fail compilation because of that... - -Upstream-Status: Inappropriate [workaround] ---- - meson.build | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/meson.build b/meson.build -index 2734b0d2..c9da6b4d 100644 ---- a/meson.build -+++ b/meson.build -@@ -1,7 +1,7 @@ - project('pipewire', ['c' ], - version : '0.2.9', - license : 'MIT', -- meson_version : '>= 0.50.0', -+ meson_version : '>= 0.47.0', - default_options : [ 'warning_level=1', - 'c_std=gnu99', - 'buildtype=debugoptimized' ]) --- -2.24.0 - diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0001-pipewiresink-use-all-the-available-dest-memory-when-.patch b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0001-pipewiresink-use-all-the-available-dest-memory-when-.patch new file mode 100644 index 000000000..a3bde14bc --- /dev/null +++ b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0001-pipewiresink-use-all-the-available-dest-memory-when-.patch @@ -0,0 +1,33 @@ +From b86e5cabfae3ab354f350f8f7589b21a153a8a5d Mon Sep 17 00:00:00 2001 +From: George Kiagiadakis +Date: Mon, 10 May 2021 17:12:12 +0300 +Subject: pipewiresink: use all the available dest memory when copying buffer + +When pipewiresink needs to copy data, it has to resize the destination +buffer (to a smaller size) in order to send the correct data size to +pipewire. When this dest buffer is reused later, it will still have +this smaller size as its total size and the copy may discard data +from upstream if the new upstream buffer is bigger than the last one +that was copied on the same dest buffer. + +Upstream-Status: Backport [from master/0.3.28] +--- + src/gst/gstpipewiresink.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/gst/gstpipewiresink.c b/src/gst/gstpipewiresink.c +index 966b12c7..031b3ae0 100644 +--- a/src/gst/gstpipewiresink.c ++++ b/src/gst/gstpipewiresink.c +@@ -616,7 +616,7 @@ gst_pipewire_sink_render (GstBaseSink * bsink, GstBuffer * buffer) + goto done; + + gst_buffer_map (b, &info, GST_MAP_WRITE); +- gst_buffer_extract (buffer, 0, info.data, info.size); ++ gst_buffer_extract (buffer, 0, info.data, info.maxsize); + gst_buffer_unmap (b, &info); + gst_buffer_resize (b, 0, gst_buffer_get_size (buffer)); + buffer = b; +-- +2.30.2 + diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0002-arm-build-with-mno-unaligned-access.patch b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0002-arm-build-with-mno-unaligned-access.patch deleted file mode 100644 index 2077af63d..000000000 --- a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0002-arm-build-with-mno-unaligned-access.patch +++ /dev/null @@ -1,30 +0,0 @@ -From e4b81946baf2d8c08de87088c01a1d87ae4f03d9 Mon Sep 17 00:00:00 2001 -From: George Kiagiadakis -Date: Mon, 24 Jun 2019 12:19:20 +0300 -Subject: [PATCH] arm: build with -mno-unaligned-access - -Upstream-Status: Inappropriate [workaround] -See also https://gitlab.freedesktop.org/pipewire/pipewire/issues/161 ---- - meson.build | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/meson.build b/meson.build -index c9da6b4d..5c121339 100644 ---- a/meson.build -+++ b/meson.build -@@ -52,6 +52,11 @@ if cc.get_id() == 'gcc' - language : 'c') - endif - -+if host_machine.cpu_family() == 'arm' -+ add_global_arguments('-mno-unaligned-access', -+ language: 'c') -+endif -+ - sse_args = '-msse' - sse2_args = '-msse2' - ssse3_args = '-mssse3' --- -2.24.0 - diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0002-pipewiresink-release-manually-acquired-buffers-back-.patch b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0002-pipewiresink-release-manually-acquired-buffers-back-.patch new file mode 100644 index 000000000..aeafae616 --- /dev/null +++ b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0002-pipewiresink-release-manually-acquired-buffers-back-.patch @@ -0,0 +1,52 @@ +From 8911e22793ed3713ceb78be5414eeb03ebde962e Mon Sep 17 00:00:00 2001 +From: George Kiagiadakis +Date: Mon, 10 May 2021 17:25:57 +0300 +Subject: pipewiresink: release manually acquired buffers back to the pool + +When we manually acquire buffers from the pool, we never release them. +But because gst_buffer_pool_acquire_buffer() adds a reference to the pool, +this leaks the pool eventually. + +To fix this, just unref the buffer after it has been sent. This releases +it back to the pool and unrefs the pool. + +This has no significant effect to the stream, since the underlying +pw buffers are actually pooled in the pw_stream. It just prevents leaking. + +Upstream-Status: Backport [from master/0.3.28] +--- + src/gst/gstpipewiresink.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/src/gst/gstpipewiresink.c b/src/gst/gstpipewiresink.c +index 031b3ae0..2f79a4f7 100644 +--- a/src/gst/gstpipewiresink.c ++++ b/src/gst/gstpipewiresink.c +@@ -578,6 +578,7 @@ gst_pipewire_sink_render (GstBaseSink * bsink, GstBuffer * buffer) + GstPipeWireSink *pwsink; + GstFlowReturn res = GST_FLOW_OK; + const char *error = NULL; ++ gboolean unref_buffer = FALSE; + + pwsink = GST_PIPEWIRE_SINK (bsink); + +@@ -620,6 +621,7 @@ gst_pipewire_sink_render (GstBaseSink * bsink, GstBuffer * buffer) + gst_buffer_unmap (b, &info); + gst_buffer_resize (b, 0, gst_buffer_get_size (buffer)); + buffer = b; ++ unref_buffer = TRUE; + + pw_thread_loop_lock (pwsink->core->loop); + if (pw_stream_get_state (pwsink->stream, &error) != PW_STREAM_STATE_STREAMING) +@@ -628,6 +630,8 @@ gst_pipewire_sink_render (GstBaseSink * bsink, GstBuffer * buffer) + + GST_DEBUG ("push buffer"); + do_send_buffer (pwsink, buffer); ++ if (unref_buffer) ++ gst_buffer_unref (buffer); + + done_unlock: + pw_thread_loop_unlock (pwsink->core->loop); +-- +2.30.2 + diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0003-gst-Implement-new-pwaudio-src-sink-elements-based-on.patch b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0003-gst-Implement-new-pwaudio-src-sink-elements-based-on.patch deleted file mode 100644 index b3eba21f7..000000000 --- a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0003-gst-Implement-new-pwaudio-src-sink-elements-based-on.patch +++ /dev/null @@ -1,1280 +0,0 @@ -From 1b1f884a165ed7b2147affbdddf85a641d4cf180 Mon Sep 17 00:00:00 2001 -From: George Kiagiadakis -Date: Tue, 19 Feb 2019 18:23:19 +0200 -Subject: [PATCH] gst: Implement new pwaudio{src,sink} elements, based on - GstAudioBase{Src,Sink} - -These are much more reliable elements to use for audio data. -* GstAudioBaseSink provides a reliable clock implementation based - on the number of samples read/written -* on the pipewire side we make sure to dequeue, fill and enqueue - a single buffer inside the process() function, which avoids - underruns - -Both elements share a common ringbuffer that actually implements -the pipewire integration. - -Upstream-Status: Denied -See https://gitlab.freedesktop.org/pipewire/pipewire/merge_requests/140 ---- - src/gst/gstpipewire.c | 8 +- - src/gst/gstpwaudioringbuffer.c | 565 +++++++++++++++++++++++++++++++++ - src/gst/gstpwaudioringbuffer.h | 83 +++++ - src/gst/gstpwaudiosink.c | 207 ++++++++++++ - src/gst/gstpwaudiosink.h | 48 +++ - src/gst/gstpwaudiosrc.c | 200 ++++++++++++ - src/gst/gstpwaudiosrc.h | 48 +++ - src/gst/meson.build | 6 + - 8 files changed, 1164 insertions(+), 1 deletion(-) - create mode 100644 src/gst/gstpwaudioringbuffer.c - create mode 100644 src/gst/gstpwaudioringbuffer.h - create mode 100644 src/gst/gstpwaudiosink.c - create mode 100644 src/gst/gstpwaudiosink.h - create mode 100644 src/gst/gstpwaudiosrc.c - create mode 100644 src/gst/gstpwaudiosrc.h - -diff --git a/src/gst/gstpipewire.c b/src/gst/gstpipewire.c -index 4040264b..68fd446f 100644 ---- a/src/gst/gstpipewire.c -+++ b/src/gst/gstpipewire.c -@@ -40,6 +40,8 @@ - #include "gstpipewiresrc.h" - #include "gstpipewiresink.h" - #include "gstpipewiredeviceprovider.h" -+#include "gstpwaudiosrc.h" -+#include "gstpwaudiosink.h" - - GST_DEBUG_CATEGORY (pipewire_debug); - -@@ -52,12 +54,16 @@ plugin_init (GstPlugin *plugin) - GST_TYPE_PIPEWIRE_SRC); - gst_element_register (plugin, "pipewiresink", GST_RANK_NONE, - GST_TYPE_PIPEWIRE_SINK); -+ gst_element_register (plugin, "pwaudiosrc", GST_RANK_NONE, -+ GST_TYPE_PW_AUDIO_SRC); -+ gst_element_register (plugin, "pwaudiosink", GST_RANK_NONE, -+ GST_TYPE_PW_AUDIO_SINK); - - if (!gst_device_provider_register (plugin, "pipewiredeviceprovider", - GST_RANK_PRIMARY + 1, GST_TYPE_PIPEWIRE_DEVICE_PROVIDER)) - return FALSE; - -- GST_DEBUG_CATEGORY_INIT (pipewire_debug, "pipewire", 0, "PipeWirie elements"); -+ GST_DEBUG_CATEGORY_INIT (pipewire_debug, "pipewire", 0, "PipeWire elements"); - - return TRUE; - } -diff --git a/src/gst/gstpwaudioringbuffer.c b/src/gst/gstpwaudioringbuffer.c -new file mode 100644 -index 00000000..babf2d83 ---- /dev/null -+++ b/src/gst/gstpwaudioringbuffer.c -@@ -0,0 +1,565 @@ -+/* PipeWire -+ * -+ * Copyright © 2018 Wim Taymans -+ * Copyright © 2019 Collabora Ltd. -+ * @author George Kiagiadakis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif -+ -+#include "gstpwaudioringbuffer.h" -+ -+#include -+#include -+ -+GST_DEBUG_CATEGORY_STATIC (pw_audio_ring_buffer_debug); -+#define GST_CAT_DEFAULT pw_audio_ring_buffer_debug -+ -+#define gst_pw_audio_ring_buffer_parent_class parent_class -+G_DEFINE_TYPE (GstPwAudioRingBuffer, gst_pw_audio_ring_buffer, GST_TYPE_AUDIO_RING_BUFFER); -+ -+enum -+{ -+ PROP_0, -+ PROP_ELEMENT, -+ PROP_DIRECTION, -+ PROP_PROPS -+}; -+ -+static void -+gst_pw_audio_ring_buffer_init (GstPwAudioRingBuffer * self) -+{ -+ self->loop = pw_loop_new (NULL); -+ self->main_loop = pw_thread_loop_new (self->loop, "pw-audioringbuffer-loop"); -+ self->core = pw_core_new (self->loop, NULL, 0); -+} -+ -+static void -+gst_pw_audio_ring_buffer_finalize (GObject * object) -+{ -+ GstPwAudioRingBuffer *self = GST_PW_AUDIO_RING_BUFFER (object); -+ -+ pw_core_destroy (self->core); -+ pw_thread_loop_destroy (self->main_loop); -+ pw_loop_destroy (self->loop); -+} -+ -+static void -+gst_pw_audio_ring_buffer_set_property (GObject * object, guint prop_id, -+ const GValue * value, GParamSpec * pspec) -+{ -+ GstPwAudioRingBuffer *self = GST_PW_AUDIO_RING_BUFFER (object); -+ -+ switch (prop_id) { -+ case PROP_ELEMENT: -+ self->elem = g_value_get_object (value); -+ break; -+ -+ case PROP_DIRECTION: -+ self->direction = g_value_get_int (value); -+ break; -+ -+ case PROP_PROPS: -+ self->props = g_value_get_pointer (value); -+ break; -+ -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -+ break; -+ } -+} -+ -+static void -+on_remote_state_changed (void *data, enum pw_remote_state old, -+ enum pw_remote_state state, const char *error) -+{ -+ GstPwAudioRingBuffer *self = GST_PW_AUDIO_RING_BUFFER (data); -+ -+ GST_DEBUG_OBJECT (self->elem, "got remote state %d", state); -+ -+ switch (state) { -+ case PW_REMOTE_STATE_UNCONNECTED: -+ case PW_REMOTE_STATE_CONNECTING: -+ case PW_REMOTE_STATE_CONNECTED: -+ break; -+ case PW_REMOTE_STATE_ERROR: -+ GST_ELEMENT_ERROR (self->elem, RESOURCE, FAILED, -+ ("remote error: %s", error), (NULL)); -+ break; -+ } -+ pw_thread_loop_signal (self->main_loop, FALSE); -+} -+ -+static const struct pw_remote_events remote_events = { -+ PW_VERSION_REMOTE_EVENTS, -+ .state_changed = on_remote_state_changed, -+}; -+ -+static gboolean -+wait_for_remote_state (GstPwAudioRingBuffer *self, -+ enum pw_remote_state target) -+{ -+ while (TRUE) { -+ enum pw_remote_state state = pw_remote_get_state (self->remote, NULL); -+ if (state == target) -+ return TRUE; -+ if (state == PW_REMOTE_STATE_ERROR) -+ return FALSE; -+ pw_thread_loop_wait (self->main_loop); -+ } -+} -+ -+static gboolean -+gst_pw_audio_ring_buffer_open_device (GstAudioRingBuffer *buf) -+{ -+ GstPwAudioRingBuffer *self = GST_PW_AUDIO_RING_BUFFER (buf); -+ -+ GST_DEBUG_OBJECT (self->elem, "open device"); -+ -+ if (pw_thread_loop_start (self->main_loop) < 0) -+ goto mainloop_error; -+ -+ pw_thread_loop_lock (self->main_loop); -+ -+ self->remote = pw_remote_new (self->core, NULL, 0); -+ pw_remote_add_listener (self->remote, &self->remote_listener, &remote_events, -+ self); -+ -+ if (self->props->fd == -1) -+ pw_remote_connect (self->remote); -+ else -+ pw_remote_connect_fd (self->remote, self->props->fd); -+ -+ GST_DEBUG_OBJECT (self->elem, "waiting for connection"); -+ -+ if (!wait_for_remote_state (self, PW_REMOTE_STATE_CONNECTED)) -+ goto connect_error; -+ -+ pw_thread_loop_unlock (self->main_loop); -+ -+ return TRUE; -+ -+ /* ERRORS */ -+mainloop_error: -+ { -+ GST_ELEMENT_ERROR (self->elem, RESOURCE, FAILED, -+ ("Failed to start mainloop"), (NULL)); -+ return FALSE; -+ } -+connect_error: -+ { -+ pw_thread_loop_unlock (self->main_loop); -+ return FALSE; -+ } -+} -+ -+static gboolean -+gst_pw_audio_ring_buffer_close_device (GstAudioRingBuffer *buf) -+{ -+ GstPwAudioRingBuffer *self = GST_PW_AUDIO_RING_BUFFER (buf); -+ -+ GST_DEBUG_OBJECT (self->elem, "closing device"); -+ -+ pw_thread_loop_lock (self->main_loop); -+ if (self->remote) { -+ pw_remote_disconnect (self->remote); -+ wait_for_remote_state (self, PW_REMOTE_STATE_UNCONNECTED); -+ } -+ pw_thread_loop_unlock (self->main_loop); -+ -+ pw_thread_loop_stop (self->main_loop); -+ -+ if (self->remote) { -+ pw_remote_destroy (self->remote); -+ self->remote = NULL; -+ } -+ return TRUE; -+} -+ -+static void -+on_stream_state_changed (void *data, enum pw_stream_state old, -+ enum pw_stream_state state, const char *error) -+{ -+ GstPwAudioRingBuffer *self = GST_PW_AUDIO_RING_BUFFER (data); -+ GstMessage *msg; -+ -+ GST_DEBUG_OBJECT (self->elem, "got stream state: %s", -+ pw_stream_state_as_string (state)); -+ -+ switch (state) { -+ case PW_STREAM_STATE_ERROR: -+ GST_ELEMENT_ERROR (self->elem, RESOURCE, FAILED, -+ ("stream error: %s", error), (NULL)); -+ break; -+ case PW_STREAM_STATE_UNCONNECTED: -+ GST_ELEMENT_ERROR (self->elem, RESOURCE, FAILED, -+ ("stream disconnected unexpectedly"), (NULL)); -+ break; -+ case PW_STREAM_STATE_CONNECTING: -+ break; -+ case PW_STREAM_STATE_PAUSED: -+ if (old == PW_STREAM_STATE_STREAMING) { -+ if (GST_STATE (self->elem) != GST_STATE_PAUSED && -+ GST_STATE_TARGET (self->elem) != GST_STATE_PAUSED) { -+ GST_DEBUG_OBJECT (self->elem, "requesting GST_STATE_PAUSED"); -+ msg = gst_message_new_request_state (GST_OBJECT (self->elem), -+ GST_STATE_PAUSED); -+ gst_element_post_message (self->elem, msg); -+ } -+ } -+ break; -+ case PW_STREAM_STATE_STREAMING: -+ if (GST_STATE (self->elem) != GST_STATE_PLAYING && -+ GST_STATE_TARGET (self->elem) != GST_STATE_PLAYING) { -+ GST_DEBUG_OBJECT (self->elem, "requesting GST_STATE_PLAYING"); -+ msg = gst_message_new_request_state (GST_OBJECT (self->elem), -+ GST_STATE_PLAYING); -+ gst_element_post_message (self->elem, msg); -+ } -+ break; -+ } -+ pw_thread_loop_signal (self->main_loop, FALSE); -+} -+ -+static gboolean -+wait_for_stream_state (GstPwAudioRingBuffer *self, -+ enum pw_stream_state target) -+{ -+ while (TRUE) { -+ enum pw_stream_state state = pw_stream_get_state (self->stream, NULL); -+ if (state >= target) -+ return TRUE; -+ if (state == PW_STREAM_STATE_ERROR || state == PW_STREAM_STATE_UNCONNECTED) -+ return FALSE; -+ pw_thread_loop_wait (self->main_loop); -+ } -+} -+ -+static void -+on_stream_param_changed (void *data, uint32_t id, const struct spa_pod *format) -+{ -+ GstPwAudioRingBuffer *self = GST_PW_AUDIO_RING_BUFFER (data); -+ const struct spa_pod *params[1]; -+ struct spa_pod_builder b = { NULL }; -+ uint8_t buffer[512]; -+ -+ if (format == NULL || id != SPA_PARAM_Format) -+ return; -+ -+ spa_pod_builder_init (&b, buffer, sizeof (buffer)); -+ params[0] = spa_pod_builder_add_object (&b, -+ SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers, -+ SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(16, 1, INT32_MAX), -+ SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1), -+ SPA_PARAM_BUFFERS_size, SPA_POD_Int(self->segsize), -+ SPA_PARAM_BUFFERS_stride, SPA_POD_Int(self->bpf), -+ SPA_PARAM_BUFFERS_align, SPA_POD_Int(16)); -+ -+ GST_DEBUG_OBJECT (self->elem, "doing finish format, buffer size:%d", self->segsize); -+ pw_stream_update_params (self->stream, params, 1); -+} -+ -+static void -+on_stream_process (void *data) -+{ -+ GstPwAudioRingBuffer *self = GST_PW_AUDIO_RING_BUFFER (data); -+ GstAudioRingBuffer *buf = GST_AUDIO_RING_BUFFER (data); -+ struct pw_buffer *b; -+ struct spa_data *d; -+ gint size; /*< size to read/write from/to the spa buffer */ -+ gint offset; /*< offset to read/write from/to in the spa buffer */ -+ gint segment; /*< the current segment number in the ringbuffer */ -+ guint8 *ringptr; /*< pointer to the beginning of the current segment */ -+ gint segsize; /*< the size of one segment in the ringbuffer */ -+ gint copy_size; /*< the bytes to copy in one memcpy() invocation */ -+ gint remain; /*< remainder of bytes available in the spa buffer */ -+ -+ if (g_atomic_int_get (&buf->state) != GST_AUDIO_RING_BUFFER_STATE_STARTED) { -+ GST_LOG_OBJECT (self->elem, "ring buffer is not started"); -+ return; -+ } -+ -+ b = pw_stream_dequeue_buffer (self->stream); -+ if (!b) { -+ GST_INFO_OBJECT (self->elem, "no pipewire buffer available"); -+ return; -+ } -+ -+ d = &b->buffer->datas[0]; -+ -+ if (self->direction == PW_DIRECTION_OUTPUT) { -+ /* in output mode, always fill the entire spa buffer */ -+ offset = d->chunk->offset = 0; -+ size = d->chunk->size = d->maxsize; -+ b->size = size / self->bpf; -+ } else { -+ offset = SPA_MIN (d->chunk->offset, d->maxsize); -+ size = SPA_MIN (d->chunk->size, d->maxsize - offset); -+ } -+ -+ do { -+ gst_audio_ring_buffer_prepare_read (buf, &segment, &ringptr, &segsize); -+ -+ /* in INPUT (src) mode, it is possible that the skew algorithm -+ * advances the ringbuffer behind our back */ -+ if (self->segoffset > 0 && self->cur_segment != segment) -+ self->segoffset = 0; -+ -+ copy_size = SPA_MIN (size, segsize - self->segoffset); -+ -+ if (self->direction == PW_DIRECTION_OUTPUT) { -+ memcpy (((guint8*) d->data) + offset, ringptr + self->segoffset, -+ copy_size); -+ } else { -+ memcpy (ringptr + self->segoffset, ((guint8*) d->data) + offset, -+ copy_size); -+ } -+ -+ remain = size - (segsize - self->segoffset); -+ -+ GST_TRACE_OBJECT (self->elem, -+ "seg %d: %s %d bytes remained:%d offset:%d segoffset:%d", segment, -+ self->direction == PW_DIRECTION_INPUT ? "INPUT" : "OUTPUT", -+ copy_size, remain, offset, self->segoffset); -+ -+ if (remain >= 0) { -+ offset += (segsize - self->segoffset); -+ size = remain; -+ -+ /* write silence on the segment we just read */ -+ if (self->direction == PW_DIRECTION_OUTPUT) -+ gst_audio_ring_buffer_clear (buf, segment); -+ -+ /* notify that we have read a complete segment */ -+ gst_audio_ring_buffer_advance (buf, 1); -+ self->segoffset = 0; -+ } else { -+ self->segoffset += size; -+ self->cur_segment = segment; -+ } -+ } while (remain > 0); -+ -+ pw_stream_queue_buffer (self->stream, b); -+} -+ -+static const struct pw_stream_events stream_events = { -+ PW_VERSION_STREAM_EVENTS, -+ .state_changed = on_stream_state_changed, -+ .param_changed = on_stream_param_changed, -+ .process = on_stream_process, -+}; -+ -+static gboolean -+copy_properties (GQuark field_id, const GValue *value, gpointer user_data) -+{ -+ struct pw_properties *properties = user_data; -+ -+ if (G_VALUE_HOLDS_STRING (value)) -+ pw_properties_set (properties, -+ g_quark_to_string (field_id), -+ g_value_get_string (value)); -+ return TRUE; -+} -+ -+static gboolean -+gst_pw_audio_ring_buffer_acquire (GstAudioRingBuffer *buf, -+ GstAudioRingBufferSpec *spec) -+{ -+ GstPwAudioRingBuffer *self = GST_PW_AUDIO_RING_BUFFER (buf); -+ struct pw_properties *props; -+ struct spa_pod_builder b = { NULL }; -+ uint8_t buffer[512]; -+ const struct spa_pod *params[1]; -+ -+ g_return_val_if_fail (spec, FALSE); -+ g_return_val_if_fail (GST_AUDIO_INFO_IS_VALID (&spec->info), FALSE); -+ g_return_val_if_fail (!self->stream, TRUE); /* already acquired */ -+ -+ g_return_val_if_fail (spec->type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW, FALSE); -+ g_return_val_if_fail (GST_AUDIO_INFO_IS_FLOAT (&spec->info), FALSE); -+ -+ GST_DEBUG_OBJECT (self->elem, "acquire"); -+ -+ /* construct param & props objects */ -+ -+ props = pw_properties_new (NULL, NULL); -+ if (self->props->properties) { -+ gst_structure_foreach (self->props->properties, copy_properties, props); -+ } -+ -+ spa_pod_builder_init (&b, buffer, sizeof (buffer)); -+ params[0] = spa_pod_builder_add_object (&b, -+ SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, -+ SPA_FORMAT_mediaType, SPA_POD_Id (SPA_MEDIA_TYPE_audio), -+ SPA_FORMAT_mediaSubtype, SPA_POD_Id (SPA_MEDIA_SUBTYPE_raw), -+ SPA_FORMAT_AUDIO_format, SPA_POD_Id (SPA_AUDIO_FORMAT_F32), -+ SPA_FORMAT_AUDIO_rate, SPA_POD_Int (GST_AUDIO_INFO_RATE (&spec->info)), -+ SPA_FORMAT_AUDIO_channels, SPA_POD_Int (GST_AUDIO_INFO_CHANNELS (&spec->info))); -+ -+ self->segsize = spec->segsize; -+ self->bpf = GST_AUDIO_INFO_BPF (&spec->info); -+ self->rate = GST_AUDIO_INFO_RATE (&spec->info); -+ self->segoffset = 0; -+ -+ pw_properties_setf(props, PW_KEY_NODE_LATENCY, "%u/%u", -+ self->segsize / self->bpf, self->rate); -+ GST_DEBUG_OBJECT (self->elem, "segsize:%u, bpf:%u, node.latency = %s", -+ self->segsize, self->bpf, pw_properties_get (props, PW_KEY_NODE_LATENCY)); -+ -+ /* connect stream */ -+ -+ pw_thread_loop_lock (self->main_loop); -+ -+ GST_DEBUG_OBJECT (self->elem, "creating stream"); -+ -+ self->stream = pw_stream_new (self->remote, self->props->client_name, props); -+ pw_stream_add_listener(self->stream, &self->stream_listener, &stream_events, -+ self); -+ -+ if (pw_stream_connect (self->stream, -+ self->direction, -+ self->props->path ? (uint32_t)atoi(self->props->path) : SPA_ID_INVALID, -+ PW_STREAM_FLAG_AUTOCONNECT | -+ PW_STREAM_FLAG_MAP_BUFFERS | -+ PW_STREAM_FLAG_RT_PROCESS, -+ params, 1) < 0) -+ goto start_error; -+ -+ GST_DEBUG_OBJECT (self->elem, "waiting for stream CONFIGURE"); -+ -+ if (!wait_for_stream_state (self, PW_STREAM_STATE_PAUSED)) -+ goto start_error; -+ -+ pw_thread_loop_unlock (self->main_loop); -+ -+ /* allocate the internal ringbuffer */ -+ -+ spec->seglatency = spec->segtotal + 1; -+ buf->size = spec->segtotal * spec->segsize; -+ buf->memory = g_malloc (buf->size); -+ -+ gst_audio_format_fill_silence (buf->spec.info.finfo, buf->memory, -+ buf->size); -+ -+ GST_DEBUG_OBJECT (self->elem, "acquire done"); -+ -+ return TRUE; -+ -+start_error: -+ { -+ GST_ERROR_OBJECT (self->elem, "could not start stream"); -+ pw_stream_destroy (self->stream); -+ self->stream = NULL; -+ pw_thread_loop_unlock (self->main_loop); -+ return FALSE; -+ } -+} -+ -+static gboolean -+gst_pw_audio_ring_buffer_release (GstAudioRingBuffer *buf) -+{ -+ GstPwAudioRingBuffer *self = GST_PW_AUDIO_RING_BUFFER (buf); -+ -+ GST_DEBUG_OBJECT (self->elem, "release"); -+ -+ pw_thread_loop_lock (self->main_loop); -+ if (self->stream) { -+ spa_hook_remove (&self->stream_listener); -+ pw_stream_disconnect (self->stream); -+ pw_stream_destroy (self->stream); -+ self->stream = NULL; -+ } -+ pw_thread_loop_unlock (self->main_loop); -+ -+ /* free the buffer */ -+ g_free (buf->memory); -+ buf->memory = NULL; -+ -+ return TRUE; -+} -+ -+static guint -+gst_pw_audio_ring_buffer_delay (GstAudioRingBuffer *buf) -+{ -+ GstPwAudioRingBuffer *self = GST_PW_AUDIO_RING_BUFFER (buf); -+ struct pw_time t; -+ -+ if (!self->stream || pw_stream_get_time (self->stream, &t) < 0) -+ return 0; -+ -+ if (self->direction == PW_DIRECTION_OUTPUT) { -+ /* on output streams, we set the pw_buffer.size in frames, -+ so no conversion is necessary */ -+ return t.queued; -+ } else { -+ /* on input streams, pw_buffer.size is set by pw_stream in ticks, -+ so we need to convert it to frames and also add segoffset, which -+ is the number of bytes we have read but not advertised yet, as -+ the segment is incomplete */ -+ if (t.rate.denom > 0) -+ return -+ gst_util_uint64_scale (t.queued, self->rate * t.rate.num, t.rate.denom) -+ + self->segoffset / self->bpf; -+ else -+ return self->segoffset / self->bpf; -+ } -+ -+ return 0; -+} -+ -+static void -+gst_pw_audio_ring_buffer_class_init (GstPwAudioRingBufferClass * klass) -+{ -+ GObjectClass *gobject_class; -+ GstAudioRingBufferClass *gstaudiorbuf_class; -+ -+ gobject_class = (GObjectClass *) klass; -+ gstaudiorbuf_class = (GstAudioRingBufferClass *) klass; -+ -+ gobject_class->finalize = gst_pw_audio_ring_buffer_finalize; -+ gobject_class->set_property = gst_pw_audio_ring_buffer_set_property; -+ -+ gstaudiorbuf_class->open_device = gst_pw_audio_ring_buffer_open_device; -+ gstaudiorbuf_class->acquire = gst_pw_audio_ring_buffer_acquire; -+ gstaudiorbuf_class->release = gst_pw_audio_ring_buffer_release; -+ gstaudiorbuf_class->close_device = gst_pw_audio_ring_buffer_close_device; -+ gstaudiorbuf_class->delay = gst_pw_audio_ring_buffer_delay; -+ -+ g_object_class_install_property (gobject_class, PROP_ELEMENT, -+ g_param_spec_object ("element", "Element", "The audio source or sink", -+ GST_TYPE_ELEMENT, -+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); -+ -+ g_object_class_install_property (gobject_class, PROP_DIRECTION, -+ g_param_spec_int ("direction", "Direction", "The stream direction", -+ PW_DIRECTION_INPUT, PW_DIRECTION_OUTPUT, PW_DIRECTION_INPUT, -+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); -+ -+ g_object_class_install_property (gobject_class, PROP_PROPS, -+ g_param_spec_pointer ("props", "Properties", "The properties struct", -+ G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); -+ -+ GST_DEBUG_CATEGORY_INIT (pw_audio_ring_buffer_debug, "pwaudioringbuffer", 0, -+ "PipeWire Audio Ring Buffer"); -+} -diff --git a/src/gst/gstpwaudioringbuffer.h b/src/gst/gstpwaudioringbuffer.h -new file mode 100644 -index 00000000..f47f668a ---- /dev/null -+++ b/src/gst/gstpwaudioringbuffer.h -@@ -0,0 +1,83 @@ -+/* PipeWire -+ * -+ * Copyright © 2018 Wim Taymans -+ * Copyright © 2019 Collabora Ltd. -+ * @author George Kiagiadakis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#ifndef __GST_PW_AUDIO_RING_BUFFER_H__ -+#define __GST_PW_AUDIO_RING_BUFFER_H__ -+ -+#include -+#include -+#include -+ -+G_BEGIN_DECLS -+ -+#define GST_TYPE_PW_AUDIO_RING_BUFFER \ -+ (gst_pw_audio_ring_buffer_get_type ()) -+ -+G_DECLARE_FINAL_TYPE(GstPwAudioRingBuffer, gst_pw_audio_ring_buffer, -+ GST, PW_AUDIO_RING_BUFFER, GstAudioRingBuffer); -+ -+typedef struct _GstPwAudioRingBufferProps GstPwAudioRingBufferProps; -+ -+struct _GstPwAudioRingBuffer -+{ -+ GstAudioRingBuffer parent; -+ -+ /* properties */ -+ GstElement *elem; -+ enum pw_direction direction; -+ GstPwAudioRingBufferProps *props; -+ -+ /* internal */ -+ struct pw_loop *loop; -+ struct pw_thread_loop *main_loop; -+ -+ struct pw_core *core; -+ struct pw_remote *remote; -+ struct spa_hook remote_listener; -+ -+ struct pw_stream *stream; -+ struct spa_hook stream_listener; -+ -+ gint segsize; -+ gint bpf; -+ gint rate; -+ -+ /* on_stream_process() state */ -+ gint segoffset; -+ gint cur_segment; -+}; -+ -+struct _GstPwAudioRingBufferProps -+{ -+ gchar *path; -+ gchar *client_name; -+ GstStructure *properties; -+ int fd; -+}; -+ -+G_END_DECLS -+ -+#endif -diff --git a/src/gst/gstpwaudiosink.c b/src/gst/gstpwaudiosink.c -new file mode 100644 -index 00000000..069996c3 ---- /dev/null -+++ b/src/gst/gstpwaudiosink.c -@@ -0,0 +1,207 @@ -+/* PipeWire -+ * -+ * Copyright © 2018 Wim Taymans -+ * Copyright © 2019 Collabora Ltd. -+ * @author George Kiagiadakis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif -+ -+#include "gstpwaudiosink.h" -+ -+GST_DEBUG_CATEGORY_STATIC (pw_audio_sink_debug); -+#define GST_CAT_DEFAULT pw_audio_sink_debug -+ -+G_DEFINE_TYPE (GstPwAudioSink, gst_pw_audio_sink, GST_TYPE_AUDIO_BASE_SINK); -+ -+enum -+{ -+ PROP_0, -+ PROP_PATH, -+ PROP_CLIENT_NAME, -+ PROP_STREAM_PROPERTIES, -+ PROP_FD -+}; -+ -+static GstStaticPadTemplate gst_pw_audio_sink_template = -+GST_STATIC_PAD_TEMPLATE ("sink", -+ GST_PAD_SINK, -+ GST_PAD_ALWAYS, -+ GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_NE (F32)) -+ ", layout = (string)\"interleaved\"") -+); -+ -+ -+static void -+gst_pw_audio_sink_init (GstPwAudioSink * self) -+{ -+ self->props.fd = -1; -+ -+ /* Bump the default buffer size up to 21.3 ms, which is the default on most -+ * sound cards, in hope to match the alsa buffer size on the pipewire server. -+ * This may not always happen, but it still sounds better than the 10ms -+ * default latency. This is temporary until we have a better mechanism to -+ * select the appropriate latency */ -+ GST_AUDIO_BASE_SINK (self)->latency_time = 21333; -+} -+ -+static void -+gst_pw_audio_sink_finalize (GObject * object) -+{ -+ GstPwAudioSink *pwsink = GST_PW_AUDIO_SINK (object); -+ -+ g_free (pwsink->props.path); -+ g_free (pwsink->props.client_name); -+ if (pwsink->props.properties) -+ gst_structure_free (pwsink->props.properties); -+} -+ -+static void -+gst_pw_audio_sink_set_property (GObject * object, guint prop_id, -+ const GValue * value, GParamSpec * pspec) -+{ -+ GstPwAudioSink *pwsink = GST_PW_AUDIO_SINK (object); -+ -+ switch (prop_id) { -+ case PROP_PATH: -+ g_free (pwsink->props.path); -+ pwsink->props.path = g_value_dup_string (value); -+ break; -+ -+ case PROP_CLIENT_NAME: -+ g_free (pwsink->props.client_name); -+ pwsink->props.client_name = g_value_dup_string (value); -+ break; -+ -+ case PROP_STREAM_PROPERTIES: -+ if (pwsink->props.properties) -+ gst_structure_free (pwsink->props.properties); -+ pwsink->props.properties = -+ gst_structure_copy (gst_value_get_structure (value)); -+ break; -+ -+ case PROP_FD: -+ pwsink->props.fd = g_value_get_int (value); -+ break; -+ -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -+ break; -+ } -+} -+ -+static void -+gst_pw_audio_sink_get_property (GObject * object, guint prop_id, -+ GValue * value, GParamSpec * pspec) -+{ -+ GstPwAudioSink *pwsink = GST_PW_AUDIO_SINK (object); -+ -+ switch (prop_id) { -+ case PROP_PATH: -+ g_value_set_string (value, pwsink->props.path); -+ break; -+ -+ case PROP_CLIENT_NAME: -+ g_value_set_string (value, pwsink->props.client_name); -+ break; -+ -+ case PROP_STREAM_PROPERTIES: -+ gst_value_set_structure (value, pwsink->props.properties); -+ break; -+ -+ case PROP_FD: -+ g_value_set_int (value, pwsink->props.fd); -+ break; -+ -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -+ break; -+ } -+} -+ -+static GstAudioRingBuffer * -+gst_pw_audio_sink_create_ringbuffer (GstAudioBaseSink * sink) -+{ -+ GstPwAudioSink *self = GST_PW_AUDIO_SINK (sink); -+ GstAudioRingBuffer *buffer; -+ -+ GST_DEBUG_OBJECT (sink, "creating ringbuffer"); -+ buffer = g_object_new (GST_TYPE_PW_AUDIO_RING_BUFFER, -+ "element", sink, -+ "direction", PW_DIRECTION_OUTPUT, -+ "props", &self->props, -+ NULL); -+ GST_DEBUG_OBJECT (sink, "created ringbuffer @%p", buffer); -+ -+ return buffer; -+} -+ -+static void -+gst_pw_audio_sink_class_init (GstPwAudioSinkClass * klass) -+{ -+ GObjectClass *gobject_class; -+ GstElementClass *gstelement_class; -+ GstAudioBaseSinkClass *gstaudiobsink_class; -+ -+ gobject_class = (GObjectClass *) klass; -+ gstelement_class = (GstElementClass *) klass; -+ gstaudiobsink_class = (GstAudioBaseSinkClass *) klass; -+ -+ gobject_class->finalize = gst_pw_audio_sink_finalize; -+ gobject_class->set_property = gst_pw_audio_sink_set_property; -+ gobject_class->get_property = gst_pw_audio_sink_get_property; -+ -+ gstaudiobsink_class->create_ringbuffer = gst_pw_audio_sink_create_ringbuffer; -+ -+ g_object_class_install_property (gobject_class, PROP_PATH, -+ g_param_spec_string ("path", "Path", -+ "The sink path to connect to (NULL = default)", NULL, -+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -+ -+ g_object_class_install_property (gobject_class, PROP_CLIENT_NAME, -+ g_param_spec_string ("client-name", "Client Name", -+ "The client name to use (NULL = default)", NULL, -+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -+ -+ g_object_class_install_property (gobject_class, PROP_STREAM_PROPERTIES, -+ g_param_spec_boxed ("stream-properties", "Stream properties", -+ "List of PipeWire stream properties", GST_TYPE_STRUCTURE, -+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -+ -+ g_object_class_install_property (gobject_class, PROP_FD, -+ g_param_spec_int ("fd", "Fd", "The fd to connect with", -1, G_MAXINT, -1, -+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -+ -+ gst_element_class_set_static_metadata (gstelement_class, -+ "PipeWire Audio sink", "Sink/Audio", -+ "Send audio to PipeWire", -+ "George Kiagiadakis "); -+ -+ gst_element_class_add_pad_template (gstelement_class, -+ gst_static_pad_template_get (&gst_pw_audio_sink_template)); -+ -+ GST_DEBUG_CATEGORY_INIT (pw_audio_sink_debug, "pwaudiosink", 0, -+ "PipeWire Audio Sink"); -+} -+ -diff --git a/src/gst/gstpwaudiosink.h b/src/gst/gstpwaudiosink.h -new file mode 100644 -index 00000000..7ed0de7b ---- /dev/null -+++ b/src/gst/gstpwaudiosink.h -@@ -0,0 +1,48 @@ -+/* PipeWire -+ * -+ * Copyright © 2018 Wim Taymans -+ * Copyright © 2019 Collabora Ltd. -+ * @author George Kiagiadakis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#ifndef __GST_PW_AUDIO_SINK_H__ -+#define __GST_PW_AUDIO_SINK_H__ -+ -+#include "gstpwaudioringbuffer.h" -+ -+G_BEGIN_DECLS -+ -+#define GST_TYPE_PW_AUDIO_SINK \ -+ (gst_pw_audio_sink_get_type ()) -+ -+G_DECLARE_FINAL_TYPE(GstPwAudioSink, gst_pw_audio_sink, -+ GST, PW_AUDIO_SINK, GstAudioBaseSink); -+ -+struct _GstPwAudioSink -+{ -+ GstAudioBaseSink parent; -+ GstPwAudioRingBufferProps props; -+}; -+ -+G_END_DECLS -+ -+#endif -diff --git a/src/gst/gstpwaudiosrc.c b/src/gst/gstpwaudiosrc.c -new file mode 100644 -index 00000000..6c522982 ---- /dev/null -+++ b/src/gst/gstpwaudiosrc.c -@@ -0,0 +1,200 @@ -+/* PipeWire -+ * -+ * Copyright © 2018 Wim Taymans -+ * Copyright © 2019 Collabora Ltd. -+ * @author George Kiagiadakis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#ifdef HAVE_CONFIG_H -+#include "config.h" -+#endif -+ -+#include "gstpwaudiosrc.h" -+ -+GST_DEBUG_CATEGORY_STATIC (pw_audio_src_debug); -+#define GST_CAT_DEFAULT pw_audio_src_debug -+ -+G_DEFINE_TYPE (GstPwAudioSrc, gst_pw_audio_src, GST_TYPE_AUDIO_BASE_SRC); -+ -+enum -+{ -+ PROP_0, -+ PROP_PATH, -+ PROP_CLIENT_NAME, -+ PROP_STREAM_PROPERTIES, -+ PROP_FD -+}; -+ -+static GstStaticPadTemplate gst_pw_audio_src_template = -+GST_STATIC_PAD_TEMPLATE ("src", -+ GST_PAD_SRC, -+ GST_PAD_ALWAYS, -+ GST_STATIC_CAPS (GST_AUDIO_CAPS_MAKE (GST_AUDIO_NE (F32)) -+ ", layout = (string)\"interleaved\"") -+); -+ -+ -+static void -+gst_pw_audio_src_init (GstPwAudioSrc * self) -+{ -+ self->props.fd = -1; -+} -+ -+static void -+gst_pw_audio_src_finalize (GObject * object) -+{ -+ GstPwAudioSrc *self = GST_PW_AUDIO_SRC (object); -+ -+ g_free (self->props.path); -+ g_free (self->props.client_name); -+ if (self->props.properties) -+ gst_structure_free (self->props.properties); -+} -+ -+static void -+gst_pw_audio_src_set_property (GObject * object, guint prop_id, -+ const GValue * value, GParamSpec * pspec) -+{ -+ GstPwAudioSrc *self = GST_PW_AUDIO_SRC (object); -+ -+ switch (prop_id) { -+ case PROP_PATH: -+ g_free (self->props.path); -+ self->props.path = g_value_dup_string (value); -+ break; -+ -+ case PROP_CLIENT_NAME: -+ g_free (self->props.client_name); -+ self->props.client_name = g_value_dup_string (value); -+ break; -+ -+ case PROP_STREAM_PROPERTIES: -+ if (self->props.properties) -+ gst_structure_free (self->props.properties); -+ self->props.properties = -+ gst_structure_copy (gst_value_get_structure (value)); -+ break; -+ -+ case PROP_FD: -+ self->props.fd = g_value_get_int (value); -+ break; -+ -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -+ break; -+ } -+} -+ -+static void -+gst_pw_audio_src_get_property (GObject * object, guint prop_id, -+ GValue * value, GParamSpec * pspec) -+{ -+ GstPwAudioSrc *self = GST_PW_AUDIO_SRC (object); -+ -+ switch (prop_id) { -+ case PROP_PATH: -+ g_value_set_string (value, self->props.path); -+ break; -+ -+ case PROP_CLIENT_NAME: -+ g_value_set_string (value, self->props.client_name); -+ break; -+ -+ case PROP_STREAM_PROPERTIES: -+ gst_value_set_structure (value, self->props.properties); -+ break; -+ -+ case PROP_FD: -+ g_value_set_int (value, self->props.fd); -+ break; -+ -+ default: -+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); -+ break; -+ } -+} -+ -+static GstAudioRingBuffer * -+gst_pw_audio_src_create_ringbuffer (GstAudioBaseSrc * sink) -+{ -+ GstPwAudioSrc *self = GST_PW_AUDIO_SRC (sink); -+ GstAudioRingBuffer *buffer; -+ -+ GST_DEBUG_OBJECT (sink, "creating ringbuffer"); -+ buffer = g_object_new (GST_TYPE_PW_AUDIO_RING_BUFFER, -+ "element", sink, -+ "direction", PW_DIRECTION_INPUT, -+ "props", &self->props, -+ NULL); -+ GST_DEBUG_OBJECT (sink, "created ringbuffer @%p", buffer); -+ -+ return buffer; -+} -+ -+static void -+gst_pw_audio_src_class_init (GstPwAudioSrcClass * klass) -+{ -+ GObjectClass *gobject_class; -+ GstElementClass *gstelement_class; -+ GstAudioBaseSrcClass *gstaudiobsrc_class; -+ -+ gobject_class = (GObjectClass *) klass; -+ gstelement_class = (GstElementClass *) klass; -+ gstaudiobsrc_class = (GstAudioBaseSrcClass *) klass; -+ -+ gobject_class->finalize = gst_pw_audio_src_finalize; -+ gobject_class->set_property = gst_pw_audio_src_set_property; -+ gobject_class->get_property = gst_pw_audio_src_get_property; -+ -+ gstaudiobsrc_class->create_ringbuffer = gst_pw_audio_src_create_ringbuffer; -+ -+ g_object_class_install_property (gobject_class, PROP_PATH, -+ g_param_spec_string ("path", "Path", -+ "The sink path to connect to (NULL = default)", NULL, -+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -+ -+ g_object_class_install_property (gobject_class, PROP_CLIENT_NAME, -+ g_param_spec_string ("client-name", "Client Name", -+ "The client name to use (NULL = default)", NULL, -+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -+ -+ g_object_class_install_property (gobject_class, PROP_STREAM_PROPERTIES, -+ g_param_spec_boxed ("stream-properties", "Stream properties", -+ "List of PipeWire stream properties", GST_TYPE_STRUCTURE, -+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -+ -+ g_object_class_install_property (gobject_class, PROP_FD, -+ g_param_spec_int ("fd", "Fd", "The fd to connect with", -1, G_MAXINT, -1, -+ G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -+ -+ gst_element_class_set_static_metadata (gstelement_class, -+ "PipeWire Audio source", "Source/Audio", -+ "Receive audio from PipeWire", -+ "George Kiagiadakis "); -+ -+ gst_element_class_add_pad_template (gstelement_class, -+ gst_static_pad_template_get (&gst_pw_audio_src_template)); -+ -+ GST_DEBUG_CATEGORY_INIT (pw_audio_src_debug, "pwaudiosrc", 0, -+ "PipeWire Audio Src"); -+} -+ -diff --git a/src/gst/gstpwaudiosrc.h b/src/gst/gstpwaudiosrc.h -new file mode 100644 -index 00000000..c46e644c ---- /dev/null -+++ b/src/gst/gstpwaudiosrc.h -@@ -0,0 +1,48 @@ -+/* PipeWire -+ * -+ * Copyright © 2018 Wim Taymans -+ * Copyright © 2019 Collabora Ltd. -+ * @author George Kiagiadakis -+ * -+ * Permission is hereby granted, free of charge, to any person obtaining a -+ * copy of this software and associated documentation files (the "Software"), -+ * to deal in the Software without restriction, including without limitation -+ * the rights to use, copy, modify, merge, publish, distribute, sublicense, -+ * and/or sell copies of the Software, and to permit persons to whom the -+ * Software is furnished to do so, subject to the following conditions: -+ * -+ * The above copyright notice and this permission notice (including the next -+ * paragraph) shall be included in all copies or substantial portions of the -+ * Software. -+ * -+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -+ * DEALINGS IN THE SOFTWARE. -+ */ -+ -+#ifndef __GST_PW_AUDIO_SRC_H__ -+#define __GST_PW_AUDIO_SRC_H__ -+ -+#include "gstpwaudioringbuffer.h" -+ -+G_BEGIN_DECLS -+ -+#define GST_TYPE_PW_AUDIO_SRC \ -+ (gst_pw_audio_src_get_type ()) -+ -+G_DECLARE_FINAL_TYPE(GstPwAudioSrc, gst_pw_audio_src, -+ GST, PW_AUDIO_SRC, GstAudioBaseSrc); -+ -+struct _GstPwAudioSrc -+{ -+ GstAudioBaseSrc parent; -+ GstPwAudioRingBufferProps props; -+}; -+ -+G_END_DECLS -+ -+#endif -diff --git a/src/gst/meson.build b/src/gst/meson.build -index ad0e0801..0e922347 100644 ---- a/src/gst/meson.build -+++ b/src/gst/meson.build -@@ -6,6 +6,9 @@ pipewire_gst_sources = [ - 'gstpipewirepool.c', - 'gstpipewiresink.c', - 'gstpipewiresrc.c', -+ 'gstpwaudioringbuffer.c', -+ 'gstpwaudiosink.c', -+ 'gstpwaudiosrc.c', - ] - - pipewire_gst_headers = [ -@@ -15,6 +18,9 @@ pipewire_gst_headers = [ - 'gstpipewirepool.h', - 'gstpipewiresink.h', - 'gstpipewiresrc.h', -+ 'gstpwaudioringbuffer.h', -+ 'gstpwaudiosink.h', -+ 'gstpwaudiosrc.h', - ] - - pipewire_gst_c_args = [ --- -2.24.0 - diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0004-audioconvert-always-assume-that-output-ports-are-NOT.patch b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0004-audioconvert-always-assume-that-output-ports-are-NOT.patch deleted file mode 100644 index beb878390..000000000 --- a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0004-audioconvert-always-assume-that-output-ports-are-NOT.patch +++ /dev/null @@ -1,35 +0,0 @@ -From ce155eb0073fba84556782633f79bb7d03492c07 Mon Sep 17 00:00:00 2001 -From: George Kiagiadakis -Date: Wed, 2 Oct 2019 21:40:34 +0300 -Subject: [PATCH] audioconvert: always assume that output ports are NOT monitor - ports - -Otherwise, when we setup audioconvert in merge+split mode, -it assumes that the splitter's ports are monitor ports and -belong to the merger. - -Upstream-Status: Inappropriate [workaround] ---- - spa/plugins/audioconvert/audioconvert.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/spa/plugins/audioconvert/audioconvert.c b/spa/plugins/audioconvert/audioconvert.c -index 74a62a35..72da37d1 100644 ---- a/spa/plugins/audioconvert/audioconvert.c -+++ b/spa/plugins/audioconvert/audioconvert.c -@@ -113,8 +113,12 @@ struct impl { - unsigned int add_listener:1; - }; - -+#if 0 - #define IS_MONITOR_PORT(this,dir,port_id) (dir == SPA_DIRECTION_OUTPUT && port_id > 0 && \ - this->mode[SPA_DIRECTION_INPUT] == SPA_PARAM_PORT_CONFIG_MODE_dsp) -+#else -+#define IS_MONITOR_PORT(this,dir,port_id) (false) -+#endif - - static void emit_node_info(struct impl *this, bool full) - { --- -2.24.0 - diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0005-module-access-add-same-sec-label-mode.patch b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0005-module-access-add-same-sec-label-mode.patch deleted file mode 100644 index 07a1ec114..000000000 --- a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0005-module-access-add-same-sec-label-mode.patch +++ /dev/null @@ -1,94 +0,0 @@ -From 19fad1a4fa8bdc4f02aac4e169e7ff9cab18bdcd Mon Sep 17 00:00:00 2001 -From: George Kiagiadakis -Date: Tue, 19 Nov 2019 17:09:07 +0200 -Subject: [PATCH] module-access: add same-sec-label-mode - -This is a mode where the access module allows all clients that have -the same security label as the pipewire daemon, and every other -client is put on the restricted state. - -In systems that use SMACK security labels, such as AGL, this allows -the session manager (which is spawned by pipewire, inheriting the -same smack label) to have full access to all objects, while every -other client is restricted and the session manager must decide -what to do with it - -Note that while this option is configurable, there is no loss of -security if this option is not set in the configuration. Clients -that don't have the same security context will be considered to -be flatpak clients because pipewire will not be able to open -/proc/pid/cmdline. This however results in some unwanted error -messages that may be confusing. - -Upstream-Status: Inappropriate [agl/smack specific] ---- - src/modules/module-access.c | 45 ++++++++++++++++++++++++++++++++++++- - 1 file changed, 44 insertions(+), 1 deletion(-) - -diff --git a/src/modules/module-access.c b/src/modules/module-access.c -index 09dafa43..f75306d9 100644 ---- a/src/modules/module-access.c -+++ b/src/modules/module-access.c -@@ -50,6 +50,30 @@ struct impl { - struct spa_hook module_listener; - }; - -+static int check_seclabel(const char *str) -+{ -+ char attr[1024]; -+ int fd, len; -+ -+ fd = open("/proc/self/attr/current", O_RDONLY); -+ if (fd < 0) -+ return -errno; -+ -+ if ((len = read(fd, attr, 1024)) <= 0) { -+ close(fd); -+ return -EIO; -+ } -+ attr[len] = '\0'; -+ -+ if (strcmp(attr, str) == 0) { -+ close(fd); -+ return 1; -+ } -+ -+ close(fd); -+ return 0; -+} -+ - static int check_cmdline(struct pw_client *client, int pid, const char *str) - { - char path[2048]; -@@ -121,8 +145,27 @@ core_check_access(void *data, struct pw_client *client) - const char *str; - int pid, res; - -+ props = pw_client_get_properties(client); -+ -+ if (impl->properties && -+ (str = pw_properties_get(impl->properties, "same-sec-label-mode")) != NULL && -+ strcmp(str, "1") == 0) { -+ if (props && (str = pw_properties_get(props, PW_KEY_SEC_LABEL)) != NULL) { -+ res = check_seclabel(str); -+ if (res == 1) -+ goto granted; -+ else if (res < 0) -+ pw_log_warn("module %p: client %p seclabel check failed: %s", -+ impl, client, spa_strerror(res)); -+ } -+ pw_log_debug("module %p: seclabel restricted client %p added", -+ impl, client); -+ items[0] = SPA_DICT_ITEM_INIT(PW_KEY_ACCESS, "restricted"); -+ goto wait_permissions; -+ } -+ - pid = -EINVAL; -- if ((props = pw_client_get_properties(client)) != NULL) { -+ if (props != NULL) { - if ((str = pw_properties_get(props, PW_KEY_SEC_PID)) != NULL) - pid = atoi(str); - } --- -2.24.0 - diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0006-alsa-pcm-call-reuse_buffers-when-resetting-the-state.patch b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0006-alsa-pcm-call-reuse_buffers-when-resetting-the-state.patch deleted file mode 100644 index cae4d70f6..000000000 --- a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0006-alsa-pcm-call-reuse_buffers-when-resetting-the-state.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 5946fbd2ca3a7f892b4ebc10090f62df6bb1ec88 Mon Sep 17 00:00:00 2001 -From: George Kiagiadakis -Date: Thu, 9 Jan 2020 19:27:23 +0200 -Subject: [PATCH] alsa-pcm: call reuse_buffers when resetting the state of the - buffers - -This allows the upstream node to put buffers back to its pool in case -they were left around in the ready list locally when the alsa-pcm-sink -was last paused. - -Fixes #203 ---- - spa/plugins/alsa/alsa-pcm.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/spa/plugins/alsa/alsa-pcm.c b/spa/plugins/alsa/alsa-pcm.c -index 63d75549..a6f22cf0 100644 ---- a/spa/plugins/alsa/alsa-pcm.c -+++ b/spa/plugins/alsa/alsa-pcm.c -@@ -1115,6 +1115,7 @@ static void reset_buffers(struct state *this) - struct buffer *b = &this->buffers[i]; - if (this->stream == SND_PCM_STREAM_PLAYBACK) { - SPA_FLAG_SET(b->flags, BUFFER_FLAG_OUT); -+ spa_node_call_reuse_buffer(&this->callbacks, 0, b->id); - } else { - spa_list_append(&this->free, &b->link); - SPA_FLAG_CLEAR(b->flags, BUFFER_FLAG_OUT); --- -2.24.1 - diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0007-alsa-Set-period_size-depending-on-hardware.patch b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0007-alsa-Set-period_size-depending-on-hardware.patch deleted file mode 100644 index f9649400e..000000000 --- a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0007-alsa-Set-period_size-depending-on-hardware.patch +++ /dev/null @@ -1,35 +0,0 @@ -From bbf9c767d5b353142e03080762bdd805e124d50b Mon Sep 17 00:00:00 2001 -From: Walter Lozano -Date: Fri, 7 Aug 2020 10:58:29 -0300 -Subject: [PATCH] alsa: Set period_size depending on hardware - -Currently PipeWire is unable to reproduce audio in systems where DMA -granularity is not burst. - -In order to mitigate this issue, set period_size depending on hardware, -lowering it when snd_pcm_hw_params_is_batch == 1, to reduce DMA -transfers size. - -Signed-off-by: Walter Lozano ---- - spa/plugins/alsa/alsa-pcm.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/spa/plugins/alsa/alsa-pcm.c b/spa/plugins/alsa/alsa-pcm.c -index 63d75549..2d3850b7 100644 ---- a/spa/plugins/alsa/alsa-pcm.c -+++ b/spa/plugins/alsa/alsa-pcm.c -@@ -463,6 +463,10 @@ int spa_alsa_set_format(struct state *state, struct spa_audio_info *fmt, uint32_ - - dir = 0; - period_size = 1024; -+ if (snd_pcm_hw_params_is_batch(params)) { -+ period_size = 512; -+ spa_log_warn(state->log, NAME" hardware does double buffering, changing period_size to %ld", period_size); -+ } - CHECK(snd_pcm_hw_params_set_period_size_near(hndl, params, &period_size, &dir), "set_period_size_near"); - CHECK(snd_pcm_hw_params_get_buffer_size_max(params, &state->buffer_frames), "get_buffer_size_max"); - CHECK(snd_pcm_hw_params_set_buffer_size_near(hndl, params, &state->buffer_frames), "set_buffer_size_near"); --- -2.20.1 - diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0008-alsa-add-warning-in-case-of-partial-read-write.patch b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0008-alsa-add-warning-in-case-of-partial-read-write.patch deleted file mode 100644 index 98a2c98fc..000000000 --- a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0008-alsa-add-warning-in-case-of-partial-read-write.patch +++ /dev/null @@ -1,80 +0,0 @@ -From 45658f75e61da47b274f2eba3a55e62d016f8b42 Mon Sep 17 00:00:00 2001 -From: Walter Lozano -Date: Mon, 24 Aug 2020 12:08:32 -0300 -Subject: [PATCH 8/9] alsa: add warning in case of partial read/write - -Currently alsa_read and alsa_write assumes that all the frames committed -using snd_pcm_mmap_commit are read or written, which is probably true. -However, as it could be some corner cases add a warning to notice this -fact. - -Signed-off-by: Walter Lozano ---- - spa/plugins/alsa/alsa-pcm.c | 28 ++++++++++++++++++++-------- - 1 file changed, 20 insertions(+), 8 deletions(-) - -diff --git a/spa/plugins/alsa/alsa-pcm.c b/spa/plugins/alsa/alsa-pcm.c -index ed9bf42b..92ef2151 100644 ---- a/spa/plugins/alsa/alsa-pcm.c -+++ b/spa/plugins/alsa/alsa-pcm.c -@@ -721,6 +721,7 @@ int spa_alsa_write(struct state *state, snd_pcm_uframes_t silence) - snd_pcm_t *hndl = state->hndl; - const snd_pcm_channel_area_t *my_areas; - snd_pcm_uframes_t written, frames, offset, off, to_write, total_written; -+ snd_pcm_sframes_t commitres; - int res; - - if (state->position && state->duration != state->position->clock.duration) { -@@ -834,11 +835,16 @@ again: - state, offset, written, state->sample_count); - total_written += written; - -- if ((res = snd_pcm_mmap_commit(hndl, offset, written)) < 0) { -+ if ((commitres = snd_pcm_mmap_commit(hndl, offset, written)) < 0) { - spa_log_error(state->log, NAME" %p: snd_pcm_mmap_commit error: %s", -- state, snd_strerror(res)); -- if (res != -EPIPE && res != -ESTRPIPE) -- return res; -+ state, snd_strerror(commitres)); -+ if (commitres != -EPIPE && commitres != -ESTRPIPE) -+ return commitres; -+ } -+ -+ if (commitres > 0 && written != (snd_pcm_uframes_t) commitres) { -+ spa_log_warn(state->log, NAME" %p: mmap_commit wrote %ld instead of %ld", -+ state, commitres, written); - } - - if (!spa_list_is_empty(&state->ready) && written > 0) -@@ -922,6 +928,7 @@ int spa_alsa_read(struct state *state, snd_pcm_uframes_t silence) - snd_pcm_uframes_t total_read = 0, to_read; - const snd_pcm_channel_area_t *my_areas; - snd_pcm_uframes_t read, frames, offset; -+ snd_pcm_sframes_t commitres; - int res; - - if (state->position) { -@@ -994,11 +1001,16 @@ int spa_alsa_read(struct state *state, snd_pcm_uframes_t silence) - offset, read, state->sample_count); - total_read += read; - -- if ((res = snd_pcm_mmap_commit(hndl, offset, read)) < 0) { -+ if ((commitres = snd_pcm_mmap_commit(hndl, offset, read)) < 0) { - spa_log_error(state->log, NAME" %p: snd_pcm_mmap_commit error: %s", -- state, snd_strerror(res)); -- if (res != -EPIPE && res != -ESTRPIPE) -- return res; -+ state, snd_strerror(commitres)); -+ if (commitres != -EPIPE && commitres != -ESTRPIPE) -+ return commitres; -+ } -+ -+ if (commitres > 0 && read != (snd_pcm_uframes_t) commitres) { -+ spa_log_warn(state->log, NAME" %p: mmap_commit read %ld instead of %ld", -+ state, commitres, read); - } - - state->sample_count += total_read; --- -2.20.1 - diff --git a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0009-alsa-adjust-delay-depending-on-hardware.patch b/meta-pipewire/recipes-multimedia/pipewire/pipewire/0009-alsa-adjust-delay-depending-on-hardware.patch deleted file mode 100644 index a448063f1..000000000 --- a/meta-pipewire/recipes-multimedia/pipewire/pipewire/0009-alsa-adjust-delay-depending-on-hardware.patch +++ /dev/null @@ -1,64 +0,0 @@ -From 38cdfa4483de4c2e91bfccb9c22ec72d9c3720f4 Mon Sep 17 00:00:00 2001 -From: Walter Lozano -Date: Sat, 22 Aug 2020 11:51:30 -0300 -Subject: [PATCH 9/9] alsa: adjust delay depending on hardware - -Currently PipeWire is able to reproduce audio in systems where -DMA granularity is not burst but it could face an xrun. - -In order to mitigate this issue, adjust the delay PipeWire -calculates to make sure that a period is available in the buffer -when snd_pcm_hw_params_is_batch == 1. - -Signed-off-by: Walter Lozano ---- - spa/plugins/alsa/alsa-pcm.c | 12 +++++++++++- - spa/plugins/alsa/alsa-pcm.h | 1 + - 2 files changed, 12 insertions(+), 1 deletion(-) - -diff --git a/spa/plugins/alsa/alsa-pcm.c b/spa/plugins/alsa/alsa-pcm.c -index 92ef2151..1f15085f 100644 ---- a/spa/plugins/alsa/alsa-pcm.c -+++ b/spa/plugins/alsa/alsa-pcm.c -@@ -462,8 +462,9 @@ int spa_alsa_set_format(struct state *state, struct spa_audio_info *fmt, uint32_ - state->frame_size = info->channels * (snd_pcm_format_physical_width(format) / 8); - - dir = 0; -+ state->pcm_is_batch = snd_pcm_hw_params_is_batch(params); - period_size = 1024; -- if (snd_pcm_hw_params_is_batch(params)) { -+ if (state->pcm_is_batch) { - period_size = 512; - spa_log_warn(state->log, NAME" hardware does double buffering, changing period_size to %ld", period_size); - } -@@ -639,6 +640,15 @@ static int get_status(struct state *state, snd_pcm_uframes_t *delay, snd_pcm_ufr - - if (state->stream == SND_PCM_STREAM_PLAYBACK) { - *delay = state->buffer_frames - avail; -+ if (state->pcm_is_batch) { -+ /* In this case, as we don't have a good granularity in the -+ * avail report try to compensate this by tweaking the delay -+ * and make sure that a period is available in the buffer */ -+ if (*delay > state->period_frames) -+ *delay = *delay - state->period_frames; -+ else -+ *delay = 0; -+ } - } - else { - *delay = avail; -diff --git a/spa/plugins/alsa/alsa-pcm.h b/spa/plugins/alsa/alsa-pcm.h -index b7a2dd29..3b5c0d7b 100644 ---- a/spa/plugins/alsa/alsa-pcm.h -+++ b/spa/plugins/alsa/alsa-pcm.h -@@ -100,6 +100,7 @@ struct state { - - bool have_format; - struct spa_audio_info current_format; -+ bool pcm_is_batch; - - snd_pcm_uframes_t buffer_frames; - snd_pcm_uframes_t period_frames; --- -2.20.1 - -- cgit 1.2.3-korg