diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-broadband-modem.c | 13 | ||||
-rw-r--r-- | src/mm-iface-modem-voice.c | 184 | ||||
-rw-r--r-- | src/mm-iface-modem-voice.h | 16 |
3 files changed, 208 insertions, 5 deletions
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c index aceeb5df..63a55c73 100644 --- a/src/mm-broadband-modem.c +++ b/src/mm-broadband-modem.c @@ -120,6 +120,7 @@ enum { PROP_MODEM_SIM_HOT_SWAP_SUPPORTED, PROP_MODEM_SIM_HOT_SWAP_CONFIGURED, PROP_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED, + PROP_MODEM_PERIODIC_CALL_LIST_CHECK_DISABLED, PROP_MODEM_CARRIER_CONFIG_MAPPING, PROP_FLOW_CONTROL, PROP_LAST @@ -225,6 +226,7 @@ struct _MMBroadbandModemPrivate { /* Properties */ GObject *modem_voice_dbus_skeleton; MMCallList *modem_voice_call_list; + gboolean periodic_call_list_check_disabled; gboolean clcc_supported; /*<--- Modem Time interface --->*/ @@ -11357,6 +11359,9 @@ set_property (GObject *object, case PROP_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED: self->priv->periodic_signal_check_disabled = g_value_get_boolean (value); break; + case PROP_MODEM_PERIODIC_CALL_LIST_CHECK_DISABLED: + self->priv->periodic_call_list_check_disabled = g_value_get_boolean (value); + break; case PROP_MODEM_CARRIER_CONFIG_MAPPING: self->priv->carrier_config_mapping = g_value_dup_string (value); break; @@ -11480,6 +11485,9 @@ get_property (GObject *object, case PROP_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED: g_value_set_boolean (value, self->priv->periodic_signal_check_disabled); break; + case PROP_MODEM_PERIODIC_CALL_LIST_CHECK_DISABLED: + g_value_set_boolean (value, self->priv->periodic_call_list_check_disabled); + break; case PROP_MODEM_CARRIER_CONFIG_MAPPING: g_value_set_string (value, self->priv->carrier_config_mapping); break; @@ -11516,6 +11524,7 @@ mm_broadband_modem_init (MMBroadbandModem *self) self->priv->current_sms_mem2_storage = MM_SMS_STORAGE_UNKNOWN; self->priv->sim_hot_swap_supported = FALSE; self->priv->periodic_signal_check_disabled = FALSE; + self->priv->periodic_call_list_check_disabled = FALSE; self->priv->modem_cmer_enable_mode = MM_3GPP_CMER_MODE_NONE; self->priv->modem_cmer_disable_mode = MM_3GPP_CMER_MODE_NONE; self->priv->modem_cmer_ind = MM_3GPP_CMER_IND_NONE; @@ -12020,6 +12029,10 @@ mm_broadband_modem_class_init (MMBroadbandModemClass *klass) MM_IFACE_MODEM_PERIODIC_SIGNAL_CHECK_DISABLED); g_object_class_override_property (object_class, + PROP_MODEM_PERIODIC_CALL_LIST_CHECK_DISABLED, + MM_IFACE_MODEM_VOICE_PERIODIC_CALL_LIST_CHECK_DISABLED); + + g_object_class_override_property (object_class, PROP_MODEM_CARRIER_CONFIG_MAPPING, MM_IFACE_MODEM_CARRIER_CONFIG_MAPPING); diff --git a/src/mm-iface-modem-voice.c b/src/mm-iface-modem-voice.c index 1e293ba7..22582335 100644 --- a/src/mm-iface-modem-voice.c +++ b/src/mm-iface-modem-voice.c @@ -22,11 +22,13 @@ #include "mm-call-list.h" #include "mm-log.h" -#define SUPPORT_CHECKED_TAG "voice-support-checked-tag" -#define SUPPORTED_TAG "voice-supported-tag" +#define SUPPORT_CHECKED_TAG "voice-support-checked-tag" +#define SUPPORTED_TAG "voice-supported-tag" +#define CALL_LIST_POLLING_CONTEXT_TAG "voice-call-list-polling-context-tag" static GQuark support_checked_quark; static GQuark supported_quark; +static GQuark call_list_polling_context_quark; /*****************************************************************************/ @@ -541,6 +543,159 @@ handle_list (MmGdbusModemVoice *skeleton, } /*****************************************************************************/ +/* Call list polling logic + * + * The call list polling is exclusively used to detect detailed call state + * updates while a call is being established. Therefore, if there is no call + * being established (i.e. all terminated, unknown or active), then there is + * no polling to do. + * + * Any time we add a new call to the list, we'll setup polling if it's not + * already running, and the polling logic itself will decide when the polling + * should stop. + */ + +#define CALL_LIST_POLLING_TIMEOUT_SECS 2 + +typedef struct { + guint polling_id; + gboolean polling_ongoing; +} CallListPollingContext; + +static void +call_list_polling_context_free (CallListPollingContext *ctx) +{ + if (ctx->polling_id) + g_source_remove (ctx->polling_id); + g_slice_free (CallListPollingContext, ctx); +} + +static CallListPollingContext * +get_call_list_polling_context (MMIfaceModemVoice *self) +{ + CallListPollingContext *ctx; + + if (G_UNLIKELY (!call_list_polling_context_quark)) + call_list_polling_context_quark = (g_quark_from_static_string ( + CALL_LIST_POLLING_CONTEXT_TAG)); + + ctx = g_object_get_qdata (G_OBJECT (self), call_list_polling_context_quark); + if (!ctx) { + /* Create context and keep it as object data */ + ctx = g_slice_new0 (CallListPollingContext); + + g_object_set_qdata_full ( + G_OBJECT (self), + call_list_polling_context_quark, + ctx, + (GDestroyNotify)call_list_polling_context_free); + } + + return ctx; +} + +static gboolean call_list_poll (MMIfaceModemVoice *self); + +static void +load_call_list_ready (MMIfaceModemVoice *self, + GAsyncResult *res) +{ + CallListPollingContext *ctx; + GList *call_info_list = NULL; + GError *error = NULL; + + ctx = get_call_list_polling_context (self); + ctx->polling_ongoing = FALSE; + + g_assert (MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->load_call_list_finish); + if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->load_call_list_finish (self, res, &call_info_list, &error)) { + mm_warn ("couldn't load call list: %s", error->message); + g_error_free (error); + } + + /* Always report the list even if NULL (it would mean no ongoing calls) */ + mm_iface_modem_voice_report_all_calls (self, call_info_list); + mm_3gpp_call_info_list_free (call_info_list); + + /* setup the polling again */ + g_assert (!ctx->polling_id); + ctx->polling_id = g_timeout_add_seconds (CALL_LIST_POLLING_TIMEOUT_SECS, + (GSourceFunc) call_list_poll, + self); +} + +static void +call_list_foreach_count_establishing (MMBaseCall *call, + gpointer user_data) +{ + guint *n_calls_establishing = (guint *)user_data; + + switch (mm_base_call_get_state (call)) { + case MM_CALL_STATE_DIALING: + case MM_CALL_STATE_RINGING_OUT: + case MM_CALL_STATE_RINGING_IN: + case MM_CALL_STATE_HELD: + case MM_CALL_STATE_WAITING: + *n_calls_establishing = *n_calls_establishing + 1; + break; + default: + break; + } +} + +static gboolean +call_list_poll (MMIfaceModemVoice *self) +{ + CallListPollingContext *ctx; + MMCallList *list = NULL; + guint n_calls_establishing = 0; + + ctx = get_call_list_polling_context (self); + ctx->polling_id = 0; + + g_object_get (MM_BASE_MODEM (self), + MM_IFACE_MODEM_VOICE_CALL_LIST, &list, + NULL); + + if (!list) { + mm_warn ("Cannot poll call list: missing internal call list"); + goto out; + } + + mm_call_list_foreach (list, (MMCallListForeachFunc) call_list_foreach_count_establishing, &n_calls_establishing); + + /* If there is at least ONE call being established, we need the call list */ + if (n_calls_establishing > 0) { + mm_dbg ("%u calls being established: call list polling required", n_calls_establishing); + ctx->polling_ongoing = TRUE; + g_assert (MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->load_call_list); + MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->load_call_list (self, + (GAsyncReadyCallback)load_call_list_ready, + NULL); + } else + mm_dbg ("no calls being established: call list polling stopped"); + +out: + g_clear_object (&list); + return G_SOURCE_REMOVE; +} + +static void +setup_call_list_polling (MMCallList *call_list, + const gchar *call_path_added, + MMIfaceModemVoice *self) +{ + CallListPollingContext *ctx; + + ctx = get_call_list_polling_context (self); + + if (!ctx->polling_id && !ctx->polling_ongoing) + ctx->polling_id = g_timeout_add_seconds (CALL_LIST_POLLING_TIMEOUT_SECS, + (GSourceFunc) call_list_poll, + self); +} + +/*****************************************************************************/ static void update_message_list (MmGdbusModemVoice *skeleton, @@ -843,6 +998,23 @@ interface_enabling_step (GTask *task) G_CALLBACK (call_deleted), ctx->skeleton); + /* Unless we're told not to, setup call list polling logic */ + if (MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->load_call_list && + MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->load_call_list_finish) { + gboolean periodic_call_list_check_disabled = FALSE; + + g_object_get (self, + MM_IFACE_MODEM_VOICE_PERIODIC_CALL_LIST_CHECK_DISABLED, &periodic_call_list_check_disabled, + NULL); + if (!periodic_call_list_check_disabled) { + mm_dbg ("periodic call list polling will be used if supported"); + g_signal_connect (list, + MM_CALL_ADDED, + G_CALLBACK (setup_call_list_polling), + self); + } + } + g_object_unref (list); /* Fall down to next step */ @@ -1144,6 +1316,14 @@ iface_modem_voice_init (gpointer g_iface) MM_TYPE_CALL_LIST, G_PARAM_READWRITE)); + g_object_interface_install_property + (g_iface, + g_param_spec_boolean (MM_IFACE_MODEM_VOICE_PERIODIC_CALL_LIST_CHECK_DISABLED, + "Periodic call list checks disabled", + "Whether periodic call list check are disabled.", + FALSE, + G_PARAM_READWRITE)); + initialized = TRUE; } diff --git a/src/mm-iface-modem-voice.h b/src/mm-iface-modem-voice.h index 5c2c118c..f697937a 100644 --- a/src/mm-iface-modem-voice.h +++ b/src/mm-iface-modem-voice.h @@ -29,8 +29,9 @@ #define MM_IS_IFACE_MODEM_VOICE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_IFACE_MODEM_VOICE)) #define MM_IFACE_MODEM_VOICE_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), MM_TYPE_IFACE_MODEM_VOICE, MMIfaceModemVoice)) -#define MM_IFACE_MODEM_VOICE_DBUS_SKELETON "iface-modem-voice-dbus-skeleton" -#define MM_IFACE_MODEM_VOICE_CALL_LIST "iface-modem-voice-call-list" +#define MM_IFACE_MODEM_VOICE_DBUS_SKELETON "iface-modem-voice-dbus-skeleton" +#define MM_IFACE_MODEM_VOICE_CALL_LIST "iface-modem-voice-call-list" +#define MM_IFACE_MODEM_VOICE_PERIODIC_CALL_LIST_CHECK_DISABLED "iface-modem-voice-periodic-call-list-check-disabled" typedef struct _MMIfaceModemVoice MMIfaceModemVoice; @@ -77,7 +78,16 @@ struct _MMIfaceModemVoice { GAsyncResult *res, GError **error); - /* Create CALL objects */ + /* Load full list of calls (MMCallInfo list) */ + void (* load_call_list) (MMIfaceModemVoice *self, + GAsyncReadyCallback callback, + gpointer user_data); + gboolean (* load_call_list_finish) (MMIfaceModemVoice *self, + GAsyncResult *res, + GList **call_info_list, + GError **error); + + /* Create call objects */ MMBaseCall * (* create_call) (MMIfaceModemVoice *self, MMCallDirection direction, const gchar *number); |