From ecca21b0ed986b968a3a93745d1b3fcba663d6ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guido=20G=C3=BCnther?= Date: Wed, 20 May 2020 16:14:23 +0200 Subject: [PATCH] ringer: Use libfeedback This triggers e.g. haptic feeback as well and can later on be used for LED feedback. We can drop the audio theme setting completely since feedbackd picks up the global GNOME setting. Since feedbackd currently does not cancel gsound's via a cancellable this might make the phone ring a bit too long atm but that will be fixed on the feedbackd side (https://source.puri.sm/Librem5/feedbackd/-/issues/10) --- src/calls-ringer.c | 272 ++++++++++++++------------------------------- src/meson.build | 2 +- 2 files changed, 86 insertions(+), 188 deletions(-) diff --git a/src/calls-ringer.c b/src/calls-ringer.c index 3677aeb..9086a08 100644 --- a/src/calls-ringer.c +++ b/src/calls-ringer.c @@ -21,221 +21,102 @@ * SPDX-License-Identifier: GPL-3.0-or-later * */ +#define G_LOG_DOMAIN "calls-ringer" #include "calls-ringer.h" #include "calls-manager.h" #include "config.h" -#include #include #include +#define LIBFEEDBACK_USE_UNSTABLE_API +#include + struct _CallsRinger { GObject parent_instance; - gchar *theme_name; - GSoundContext *ctx; - unsigned ring_count; - GCancellable *playing; + unsigned ring_count; + gboolean playing; + LfbEvent *event; }; G_DEFINE_TYPE (CallsRinger, calls_ringer, G_TYPE_OBJECT); - static void -ringer_error (CallsRinger *self, - const gchar *prefix, - GError *error) +on_event_triggered (LfbEvent *event, + GAsyncResult *res, + CallsRinger *self) { - g_warning ("%s: %s", prefix, error->message); - g_error_free (error); + g_autoptr (GError) err = NULL; + g_return_if_fail (LFB_IS_EVENT (event)); + g_return_if_fail (CALLS_IS_RINGER (self)); - g_clear_object (&self->ctx); + if (lfb_event_trigger_feedback_finish (event, res, &err)) + { + self->playing = TRUE; + } + else + { + g_warning ("Failed to trigger feedback for '%s': %s", + lfb_event_get_event (event), err->message); + } + g_object_unref (self); } - -static void -get_theme_name (CallsRinger *self, - GtkSettings *settings) -{ - gchar *theme_name = NULL; - - g_object_get (settings, - "gtk-sound-theme-name", &theme_name, - NULL); - - g_free (self->theme_name); - self->theme_name = theme_name; - - g_debug ("Got GTK sound theme name `%s'", theme_name); -} - - -static void -notify_sound_theme_name_cb (GtkSettings *settings, - GParamSpec *pspec, - CallsRinger *self) -{ - get_theme_name (self, settings); - - if (self->ctx) - { - GError *error = NULL; - gboolean ok; - - ok = gsound_context_set_attributes - (self->ctx, - &error, - GSOUND_ATTR_CANBERRA_XDG_THEME_NAME, self->theme_name, - NULL); - - if (!ok) - { - g_warning ("Could not set GSound theme name: %s", - error->message); - g_error_free (error); - } - } -} - - -static void -monitor_theme_name (CallsRinger *self) -{ - GtkSettings *settings = gtk_settings_get_default (); - g_assert (settings != NULL); - - g_signal_connect (settings, - "notify::gtk-sound-theme-name", - G_CALLBACK (notify_sound_theme_name_cb), - self); - - get_theme_name (self, settings); -} - - -static gboolean -create_ctx (CallsRinger *self) -{ - GError *error = NULL; - gboolean ok; - GHashTable *attrs; - - self->ctx = gsound_context_new (NULL, &error); - if (!self->ctx) - { - ringer_error (self, "Error creating GSound context", error); - return FALSE; - } - - attrs = g_hash_table_new (g_str_hash, g_str_equal); - g_hash_table_insert - (attrs, GSOUND_ATTR_APPLICATION_ICON_NAME, APP_ID); - if (self->theme_name) - { - g_hash_table_insert - (attrs, GSOUND_ATTR_CANBERRA_XDG_THEME_NAME, - self->theme_name); - } - - ok = gsound_context_set_attributesv (self->ctx, attrs, &error); - g_hash_table_unref (attrs); - if (!ok) - { - ringer_error (self, "Error setting GSound attributes", error); - return FALSE; - } - - g_debug ("Created ringtone context"); - - return TRUE; -} - - -static void play (CallsRinger *self); - - -static void -play_cb (GSoundContext *ctx, - GAsyncResult *res, - CallsRinger *self) -{ - gboolean ok; - GError *error = NULL; - - ok = gsound_context_play_full_finish (ctx, res, &error); - if (!ok) - { - g_clear_object (&self->playing); - - if (error->domain == G_IO_ERROR - && error->code == G_IO_ERROR_CANCELLED) - { - g_debug ("Ringtone cancelled"); - } - else - { - ringer_error (self, "Error playing ringtone", error); - } - - return; - } - - g_assert (self->ring_count > 0); - play (self); -} - - -static void -play (CallsRinger *self) -{ - g_assert (self->ctx != NULL); - g_assert (self->playing != NULL); - - g_debug ("Playing ringtone"); - gsound_context_play_full (self->ctx, - self->playing, - (GAsyncReadyCallback)play_cb, - self, - GSOUND_ATTR_MEDIA_ROLE, "event", - GSOUND_ATTR_EVENT_ID, "phone-incoming-call", - GSOUND_ATTR_EVENT_DESCRIPTION, _("Incoming call"), - NULL); -} - - static void start (CallsRinger *self) { - g_assert (self->playing == NULL); + g_return_if_fail (self->playing == FALSE); - if (!self->ctx) + if (self->event) { - gboolean ok; - - ok = create_ctx (self); - if (!ok) - { - return; - } + g_object_ref (self); + lfb_event_trigger_feedback_async (self->event, + NULL, + (GAsyncReadyCallback)on_event_triggered, + self); } - - g_debug ("Starting ringtone"); - self->playing = g_cancellable_new (); - play (self); } +static void +on_event_feedback_ended (LfbEvent *event, + GAsyncResult *res, + CallsRinger *self) +{ + g_autoptr (GError) err = NULL; + g_return_if_fail (LFB_IS_EVENT (event)); + g_return_if_fail (CALLS_IS_RINGER (self)); + + if (lfb_event_end_feedback_finish (event, res, &err)) + { + self->playing = FALSE; + } + else + { + g_warning ("Failed to end feedback for '%s': %s", + lfb_event_get_event (event), err->message); + } +} + +static void +on_feedback_ended (LfbEvent *event, + CallsRinger *self) +{ + g_debug ("Feedback ended"); + self->playing = FALSE; +} static void stop (CallsRinger *self) { g_debug ("Stopping ringtone"); - - g_assert (self->ctx != NULL); - - g_cancellable_cancel (self->playing); + lfb_event_end_feedback_async (self->event, + NULL, + (GAsyncReadyCallback)on_event_feedback_ended, + self); } @@ -342,6 +223,22 @@ call_removed_cb (CallsRinger *self, CallsCall *call) static void calls_ringer_init (CallsRinger *self) { + g_autoptr(GError) err = NULL; + + if (lfb_init (APP_ID, &err)) + { + self->event = lfb_event_new ("phone-incoming-call"); + /* Let feedbackd do the loop */ + lfb_event_set_timeout (self->event, 0); + g_signal_connect (self->event, + "feedback-ended", + (GCallback)on_feedback_ended, + self); + } + else + { + g_warning ("Failed to init libfeedback: %s", err->message); + } } @@ -352,9 +249,6 @@ constructed (GObject *object) GList *c; CallsRinger *self = CALLS_RINGER (object); - monitor_theme_name (self); - create_ctx (self); - g_signal_connect_swapped (calls_manager_get_default (), "call-add", G_CALLBACK (call_added_cb), @@ -375,13 +269,17 @@ constructed (GObject *object) static void -finalize (GObject *object) +dispose (GObject *object) { CallsRinger *self = CALLS_RINGER (object); - g_free (self->theme_name); + if (self->event) + { + g_clear_object (&self->event); + lfb_uninit (); + } - G_OBJECT_CLASS (calls_ringer_parent_class)->finalize (object); + G_OBJECT_CLASS (calls_ringer_parent_class)->dispose (object); } @@ -391,7 +289,7 @@ calls_ringer_class_init (CallsRingerClass *klass) GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructed = constructed; - object_class->finalize = finalize; + object_class->dispose = dispose; } CallsRinger * diff --git a/src/meson.build b/src/meson.build index a7f708c..b89a0c8 100644 --- a/src/meson.build +++ b/src/meson.build @@ -31,7 +31,7 @@ calls_includes = [ top_include, src_include ] calls_deps = [ dependency('gobject-2.0', version: '>= 2.58'), dependency('gtk+-3.0'), dependency('libhandy-0.0', version: '>= 0.0.12'), - dependency('gsound'), + dependency('libfeedback-0.0'), dependency('libpeas-1.0'), dependency('gom-1.0'), dependency('libebook-contacts-1.2'),