diff --git a/modules/module-pipewire/audio-softdsp-endpoint.c b/modules/module-pipewire/audio-softdsp-endpoint.c index c38bca29..c6eed112 100644 --- a/modules/module-pipewire/audio-softdsp-endpoint.c +++ b/modules/module-pipewire/audio-softdsp-endpoint.c @@ -133,6 +133,58 @@ endpoint_prepare_link (WpBaseEndpoint * ep, guint32 stream_id, return wp_audio_stream_prepare_link (stream, properties, error); } +static void +on_exported_control_changed (WpEndpoint * ep, guint32 control_id, + WpPwAudioSoftdspEndpoint *self) +{ + switch (control_id) { + case WP_ENDPOINT_CONTROL_VOLUME: { + gfloat vol; + wp_endpoint_get_control_float (ep, control_id, &vol); + wp_audio_stream_set_volume (self->adapter, vol); + break; + } + case WP_ENDPOINT_CONTROL_MUTE: { + gboolean m; + wp_endpoint_get_control_boolean (ep, control_id, &m); + wp_audio_stream_set_mute (self->adapter, m); + break; + } + default: + break; + } +} + +static void +on_adapter_control_changed (WpAudioStream * s, guint32 control_id, + WpPwAudioSoftdspEndpoint *self) +{ + /* block to avoid recursion - WpEndpoint emits the "control-changed" + signal when we change the value here */ + g_signal_handlers_block_by_func (self->exported_ep, + on_exported_control_changed, self); + + switch (control_id) { + case WP_ENDPOINT_CONTROL_VOLUME: { + gfloat vol = wp_audio_stream_get_volume (s); + wp_endpoint_set_control_float (WP_ENDPOINT (self->exported_ep), + control_id, vol); + break; + } + case WP_ENDPOINT_CONTROL_MUTE: { + gboolean m = wp_audio_stream_get_mute (s); + wp_endpoint_set_control_boolean (WP_ENDPOINT (self->exported_ep), + control_id, m); + break; + } + default: + break; + } + + g_signal_handlers_unblock_by_func (self->exported_ep, + on_exported_control_changed, self); +} + static void on_endpoint_exported (GObject * exported, GAsyncResult *res, gpointer data) { @@ -190,6 +242,16 @@ do_export (WpPwAudioSoftdspEndpoint *self) wp_exported_endpoint_set_direction (self->exported_ep, wp_base_endpoint_get_direction (WP_BASE_ENDPOINT (self))); + wp_endpoint_set_control_float (WP_ENDPOINT (self->exported_ep), + WP_ENDPOINT_CONTROL_VOLUME, wp_audio_stream_get_volume (self->adapter)); + wp_endpoint_set_control_boolean (WP_ENDPOINT (self->exported_ep), + WP_ENDPOINT_CONTROL_MUTE, wp_audio_stream_get_mute (self->adapter)); + + g_signal_connect_object (self->exported_ep, "control-changed", + (GCallback) on_exported_control_changed, self, 0); + g_signal_connect_object (self->adapter, "control-changed", + (GCallback) on_adapter_control_changed, self, 0); + wp_exported_export (WP_EXPORTED (self->exported_ep), NULL, on_endpoint_exported, self); } @@ -355,55 +417,6 @@ endpoint_get_property (GObject * object, guint property_id, } } -static GVariant * -endpoint_get_control_value (WpBaseEndpoint * ep, guint32 id) -{ - WpPwAudioSoftdspEndpoint *self = WP_PW_AUDIO_SOFTDSP_ENDPOINT (ep); - guint stream_id, control_id; - WpAudioStream *stream = NULL; - - if (id == CONTROL_SELECTED) - return g_variant_new_boolean (self->selected); - - wp_audio_stream_id_decode (id, &stream_id, &control_id); - - /* Check if it is the adapter (master) */ - if (stream_id == WP_STREAM_ID_NONE) - return wp_audio_stream_get_control_value (self->adapter, control_id); - - /* Otherwise get the stream_id and control_id */ - g_return_val_if_fail (stream_id < self->converters->len, NULL); - stream = g_ptr_array_index (self->converters, stream_id); - g_return_val_if_fail (stream, NULL); - return wp_audio_stream_get_control_value (stream, control_id); -} - -static gboolean -endpoint_set_control_value (WpBaseEndpoint * ep, guint32 id, GVariant * value) -{ - WpPwAudioSoftdspEndpoint *self = WP_PW_AUDIO_SOFTDSP_ENDPOINT (ep); - guint stream_id, control_id; - WpAudioStream *stream = NULL; - - if (id == CONTROL_SELECTED) { - self->selected = g_variant_get_boolean (value); - wp_base_endpoint_notify_control_value (ep, CONTROL_SELECTED); - return TRUE; - } - - wp_audio_stream_id_decode (id, &stream_id, &control_id); - - /* Check if it is the adapter (master) */ - if (stream_id == WP_STREAM_ID_NONE) - return wp_audio_stream_set_control_value (self->adapter, control_id, value); - - /* Otherwise get the stream_id and control_id */ - g_return_val_if_fail (stream_id < self->converters->len, FALSE); - stream = g_ptr_array_index (self->converters, stream_id); - g_return_val_if_fail (stream, FALSE); - return wp_audio_stream_set_control_value (stream, control_id, value); -} - static void wp_base_endpoint_init_async (GAsyncInitable *initable, int io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer data) @@ -465,8 +478,6 @@ endpoint_class_init (WpPwAudioSoftdspEndpointClass * klass) endpoint_class->get_properties = endpoint_get_properties; endpoint_class->get_role = endpoint_get_role; endpoint_class->prepare_link = endpoint_prepare_link; - endpoint_class->get_control_value = endpoint_get_control_value; - endpoint_class->set_control_value = endpoint_set_control_value; /* Instal the properties */ g_object_class_install_property (object_class, PROP_PROXY_NODE, diff --git a/modules/module-pipewire/audio-softdsp-endpoint/stream.c b/modules/module-pipewire/audio-softdsp-endpoint/stream.c index ad022691..1e4ea467 100644 --- a/modules/module-pipewire/audio-softdsp-endpoint/stream.c +++ b/modules/module-pipewire/audio-softdsp-endpoint/stream.c @@ -50,50 +50,18 @@ enum { }; enum { - CONTROL_VOLUME = 0, - CONTROL_MUTE, - N_CONTROLS, + SIGNAL_CONTROL_CHANGED, + N_SIGNALS, }; +static guint32 signals[N_SIGNALS] = {0}; + static void wp_audio_stream_async_initable_init (gpointer iface, gpointer iface_data); G_DEFINE_ABSTRACT_TYPE_WITH_CODE (WpAudioStream, wp_audio_stream, G_TYPE_OBJECT, G_ADD_PRIVATE (WpAudioStream) G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_INITABLE, wp_audio_stream_async_initable_init)) -guint -wp_audio_stream_id_encode (guint stream_id, guint control_id) -{ - g_return_val_if_fail (control_id < N_CONTROLS, 0); - - /* encode NONE as 0 and everything else with +1 */ - /* NONE is MAX_UINT, so +1 will do the trick */ - stream_id += 1; - - /* Encode the stream and control Ids. The first ID is reserved - * for the "selected" control, registered in the endpoint */ - return 1 + (stream_id * N_CONTROLS) + control_id; -} - -void -wp_audio_stream_id_decode (guint id, guint *stream_id, guint *control_id) -{ - guint s_id, c_id; - - g_return_if_fail (id >= 1); - id -= 1; - - /* Decode the stream and control Ids */ - s_id = (id / N_CONTROLS) - 1; - c_id = id % N_CONTROLS; - - /* Set the output params */ - if (stream_id) - *stream_id = s_id; - if (control_id) - *control_id = c_id; -} - static void audio_stream_event_param (WpProxy *proxy, int seq, uint32_t id, uint32_t index, uint32_t next, const struct spa_pod *param, @@ -114,19 +82,15 @@ audio_stream_event_param (WpProxy *proxy, int seq, uint32_t id, switch (prop->key) { case SPA_PROP_volume: spa_pod_get_float(&prop->value, &volume); - if (priv->volume != volume) { - priv->volume = volume; - wp_base_endpoint_notify_control_value (ep, - wp_audio_stream_id_encode (priv->id, CONTROL_VOLUME)); - } + priv->volume = volume; + g_signal_emit (self, signals[SIGNAL_CONTROL_CHANGED], 0, + WP_ENDPOINT_CONTROL_VOLUME); break; case SPA_PROP_mute: spa_pod_get_bool(&prop->value, &mute); - if (priv->mute != mute) { - priv->mute = mute; - wp_base_endpoint_notify_control_value (ep, - wp_audio_stream_id_encode (priv->id, CONTROL_MUTE)); - } + priv->mute = mute; + g_signal_emit (self, signals[SIGNAL_CONTROL_CHANGED], 0, + WP_ENDPOINT_CONTROL_MUTE); break; default: break; @@ -293,36 +257,12 @@ wp_audio_stream_init_async (GAsyncInitable *initable, int io_priority, WpAudioStreamPrivate *priv = wp_audio_stream_get_instance_private (self); g_autoptr (WpBaseEndpoint) ep = g_weak_ref_get (&priv->endpoint); g_autoptr (WpCore) core = wp_audio_stream_get_core (self); - GVariantDict d; g_debug ("WpBaseEndpoint:%p init stream %s (%s:%p)", ep, priv->name, G_OBJECT_TYPE_NAME (self), self); priv->init_task = g_task_new (initable, cancellable, callback, data); - /* Register the volume control */ - g_variant_dict_init (&d, NULL); - g_variant_dict_insert (&d, "id", "u", - wp_audio_stream_id_encode (priv->id, CONTROL_VOLUME)); - if (priv->id != WP_STREAM_ID_NONE) - g_variant_dict_insert (&d, "stream-id", "u", priv->id); - g_variant_dict_insert (&d, "name", "s", "volume"); - g_variant_dict_insert (&d, "type", "s", "d"); - g_variant_dict_insert (&d, "range", "(dd)", 0.0, 1.0); - g_variant_dict_insert (&d, "default-value", "d", priv->volume); - wp_base_endpoint_register_control (ep, g_variant_dict_end (&d)); - - /* Register the mute control */ - g_variant_dict_init (&d, NULL); - g_variant_dict_insert (&d, "id", "u", - wp_audio_stream_id_encode (priv->id, CONTROL_MUTE)); - if (priv->id != WP_STREAM_ID_NONE) - g_variant_dict_insert (&d, "stream-id", "u", priv->id); - g_variant_dict_insert (&d, "name", "s", "mute"); - g_variant_dict_insert (&d, "type", "s", "b"); - g_variant_dict_insert (&d, "default-value", "b", priv->mute); - wp_base_endpoint_register_control (ep, g_variant_dict_end (&d)); - g_return_if_fail (priv->proxy); wp_proxy_augment (WP_PROXY (priv->proxy), WP_PROXY_FEATURE_PW_PROXY | WP_PROXY_FEATURE_INFO, NULL, @@ -385,6 +325,10 @@ wp_audio_stream_class_init (WpAudioStreamClass * klass) g_param_spec_object ("proxy-node", "proxy-node", "The node proxy of the stream", WP_TYPE_PROXY_NODE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); + + signals[SIGNAL_CONTROL_CHANGED] = g_signal_new ( + "control-changed", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, G_TYPE_UINT); } WpAudioStream * @@ -484,64 +428,52 @@ wp_audio_stream_prepare_link (WpAudioStream * self, GVariant ** properties, return TRUE; } -GVariant * -wp_audio_stream_get_control_value (WpAudioStream * self, guint32 control_id) +gfloat +wp_audio_stream_get_volume (WpAudioStream * self) { WpAudioStreamPrivate *priv = wp_audio_stream_get_instance_private (self); - - switch (control_id) { - case CONTROL_VOLUME: - return g_variant_new_double (priv->volume); - case CONTROL_MUTE: - return g_variant_new_boolean (priv->mute); - default: - g_warning ("Unknown control id %u", control_id); - return NULL; - } + return priv->volume; } gboolean -wp_audio_stream_set_control_value (WpAudioStream * self, guint32 control_id, - GVariant * value) +wp_audio_stream_get_mute (WpAudioStream * self) { WpAudioStreamPrivate *priv = wp_audio_stream_get_instance_private (self); + return priv->mute; +} +void +wp_audio_stream_set_volume (WpAudioStream * self, gfloat volume) +{ + WpAudioStreamPrivate *priv = wp_audio_stream_get_instance_private (self); char buf[1024]; struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf)); - float volume; - bool mute; /* Make sure the proxy is valid */ - g_return_val_if_fail (priv->proxy, FALSE); + g_return_if_fail (priv->proxy); - /* Set the specific constrol */ - switch (control_id) { - case CONTROL_VOLUME: - volume = g_variant_get_double (value); - wp_proxy_node_set_param (priv->proxy, - SPA_PARAM_Props, 0, - spa_pod_builder_add_object (&b, - SPA_TYPE_OBJECT_Props, SPA_PARAM_Props, - SPA_PROP_volume, SPA_POD_Float(volume), - NULL)); - break; + wp_proxy_node_set_param (priv->proxy, + SPA_PARAM_Props, 0, + spa_pod_builder_add_object (&b, + SPA_TYPE_OBJECT_Props, SPA_PARAM_Props, + SPA_PROP_volume, SPA_POD_Float(volume))); +} - case CONTROL_MUTE: - mute = g_variant_get_boolean (value); - wp_proxy_node_set_param (priv->proxy, - SPA_PARAM_Props, 0, - spa_pod_builder_add_object (&b, - SPA_TYPE_OBJECT_Props, SPA_PARAM_Props, - SPA_PROP_mute, SPA_POD_Bool(mute), - NULL)); - break; +void +wp_audio_stream_set_mute (WpAudioStream * self, gboolean mute) +{ + WpAudioStreamPrivate *priv = wp_audio_stream_get_instance_private (self); + char buf[1024]; + struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf)); - default: - g_warning ("Unknown control id %u", control_id); - return FALSE; - } + /* Make sure the proxy is valid */ + g_return_if_fail (priv->proxy); - return TRUE; + wp_proxy_node_set_param (priv->proxy, + SPA_PARAM_Props, 0, + spa_pod_builder_add_object (&b, + SPA_TYPE_OBJECT_Props, SPA_PARAM_Props, + SPA_PROP_mute, SPA_POD_Bool(mute))); } WpCore * diff --git a/modules/module-pipewire/audio-softdsp-endpoint/stream.h b/modules/module-pipewire/audio-softdsp-endpoint/stream.h index 7f60e74b..6887569d 100644 --- a/modules/module-pipewire/audio-softdsp-endpoint/stream.h +++ b/modules/module-pipewire/audio-softdsp-endpoint/stream.h @@ -14,9 +14,6 @@ G_BEGIN_DECLS -guint wp_audio_stream_id_encode (guint stream_id, guint control_id); -void wp_audio_stream_id_decode (guint id, guint *stream_id, guint *control_id); - #define WP_TYPE_AUDIO_STREAM (wp_audio_stream_get_type ()) G_DECLARE_DERIVABLE_TYPE (WpAudioStream, wp_audio_stream, WP, AUDIO_STREAM, GObject) @@ -34,10 +31,11 @@ WpProxyNode * wp_audio_stream_get_proxy_node (WpAudioStream * self); const struct pw_node_info * wp_audio_stream_get_info (WpAudioStream * self); gboolean wp_audio_stream_prepare_link (WpAudioStream * self, GVariant ** properties, GError ** error); -GVariant * wp_audio_stream_get_control_value (WpAudioStream * self, - guint32 control_id); -gboolean wp_audio_stream_set_control_value (WpAudioStream * self, - guint32 control_id, GVariant * value); + +gfloat wp_audio_stream_get_volume (WpAudioStream * self); +gboolean wp_audio_stream_get_mute (WpAudioStream * self); +void wp_audio_stream_set_volume (WpAudioStream * self, gfloat volume); +void wp_audio_stream_set_mute (WpAudioStream * self, gboolean mute); /* for subclasses */