mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-09 13:30:06 -05:00
gst: add slave-method property
Set the slave-method to none by default to disable the resampler.
This commit is contained in:
parent
9419a12e74
commit
0658ff93d8
2 changed files with 115 additions and 37 deletions
|
|
@ -37,6 +37,7 @@ GST_DEBUG_CATEGORY_STATIC (pipewire_sink_debug);
|
||||||
#define GST_CAT_DEFAULT pipewire_sink_debug
|
#define GST_CAT_DEFAULT pipewire_sink_debug
|
||||||
|
|
||||||
#define DEFAULT_PROP_MODE GST_PIPEWIRE_SINK_MODE_DEFAULT
|
#define DEFAULT_PROP_MODE GST_PIPEWIRE_SINK_MODE_DEFAULT
|
||||||
|
#define DEFAULT_PROP_SLAVE_METHOD GST_PIPEWIRE_SINK_SLAVE_METHOD_NONE
|
||||||
|
|
||||||
#define MIN_BUFFERS 8u
|
#define MIN_BUFFERS 8u
|
||||||
|
|
||||||
|
|
@ -49,7 +50,8 @@ enum
|
||||||
PROP_CLIENT_PROPERTIES,
|
PROP_CLIENT_PROPERTIES,
|
||||||
PROP_STREAM_PROPERTIES,
|
PROP_STREAM_PROPERTIES,
|
||||||
PROP_MODE,
|
PROP_MODE,
|
||||||
PROP_FD
|
PROP_FD,
|
||||||
|
PROP_SLAVE_METHOD
|
||||||
};
|
};
|
||||||
|
|
||||||
GType
|
GType
|
||||||
|
|
@ -72,6 +74,26 @@ gst_pipewire_sink_mode_get_type (void)
|
||||||
return (GType) mode_type;
|
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 =
|
static GstStaticPadTemplate gst_pipewire_sink_template =
|
||||||
GST_STATIC_PAD_TEMPLATE ("sink",
|
GST_STATIC_PAD_TEMPLATE ("sink",
|
||||||
|
|
@ -225,6 +247,17 @@ gst_pipewire_sink_class_init (GstPipeWireSinkClass * klass)
|
||||||
G_PARAM_READWRITE |
|
G_PARAM_READWRITE |
|
||||||
G_PARAM_STATIC_STRINGS));
|
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->provide_clock = gst_pipewire_sink_provide_clock;
|
||||||
gstelement_class->change_state = gst_pipewire_sink_change_state;
|
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);
|
pwsink->stream->fd = g_value_get_int (value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PROP_SLAVE_METHOD:
|
||||||
|
pwsink->slave_method = g_value_get_enum (value);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
|
@ -449,12 +486,66 @@ gst_pipewire_sink_get_property (GObject * object, guint prop_id,
|
||||||
g_value_set_int (value, pwsink->stream->fd);
|
g_value_set_int (value, pwsink->stream->fd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case PROP_SLAVE_METHOD:
|
||||||
|
g_value_set_enum (value, pwsink->slave_method);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||||
break;
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
pw_stream_set_rate (stream->pwstream, corr);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
on_add_buffer (void *_data, struct pw_buffer *b)
|
on_add_buffer (void *_data, struct pw_buffer *b)
|
||||||
{
|
{
|
||||||
|
|
@ -539,42 +630,12 @@ do_send_buffer (GstPipeWireSink *pwsink, GstBuffer *buffer)
|
||||||
g_warning ("can't send buffer %s", spa_strerror(res));
|
g_warning ("can't send buffer %s", spa_strerror(res));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pwsink->rate_match) {
|
switch (pwsink->slave_method) {
|
||||||
double err, corr;
|
case GST_PIPEWIRE_SINK_SLAVE_METHOD_NONE:
|
||||||
struct pw_time ts;
|
break;
|
||||||
guint64 queued, now, elapsed, target;
|
case GST_PIPEWIRE_SINK_SLAVE_METHOD_RESAMPLE:
|
||||||
|
rate_match_resample(pwsink);
|
||||||
pw_stream_get_time_n(stream->pwstream, &ts, sizeof(ts));
|
break;
|
||||||
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) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
pw_stream_set_rate (stream->pwstream, corr);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,22 @@ typedef enum
|
||||||
|
|
||||||
#define GST_TYPE_PIPEWIRE_SINK_MODE (gst_pipewire_sink_mode_get_type ())
|
#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:
|
* GstPipeWireSink:
|
||||||
*
|
*
|
||||||
|
|
@ -54,6 +70,7 @@ struct _GstPipeWireSink {
|
||||||
gint rate;
|
gint rate;
|
||||||
|
|
||||||
GstPipeWireSinkMode mode;
|
GstPipeWireSinkMode mode;
|
||||||
|
GstPipeWireSinkSlaveMethod slave_method;
|
||||||
};
|
};
|
||||||
|
|
||||||
GType gst_pipewire_sink_mode_get_type (void);
|
GType gst_pipewire_sink_mode_get_type (void);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue