diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/audio.c | 44 | ||||
-rw-r--r-- | src/endpoint.c | 19 | ||||
-rw-r--r-- | src/video.c | 40 | ||||
-rw-r--r-- | src/wireplumber.c | 84 |
4 files changed, 122 insertions, 65 deletions
diff --git a/src/audio.c b/src/audio.c index 9c2841b..15582d7 100644 --- a/src/audio.c +++ b/src/audio.c @@ -4,6 +4,7 @@ #include "device.h" #include "endpoint.h" +#include "glib-object.h" #include "wp.h" struct _AstalWpAudio { @@ -382,34 +383,10 @@ static void astal_wp_audio_object_removed(AstalWpAudio *self, gpointer object) { } } -/** - * astal_wp_audio_get_default - * - * gets the default audio object. - * - * Returns: (nullable) (transfer none) - */ -AstalWpAudio *astal_wp_audio_get_default() { - static AstalWpAudio *self = NULL; - - if (self == NULL) self = g_object_new(ASTAL_WP_TYPE_AUDIO, NULL); - - return self; -} - -/** - * astal_wp_get_default_audio - * - * gets the default audio object. This function does the same as [[email protected]_default] - * - * Returns: (nullable) (transfer none) - */ -AstalWpAudio *astal_wp_get_default_audio() { return astal_wp_audio_get_default(); } - -static void astal_wp_audio_init(AstalWpAudio *self) { +AstalWpAudio *astal_wp_audio_new(AstalWpWp *wp) { + AstalWpAudio *self = g_object_new(ASTAL_WP_TYPE_AUDIO, NULL); AstalWpAudioPrivate *priv = astal_wp_audio_get_instance_private(self); - - priv->wp = astal_wp_wp_get_default(); + priv->wp = g_object_ref(wp); g_signal_connect_swapped(priv->wp, "endpoint-added", G_CALLBACK(astal_wp_audio_object_added), self); @@ -419,11 +396,24 @@ static void astal_wp_audio_init(AstalWpAudio *self) { self); g_signal_connect_swapped(priv->wp, "device-removed", G_CALLBACK(astal_wp_audio_device_removed), self); + + return self; +} + +static void astal_wp_audio_dispose(GObject *object) { + AstalWpAudio *self = ASTAL_WP_AUDIO(object); + AstalWpAudioPrivate *priv = astal_wp_audio_get_instance_private(self); + g_clear_object(&priv->wp); +} + +static void astal_wp_audio_init(AstalWpAudio *self) { + AstalWpAudioPrivate *priv = astal_wp_audio_get_instance_private(self); } static void astal_wp_audio_class_init(AstalWpAudioClass *class) { GObjectClass *object_class = G_OBJECT_CLASS(class); object_class->get_property = astal_wp_audio_get_property; + object_class->dispose = astal_wp_audio_dispose; /** * AstalWpAudio:microphones: (type GList(AstalWpEndpoint)) (transfer container) diff --git a/src/endpoint.c b/src/endpoint.c index 1a6f207..13979d1 100644 --- a/src/endpoint.c +++ b/src/endpoint.c @@ -26,6 +26,7 @@ typedef struct { WpNode *node; WpPlugin *mixer; WpPlugin *defaults; + AstalWpWp *wp; gboolean is_default_node; AstalWpMediaClass media_class; @@ -242,8 +243,7 @@ void astal_wp_endpoint_set_lock_channels(AstalWpEndpoint *self, gboolean lock_ch } const gchar *astal_wp_endpoint_get_volume_icon(AstalWpEndpoint *self) { - AstalWpEndpointPrivate *priv = astal_wp_endpoint_get_instance_private(self); - if (priv->media_class == ASTAL_WP_MEDIA_CLASS_AUDIO_MICROPHONE) { + if (self->type == ASTAL_WP_MEDIA_CLASS_AUDIO_MICROPHONE) { if (self->mute) return "microphone-sensitivity-muted-symbolic"; if (self->volume <= 0.33) return "microphone-sensitivity-low-symbolic"; if (self->volume <= 0.66) return "microphone-sensitivity-medium-symbolic"; @@ -362,7 +362,7 @@ static void astal_wp_endpoint_update_properties(AstalWpEndpoint *self) { const gchar *dev = wp_pipewire_object_get_property(WP_PIPEWIRE_OBJECT(priv->node), "device.id"); guint device_id = g_ascii_strtoull(dev, NULL, 10); - AstalWpDevice *device = astal_wp_wp_get_device(astal_wp_wp_get_default(), device_id); + AstalWpDevice *device = astal_wp_wp_get_device(priv->wp, device_id); icon = astal_wp_device_get_icon(device); if (icon == NULL) { icon = self->type == ASTAL_WP_MEDIA_CLASS_AUDIO_SPEAKER @@ -406,8 +406,7 @@ static void astal_wp_endpoint_default_changed_as_default(AstalWpEndpoint *self) if (defaultId != self->id) { if (priv->node != NULL) g_object_unref(priv->node); - AstalWpEndpoint *default_endpoint = - astal_wp_wp_get_endpoint(astal_wp_wp_get_default(), defaultId); + AstalWpEndpoint *default_endpoint = astal_wp_wp_get_endpoint(priv->wp, defaultId); if (default_endpoint != NULL && astal_wp_endpoint_get_media_class(default_endpoint) == priv->media_class) { AstalWpEndpointPrivate *default_endpoint_priv = @@ -441,7 +440,8 @@ static void astal_wp_endpoint_mixer_changed(AstalWpEndpoint *self, guint node_id } AstalWpEndpoint *astal_wp_endpoint_init_as_default(AstalWpEndpoint *self, WpPlugin *mixer, - WpPlugin *defaults, AstalWpMediaClass type) { + WpPlugin *defaults, AstalWpMediaClass type, + AstalWpWp *wp) { AstalWpEndpointPrivate *priv = astal_wp_endpoint_get_instance_private(self); priv->mixer = g_object_ref(mixer); @@ -450,6 +450,7 @@ AstalWpEndpoint *astal_wp_endpoint_init_as_default(AstalWpEndpoint *self, WpPlug priv->media_class = type; priv->is_default_node = TRUE; self->is_default = TRUE; + priv->wp = g_object_ref(wp); priv->default_signal_handler_id = g_signal_connect_swapped( priv->defaults, "changed", G_CALLBACK(astal_wp_endpoint_default_changed_as_default), self); @@ -461,7 +462,8 @@ AstalWpEndpoint *astal_wp_endpoint_init_as_default(AstalWpEndpoint *self, WpPlug return self; } -AstalWpEndpoint *astal_wp_endpoint_create(WpNode *node, WpPlugin *mixer, WpPlugin *defaults) { +AstalWpEndpoint *astal_wp_endpoint_create(WpNode *node, WpPlugin *mixer, WpPlugin *defaults, + AstalWpWp *wp) { AstalWpEndpoint *self = g_object_new(ASTAL_WP_TYPE_ENDPOINT, NULL); AstalWpEndpointPrivate *priv = astal_wp_endpoint_get_instance_private(self); @@ -469,6 +471,7 @@ AstalWpEndpoint *astal_wp_endpoint_create(WpNode *node, WpPlugin *mixer, WpPlugi priv->defaults = g_object_ref(defaults); priv->node = g_object_ref(node); priv->is_default_node = FALSE; + priv->wp = g_object_ref(wp); priv->default_signal_handler_id = g_signal_connect_swapped( priv->defaults, "changed", G_CALLBACK(astal_wp_endpoint_default_changed), self); @@ -485,6 +488,7 @@ static void astal_wp_endpoint_init(AstalWpEndpoint *self) { priv->node = NULL; priv->mixer = NULL; priv->defaults = NULL; + priv->wp = NULL; self->volume = 0; self->mute = TRUE; @@ -502,6 +506,7 @@ static void astal_wp_endpoint_dispose(GObject *object) { g_clear_object(&priv->node); g_clear_object(&priv->mixer); g_clear_object(&priv->defaults); + g_clear_object(&priv->wp); } static void astal_wp_endpoint_finalize(GObject *object) { diff --git a/src/video.c b/src/video.c index 1d75d30..00cdd82 100644 --- a/src/video.c +++ b/src/video.c @@ -321,31 +321,10 @@ static void astal_wp_video_object_removed(AstalWpAudio *self, gpointer object) { } } -/** - * astal_wp_video_get_default - * - * Returns: (nullable) (transfer none): gets the default video object. - */ -AstalWpVideo *astal_wp_video_get_default() { - static AstalWpVideo *self = NULL; - - if (self == NULL) self = g_object_new(ASTAL_WP_TYPE_VIDEO, NULL); - - return self; -} - -/** - * astal_wp_get_default_video - * - * Returns: (nullable) (transfer none): gets the default video object. - */ -AstalWpVideo *astal_wp_get_default_video() { return astal_wp_video_get_default(); } - -static void astal_wp_video_init(AstalWpVideo *self) { +AstalWpVideo *astal_wp_video_new(AstalWpWp *wp) { + AstalWpVideo *self = g_object_new(ASTAL_WP_TYPE_VIDEO, NULL); AstalWpVideoPrivate *priv = astal_wp_video_get_instance_private(self); - - priv->wp = astal_wp_wp_get_default(); - + priv->wp = g_object_ref(wp); g_signal_connect_swapped(priv->wp, "endpoint-added", G_CALLBACK(astal_wp_video_object_added), self); g_signal_connect_swapped(priv->wp, "endpoint-removed", @@ -354,11 +333,24 @@ static void astal_wp_video_init(AstalWpVideo *self) { self); g_signal_connect_swapped(priv->wp, "device-removed", G_CALLBACK(astal_wp_video_device_removed), self); + + return self; +} + +static void astal_wp_video_dispose(GObject *object) { + AstalWpVideo *self = ASTAL_WP_VIDEO(object); + AstalWpVideoPrivate *priv = astal_wp_video_get_instance_private(self); + g_clear_object(&priv->wp); +} + +static void astal_wp_video_init(AstalWpVideo *self) { + AstalWpVideoPrivate *priv = astal_wp_video_get_instance_private(self); } static void astal_wp_video_class_init(AstalWpVideoClass *class) { GObjectClass *object_class = G_OBJECT_CLASS(class); object_class->get_property = astal_wp_video_get_property; + object_class->dispose = astal_wp_video_dispose; /** * AstalWpVideo:sources: (type GList(AstalWpEndpoint)) (transfer container) diff --git a/src/wireplumber.c b/src/wireplumber.c index f08678a..f1fa516 100644 --- a/src/wireplumber.c +++ b/src/wireplumber.c @@ -3,6 +3,8 @@ #include "audio.h" #include "device-private.h" #include "endpoint-private.h" +#include "glib-object.h" +#include "glib.h" #include "video.h" #include "wp.h" @@ -11,6 +13,11 @@ struct _AstalWpWp { AstalWpEndpoint *default_speaker; AstalWpEndpoint *default_microphone; + + AstalWpAudio *audio; + AstalWpVideo *video; + + AstalWpScale scale; }; typedef struct { @@ -27,6 +34,10 @@ typedef struct { G_DEFINE_FINAL_TYPE_WITH_PRIVATE(AstalWpWp, astal_wp_wp, G_TYPE_OBJECT); +G_DEFINE_ENUM_TYPE(AstalWpScale, astal_wp_scale, + G_DEFINE_ENUM_VALUE(ASTAL_WP_SCALE_LINEAR, "linear"), + G_DEFINE_ENUM_VALUE(ASTAL_WP_SCALE_CUBIC, "cubic")); + typedef enum { ASTAL_WP_WP_SIGNAL_ENDPOINT_ADDED, ASTAL_WP_WP_SIGNAL_ENDPOINT_REMOVED, @@ -46,6 +57,7 @@ typedef enum { ASTAL_WP_WP_PROP_DEVICES, ASTAL_WP_WP_PROP_DEFAULT_SPEAKER, ASTAL_WP_WP_PROP_DEFAULT_MICROPHONE, + ASTAL_WP_WP_PROP_SCALE, ASTAL_WP_WP_N_PROPERTIES, } AstalWpWpProperties; @@ -110,14 +122,14 @@ GList *astal_wp_wp_get_devices(AstalWpWp *self) { * * Returns: (nullable) (transfer none): gets the audio object */ -AstalWpAudio *astal_wp_wp_get_audio() { return astal_wp_audio_get_default(); } +AstalWpAudio *astal_wp_wp_get_audio(AstalWpWp *self) { return self->audio; } /** * astal_wp_wp_get_video * * Returns: (nullable) (transfer none): gets the video object */ -AstalWpVideo *astal_wp_wp_get_video() { return astal_wp_video_get_default(); } +AstalWpVideo *astal_wp_wp_get_video(AstalWpWp *self) { return self->video; } /** * astal_wp_wp_get_default_speaker @@ -135,6 +147,29 @@ AstalWpEndpoint *astal_wp_wp_get_default_microphone(AstalWpWp *self) { return self->default_microphone; } +AstalWpScale astal_wp_wp_get_scale(AstalWpWp *self) { return self->scale; } + +void astal_wp_wp_set_scale(AstalWpWp *self, AstalWpScale scale) { + AstalWpWpPrivate *priv = astal_wp_wp_get_instance_private(self); + self->scale = scale; + + if (priv->mixer == NULL) return; + + g_object_set(priv->mixer, "scale", self->scale, NULL); + + GHashTableIter iter; + gpointer key, value; + + g_hash_table_iter_init(&iter, priv->endpoints); + while (g_hash_table_iter_next(&iter, &key, &value)) { + AstalWpEndpoint *ep = ASTAL_WP_ENDPOINT(value); + astal_wp_endpoint_update_volume(ep); + } + + astal_wp_endpoint_update_volume(self->default_speaker); + astal_wp_endpoint_update_volume(self->default_microphone); +} + static void astal_wp_wp_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { AstalWpWp *self = ASTAL_WP_WP(object); @@ -142,10 +177,10 @@ static void astal_wp_wp_get_property(GObject *object, guint property_id, GValue switch (property_id) { case ASTAL_WP_WP_PROP_AUDIO: - g_value_set_object(value, astal_wp_wp_get_audio()); + g_value_set_object(value, astal_wp_wp_get_audio(self)); break; case ASTAL_WP_WP_PROP_VIDEO: - g_value_set_object(value, astal_wp_wp_get_video()); + g_value_set_object(value, astal_wp_wp_get_video(self)); break; case ASTAL_WP_WP_PROP_ENDPOINTS: g_value_set_pointer(value, g_hash_table_get_values(priv->endpoints)); @@ -159,6 +194,23 @@ static void astal_wp_wp_get_property(GObject *object, guint property_id, GValue case ASTAL_WP_WP_PROP_DEFAULT_MICROPHONE: g_value_set_object(value, self->default_microphone); break; + case ASTAL_WP_WP_PROP_SCALE: + g_value_set_enum(value, self->scale); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void astal_wp_wp_set_property(GObject *object, guint property_id, const GValue *value, + GParamSpec *pspec) { + AstalWpWp *self = ASTAL_WP_WP(object); + + switch (property_id) { + case ASTAL_WP_WP_PROP_SCALE: + astal_wp_wp_set_scale(self, g_value_get_enum(value)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); break; @@ -184,7 +236,8 @@ static void astal_wp_wp_object_added(AstalWpWp *self, gpointer object) { if (WP_IS_NODE(object)) { WpNode *node = WP_NODE(object); - AstalWpEndpoint *endpoint = astal_wp_endpoint_create(node, priv->mixer, priv->defaults); + AstalWpEndpoint *endpoint = + astal_wp_endpoint_create(node, priv->mixer, priv->defaults, self); g_hash_table_insert(priv->endpoints, GUINT_TO_POINTER(wp_proxy_get_bound_id(WP_PROXY(node))), endpoint); @@ -230,9 +283,9 @@ static void astal_wp_wp_objm_installed(AstalWpWp *self) { AstalWpWpPrivate *priv = astal_wp_wp_get_instance_private(self); astal_wp_endpoint_init_as_default(self->default_speaker, priv->mixer, priv->defaults, - ASTAL_WP_MEDIA_CLASS_AUDIO_SPEAKER); + ASTAL_WP_MEDIA_CLASS_AUDIO_SPEAKER, self); astal_wp_endpoint_init_as_default(self->default_microphone, priv->mixer, priv->defaults, - ASTAL_WP_MEDIA_CLASS_AUDIO_MICROPHONE); + ASTAL_WP_MEDIA_CLASS_AUDIO_MICROPHONE, self); } static void astal_wp_wp_plugin_activated(WpObject *obj, GAsyncResult *result, AstalWpWp *self) { @@ -248,6 +301,7 @@ static void astal_wp_wp_plugin_activated(WpObject *obj, GAsyncResult *result, As if (--priv->pending_plugins == 0) { priv->defaults = wp_plugin_find(priv->core, "default-nodes-api"); priv->mixer = wp_plugin_find(priv->core, "mixer-api"); + g_object_set(priv->mixer, "scale", self->scale, NULL); g_signal_connect_swapped(priv->obj_manager, "object-added", G_CALLBACK(astal_wp_wp_object_added), self); @@ -296,6 +350,9 @@ static void astal_wp_wp_dispose(GObject *object) { AstalWpWp *self = ASTAL_WP_WP(object); AstalWpWpPrivate *priv = astal_wp_wp_get_instance_private(self); + g_clear_object(&self->video); + g_clear_object(&self->audio); + wp_core_disconnect(priv->core); g_clear_object(&self->default_speaker); g_clear_object(&self->default_microphone); @@ -326,6 +383,7 @@ static void astal_wp_wp_init(AstalWpWp *self) { if (!wp_core_connect(priv->core)) { g_critical("could not connect to PipeWire\n"); + return; } priv->obj_manager = wp_object_manager_new(); @@ -365,6 +423,9 @@ static void astal_wp_wp_init(AstalWpWp *self) { self->default_speaker = g_object_new(ASTAL_WP_TYPE_ENDPOINT, NULL); self->default_microphone = g_object_new(ASTAL_WP_TYPE_ENDPOINT, NULL); + self->audio = astal_wp_audio_new(self); + self->video = astal_wp_video_new(self); + priv->pending_plugins = 2; wp_core_load_component(priv->core, "libwireplumber-module-default-nodes-api", "module", NULL, "default-nodes-api", NULL, @@ -378,11 +439,20 @@ static void astal_wp_wp_class_init(AstalWpWpClass *class) { object_class->finalize = astal_wp_wp_finalize; object_class->dispose = astal_wp_wp_dispose; object_class->get_property = astal_wp_wp_get_property; + object_class->set_property = astal_wp_wp_set_property; astal_wp_wp_properties[ASTAL_WP_WP_PROP_AUDIO] = g_param_spec_object("audio", "audio", "audio", ASTAL_WP_TYPE_AUDIO, G_PARAM_READABLE); astal_wp_wp_properties[ASTAL_WP_WP_PROP_VIDEO] = g_param_spec_object("video", "video", "video", ASTAL_WP_TYPE_VIDEO, G_PARAM_READABLE); + /** + * AstalWpWp:scale: (type AstalWpScale) + * + * The scale used for the volume + */ + astal_wp_wp_properties[ASTAL_WP_WP_PROP_SCALE] = + g_param_spec_enum("scale", "scale", "scale", ASTAL_WP_TYPE_SCALE, ASTAL_WP_SCALE_CUBIC, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT); /** * AstalWpWp:endpoints: (type GList(AstalWpEndpoint)) (transfer container) |