mirror of
https://anongit.gentoo.org/git/repo/gentoo.git
synced 2025-06-14 17:12:43 +02:00
From the 1.2 branch. Closes: https://bugs.gentoo.org/948169 Signed-off-by: Sam James <sam@gentoo.org>
259 lines
8.4 KiB
Diff
259 lines
8.4 KiB
Diff
From 91e26d6011bd194deffb5765f9b3306fb92738d9 Mon Sep 17 00:00:00 2001
|
|
Message-ID: <91e26d6011bd194deffb5765f9b3306fb92738d9.1737052666.git.sam@gentoo.org>
|
|
In-Reply-To: <1993383ddf67e296334c7916d6afc699ee6300c7.1737052666.git.sam@gentoo.org>
|
|
References: <1993383ddf67e296334c7916d6afc699ee6300c7.1737052666.git.sam@gentoo.org>
|
|
From: Wim Taymans <wtaymans@redhat.com>
|
|
Date: Tue, 3 Dec 2024 11:54:52 +0100
|
|
Subject: [PATCH 5/8] gst: add slave-method property
|
|
|
|
Set the slave-method to none by default to disable the resampler.
|
|
|
|
Fixes #4374
|
|
---
|
|
src/gst/gstpipewiresink.c | 141 +++++++++++++++++++++++++++-----------
|
|
src/gst/gstpipewiresink.h | 21 +++++-
|
|
2 files changed, 120 insertions(+), 42 deletions(-)
|
|
|
|
diff --git a/src/gst/gstpipewiresink.c b/src/gst/gstpipewiresink.c
|
|
index 33f2322e9..bf1b427f0 100644
|
|
--- a/src/gst/gstpipewiresink.c
|
|
+++ b/src/gst/gstpipewiresink.c
|
|
@@ -37,6 +37,7 @@ GST_DEBUG_CATEGORY_STATIC (pipewire_sink_debug);
|
|
#define GST_CAT_DEFAULT pipewire_sink_debug
|
|
|
|
#define DEFAULT_PROP_MODE GST_PIPEWIRE_SINK_MODE_DEFAULT
|
|
+#define DEFAULT_PROP_SLAVE_METHOD GST_PIPEWIRE_SINK_SLAVE_METHOD_NONE
|
|
|
|
#define MIN_BUFFERS 8u
|
|
|
|
@@ -49,7 +50,8 @@ enum
|
|
PROP_CLIENT_PROPERTIES,
|
|
PROP_STREAM_PROPERTIES,
|
|
PROP_MODE,
|
|
- PROP_FD
|
|
+ PROP_FD,
|
|
+ PROP_SLAVE_METHOD
|
|
};
|
|
|
|
GType
|
|
@@ -72,6 +74,26 @@ gst_pipewire_sink_mode_get_type (void)
|
|
return (GType) mode_type;
|
|
}
|
|
|
|
+GType
|
|
+gst_pipewire_sink_slave_method_get_type (void)
|
|
+{
|
|
+ static gsize method_type = 0;
|
|
+ static const GEnumValue method[] = {
|
|
+ {GST_PIPEWIRE_SINK_SLAVE_METHOD_NONE, "GST_PIPEWIRE_SINK_SLAVE_METHOD_NONE", "none"},
|
|
+ {GST_PIPEWIRE_SINK_SLAVE_METHOD_RESAMPLE, "GST_PIPEWIRE_SINK_SLAVE_METHOD_RESAMPLE", "resample"},
|
|
+ {0, NULL, NULL},
|
|
+ };
|
|
+
|
|
+ if (g_once_init_enter (&method_type)) {
|
|
+ GType tmp =
|
|
+ g_enum_register_static ("GstPipeWireSinkSlaveMethod", method);
|
|
+ g_once_init_leave (&method_type, tmp);
|
|
+ }
|
|
+
|
|
+ return (GType) method_type;
|
|
+}
|
|
+
|
|
+
|
|
|
|
static GstStaticPadTemplate gst_pipewire_sink_template =
|
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
|
@@ -225,6 +247,17 @@ gst_pipewire_sink_class_init (GstPipeWireSinkClass * klass)
|
|
G_PARAM_READWRITE |
|
|
G_PARAM_STATIC_STRINGS));
|
|
|
|
+ g_object_class_install_property (gobject_class,
|
|
+ PROP_SLAVE_METHOD,
|
|
+ g_param_spec_enum ("slave-method",
|
|
+ "Slave Method",
|
|
+ "Algorithm used to match the rate of the masterclock",
|
|
+ GST_TYPE_PIPEWIRE_SINK_SLAVE_METHOD,
|
|
+ DEFAULT_PROP_SLAVE_METHOD,
|
|
+ G_PARAM_READWRITE |
|
|
+ G_PARAM_STATIC_STRINGS));
|
|
+
|
|
+
|
|
gstelement_class->provide_clock = gst_pipewire_sink_provide_clock;
|
|
gstelement_class->change_state = gst_pipewire_sink_change_state;
|
|
|
|
@@ -408,6 +441,10 @@ gst_pipewire_sink_set_property (GObject * object, guint prop_id,
|
|
pwsink->stream->fd = g_value_get_int (value);
|
|
break;
|
|
|
|
+ case PROP_SLAVE_METHOD:
|
|
+ pwsink->slave_method = g_value_get_enum (value);
|
|
+ break;
|
|
+
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
@@ -449,12 +486,69 @@ gst_pipewire_sink_get_property (GObject * object, guint prop_id,
|
|
g_value_set_int (value, pwsink->stream->fd);
|
|
break;
|
|
|
|
+ case PROP_SLAVE_METHOD:
|
|
+ g_value_set_enum (value, pwsink->slave_method);
|
|
+ break;
|
|
+
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
+static void rate_match_resample(GstPipeWireSink *pwsink)
|
|
+{
|
|
+ GstPipeWireStream *stream = pwsink->stream;
|
|
+ double err, corr;
|
|
+ struct pw_time ts;
|
|
+ guint64 queued, now, elapsed, target;
|
|
+
|
|
+ if (!pwsink->rate_match)
|
|
+ return;
|
|
+
|
|
+ pw_stream_get_time_n(stream->pwstream, &ts, sizeof(ts));
|
|
+ now = pw_stream_get_nsec(stream->pwstream);
|
|
+ if (ts.now != 0)
|
|
+ elapsed = gst_util_uint64_scale_int (now - ts.now, ts.rate.denom, GST_SECOND * ts.rate.num);
|
|
+ else
|
|
+ elapsed = 0;
|
|
+
|
|
+ queued = ts.queued - ts.size;
|
|
+ target = elapsed;
|
|
+ err = ((gint64)queued - ((gint64)target));
|
|
+
|
|
+ corr = spa_dll_update(&stream->dll, SPA_CLAMPD(err, -128.0, 128.0));
|
|
+
|
|
+ stream->err_wdw = (double)ts.rate.denom/ts.size;
|
|
+
|
|
+ double avg = (stream->err_avg * stream->err_wdw + (err - stream->err_avg)) / (stream->err_wdw + 1.0);
|
|
+ stream->err_var = (stream->err_var * stream->err_wdw +
|
|
+ (err - stream->err_avg) * (err - avg)) / (stream->err_wdw + 1.0);
|
|
+ stream->err_avg = avg;
|
|
+
|
|
+ if (stream->last_ts == 0 || stream->last_ts + SPA_NSEC_PER_SEC < now) {
|
|
+ double bw;
|
|
+
|
|
+ stream->last_ts = now;
|
|
+
|
|
+ if (stream->err_var == 0.0)
|
|
+ bw = 0.0;
|
|
+ else
|
|
+ bw = fabs(stream->err_avg) / sqrt(fabs(stream->err_var));
|
|
+
|
|
+ spa_dll_set_bw(&stream->dll, SPA_CLAMPD(bw, 0.001, SPA_DLL_BW_MAX), ts.size, ts.rate.denom);
|
|
+
|
|
+ GST_INFO_OBJECT (pwsink, "q:%"PRIi64"/%"PRIi64" e:%"PRIu64" err:%+03f corr:%f %f %f %f",
|
|
+ ts.queued, ts.size, elapsed, err, corr,
|
|
+ stream->err_avg, stream->err_var, stream->dll.bw);
|
|
+ }
|
|
+
|
|
+ if (pwsink->match) {
|
|
+ pwsink->match->rate = corr;
|
|
+ SPA_FLAG_UPDATE(pwsink->match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE, true);
|
|
+ }
|
|
+}
|
|
+
|
|
static void
|
|
on_add_buffer (void *_data, struct pw_buffer *b)
|
|
{
|
|
@@ -539,45 +633,12 @@ do_send_buffer (GstPipeWireSink *pwsink, GstBuffer *buffer)
|
|
g_warning ("can't send buffer %s", spa_strerror(res));
|
|
}
|
|
|
|
- if (pwsink->rate_match) {
|
|
- double err, corr;
|
|
- struct pw_time ts;
|
|
- guint64 queued, now, elapsed, target;
|
|
-
|
|
- pw_stream_get_time_n(stream->pwstream, &ts, sizeof(ts));
|
|
- now = pw_stream_get_nsec(stream->pwstream);
|
|
- if (ts.now != 0)
|
|
- elapsed = gst_util_uint64_scale_int (now - ts.now, ts.rate.denom, GST_SECOND * ts.rate.num);
|
|
- else
|
|
- elapsed = 0;
|
|
-
|
|
- queued = ts.queued - ts.size;
|
|
- target = 2 * elapsed;
|
|
- err = ((gint64)queued - ((gint64)target));
|
|
-
|
|
- corr = spa_dll_update(&stream->dll, SPA_CLAMPD(err, -128.0, 128.0));
|
|
-
|
|
- stream->err_wdw = (double)ts.rate.denom/ts.size;
|
|
-
|
|
- double avg = (stream->err_avg * stream->err_wdw + (err - stream->err_avg)) / (stream->err_wdw + 1.0);
|
|
- stream->err_var = (stream->err_var * stream->err_wdw +
|
|
- (err - stream->err_avg) * (err - avg)) / (stream->err_wdw + 1.0);
|
|
- stream->err_avg = avg;
|
|
-
|
|
- if (stream->last_ts == 0 || stream->last_ts + SPA_NSEC_PER_SEC < now) {
|
|
- stream->last_ts = now;
|
|
- spa_dll_set_bw(&stream->dll, SPA_CLAMPD(fabs(stream->err_avg) / sqrt(fabs(stream->err_var)), 0.001, SPA_DLL_BW_MAX),
|
|
- ts.size, ts.rate.denom);
|
|
- GST_INFO_OBJECT (pwsink, "queue buffer %p, pw_buffer %p q:%"PRIi64"/%"PRIi64" e:%"PRIu64
|
|
- " err:%+03f corr:%f %f %f %f",
|
|
- buffer, data->b, ts.queued, ts.size, elapsed, err, corr,
|
|
- stream->err_avg, stream->err_var, stream->dll.bw);
|
|
- }
|
|
-
|
|
- if (pwsink->match) {
|
|
- pwsink->match->rate = corr;
|
|
- SPA_FLAG_UPDATE(pwsink->match->flags, SPA_IO_RATE_MATCH_FLAG_ACTIVE, true);
|
|
- }
|
|
+ switch (pwsink->slave_method) {
|
|
+ case GST_PIPEWIRE_SINK_SLAVE_METHOD_NONE:
|
|
+ break;
|
|
+ case GST_PIPEWIRE_SINK_SLAVE_METHOD_RESAMPLE:
|
|
+ rate_match_resample(pwsink);
|
|
+ break;
|
|
}
|
|
}
|
|
|
|
diff --git a/src/gst/gstpipewiresink.h b/src/gst/gstpipewiresink.h
|
|
index 33d7b5b4f..306297d0e 100644
|
|
--- a/src/gst/gstpipewiresink.h
|
|
+++ b/src/gst/gstpipewiresink.h
|
|
@@ -37,6 +37,22 @@ typedef enum
|
|
|
|
#define GST_TYPE_PIPEWIRE_SINK_MODE (gst_pipewire_sink_mode_get_type ())
|
|
|
|
+
|
|
+/**
|
|
+ * GstPipeWireSinkSlaveMethod:
|
|
+ * @GST_PIPEWIRE_SINK_SLAVE_METHOD_NONE: no clock and timestamp slaving
|
|
+ * @GST_PIPEWIRE_SINK_SLAVE_METHOD_RESAMPLE: resample audio
|
|
+ *
|
|
+ * Different clock slaving methods
|
|
+ */
|
|
+typedef enum
|
|
+{
|
|
+ GST_PIPEWIRE_SINK_SLAVE_METHOD_NONE,
|
|
+ GST_PIPEWIRE_SINK_SLAVE_METHOD_RESAMPLE,
|
|
+} GstPipeWireSinkSlaveMethod;
|
|
+
|
|
+#define GST_TYPE_PIPEWIRE_SINK_SLAVE_METHOD (gst_pipewire_sink_slave_method_get_type ())
|
|
+
|
|
/**
|
|
* GstPipeWireSink:
|
|
*
|
|
@@ -53,9 +69,10 @@ struct _GstPipeWireSink {
|
|
gboolean rate_match;
|
|
gint rate;
|
|
|
|
- GstPipeWireSinkMode mode;
|
|
-
|
|
struct spa_io_rate_match *match;
|
|
+
|
|
+ GstPipeWireSinkMode mode;
|
|
+ GstPipeWireSinkSlaveMethod slave_method;
|
|
};
|
|
|
|
GType gst_pipewire_sink_mode_get_type (void);
|
|
--
|
|
2.48.0
|
|
|