iface-modem-voice: allow reporting the state of all ongoing calls

E.g. as per the AT+CLCC output.
This commit is contained in:
Aleksander Morgado
2019-07-11 23:00:50 +02:00
parent 1cc31df425
commit ca88cdb9f7
2 changed files with 179 additions and 4 deletions
+173 -2
View File
@@ -94,8 +94,8 @@ mm_iface_modem_voice_report_incoming_call (MMIfaceModemVoice *self,
/* If call exists already, refresh its validity and set number if it wasn't set */
if (call) {
if (number && !mm_gdbus_call_get_number (MM_GDBUS_CALL (call)))
mm_gdbus_call_set_number (MM_GDBUS_CALL (call), number);
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;
@@ -117,6 +117,177 @@ mm_iface_modem_voice_report_incoming_call (MMIfaceModemVoice *self,
g_object_unref (list);
}
/*****************************************************************************/
/* Full current call list reporting
*
* This method receives as input a list with all the currently active calls,
* including the specific state they're in.
*
* This method should:
* - Check whether we're reporting a new call (i.e. not in our internal call
* list yet). We'll create a new call object if so.
* - Check whether any of the known calls has changed state, and if so,
* update it.
* - Check whether any of the known calls is NOT given in the input list of
* call infos, which would mean the call is terminated.
*/
typedef struct {
GList *call_info_list;
} ReportAllCallsForeachContext;
static void
report_all_calls_foreach (MMBaseCall *call,
ReportAllCallsForeachContext *ctx)
{
GList *l;
MMCallState state;
MMCallDirection direction;
const gchar *number;
guint idx;
/* fully ignore already terminated calls */
state = mm_base_call_get_state (call);
if (state == 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);
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 */
ctx->call_info_list = g_list_delete_link (ctx->call_info_list, l);
return;
}
}
/* not found in list! this call is now terminated */
mm_base_call_change_state (call, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_UNKNOWN);
}
void
mm_iface_modem_voice_report_all_calls (MMIfaceModemVoice *self,
GList *call_info_list)
{
ReportAllCallsForeachContext ctx = { 0 };
MMCallList *list = NULL;
GList *l;
/* Early debugging of the full list of calls */
mm_dbg ("Reported %u ongoing calls", g_list_length (call_info_list));
for (l = call_info_list; l; l = g_list_next (l)) {
MMCallInfo *call_info = (MMCallInfo *)(l->data);
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");
}
/* Retrieve list of known calls */
g_object_get (MM_BASE_MODEM (self),
MM_IFACE_MODEM_VOICE_CALL_LIST, &list,
NULL);
if (!list) {
mm_warn ("Cannot report all calls: missing call list");
return;
}
/* Iterate over all the calls already known to us.
* Whenever a known call is updated, it will be removed from the call info list */
ctx.call_info_list = g_list_copy (call_info_list);
mm_call_list_foreach (list, (MMCallListForeachFunc)report_all_calls_foreach, &ctx);
/* Once processed, the call info list will have all calls that were unknown to
* us, i.e. the new calls to create. We really only expect new incoming calls, so
* we'll warn if we get any outgoing call reported here. */
for (l = ctx.call_info_list; l; l = g_list_next (l)) {
MMCallInfo *call_info = (MMCallInfo *)(l->data);
if (call_info->direction == MM_CALL_DIRECTION_OUTGOING) {
mm_warn ("unexpected outgoing call to number '%s' reported in call list: state %s",
call_info->number ? call_info->number : "n/a",
mm_call_state_get_string (call_info->state));
continue;
}
if (call_info->direction == MM_CALL_DIRECTION_INCOMING) {
MMBaseCall *call;
/* We only expect either RINGING-IN or WAITING states */
if ((call_info->state != MM_CALL_STATE_RINGING_IN) &&
(call_info->state != MM_CALL_STATE_WAITING)) {
mm_warn ("unexpected incoming call to number '%s' reported in call list: state %s",
call_info->number ? call_info->number : "n/a",
mm_call_state_get_string (call_info->state));
continue;
}
mm_dbg ("Creating new incoming call...");
call = create_incoming_call (self, call_info->number);
/* Set the state and the index */
mm_base_call_change_state (call, call_info->state, MM_CALL_STATE_REASON_INCOMING_NEW);
mm_base_call_set_index (call, call_info->index);
/* Start its validity timeout */
mm_base_call_incoming_refresh (call);
/* Only export once properly created */
mm_base_call_export (call);
mm_call_list_add_call (list, call);
g_object_unref (call);
continue;
}
mm_warn ("unexpected call to number '%s' reported in call list: state %s, direction unknown",
call_info->number ? call_info->number : "n/a",
mm_call_state_get_string (call_info->state));
}
g_list_free (ctx.call_info_list);
g_object_unref (list);
}
/*****************************************************************************/
typedef struct {
+6 -2
View File
@@ -116,11 +116,15 @@ void mm_iface_modem_voice_shutdown (MMIfaceModemVoice *self);
/* Bind properties for simple GetStatus() */
void mm_iface_modem_voice_bind_simple_status (MMIfaceModemVoice *self,
MMSimpleStatus *status);
MMSimpleStatus *status);
/* Incoming call management */
/* Incoming call reporting */
void mm_iface_modem_voice_report_incoming_call (MMIfaceModemVoice *self,
const gchar *number,
MMCallState state);
/* Full current call list reporting (MMCallInfo list) */
void mm_iface_modem_voice_report_all_calls (MMIfaceModemVoice *self,
GList *call_info_list);
#endif /* MM_IFACE_MODEM_VOICE_H */