From 0f727808143da594c2cfeb680e1a5a283594d243 Mon Sep 17 00:00:00 2001 From: Evangelos Ribeiro Tzaras Date: Fri, 26 Nov 2021 07:42:40 +0100 Subject: [PATCH] ringer: Restart ringer if quiet parameter changed This makes sure the following sequence of events works: - Call A incoming - Rings loudly - Call B incoming - Still rings loudly - Call A accepted - Rings quietly - Call A hung up - Rings loudly again Being able to restart the ringing is needed for this case because we cannot retroactively change the feedback levels of a event that has already been triggered. Without this patch Calls would continue ringing for the scenario above even after call A was accepted. --- src/calls-ringer.c | 79 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 78 insertions(+), 1 deletion(-) diff --git a/src/calls-ringer.c b/src/calls-ringer.c index 97bef3c..6e566fb 100644 --- a/src/calls-ringer.c +++ b/src/calls-ringer.c @@ -58,6 +58,7 @@ struct _CallsRinger { GCancellable *cancel_ring; CallsRingState state; + guint restart_id; gboolean is_quiet; }; @@ -91,6 +92,10 @@ change_ring_state (CallsRinger *self, self->state = state; + /* Currently restarting, so don't notify */ + if (self->restart_id) + return; + /* Ringing has not yet started/stopped */ if (state == CALLS_RING_STATE_REQUEST_PLAY || state == CALLS_RING_STATE_REQUEST_STOP) @@ -124,6 +129,9 @@ on_event_triggered (LfbEvent *event, g_object_unref (self); } + +static void restart (CallsRinger *self, gboolean quiet); + static void start (CallsRinger *self, gboolean quiet) @@ -133,8 +141,12 @@ start (CallsRinger *self, lfb_event_set_feedback_profile (self->event, quiet ? "quiet" : NULL); if (self->state == CALLS_RING_STATE_PLAYING || - self->state == CALLS_RING_STATE_REQUEST_PLAY) + self->state == CALLS_RING_STATE_REQUEST_PLAY) { + if (self->is_quiet != quiet) + restart (self, quiet); + return; + } if (self->event) { g_clear_object (&self->cancel_ring); @@ -208,6 +220,69 @@ stop (CallsRinger *self) } +typedef struct { + CallsRinger *ringer; + gboolean quiet; +} RestartRingerData; + + +static gboolean +on_ringer_restart (gpointer user_data) +{ + RestartRingerData *data = user_data; + + if (data->ringer->state == CALLS_RING_STATE_PLAYING) { + stop (data->ringer); + + return G_SOURCE_CONTINUE; + } + + /* wait until requests have been fulfilled */ + if (data->ringer->state == CALLS_RING_STATE_REQUEST_PLAY || + data->ringer->state == CALLS_RING_STATE_REQUEST_STOP) { + return G_SOURCE_CONTINUE; + } + + if (data->ringer->state == CALLS_RING_STATE_INACTIVE) { + start (data->ringer, data->quiet); + + return G_SOURCE_REMOVE; + } + + g_return_val_if_reached (G_SOURCE_CONTINUE); +} + + +static void +clean_up_restart_data (gpointer user_data) +{ + RestartRingerData *data = user_data; + + data->ringer->restart_id = 0; + + g_free (data); +} + + +static void +restart (CallsRinger *self, + gboolean quiet) +{ + RestartRingerData *data = g_new0 (RestartRingerData, 1); + + data->ringer = self; + data->quiet = quiet; + + if (self->restart_id) + g_source_remove (self->restart_id); + + self->restart_id = g_idle_add_full (G_PRIORITY_DEFAULT_IDLE, + G_SOURCE_FUNC (on_ringer_restart), + data, + clean_up_restart_data); +} + + static inline gboolean is_ring_state (CallsCallState state) { @@ -395,6 +470,8 @@ dispose (GObject *object) } g_signal_handlers_disconnect_by_data (calls_manager_get_default (), self); + g_clear_handle_id (&self->restart_id, g_source_remove); + G_OBJECT_CLASS (calls_ringer_parent_class)->dispose (object); }