aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2019-07-02 10:56:18 +0200
committerAleksander Morgado <aleksander@aleksander.es>2019-07-11 23:21:00 +0200
commit55e37a6836a358e60a67b0aff3dfea77c1c78f30 (patch)
tree66638e1f1a156cc1e3d4f3ea961b1781aeec82c1 /src
parent86aeb84f950c3b3e3be63c8920e63877a9c622f2 (diff)
iface-modem-voice: allow reporting state updates of any single call
Instead of providing a method to exclusively provide incoming call updates, make it more generic so that we allow plugins to provide state updates for any kind of call, not just incoming ones. The logic to match the call info provided by URCs is updated so that it can be reused also by the single call reports, in addition to the full call list reports.
Diffstat (limited to 'src')
-rw-r--r--src/mm-broadband-modem.c65
-rw-r--r--src/mm-iface-modem-voice.c220
-rw-r--r--src/mm-iface-modem-voice.h7
3 files changed, 202 insertions, 90 deletions
diff --git a/src/mm-broadband-modem.c b/src/mm-broadband-modem.c
index 15194f42..696f31a0 100644
--- a/src/mm-broadband-modem.c
+++ b/src/mm-broadband-modem.c
@@ -7331,53 +7331,76 @@ modem_voice_setup_cleanup_unsolicited_events_finish (MMIfaceModemVoice *self,
}
static void
-ccwa_received (MMPortSerialAt *port,
- GMatchInfo *info,
+ccwa_received (MMPortSerialAt *port,
+ GMatchInfo *info,
MMBroadbandModem *self)
{
- gchar *str;
+ MMCallInfo call_info;
- str = mm_get_string_unquoted_from_match_info (info, 1);
- mm_dbg ("Call waiting (%s)", str);
- mm_iface_modem_voice_report_incoming_call (MM_IFACE_MODEM_VOICE (self), str, MM_CALL_STATE_WAITING);
- g_free (str);
+ call_info.index = 0;
+ call_info.direction = MM_CALL_DIRECTION_INCOMING;
+ call_info.state = MM_CALL_STATE_WAITING;
+ call_info.number = mm_get_string_unquoted_from_match_info (info, 1);
+
+ mm_dbg ("Call waiting (%s)", call_info.number);
+ mm_iface_modem_voice_report_call (MM_IFACE_MODEM_VOICE (self), &call_info);
+
+ g_free (call_info.number);
}
static void
-ring_received (MMPortSerialAt *port,
- GMatchInfo *info,
+ring_received (MMPortSerialAt *port,
+ GMatchInfo *info,
MMBroadbandModem *self)
{
+ MMCallInfo call_info;
+
+ call_info.index = 0;
+ call_info.direction = MM_CALL_DIRECTION_INCOMING;
+ call_info.state = MM_CALL_STATE_RINGING_IN;
+ call_info.number = NULL;
+
mm_dbg ("Ringing");
- mm_iface_modem_voice_report_incoming_call (MM_IFACE_MODEM_VOICE (self), NULL, MM_CALL_STATE_RINGING_IN);
+ mm_iface_modem_voice_report_call (MM_IFACE_MODEM_VOICE (self), &call_info);
}
static void
-cring_received (MMPortSerialAt *port,
- GMatchInfo *info,
+cring_received (MMPortSerialAt *port,
+ GMatchInfo *info,
MMBroadbandModem *self)
{
- gchar *str;
+ MMCallInfo call_info;
+ gchar *str;
/* We could have "VOICE" or "DATA". Now consider only "VOICE" */
-
str = mm_get_string_unquoted_from_match_info (info, 1);
mm_dbg ("Ringing (%s)", str);
g_free (str);
- mm_iface_modem_voice_report_incoming_call (MM_IFACE_MODEM_VOICE (self), NULL, MM_CALL_STATE_RINGING_IN);
+ call_info.index = 0;
+ call_info.direction = MM_CALL_DIRECTION_INCOMING;
+ call_info.state = MM_CALL_STATE_RINGING_IN;
+ call_info.number = NULL;
+
+ mm_iface_modem_voice_report_call (MM_IFACE_MODEM_VOICE (self), &call_info);
}
static void
-clip_received (MMPortSerialAt *port,
- GMatchInfo *info,
+clip_received (MMPortSerialAt *port,
+ GMatchInfo *info,
MMBroadbandModem *self)
{
- gchar *str;
+ MMCallInfo call_info;
- str = mm_get_string_unquoted_from_match_info (info, 1);
- mm_iface_modem_voice_report_incoming_call (MM_IFACE_MODEM_VOICE (self), str, MM_CALL_STATE_RINGING_IN);
- g_free (str);
+ call_info.index = 0;
+ call_info.direction = MM_CALL_DIRECTION_INCOMING;
+ call_info.state = MM_CALL_STATE_RINGING_IN;
+ call_info.number = mm_get_string_unquoted_from_match_info (info, 1);
+
+ mm_dbg ("Ringing (%s)", call_info.number);
+ mm_iface_modem_voice_report_call (MM_IFACE_MODEM_VOICE (self), &call_info);
+
+ g_free (call_info.number);
}
static void
diff --git a/src/mm-iface-modem-voice.c b/src/mm-iface-modem-voice.c
index 7e91fbd8..a051aad7 100644
--- a/src/mm-iface-modem-voice.c
+++ b/src/mm-iface-modem-voice.c
@@ -85,42 +85,169 @@ create_outgoing_call_from_properties (MMIfaceModemVoice *self,
}
/*****************************************************************************/
+/* Common helper to match call info against a known call object */
+
+static gboolean
+match_single_call_info (const MMCallInfo *call_info,
+ MMBaseCall *call)
+{
+ MMCallState state;
+ MMCallDirection direction;
+ const gchar *number;
+ guint idx;
+ gboolean match_direction_and_state = FALSE;
+ gboolean match_index = FALSE;
+ gboolean match_terminated = FALSE;
+
+ /* try to look for a matching call by direction/number/index */
+ state = mm_base_call_get_state (call);
+ direction = mm_base_call_get_direction (call);
+ number = mm_base_call_get_number (call);
+ idx = mm_base_call_get_index (call);
+
+ /* Match index */
+ if (call_info->index && (call_info->index == idx))
+ match_index = TRUE;
+
+ /* Match direction and state.
+ * We cannot apply this match if both call info and call have an index set
+ * and they're different already. */
+ if ((call_info->direction == direction) &&
+ (call_info->state == state) &&
+ (!call_info->index || !idx || match_index))
+ match_direction_and_state = TRUE;
+
+ /* Match special terminated event */
+ if ((call_info->state == MM_CALL_STATE_TERMINATED) &&
+ (call_info->direction == MM_CALL_DIRECTION_UNKNOWN) &&
+ !call_info->index &&
+ !call_info->number)
+ match_terminated = TRUE;
+
+ /* If no clear match, nothing to do */
+ if (!match_index && !match_direction_and_state && !match_terminated)
+ return FALSE;
+
+ mm_dbg ("call info matched (matched direction/state %s, matched index %s, matched terminated %s) with call at '%s'",
+ match_direction_and_state ? "yes" : "no",
+ match_index ? "yes" : "no",
+ match_terminated ? "yes" : "no",
+ mm_base_call_get_path (call));
+
+ /* Early detect if a known incoming call that was created
+ * from a plain CRING URC (i.e. without caller number)
+ * needs to have the number provided.
+ */
+ if (call_info->number && !number) {
+ mm_dbg (" number set: %s", call_info->number);
+ mm_base_call_set_number (call, call_info->number);
+ }
+
+ /* Early detect if a known incoming/outgoing call does
+ * not have a known call index yet.
+ */
+ if (call_info->index && !idx) {
+ mm_dbg (" index set: %u", call_info->index);
+ mm_base_call_set_index (call, call_info->index);
+ }
+
+ /* Update state if it changed */
+ if (call_info->state != state) {
+ mm_dbg (" state updated: %s", mm_call_state_get_string (call_info->state));
+ mm_base_call_change_state (call, call_info->state, MM_CALL_STATE_REASON_UNKNOWN);
+ }
+
+ /* refresh if incoming and new state is not terminated */
+ if ((call_info->state != MM_CALL_STATE_TERMINATED) &&
+ (direction == MM_CALL_DIRECTION_INCOMING)) {
+ mm_dbg (" incoming refreshed");
+ mm_base_call_incoming_refresh (call);
+ }
+
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+typedef struct {
+ const MMCallInfo *call_info;
+} ReportCallForeachContext;
+
+static void
+report_call_foreach (MMBaseCall *call,
+ ReportCallForeachContext *ctx)
+{
+ /* Do nothing if already matched */
+ if (!ctx->call_info)
+ return;
+
+ /* fully ignore already terminated calls */
+ if (mm_base_call_get_state (call) == MM_CALL_STATE_TERMINATED)
+ return;
+
+ /* Reset call info in context if the call info matches an existing call */
+ if (match_single_call_info (ctx->call_info, call))
+ ctx->call_info = NULL;
+}
void
-mm_iface_modem_voice_report_incoming_call (MMIfaceModemVoice *self,
- const gchar *number,
- MMCallState state)
+mm_iface_modem_voice_report_call (MMIfaceModemVoice *self,
+ const MMCallInfo *call_info)
{
- MMBaseCall *call = NULL;
- MMCallList *list = NULL;
+ ReportCallForeachContext ctx = { 0 };
+ MMBaseCall *call = NULL;
+ MMCallList *list = NULL;
- g_assert (state == MM_CALL_STATE_RINGING_IN || state == MM_CALL_STATE_WAITING);
+ /* When reporting single call, the only mandatory parameter is the state:
+ * - index is optional (e.g. unavailable when receiving +CLIP URCs)
+ * - number is optional (e.g. unavailable when receiving +CRING URCs)
+ * - direction is optional (e.g. unavailable when receiving some vendor-specific URCs)
+ */
+ g_assert (call_info->state != MM_CALL_STATE_UNKNOWN);
+
+ /* Early debugging of the call state update */
+ mm_dbg ("call at index %u: direction %s, state %s, number %s",
+ call_info->index,
+ mm_call_direction_get_string (call_info->direction),
+ mm_call_state_get_string (call_info->state),
+ call_info->number ? call_info->number : "n/a");
g_object_get (MM_BASE_MODEM (self),
MM_IFACE_MODEM_VOICE_CALL_LIST, &list,
NULL);
if (!list) {
- mm_warn ("Cannot create incoming call: missing call list");
+ mm_warn ("Cannot process call state update: missing call list");
return;
}
- call = mm_call_list_get_first_incoming_call (list, state);
+ /* Iterate over all known calls and try to match a known one */
+ ctx.call_info = call_info;
+ mm_call_list_foreach (list, (MMCallListForeachFunc)report_call_foreach, &ctx);
- /* If call exists already, refresh its validity and set number if it wasn't set */
- if (call) {
- if (number && !mm_base_call_get_number (call))
- mm_base_call_set_number (call, number);
- mm_base_call_incoming_refresh (call);
- g_object_unref (list);
- return;
+ /* If call info matched with an existing one, the context call info would have been reseted */
+ if (!ctx.call_info)
+ goto out;
+
+ /* If call info didn't match with any known call, it may be because we're being
+ * reported a NEW incoming call. If that's not the case, we'll ignore the report. */
+ if ((call_info->direction != MM_CALL_DIRECTION_INCOMING) ||
+ ((call_info->state != MM_CALL_STATE_WAITING) && (call_info->state != MM_CALL_STATE_RINGING_IN))) {
+ mm_dbg ("unhandled call state update reported: direction: %s, state %s",
+ mm_call_direction_get_string (call_info->direction),
+ mm_call_state_get_string (call_info->state));
+ goto out;
}
mm_dbg ("Creating new incoming call...");
- call = create_incoming_call (self, number);
+ call = create_incoming_call (self, call_info->number);
/* Set the state */
- mm_base_call_change_state (call, state, MM_CALL_STATE_REASON_INCOMING_NEW);
+ mm_base_call_change_state (call, call_info->state, MM_CALL_STATE_REASON_INCOMING_NEW);
+
+ /* Set the index, if known */
+ if (call_info->index)
+ mm_base_call_set_index (call, call_info->index);
/* Start its validity timeout */
mm_base_call_incoming_refresh (call);
@@ -129,6 +256,8 @@ mm_iface_modem_voice_report_incoming_call (MMIfaceModemVoice *self,
mm_base_call_export (call);
mm_call_list_add_call (list, call);
g_object_unref (call);
+
+ out:
g_object_unref (list);
}
@@ -155,61 +284,18 @@ static void
report_all_calls_foreach (MMBaseCall *call,
ReportAllCallsForeachContext *ctx)
{
- GList *l;
- MMCallState state;
- MMCallDirection direction;
- const gchar *number;
- guint idx;
+ GList *l;
/* fully ignore already terminated calls */
- state = mm_base_call_get_state (call);
- if (state == MM_CALL_STATE_TERMINATED)
+ if (mm_base_call_get_state (call) == MM_CALL_STATE_TERMINATED)
return;
- /* try to look for a matching call by direction/number/index */
- direction = mm_base_call_get_direction (call);
- number = mm_base_call_get_number (call);
- idx = mm_base_call_get_index (call);
+ /* Iterate over the call info list */
for (l = ctx->call_info_list; l; l = g_list_next (l)) {
MMCallInfo *call_info = (MMCallInfo *)(l->data);
- /* Early detect if a known incoming call that was created
- * from a plain CRING URC (i.e. without caller number)
- * needs to have the number provided. We match by state
- * as well as there may be different types of incoming
- * calls reported here (e.g. ringing, waiting).
- */
- if ((direction == MM_CALL_DIRECTION_INCOMING) &&
- (call_info->direction == direction) &&
- (call_info->state == state) &&
- (call_info->number && !number))
- mm_base_call_set_number (call, call_info->number);
-
- /* Early detect if a known incoming/outgoing call does
- * not have a known call index yet.
- */
- if ((call_info->direction == direction) &&
- (call_info->state == state) &&
- (call_info->index && !idx)) {
- mm_base_call_set_index (call, call_info->index);
- idx = call_info->index; /* so that we match next properly */
- }
-
- /* Exact match? note that if both numbers are NULL, it will
- * also match (e.g. if network doesn't report the caller number).
- */
- if ((call_info->direction == direction) &&
- (g_strcmp0 (call_info->number, number) == 0) &&
- (call_info->index == idx)) {
- /* Update state if it changed */
- if (state != call_info->state)
- mm_base_call_change_state (call, call_info->state, MM_CALL_STATE_REASON_UNKNOWN);
- /* refresh if incoming and new state is not terminated */
- if ((call_info->state != MM_CALL_STATE_TERMINATED) &&
- (direction == MM_CALL_DIRECTION_INCOMING)) {
- mm_base_call_incoming_refresh (call);
- }
- /* delete item from list and halt iteration right away */
+ /* if match found, delete item from list and halt iteration right away */
+ if (match_single_call_info (call_info, call)) {
ctx->call_info_list = g_list_delete_link (ctx->call_info_list, l);
return;
}
@@ -232,6 +318,10 @@ mm_iface_modem_voice_report_all_calls (MMIfaceModemVoice *self,
for (l = call_info_list; l; l = g_list_next (l)) {
MMCallInfo *call_info = (MMCallInfo *)(l->data);
+ /* When reporting full list of calls, index and state are mandatory */
+ g_assert (call_info->index != 0);
+ g_assert (call_info->state != MM_CALL_STATE_UNKNOWN);
+
mm_dbg ("call at index %u: direction %s, state %s, number %s",
call_info->index,
mm_call_direction_get_string (call_info->direction),
diff --git a/src/mm-iface-modem-voice.h b/src/mm-iface-modem-voice.h
index 7cc82601..0e91d7c7 100644
--- a/src/mm-iface-modem-voice.h
+++ b/src/mm-iface-modem-voice.h
@@ -194,10 +194,9 @@ void mm_iface_modem_voice_shutdown (MMIfaceModemVoice *self);
void mm_iface_modem_voice_bind_simple_status (MMIfaceModemVoice *self,
MMSimpleStatus *status);
-/* Incoming call reporting */
-void mm_iface_modem_voice_report_incoming_call (MMIfaceModemVoice *self,
- const gchar *number,
- MMCallState state);
+/* Single call info reporting */
+void mm_iface_modem_voice_report_call (MMIfaceModemVoice *self,
+ const MMCallInfo *call_info);
/* Full current call list reporting (MMCallInfo list) */
void mm_iface_modem_voice_report_all_calls (MMIfaceModemVoice *self,