huawei,call: handle in-call URCs in the call object itself
Instead of handling the URCs in the modem object and using the MMIfaceModem as a bridge to report the status read from the URC to a call obtained from the MMCallList... just handle the URCs in the call object itself.
This commit is contained in:

committed by
Dan Williams

parent
f71e120fb7
commit
fc0feee654
@@ -103,12 +103,6 @@ struct _MMBroadbandModemHuaweiPrivate {
|
|||||||
GRegex *dsflowrpt_regex;
|
GRegex *dsflowrpt_regex;
|
||||||
GRegex *ndisstat_regex;
|
GRegex *ndisstat_regex;
|
||||||
|
|
||||||
/* Regex for voice call related notifications */
|
|
||||||
GRegex *conf_regex;
|
|
||||||
GRegex *conn_regex;
|
|
||||||
GRegex *cend_regex;
|
|
||||||
GRegex *ddtmf_regex;
|
|
||||||
|
|
||||||
/* Regex to ignore */
|
/* Regex to ignore */
|
||||||
GRegex *boot_regex;
|
GRegex *boot_regex;
|
||||||
GRegex *connect_regex;
|
GRegex *connect_regex;
|
||||||
@@ -151,8 +145,8 @@ struct _MMBroadbandModemHuaweiPrivate {
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static GList *
|
GList *
|
||||||
get_at_port_list (MMBroadbandModemHuawei *self)
|
mm_broadband_modem_huawei_get_at_port_list (MMBroadbandModemHuawei *self)
|
||||||
{
|
{
|
||||||
GList *out = NULL;
|
GList *out = NULL;
|
||||||
MMPortSerialAt *port;
|
MMPortSerialAt *port;
|
||||||
@@ -1853,7 +1847,7 @@ set_3gpp_unsolicited_events_handlers (MMBroadbandModemHuawei *self,
|
|||||||
{
|
{
|
||||||
GList *ports, *l;
|
GList *ports, *l;
|
||||||
|
|
||||||
ports = get_at_port_list (self);
|
ports = mm_broadband_modem_huawei_get_at_port_list (self);
|
||||||
|
|
||||||
/* Enable/disable unsolicited events in given port */
|
/* Enable/disable unsolicited events in given port */
|
||||||
for (l = ports; l; l = g_list_next (l)) {
|
for (l = ports; l; l = g_list_next (l)) {
|
||||||
@@ -2517,7 +2511,7 @@ set_cdma_unsolicited_events_handlers (MMBroadbandModemHuawei *self,
|
|||||||
{
|
{
|
||||||
GList *ports, *l;
|
GList *ports, *l;
|
||||||
|
|
||||||
ports = get_at_port_list (self);
|
ports = mm_broadband_modem_huawei_get_at_port_list (self);
|
||||||
|
|
||||||
/* Enable/disable unsolicited events in given port */
|
/* Enable/disable unsolicited events in given port */
|
||||||
for (l = ports; l; l = g_list_next (l)) {
|
for (l = ports; l; l = g_list_next (l)) {
|
||||||
@@ -2862,200 +2856,6 @@ get_detailed_registration_state (MMIfaceModemCdma *self,
|
|||||||
task);
|
task);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
|
||||||
/* Setup/Cleanup unsolicited events (Voice interface) */
|
|
||||||
|
|
||||||
static void
|
|
||||||
huawei_voice_ringback_tone (MMPortSerialAt *port,
|
|
||||||
GMatchInfo *match_info,
|
|
||||||
MMBroadbandModemHuawei *self)
|
|
||||||
{
|
|
||||||
guint call_x = 0;
|
|
||||||
|
|
||||||
if (!mm_get_uint_from_match_info (match_info, 1, &call_x))
|
|
||||||
return;
|
|
||||||
|
|
||||||
mm_dbg ("[^CONF] Ringback tone from call id '%u'", call_x);
|
|
||||||
|
|
||||||
mm_iface_modem_voice_call_dialing_to_ringing (MM_IFACE_MODEM_VOICE (self));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
huawei_voice_call_connection (MMPortSerialAt *port,
|
|
||||||
GMatchInfo *match_info,
|
|
||||||
MMBroadbandModemHuawei *self)
|
|
||||||
{
|
|
||||||
guint call_x = 0;
|
|
||||||
guint call_type = 0;
|
|
||||||
|
|
||||||
if (!mm_get_uint_from_match_info (match_info, 1, &call_x))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!mm_get_uint_from_match_info (match_info, 2, &call_type))
|
|
||||||
return;
|
|
||||||
|
|
||||||
mm_dbg ("[^CONN] Call id '%u' of type '%u' connected", call_x, call_type);
|
|
||||||
|
|
||||||
mm_iface_modem_voice_call_ringing_to_active (MM_IFACE_MODEM_VOICE (self));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
huawei_voice_call_end (MMPortSerialAt *port,
|
|
||||||
GMatchInfo *match_info,
|
|
||||||
MMBroadbandModemHuawei *self)
|
|
||||||
{
|
|
||||||
guint call_x = 0;
|
|
||||||
guint duration = 0;
|
|
||||||
guint cc_cause = 0;
|
|
||||||
guint end_status = 0;
|
|
||||||
|
|
||||||
if (!mm_get_uint_from_match_info (match_info, 1, &call_x))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!mm_get_uint_from_match_info (match_info, 2, &duration))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!mm_get_uint_from_match_info (match_info, 3, &end_status))
|
|
||||||
return;
|
|
||||||
|
|
||||||
//This is optional
|
|
||||||
mm_get_uint_from_match_info (match_info, 4, &cc_cause);
|
|
||||||
|
|
||||||
mm_dbg ("[^CEND] Call '%u' terminated with status '%u' and cause '%u'. Duration of call '%d'", call_x, end_status, cc_cause, duration);
|
|
||||||
|
|
||||||
mm_iface_modem_voice_network_hangup (MM_IFACE_MODEM_VOICE (self));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
huawei_voice_received_dtmf (MMPortSerialAt *port,
|
|
||||||
GMatchInfo *match_info,
|
|
||||||
MMBroadbandModemHuawei *self)
|
|
||||||
{
|
|
||||||
gchar *key;
|
|
||||||
|
|
||||||
key = g_match_info_fetch (match_info, 1);
|
|
||||||
|
|
||||||
if (key) {
|
|
||||||
mm_dbg ("[^DDTMF] Received DTMF '%s'", key);
|
|
||||||
mm_iface_modem_voice_received_dtmf (MM_IFACE_MODEM_VOICE (self), key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
set_voice_unsolicited_events_handlers (MMBroadbandModemHuawei *self,
|
|
||||||
gboolean enable)
|
|
||||||
{
|
|
||||||
GList *ports, *l;
|
|
||||||
|
|
||||||
ports = get_at_port_list (self);
|
|
||||||
|
|
||||||
/* Enable/disable unsolicited events in given port */
|
|
||||||
for (l = ports; l; l = g_list_next (l)) {
|
|
||||||
MMPortSerialAt *port = MM_PORT_SERIAL_AT (l->data);
|
|
||||||
|
|
||||||
mm_port_serial_at_add_unsolicited_msg_handler (
|
|
||||||
port,
|
|
||||||
self->priv->conf_regex,
|
|
||||||
enable ? (MMPortSerialAtUnsolicitedMsgFn)huawei_voice_ringback_tone : NULL,
|
|
||||||
enable ? self : NULL,
|
|
||||||
NULL);
|
|
||||||
mm_port_serial_at_add_unsolicited_msg_handler (
|
|
||||||
port,
|
|
||||||
self->priv->conn_regex,
|
|
||||||
enable ? (MMPortSerialAtUnsolicitedMsgFn)huawei_voice_call_connection : NULL,
|
|
||||||
enable ? self : NULL,
|
|
||||||
NULL);
|
|
||||||
mm_port_serial_at_add_unsolicited_msg_handler (
|
|
||||||
port,
|
|
||||||
self->priv->cend_regex,
|
|
||||||
enable ? (MMPortSerialAtUnsolicitedMsgFn)huawei_voice_call_end : NULL,
|
|
||||||
enable ? self : NULL,
|
|
||||||
NULL);
|
|
||||||
mm_port_serial_at_add_unsolicited_msg_handler (
|
|
||||||
port,
|
|
||||||
self->priv->ddtmf_regex,
|
|
||||||
enable ? (MMPortSerialAtUnsolicitedMsgFn)huawei_voice_received_dtmf: NULL,
|
|
||||||
enable ? self : NULL,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_list_free_full (ports, g_object_unref);
|
|
||||||
}
|
|
||||||
|
|
||||||
static gboolean
|
|
||||||
modem_voice_setup_cleanup_unsolicited_events_finish (MMIfaceModemVoice *self,
|
|
||||||
GAsyncResult *res,
|
|
||||||
GError **error)
|
|
||||||
{
|
|
||||||
return g_task_propagate_boolean (G_TASK (res), error);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
parent_voice_setup_unsolicited_events_ready (MMIfaceModemVoice *self,
|
|
||||||
GAsyncResult *res,
|
|
||||||
GTask *task)
|
|
||||||
{
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
if (!iface_modem_voice_parent->setup_unsolicited_events_finish (self, res, &error))
|
|
||||||
g_task_return_error (task, error);
|
|
||||||
else {
|
|
||||||
/* Our own setup now */
|
|
||||||
set_voice_unsolicited_events_handlers (MM_BROADBAND_MODEM_HUAWEI (self), TRUE);
|
|
||||||
g_task_return_boolean (task, TRUE);
|
|
||||||
}
|
|
||||||
g_object_unref (task);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
modem_voice_setup_unsolicited_events (MMIfaceModemVoice *self,
|
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
GTask *task;
|
|
||||||
|
|
||||||
task = g_task_new (self, NULL, callback, user_data);
|
|
||||||
|
|
||||||
/* Chain up parent's setup */
|
|
||||||
iface_modem_voice_parent->setup_unsolicited_events (
|
|
||||||
self,
|
|
||||||
(GAsyncReadyCallback)parent_voice_setup_unsolicited_events_ready,
|
|
||||||
task);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
parent_voice_cleanup_unsolicited_events_ready (MMIfaceModemVoice *self,
|
|
||||||
GAsyncResult *res,
|
|
||||||
GTask *task)
|
|
||||||
{
|
|
||||||
GError *error = NULL;
|
|
||||||
|
|
||||||
if (!iface_modem_voice_parent->cleanup_unsolicited_events_finish (self, res, &error))
|
|
||||||
g_task_return_error (task, error);
|
|
||||||
else
|
|
||||||
g_task_return_boolean (task, TRUE);
|
|
||||||
g_object_unref (task);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
modem_voice_cleanup_unsolicited_events (MMIfaceModemVoice *self,
|
|
||||||
GAsyncReadyCallback callback,
|
|
||||||
gpointer user_data)
|
|
||||||
{
|
|
||||||
GTask *task;
|
|
||||||
|
|
||||||
task = g_task_new (self, NULL, callback, user_data);
|
|
||||||
|
|
||||||
/* Our own cleanup first */
|
|
||||||
set_voice_unsolicited_events_handlers (MM_BROADBAND_MODEM_HUAWEI (self), FALSE);
|
|
||||||
|
|
||||||
/* And now chain up parent's cleanup */
|
|
||||||
iface_modem_voice_parent->cleanup_unsolicited_events (
|
|
||||||
self,
|
|
||||||
(GAsyncReadyCallback)parent_voice_cleanup_unsolicited_events_ready,
|
|
||||||
task);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Enabling unsolicited events (Voice interface) */
|
/* Enabling unsolicited events (Voice interface) */
|
||||||
|
|
||||||
@@ -3275,7 +3075,7 @@ enable_disable_unsolicited_rfswitch_event_handler (MMBroadbandModemHuawei *self,
|
|||||||
{
|
{
|
||||||
GList *ports, *l;
|
GList *ports, *l;
|
||||||
|
|
||||||
ports = get_at_port_list (self);
|
ports = mm_broadband_modem_huawei_get_at_port_list (self);
|
||||||
|
|
||||||
mm_dbg ("%s ^RFSWITCH unsolicited event handler",
|
mm_dbg ("%s ^RFSWITCH unsolicited event handler",
|
||||||
enable ? "Enable" : "Disable");
|
enable ? "Enable" : "Disable");
|
||||||
@@ -4053,7 +3853,7 @@ set_ignored_unsolicited_events_handlers (MMBroadbandModemHuawei *self)
|
|||||||
{
|
{
|
||||||
GList *ports, *l;
|
GList *ports, *l;
|
||||||
|
|
||||||
ports = get_at_port_list (self);
|
ports = mm_broadband_modem_huawei_get_at_port_list (self);
|
||||||
|
|
||||||
/* Enable/disable unsolicited events in given port */
|
/* Enable/disable unsolicited events in given port */
|
||||||
for (l = ports; l; l = g_list_next (l)) {
|
for (l = ports; l; l = g_list_next (l)) {
|
||||||
@@ -4162,7 +3962,6 @@ setup_ports (MMBroadbandModem *self)
|
|||||||
/* Now reset the unsolicited messages we'll handle when enabled */
|
/* Now reset the unsolicited messages we'll handle when enabled */
|
||||||
set_3gpp_unsolicited_events_handlers (MM_BROADBAND_MODEM_HUAWEI (self), FALSE);
|
set_3gpp_unsolicited_events_handlers (MM_BROADBAND_MODEM_HUAWEI (self), FALSE);
|
||||||
set_cdma_unsolicited_events_handlers (MM_BROADBAND_MODEM_HUAWEI (self), FALSE);
|
set_cdma_unsolicited_events_handlers (MM_BROADBAND_MODEM_HUAWEI (self), FALSE);
|
||||||
set_voice_unsolicited_events_handlers(MM_BROADBAND_MODEM_HUAWEI (self), FALSE);
|
|
||||||
|
|
||||||
/* NMEA GPS monitoring */
|
/* NMEA GPS monitoring */
|
||||||
gps_data_port = mm_base_modem_peek_port_gps (MM_BASE_MODEM (self));
|
gps_data_port = mm_base_modem_peek_port_gps (MM_BASE_MODEM (self));
|
||||||
@@ -4259,28 +4058,8 @@ mm_broadband_modem_huawei_init (MMBroadbandModemHuawei *self)
|
|||||||
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||||
self->priv->eons_regex = g_regex_new ("\\r\\n\\^EONS:.+\\r\\n",
|
self->priv->eons_regex = g_regex_new ("\\r\\n\\^EONS:.+\\r\\n",
|
||||||
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||||
|
|
||||||
/* Voice related regex
|
|
||||||
* <CR><LF>^ORIG: <call_x>,<call_type><CR><LF> (ignored)
|
|
||||||
* <CR><LF>^CONF: <call_x><CR><LF>
|
|
||||||
* <CR><LF>^CONN: <call_x>,<call_type><CR><LF>
|
|
||||||
* <CR><LF>^CEND: <call_x>,<duration>,<end_status>[,<cc_cause>]<CR><LF>
|
|
||||||
*/
|
|
||||||
self->priv->orig_regex = g_regex_new ("\\r\\n\\^ORIG:.+\\r\\n",
|
self->priv->orig_regex = g_regex_new ("\\r\\n\\^ORIG:.+\\r\\n",
|
||||||
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||||
self->priv->conf_regex = g_regex_new ("\\r\\n\\^CONF:\\s*(\\d+)\\r\\n",
|
|
||||||
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
|
||||||
self->priv->conn_regex = g_regex_new ("\\r\\n\\^CONN:\\s*(\\d+),(\\d+)\\r\\n",
|
|
||||||
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
|
||||||
self->priv->cend_regex = g_regex_new ("\\r\\n\\^CEND:\\s*(\\d+),\\s*(\\d+),\\s*(\\d+),?\\s*(\\d*)\\r\\n",
|
|
||||||
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
|
||||||
|
|
||||||
/* Voice: receive DTMF regex
|
|
||||||
* <CR><LF>^DDTMF: <key><CR><LF>
|
|
||||||
* Key should be 0-9, A-D, *, #
|
|
||||||
*/
|
|
||||||
self->priv->ddtmf_regex = g_regex_new ("\\r\\n\\^DDTMF:\\s*([0-9A-D\\*\\#])\\r\\n",
|
|
||||||
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
|
||||||
|
|
||||||
self->priv->ndisdup_support = FEATURE_SUPPORT_UNKNOWN;
|
self->priv->ndisdup_support = FEATURE_SUPPORT_UNKNOWN;
|
||||||
self->priv->rfswitch_support = FEATURE_SUPPORT_UNKNOWN;
|
self->priv->rfswitch_support = FEATURE_SUPPORT_UNKNOWN;
|
||||||
@@ -4330,13 +4109,9 @@ finalize (GObject *object)
|
|||||||
g_regex_unref (self->priv->posend_regex);
|
g_regex_unref (self->priv->posend_regex);
|
||||||
g_regex_unref (self->priv->ecclist_regex);
|
g_regex_unref (self->priv->ecclist_regex);
|
||||||
g_regex_unref (self->priv->ltersrp_regex);
|
g_regex_unref (self->priv->ltersrp_regex);
|
||||||
g_regex_unref (self->priv->orig_regex);
|
|
||||||
g_regex_unref (self->priv->conf_regex);
|
|
||||||
g_regex_unref (self->priv->conn_regex);
|
|
||||||
g_regex_unref (self->priv->cend_regex);
|
|
||||||
g_regex_unref (self->priv->ddtmf_regex);
|
|
||||||
g_regex_unref (self->priv->cschannelinfo_regex);
|
g_regex_unref (self->priv->cschannelinfo_regex);
|
||||||
g_regex_unref (self->priv->eons_regex);
|
g_regex_unref (self->priv->eons_regex);
|
||||||
|
g_regex_unref (self->priv->orig_regex);
|
||||||
|
|
||||||
if (self->priv->syscfg_supported_modes)
|
if (self->priv->syscfg_supported_modes)
|
||||||
g_array_unref (self->priv->syscfg_supported_modes);
|
g_array_unref (self->priv->syscfg_supported_modes);
|
||||||
@@ -4451,10 +4226,6 @@ iface_modem_voice_init (MMIfaceModemVoice *iface)
|
|||||||
{
|
{
|
||||||
iface_modem_voice_parent = g_type_interface_peek_parent (iface);
|
iface_modem_voice_parent = g_type_interface_peek_parent (iface);
|
||||||
|
|
||||||
iface->setup_unsolicited_events = modem_voice_setup_unsolicited_events;
|
|
||||||
iface->setup_unsolicited_events_finish = modem_voice_setup_cleanup_unsolicited_events_finish;
|
|
||||||
iface->cleanup_unsolicited_events = modem_voice_cleanup_unsolicited_events;
|
|
||||||
iface->cleanup_unsolicited_events_finish = modem_voice_setup_cleanup_unsolicited_events_finish;
|
|
||||||
iface->enable_unsolicited_events = modem_voice_enable_unsolicited_events;
|
iface->enable_unsolicited_events = modem_voice_enable_unsolicited_events;
|
||||||
iface->enable_unsolicited_events_finish = modem_voice_enable_unsolicited_events_finish;
|
iface->enable_unsolicited_events_finish = modem_voice_enable_unsolicited_events_finish;
|
||||||
iface->disable_unsolicited_events = modem_voice_disable_unsolicited_events;
|
iface->disable_unsolicited_events = modem_voice_disable_unsolicited_events;
|
||||||
|
@@ -50,5 +50,6 @@ MMBroadbandModemHuawei *mm_broadband_modem_huawei_new (const gchar *device,
|
|||||||
|
|
||||||
MMPortSerialAt *mm_broadband_modem_huawei_peek_port_at_for_data (MMBroadbandModemHuawei *self,
|
MMPortSerialAt *mm_broadband_modem_huawei_peek_port_at_for_data (MMBroadbandModemHuawei *self,
|
||||||
MMPort *port);
|
MMPort *port);
|
||||||
|
GList *mm_broadband_modem_huawei_get_at_port_list (MMBroadbandModemHuawei *self);
|
||||||
|
|
||||||
#endif /* MM_BROADBAND_MODEM_HUAWEI_H */
|
#endif /* MM_BROADBAND_MODEM_HUAWEI_H */
|
||||||
|
@@ -26,10 +26,178 @@
|
|||||||
|
|
||||||
#include "mm-log.h"
|
#include "mm-log.h"
|
||||||
#include "mm-base-modem-at.h"
|
#include "mm-base-modem-at.h"
|
||||||
|
#include "mm-broadband-modem-huawei.h"
|
||||||
#include "mm-call-huawei.h"
|
#include "mm-call-huawei.h"
|
||||||
|
|
||||||
G_DEFINE_TYPE (MMCallHuawei, mm_call_huawei, MM_TYPE_BASE_CALL)
|
G_DEFINE_TYPE (MMCallHuawei, mm_call_huawei, MM_TYPE_BASE_CALL)
|
||||||
|
|
||||||
|
struct _MMCallHuaweiPrivate {
|
||||||
|
GRegex *conf_regex;
|
||||||
|
GRegex *conn_regex;
|
||||||
|
GRegex *cend_regex;
|
||||||
|
GRegex *ddtmf_regex;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* In-call unsolicited events */
|
||||||
|
|
||||||
|
static void
|
||||||
|
huawei_voice_ringback_tone (MMPortSerialAt *port,
|
||||||
|
GMatchInfo *match_info,
|
||||||
|
MMCallHuawei *self)
|
||||||
|
{
|
||||||
|
guint call_x = 0;
|
||||||
|
|
||||||
|
if (!mm_get_uint_from_match_info (match_info, 1, &call_x))
|
||||||
|
return;
|
||||||
|
|
||||||
|
mm_dbg ("Ringback tone from call id '%u'", call_x);
|
||||||
|
|
||||||
|
if (mm_gdbus_call_get_state (MM_GDBUS_CALL (self)) == MM_CALL_STATE_DIALING)
|
||||||
|
mm_base_call_change_state (MM_BASE_CALL (self), MM_CALL_STATE_RINGING_OUT, MM_CALL_STATE_REASON_OUTGOING_STARTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
huawei_voice_call_connection (MMPortSerialAt *port,
|
||||||
|
GMatchInfo *match_info,
|
||||||
|
MMCallHuawei *self)
|
||||||
|
{
|
||||||
|
guint call_x = 0;
|
||||||
|
guint call_type = 0;
|
||||||
|
|
||||||
|
if (!mm_get_uint_from_match_info (match_info, 1, &call_x))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!mm_get_uint_from_match_info (match_info, 2, &call_type))
|
||||||
|
return;
|
||||||
|
|
||||||
|
mm_dbg ("Call id '%u' of type '%u' connected", call_x, call_type);
|
||||||
|
|
||||||
|
if (mm_gdbus_call_get_state (MM_GDBUS_CALL (self)) == MM_CALL_STATE_RINGING_OUT)
|
||||||
|
mm_base_call_change_state (MM_BASE_CALL (self), MM_CALL_STATE_ACTIVE, MM_CALL_STATE_REASON_ACCEPTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
huawei_voice_call_end (MMPortSerialAt *port,
|
||||||
|
GMatchInfo *match_info,
|
||||||
|
MMCallHuawei *self)
|
||||||
|
{
|
||||||
|
guint call_x = 0;
|
||||||
|
guint duration = 0;
|
||||||
|
guint cc_cause = 0;
|
||||||
|
guint end_status = 0;
|
||||||
|
|
||||||
|
if (!mm_get_uint_from_match_info (match_info, 1, &call_x))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!mm_get_uint_from_match_info (match_info, 2, &duration))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!mm_get_uint_from_match_info (match_info, 3, &end_status))
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* This is optional */
|
||||||
|
mm_get_uint_from_match_info (match_info, 4, &cc_cause);
|
||||||
|
|
||||||
|
mm_dbg ("Call id '%u' terminated with status '%u' and cause '%u'. Duration of call '%d'",
|
||||||
|
call_x, end_status, cc_cause, duration);
|
||||||
|
|
||||||
|
mm_base_call_change_state (MM_BASE_CALL (self), MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_TERMINATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
huawei_voice_received_dtmf (MMPortSerialAt *port,
|
||||||
|
GMatchInfo *match_info,
|
||||||
|
MMCallHuawei *self)
|
||||||
|
{
|
||||||
|
gchar *key;
|
||||||
|
|
||||||
|
key = g_match_info_fetch (match_info, 1);
|
||||||
|
|
||||||
|
if (!key)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mm_dbg ("Received DTMF '%s'", key);
|
||||||
|
mm_base_call_received_dtmf (MM_BASE_CALL (self), key);
|
||||||
|
g_free (key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
common_setup_cleanup_unsolicited_events (MMCallHuawei *self,
|
||||||
|
gboolean enable,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
MMBaseModem *modem = NULL;
|
||||||
|
GList *ports, *l;
|
||||||
|
|
||||||
|
if (G_UNLIKELY (!self->priv->conf_regex))
|
||||||
|
self->priv->conf_regex = g_regex_new ("\\r\\n\\^CONF:\\s*(\\d+)\\r\\n",
|
||||||
|
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||||
|
if (G_UNLIKELY (!self->priv->conn_regex))
|
||||||
|
self->priv->conn_regex = g_regex_new ("\\r\\n\\^CONN:\\s*(\\d+),(\\d+)\\r\\n",
|
||||||
|
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||||
|
if (G_UNLIKELY (!self->priv->cend_regex))
|
||||||
|
self->priv->cend_regex = g_regex_new ("\\r\\n\\^CEND:\\s*(\\d+),\\s*(\\d+),\\s*(\\d+),?\\s*(\\d*)\\r\\n",
|
||||||
|
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||||
|
if (G_UNLIKELY (!self->priv->ddtmf_regex))
|
||||||
|
self->priv->ddtmf_regex = g_regex_new ("\\r\\n\\^DDTMF:\\s*([0-9A-D\\*\\#])\\r\\n",
|
||||||
|
G_REGEX_RAW | G_REGEX_OPTIMIZE, 0, NULL);
|
||||||
|
|
||||||
|
g_object_get (self,
|
||||||
|
MM_BASE_CALL_MODEM, &modem,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
ports = mm_broadband_modem_huawei_get_at_port_list (MM_BROADBAND_MODEM_HUAWEI (modem));
|
||||||
|
|
||||||
|
for (l = ports; l; l = g_list_next (l)) {
|
||||||
|
MMPortSerialAt *port;
|
||||||
|
|
||||||
|
port = MM_PORT_SERIAL_AT (l->data);
|
||||||
|
mm_port_serial_at_add_unsolicited_msg_handler (
|
||||||
|
port,
|
||||||
|
self->priv->conf_regex,
|
||||||
|
enable ? (MMPortSerialAtUnsolicitedMsgFn)huawei_voice_ringback_tone : NULL,
|
||||||
|
enable ? self : NULL,
|
||||||
|
NULL);
|
||||||
|
mm_port_serial_at_add_unsolicited_msg_handler (
|
||||||
|
port,
|
||||||
|
self->priv->conn_regex,
|
||||||
|
enable ? (MMPortSerialAtUnsolicitedMsgFn)huawei_voice_call_connection : NULL,
|
||||||
|
enable ? self : NULL,
|
||||||
|
NULL);
|
||||||
|
mm_port_serial_at_add_unsolicited_msg_handler (
|
||||||
|
port,
|
||||||
|
self->priv->cend_regex,
|
||||||
|
enable ? (MMPortSerialAtUnsolicitedMsgFn)huawei_voice_call_end : NULL,
|
||||||
|
enable ? self : NULL,
|
||||||
|
NULL);
|
||||||
|
mm_port_serial_at_add_unsolicited_msg_handler (
|
||||||
|
port,
|
||||||
|
self->priv->ddtmf_regex,
|
||||||
|
enable ? (MMPortSerialAtUnsolicitedMsgFn)huawei_voice_received_dtmf: NULL,
|
||||||
|
enable ? self : NULL,
|
||||||
|
NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free_full (ports, g_object_unref);
|
||||||
|
g_object_unref (modem);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
setup_unsolicited_events (MMBaseCall *self,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return common_setup_cleanup_unsolicited_events (MM_CALL_HUAWEI (self), TRUE, error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
cleanup_unsolicited_events (MMBaseCall *self,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return common_setup_cleanup_unsolicited_events (MM_CALL_HUAWEI (self), FALSE, error);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
MMBaseCall *
|
MMBaseCall *
|
||||||
@@ -45,13 +213,37 @@ mm_call_huawei_new (MMBaseModem *modem)
|
|||||||
static void
|
static void
|
||||||
mm_call_huawei_init (MMCallHuawei *self)
|
mm_call_huawei_init (MMCallHuawei *self)
|
||||||
{
|
{
|
||||||
|
/* Initialize private data */
|
||||||
|
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_CALL_HUAWEI, MMCallHuaweiPrivate);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
finalize (GObject *object)
|
||||||
|
{
|
||||||
|
MMCallHuawei *self = MM_CALL_HUAWEI (object);
|
||||||
|
|
||||||
|
if (self->priv->conf_regex)
|
||||||
|
g_regex_unref (self->priv->conf_regex);
|
||||||
|
if (self->priv->conn_regex)
|
||||||
|
g_regex_unref (self->priv->conn_regex);
|
||||||
|
if (self->priv->cend_regex)
|
||||||
|
g_regex_unref (self->priv->cend_regex);
|
||||||
|
if (self->priv->ddtmf_regex)
|
||||||
|
g_regex_unref (self->priv->ddtmf_regex);
|
||||||
|
|
||||||
|
G_OBJECT_CLASS (mm_call_huawei_parent_class)->finalize (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
mm_call_huawei_class_init (MMCallHuaweiClass *klass)
|
mm_call_huawei_class_init (MMCallHuaweiClass *klass)
|
||||||
{
|
{
|
||||||
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||||
MMBaseCallClass *base_call_class = MM_BASE_CALL_CLASS (klass);
|
MMBaseCallClass *base_call_class = MM_BASE_CALL_CLASS (klass);
|
||||||
|
|
||||||
base_call_class->setup_unsolicited_events = NULL;
|
g_type_class_add_private (object_class, sizeof (MMCallHuaweiPrivate));
|
||||||
base_call_class->cleanup_unsolicited_events = NULL;
|
|
||||||
|
object_class->finalize = finalize;
|
||||||
|
|
||||||
|
base_call_class->setup_unsolicited_events = setup_unsolicited_events;
|
||||||
|
base_call_class->cleanup_unsolicited_events = cleanup_unsolicited_events;
|
||||||
}
|
}
|
||||||
|
@@ -30,9 +30,11 @@
|
|||||||
|
|
||||||
typedef struct _MMCallHuawei MMCallHuawei;
|
typedef struct _MMCallHuawei MMCallHuawei;
|
||||||
typedef struct _MMCallHuaweiClass MMCallHuaweiClass;
|
typedef struct _MMCallHuaweiClass MMCallHuaweiClass;
|
||||||
|
typedef struct _MMCallHuaweiPrivate MMCallHuaweiPrivate;
|
||||||
|
|
||||||
struct _MMCallHuawei {
|
struct _MMCallHuawei {
|
||||||
MMBaseCall parent;
|
MMBaseCall parent;
|
||||||
|
MMCallHuaweiPrivate *priv;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _MMCallHuaweiClass {
|
struct _MMCallHuaweiClass {
|
||||||
|
@@ -109,99 +109,6 @@ mm_call_list_get_first_ringing_in_call (MMCallList *self)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
MMBaseCall *
|
|
||||||
mm_call_list_get_first_ringing_out_call (MMCallList *self)
|
|
||||||
{
|
|
||||||
MMBaseCall *call = NULL;
|
|
||||||
GList *l;
|
|
||||||
|
|
||||||
for (l = self->priv->list; l; l = g_list_next (l)) {
|
|
||||||
MMCallState state;
|
|
||||||
|
|
||||||
g_object_get (MM_BASE_CALL (l->data),
|
|
||||||
"state", &state,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (state == MM_CALL_STATE_RINGING_IN ||
|
|
||||||
state == MM_CALL_STATE_RINGING_OUT) {
|
|
||||||
call = MM_BASE_CALL (l->data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return call;
|
|
||||||
}
|
|
||||||
|
|
||||||
MMBaseCall *
|
|
||||||
mm_call_list_get_first_outgoing_dialing_call (MMCallList *self)
|
|
||||||
{
|
|
||||||
MMBaseCall *call = NULL;
|
|
||||||
GList *l;
|
|
||||||
|
|
||||||
for (l = self->priv->list; l; l = g_list_next (l)) {
|
|
||||||
MMCallState state;
|
|
||||||
MMCallDirection direction;
|
|
||||||
|
|
||||||
g_object_get (MM_BASE_CALL (l->data),
|
|
||||||
"state", &state,
|
|
||||||
"direction", &direction,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (direction == MM_CALL_DIRECTION_OUTGOING &&
|
|
||||||
state == MM_CALL_STATE_DIALING) {
|
|
||||||
call = MM_BASE_CALL (l->data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return call;
|
|
||||||
}
|
|
||||||
|
|
||||||
MMBaseCall *
|
|
||||||
mm_call_list_get_first_non_terminated_call (MMCallList *self)
|
|
||||||
{
|
|
||||||
MMBaseCall *call = NULL;
|
|
||||||
GList *l;
|
|
||||||
|
|
||||||
for (l = self->priv->list; l; l = g_list_next (l)) {
|
|
||||||
MMCallState state;
|
|
||||||
|
|
||||||
g_object_get (MM_BASE_CALL (l->data),
|
|
||||||
"state", &state,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (state != MM_CALL_STATE_TERMINATED) {
|
|
||||||
call = MM_BASE_CALL (l->data);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return call;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
mm_call_list_send_dtmf_to_active_calls (MMCallList *self,
|
|
||||||
const gchar *dtmf)
|
|
||||||
{
|
|
||||||
gboolean signaled = FALSE;
|
|
||||||
GList *l;
|
|
||||||
|
|
||||||
for (l = self->priv->list; l; l = g_list_next (l)) {
|
|
||||||
MMCallState state;
|
|
||||||
|
|
||||||
g_object_get (MM_BASE_CALL (l->data),
|
|
||||||
"state", &state,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (state == MM_CALL_STATE_ACTIVE) {
|
|
||||||
signaled = TRUE;
|
|
||||||
mm_base_call_received_dtmf (MM_BASE_CALL (l->data), dtmf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return signaled;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static guint
|
static guint
|
||||||
|
@@ -69,10 +69,5 @@ gboolean mm_call_list_delete_call (MMCallList *self,
|
|||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
MMBaseCall *mm_call_list_get_first_ringing_in_call (MMCallList *self);
|
MMBaseCall *mm_call_list_get_first_ringing_in_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_non_terminated_call (MMCallList *self);
|
|
||||||
gboolean mm_call_list_send_dtmf_to_active_calls (MMCallList *self,
|
|
||||||
const gchar *dtmf);
|
|
||||||
|
|
||||||
#endif /* MM_CALL_LIST_H */
|
#endif /* MM_CALL_LIST_H */
|
||||||
|
@@ -123,99 +123,6 @@ mm_iface_modem_voice_update_incoming_call_number (MMIfaceModemVoice *self,
|
|||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
|
||||||
mm_iface_modem_voice_call_dialing_to_ringing (MMIfaceModemVoice *self)
|
|
||||||
{
|
|
||||||
gboolean updated = FALSE;
|
|
||||||
MMBaseCall *call = NULL;
|
|
||||||
MMCallList *list = NULL;
|
|
||||||
|
|
||||||
g_object_get (MM_BASE_MODEM (self),
|
|
||||||
MM_IFACE_MODEM_VOICE_CALL_LIST, &list,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (list) {
|
|
||||||
call = mm_call_list_get_first_outgoing_dialing_call (list);
|
|
||||||
|
|
||||||
if (call) {
|
|
||||||
mm_base_call_change_state (call, MM_CALL_STATE_RINGING_OUT, MM_CALL_STATE_REASON_OUTGOING_STARTED);
|
|
||||||
updated = TRUE;
|
|
||||||
} else {
|
|
||||||
mm_dbg ("Outgoing dialing call does not exist");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return updated;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
mm_iface_modem_voice_call_ringing_to_active (MMIfaceModemVoice *self)
|
|
||||||
{
|
|
||||||
gboolean updated = FALSE;
|
|
||||||
MMBaseCall *call = NULL;
|
|
||||||
MMCallList *list = NULL;
|
|
||||||
|
|
||||||
g_object_get (MM_BASE_MODEM (self),
|
|
||||||
MM_IFACE_MODEM_VOICE_CALL_LIST, &list,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (list) {
|
|
||||||
call = mm_call_list_get_first_ringing_out_call (list);
|
|
||||||
|
|
||||||
if (call) {
|
|
||||||
mm_base_call_change_state (call, MM_CALL_STATE_ACTIVE, MM_CALL_STATE_REASON_ACCEPTED);
|
|
||||||
updated = TRUE;
|
|
||||||
} else {
|
|
||||||
mm_dbg ("Ringing call does not exist");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return updated;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
mm_iface_modem_voice_network_hangup (MMIfaceModemVoice *self)
|
|
||||||
{
|
|
||||||
gboolean updated = FALSE;
|
|
||||||
MMBaseCall *call = NULL;
|
|
||||||
MMCallList *list = NULL;
|
|
||||||
|
|
||||||
g_object_get (MM_BASE_MODEM (self),
|
|
||||||
MM_IFACE_MODEM_VOICE_CALL_LIST, &list,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (list) {
|
|
||||||
call = mm_call_list_get_first_non_terminated_call (list);
|
|
||||||
|
|
||||||
if (call) {
|
|
||||||
mm_base_call_change_state (call, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_TERMINATED);
|
|
||||||
updated = TRUE;
|
|
||||||
} else {
|
|
||||||
mm_dbg ("No call to hangup");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return updated;
|
|
||||||
}
|
|
||||||
|
|
||||||
gboolean
|
|
||||||
mm_iface_modem_voice_received_dtmf (MMIfaceModemVoice *self,
|
|
||||||
gchar *dtmf)
|
|
||||||
{
|
|
||||||
gboolean updated = FALSE;
|
|
||||||
MMCallList *list = NULL;
|
|
||||||
|
|
||||||
g_object_get (MM_BASE_MODEM (self),
|
|
||||||
MM_IFACE_MODEM_VOICE_CALL_LIST, &list,
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
if (list) {
|
|
||||||
updated = mm_call_list_send_dtmf_to_active_calls (list, dtmf);
|
|
||||||
}
|
|
||||||
|
|
||||||
return updated;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@@ -123,11 +123,6 @@ gboolean mm_iface_modem_voice_update_incoming_call_number (MMIfaceModemVoi
|
|||||||
gchar *number,
|
gchar *number,
|
||||||
guint type,
|
guint type,
|
||||||
guint validity);
|
guint validity);
|
||||||
gboolean mm_iface_modem_voice_call_dialing_to_ringing (MMIfaceModemVoice *self);
|
|
||||||
gboolean mm_iface_modem_voice_call_ringing_to_active (MMIfaceModemVoice *self);
|
|
||||||
gboolean mm_iface_modem_voice_network_hangup (MMIfaceModemVoice *self);
|
|
||||||
gboolean mm_iface_modem_voice_received_dtmf (MMIfaceModemVoice *self,
|
|
||||||
gchar *dtmf);
|
|
||||||
|
|
||||||
/* Look for a new valid multipart reference */
|
/* Look for a new valid multipart reference */
|
||||||
guint8 mm_iface_modem_voice_get_local_multipart_reference (MMIfaceModemVoice *self,
|
guint8 mm_iface_modem_voice_get_local_multipart_reference (MMIfaceModemVoice *self,
|
||||||
|
Reference in New Issue
Block a user