diff --git a/plugins/huawei/mm-call-huawei.c b/plugins/huawei/mm-call-huawei.c index ee8c3f79a25da4c27dfb8ec899fbd91e0a8b1889..f1c4b13310e90467db3d761710081693b6946d92 100644 --- a/plugins/huawei/mm-call-huawei.c +++ b/plugins/huawei/mm-call-huawei.c @@ -139,5 +139,7 @@ mm_call_huawei_class_init (MMCallHuaweiClass *klass) { MMBaseCallClass *base_call_class = MM_BASE_CALL_CLASS (klass); - base_call_class->start = call_start; + base_call_class->start = call_start; + base_call_class->setup_unsolicited_events = NULL; + base_call_class->cleanup_unsolicited_events = NULL; } diff --git a/src/mm-base-call.c b/src/mm-base-call.c index dfbdb702191588815a2c0fed9ec83ace68de0a49..949e7ccb222f042f849c64f3811cea38357a44b7 100644 --- a/src/mm-base-call.c +++ b/src/mm-base-call.c @@ -59,8 +59,82 @@ struct _MMBaseCallPrivate { gboolean supports_ringing_to_active; guint incoming_timeout; + GRegex *in_call_events; }; +/*****************************************************************************/ +/* In-call unsolicited events + * Once a call is started, we may need to detect special URCs to trigger call + * state changes, e.g. "NO CARRIER" when the remote party hangs up. */ + +static void +in_call_event_received (MMPortSerialAt *port, + GMatchInfo *info, + MMBaseCall *self) +{ + gchar *str; + + str = g_match_info_fetch (info, 1); + if (!str) + return; + + if (!strcmp (str, "NO DIALTONE")) + mm_base_call_change_state (self, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_ERROR); + else if (!strcmp (str, "NO CARRIER") || !strcmp (str, "BUSY") || !strcmp (str, "NO ANSWER")) + mm_base_call_change_state (self, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_REFUSED_OR_BUSY); + + g_free (str); +} + +static gboolean +common_setup_cleanup_unsolicited_events (MMBaseCall *self, + gboolean enable, + GError **error) +{ + MMBaseModem *modem = NULL; + MMPortSerialAt *ports[2]; + gint i; + + if (G_UNLIKELY (!self->priv->in_call_events)) + self->priv->in_call_events = g_regex_new ("\\r\\n(NO CARRIER)|(BUSY)|(NO ANSWER)|(NO DIALTONE)\\r\\n$", + G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL); + + g_object_get (self, + MM_BASE_CALL_MODEM, &modem, + NULL); + + ports[0] = mm_base_modem_peek_port_primary (modem); + ports[1] = mm_base_modem_peek_port_secondary (modem); + + for (i = 0; i < G_N_ELEMENTS (ports); i++) { + if (!ports[i]) + continue; + + mm_port_serial_at_add_unsolicited_msg_handler (ports[i], + self->priv->in_call_events, + enable ? (MMPortSerialAtUnsolicitedMsgFn) in_call_event_received : NULL, + enable ? self : NULL, + NULL); + } + + g_object_unref (modem); + return TRUE; +} + +static gboolean +setup_unsolicited_events (MMBaseCall *self, + GError **error) +{ + return common_setup_cleanup_unsolicited_events (self, TRUE, error); +} + +static gboolean +cleanup_unsolicited_events (MMBaseCall *self, + GError **error) +{ + return common_setup_cleanup_unsolicited_events (self, FALSE, error); +} + /*****************************************************************************/ /* 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 @@ -991,6 +1065,8 @@ finalize (GObject *object) { MMBaseCall *self = MM_BASE_CALL (object); + if (self->priv->in_call_events) + g_regex_unref (self->priv->in_call_events); g_free (self->priv->path); G_OBJECT_CLASS (mm_base_call_parent_class)->finalize (object); @@ -1031,14 +1107,17 @@ mm_base_call_class_init (MMBaseCallClass *klass) object_class->finalize = finalize; object_class->dispose = dispose; - klass->start = call_start; - klass->start_finish = call_start_finish; - klass->accept = call_accept; - klass->accept_finish = call_accept_finish; - klass->hangup = call_hangup; - klass->hangup_finish = call_hangup_finish; - klass->send_dtmf = call_send_dtmf; - klass->send_dtmf_finish = call_send_dtmf_finish; + klass->start = call_start; + klass->start_finish = call_start_finish; + klass->accept = call_accept; + klass->accept_finish = call_accept_finish; + klass->hangup = call_hangup; + klass->hangup_finish = call_hangup_finish; + klass->send_dtmf = call_send_dtmf; + klass->send_dtmf_finish = call_send_dtmf_finish; + klass->setup_unsolicited_events = setup_unsolicited_events; + klass->cleanup_unsolicited_events = cleanup_unsolicited_events; + properties[PROP_CONNECTION] = g_param_spec_object (MM_BASE_CALL_CONNECTION,