base-call: automatically terminate unanswered incoming calls

Try to automatically detect when the caller finishes the attempt to
establish the call.
This commit is contained in:
Aleksander Morgado
2018-06-14 15:36:06 +02:00
committed by Dan Williams
parent 0090124ec0
commit bd3b5aca01
7 changed files with 110 additions and 59 deletions

View File

@@ -57,8 +57,37 @@ struct _MMBaseCallPrivate {
/* Features */ /* Features */
gboolean supports_dialing_to_ringing; gboolean supports_dialing_to_ringing;
gboolean supports_ringing_to_active; gboolean supports_ringing_to_active;
guint incoming_timeout;
}; };
/*****************************************************************************/
/* Incoming calls are reported via RING URCs. If the caller stops the call
* attempt before it has been answered, the only thing we would see is that the
* URCs are no longer received. So, we will start a timeout whenever a new RING
* URC is received, and we refresh the timeout any time a new URC arrives. If
* the timeout is expired (meaning no URCs were received in the last N seconds)
* then we assume the call attempt is finished and we transition to TERMINATED.
*/
#define INCOMING_TIMEOUT_SECS 5
static gboolean
incoming_timeout_cb (MMBaseCall *self)
{
self->priv->incoming_timeout = 0;
mm_base_call_change_state (self, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_TERMINATED);
return G_SOURCE_REMOVE;
}
void
mm_base_call_incoming_refresh (MMBaseCall *self)
{
if (self->priv->incoming_timeout)
g_source_remove (self->priv->incoming_timeout);
self->priv->incoming_timeout = g_timeout_add_seconds (INCOMING_TIMEOUT_SECS, (GSourceFunc)incoming_timeout_cb, self);
}
/*****************************************************************************/ /*****************************************************************************/
/* Start call (DBus call handling) */ /* Start call (DBus call handling) */
@@ -205,6 +234,10 @@ handle_accept_ready (MMBaseCall *self,
mm_base_call_change_state (self, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_ERROR); mm_base_call_change_state (self, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_ERROR);
g_dbus_method_invocation_take_error (ctx->invocation, error); g_dbus_method_invocation_take_error (ctx->invocation, error);
} else { } else {
if (ctx->self->priv->incoming_timeout) {
g_source_remove (ctx->self->priv->incoming_timeout);
ctx->self->priv->incoming_timeout = 0;
}
mm_base_call_change_state (self, MM_CALL_STATE_ACTIVE, MM_CALL_STATE_REASON_ACCEPTED); mm_base_call_change_state (self, MM_CALL_STATE_ACTIVE, MM_CALL_STATE_REASON_ACCEPTED);
mm_gdbus_call_complete_accept (MM_GDBUS_CALL (ctx->self), ctx->invocation); mm_gdbus_call_complete_accept (MM_GDBUS_CALL (ctx->self), ctx->invocation);
} }
@@ -305,8 +338,13 @@ handle_hangup_ready (MMBaseCall *self,
if (!MM_BASE_CALL_GET_CLASS (self)->hangup_finish (self, res, &error)) if (!MM_BASE_CALL_GET_CLASS (self)->hangup_finish (self, res, &error))
g_dbus_method_invocation_take_error (ctx->invocation, error); g_dbus_method_invocation_take_error (ctx->invocation, error);
else else {
if (ctx->self->priv->incoming_timeout) {
g_source_remove (ctx->self->priv->incoming_timeout);
ctx->self->priv->incoming_timeout = 0;
}
mm_gdbus_call_complete_hangup (MM_GDBUS_CALL (ctx->self), ctx->invocation); mm_gdbus_call_complete_hangup (MM_GDBUS_CALL (ctx->self), ctx->invocation);
}
handle_hangup_context_free (ctx); handle_hangup_context_free (ctx);
} }
@@ -963,6 +1001,11 @@ dispose (GObject *object)
{ {
MMBaseCall *self = MM_BASE_CALL (object); MMBaseCall *self = MM_BASE_CALL (object);
if (self->priv->incoming_timeout) {
g_source_remove (self->priv->incoming_timeout);
self->priv->incoming_timeout = 0;
}
if (self->priv->connection) { if (self->priv->connection) {
/* If we arrived here with a valid connection, make sure we unexport /* If we arrived here with a valid connection, make sure we unexport
* the object */ * the object */

View File

@@ -97,13 +97,17 @@ MMBaseCall *mm_base_call_new_from_properties (MMBaseModem *modem,
MMCallProperties *properties, MMCallProperties *properties,
GError **error); GError **error);
void mm_base_call_export (MMBaseCall *self); void mm_base_call_export (MMBaseCall *self);
void mm_base_call_unexport (MMBaseCall *self); void mm_base_call_unexport (MMBaseCall *self);
const gchar *mm_base_call_get_path (MMBaseCall *self); const gchar *mm_base_call_get_path (MMBaseCall *self);
void mm_base_call_change_state (MMBaseCall *self,
MMCallState new_state, void mm_base_call_change_state (MMBaseCall *self,
MMCallStateReason reason); MMCallState new_state,
void mm_base_call_received_dtmf (MMBaseCall *self, MMCallStateReason reason);
const gchar *dtmf);
void mm_base_call_received_dtmf (MMBaseCall *self,
const gchar *dtmf);
void mm_base_call_incoming_refresh (MMBaseCall *self);
#endif /* MM_BASE_CALL_H */ #endif /* MM_BASE_CALL_H */

View File

@@ -6928,7 +6928,7 @@ ring_received (MMPortSerialAt *port,
MMBroadbandModem *self) MMBroadbandModem *self)
{ {
mm_dbg ("Ringing"); mm_dbg ("Ringing");
mm_iface_modem_voice_create_incoming_call (MM_IFACE_MODEM_VOICE (self)); mm_iface_modem_voice_incoming_call (MM_IFACE_MODEM_VOICE (self));
} }
static void static void
@@ -6945,7 +6945,7 @@ cring_received (MMPortSerialAt *port,
mm_dbg ("Ringing (%s)", str); mm_dbg ("Ringing (%s)", str);
g_free (str); g_free (str);
mm_iface_modem_voice_create_incoming_call (MM_IFACE_MODEM_VOICE (self)); mm_iface_modem_voice_incoming_call (MM_IFACE_MODEM_VOICE (self));
} }
static void static void

View File

@@ -84,36 +84,33 @@ mm_call_list_get_paths (MMCallList *self)
/*****************************************************************************/ /*****************************************************************************/
MMBaseCall * MMBaseCall *
mm_call_list_get_new_incoming (MMCallList *self) mm_call_list_get_first_ringing_in_call (MMCallList *self)
{ {
MMBaseCall *call = NULL;
GList *l; GList *l;
for (l = self->priv->list; l; l = g_list_next (l)) { for (l = self->priv->list; l; l = g_list_next (l)) {
MMBaseCall *call;
MMCallState state; MMCallState state;
MMCallStateReason reason; MMCallDirection direction;
MMCallDirection direct;
g_object_get (MM_BASE_CALL (l->data), call = MM_BASE_CALL (l->data);
"state", &state,
"state-reason", &reason, g_object_get (call,
"direction", &direct, "state", &state,
"direction", &direction,
NULL); NULL);
if (direct == MM_CALL_DIRECTION_INCOMING && if (direction == MM_CALL_DIRECTION_INCOMING &&
state == MM_CALL_STATE_RINGING_IN && state == MM_CALL_STATE_RINGING_IN) {
reason == MM_CALL_STATE_REASON_INCOMING_NEW ) { return call;
call = MM_BASE_CALL (l->data);
break;
} }
} }
return call; return NULL;
} }
MMBaseCall * MMBaseCall *
mm_call_list_get_first_ringing_call (MMCallList *self) mm_call_list_get_first_ringing_out_call (MMCallList *self)
{ {
MMBaseCall *call = NULL; MMBaseCall *call = NULL;
GList *l; GList *l;

View File

@@ -68,11 +68,11 @@ gboolean mm_call_list_delete_call (MMCallList *self,
const gchar *call_path, const gchar *call_path,
GError **error); GError **error);
MMBaseCall *mm_call_list_get_new_incoming (MMCallList *self); MMBaseCall *mm_call_list_get_first_ringing_in_call (MMCallList *self);
MMBaseCall *mm_call_list_get_first_ringing_call (MMCallList *self); MMBaseCall *mm_call_list_get_first_ringing_out_call (MMCallList *self);
MMBaseCall *mm_call_list_get_first_outgoing_dialing_call(MMCallList *self); MMBaseCall *mm_call_list_get_first_outgoing_dialing_call (MMCallList *self);
MMBaseCall *mm_call_list_get_first_non_terminated_call (MMCallList *self); MMBaseCall *mm_call_list_get_first_non_terminated_call (MMCallList *self);
gboolean mm_call_list_send_dtmf_to_active_calls (MMCallList *self, gboolean mm_call_list_send_dtmf_to_active_calls (MMCallList *self,
const gchar *dtmf); const gchar *dtmf);
#endif /* MM_CALL_LIST_H */ #endif /* MM_CALL_LIST_H */

View File

@@ -46,8 +46,8 @@ mm_iface_modem_voice_create_call (MMIfaceModemVoice *self)
return MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->create_call (self); return MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->create_call (self);
} }
MMBaseCall * void
mm_iface_modem_voice_create_incoming_call (MMIfaceModemVoice *self) mm_iface_modem_voice_incoming_call (MMIfaceModemVoice *self)
{ {
MMBaseCall *call = NULL; MMBaseCall *call = NULL;
MMCallList *list = NULL; MMCallList *list = NULL;
@@ -56,29 +56,36 @@ mm_iface_modem_voice_create_incoming_call (MMIfaceModemVoice *self)
MM_IFACE_MODEM_VOICE_CALL_LIST, &list, MM_IFACE_MODEM_VOICE_CALL_LIST, &list,
NULL); NULL);
if (list) { if (!list) {
call = mm_call_list_get_new_incoming (list); mm_warn ("Cannot create incoming call: missing call list");
return;
if (!call) {
mm_dbg ("Creating new incoming call...");
call = mm_base_call_new (MM_BASE_MODEM (self));
g_object_set (call,
"state", MM_CALL_STATE_RINGING_IN,
"state-reason", MM_CALL_STATE_REASON_INCOMING_NEW,
"direction", MM_CALL_DIRECTION_INCOMING,
NULL);
/* Only export once properly created */
mm_base_call_export (call);
mm_call_list_add_call (list, call);
g_object_unref (call);
}
g_object_unref (list);
} }
return call; call = mm_call_list_get_first_ringing_in_call (list);
/* If call exists already, refresh its validity */
if (call) {
mm_base_call_incoming_refresh (call);
g_object_unref (list);
return;
}
mm_dbg ("Creating new incoming call...");
call = mm_base_call_new (MM_BASE_MODEM (self));
g_object_set (call,
"state", MM_CALL_STATE_RINGING_IN,
"state-reason", MM_CALL_STATE_REASON_INCOMING_NEW,
"direction", MM_CALL_DIRECTION_INCOMING,
NULL);
/* 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);
g_object_unref (list);
} }
gboolean gboolean
@@ -96,7 +103,7 @@ mm_iface_modem_voice_update_incoming_call_number (MMIfaceModemVoice *self,
NULL); NULL);
if (list) { if (list) {
call = mm_call_list_get_new_incoming (list); call = mm_call_list_get_first_ringing_in_call (list);
if (call) { if (call) {
mm_gdbus_call_set_number (MM_GDBUS_CALL (call), number); mm_gdbus_call_set_number (MM_GDBUS_CALL (call), number);
@@ -153,7 +160,7 @@ mm_iface_modem_voice_call_ringing_to_active (MMIfaceModemVoice *self)
NULL); NULL);
if (list) { if (list) {
call = mm_call_list_get_first_ringing_call (list); call = mm_call_list_get_first_ringing_out_call (list);
if (call) { if (call) {
mm_base_call_change_state (call, MM_CALL_STATE_ACTIVE, MM_CALL_STATE_REASON_ACCEPTED); mm_base_call_change_state (call, MM_CALL_STATE_ACTIVE, MM_CALL_STATE_REASON_ACCEPTED);

View File

@@ -118,7 +118,7 @@ void mm_iface_modem_voice_bind_simple_status (MMIfaceModemVoice *self,
/* CALL creation */ /* CALL creation */
MMBaseCall *mm_iface_modem_voice_create_call (MMIfaceModemVoice *self); MMBaseCall *mm_iface_modem_voice_create_call (MMIfaceModemVoice *self);
MMBaseCall *mm_iface_modem_voice_create_incoming_call (MMIfaceModemVoice *self); void mm_iface_modem_voice_incoming_call (MMIfaceModemVoice *self);
gboolean mm_iface_modem_voice_update_incoming_call_number (MMIfaceModemVoice *self, gboolean mm_iface_modem_voice_update_incoming_call_number (MMIfaceModemVoice *self,
gchar *number, gchar *number,
guint type, guint type,