aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2019-06-16 23:13:14 +0200
committerAleksander Morgado <aleksander@aleksander.es>2019-07-11 23:01:08 +0200
commitd0c0e925b6e9bd86fb49524309c0335fc01ca8b4 (patch)
tree9e9fd685caa669eb69ea519a8facc44b830b1b8b /src
parentfaaaf2027662b3f00bbdb90076abd72d5eed9397 (diff)
iface-modem-voice: setup full call list polling logic
If the modem supports call list polling, we'll setup a timeout to poll for the full call list periodically, in order to get detailed call states. The timeout is setup as soon as a new call is created, and it will be kept enabled as long as there is a call being established (i.e. not unknown, not terminated, not active).
Diffstat (limited to 'src')
-rw-r--r--src/mm-broadband-modem.c13
-rw-r--r--src/mm-iface-modem-voice.c184
-rw-r--r--src/mm-iface-modem-voice.h16
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);