base-call: split AT-specific call code into MMCallAt
Signed-off-by: Dan Williams <dan@ioncontrol.co>
This commit is contained in:
@@ -324,6 +324,7 @@ sources = files(
|
||||
'mm-auth-provider.c',
|
||||
'mm-base-bearer.c',
|
||||
'mm-base-call.c',
|
||||
'mm-call-at.c',
|
||||
'mm-base-cbm.c',
|
||||
'mm-base-manager.c',
|
||||
'mm-base-modem-at.c',
|
||||
|
||||
+1
-319
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "mm-base-call.h"
|
||||
#include "mm-broadband-modem.h"
|
||||
#include "mm-auth-provider.h"
|
||||
#include "mm-iface-modem.h"
|
||||
#include "mm-iface-modem-voice.h"
|
||||
#include "mm-base-modem-at.h"
|
||||
@@ -988,314 +989,6 @@ mm_base_call_received_dtmf (MMBaseCall *self,
|
||||
mm_gdbus_call_emit_dtmf_received (MM_GDBUS_CALL (self), dtmf);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Start the CALL */
|
||||
|
||||
static gboolean
|
||||
call_start_finish (MMBaseCall *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
call_start_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
const gchar *response = NULL;
|
||||
|
||||
response = mm_base_modem_at_command_finish (modem, res, &error);
|
||||
|
||||
/* check response for error */
|
||||
if (response && response[0])
|
||||
error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Couldn't start the call: Unhandled response '%s'", response);
|
||||
|
||||
if (error)
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
call_start (MMBaseCall *self,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GTask *task;
|
||||
gchar *cmd;
|
||||
MMIfacePortAt *port;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
|
||||
port = mm_base_modem_peek_best_at_port (MM_BASE_MODEM (self->priv->modem), &error);
|
||||
if (!port) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
cmd = g_strdup_printf ("ATD%s;", mm_gdbus_call_get_number (MM_GDBUS_CALL (self)));
|
||||
mm_base_modem_at_command_full (self->priv->modem,
|
||||
port,
|
||||
cmd,
|
||||
90,
|
||||
FALSE, /* no cached */
|
||||
FALSE, /* no raw */
|
||||
cancellable,
|
||||
(GAsyncReadyCallback)call_start_ready,
|
||||
task);
|
||||
g_free (cmd);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Accept the call */
|
||||
|
||||
static gboolean
|
||||
call_accept_finish (MMBaseCall *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
call_accept_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
const gchar *response;
|
||||
|
||||
response = mm_base_modem_at_command_finish (modem, res, &error);
|
||||
|
||||
/* check response for error */
|
||||
if (response && response[0])
|
||||
g_set_error (&error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Couldn't accept the call: Unhandled response '%s'", response);
|
||||
|
||||
if (error)
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
call_accept (MMBaseCall *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
mm_base_modem_at_command (self->priv->modem,
|
||||
"ATA",
|
||||
2,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)call_accept_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Deflect the call */
|
||||
|
||||
static gboolean
|
||||
call_deflect_finish (MMBaseCall *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
call_deflect_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
mm_base_modem_at_command_finish (modem, res, &error);
|
||||
if (error)
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
call_deflect (MMBaseCall *self,
|
||||
const gchar *number,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
gchar *cmd;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
|
||||
cmd = g_strdup_printf ("+CTFR=%s", number);
|
||||
mm_base_modem_at_command (self->priv->modem,
|
||||
cmd,
|
||||
20,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)call_deflect_ready,
|
||||
task);
|
||||
g_free (cmd);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Hangup the call */
|
||||
|
||||
static gboolean
|
||||
call_hangup_finish (MMBaseCall *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
chup_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
mm_base_modem_at_command_finish (modem, res, &error);
|
||||
if (error)
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
chup_fallback (GTask *task)
|
||||
{
|
||||
MMBaseCall *self;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
mm_base_modem_at_command (self->priv->modem,
|
||||
"+CHUP",
|
||||
2,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)chup_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
static void
|
||||
chld_hangup_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBaseCall *self;
|
||||
GError *error = NULL;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
|
||||
mm_base_modem_at_command_finish (modem, res, &error);
|
||||
if (error) {
|
||||
mm_obj_warn (self, "couldn't hangup single call with call id '%u': %s",
|
||||
self->priv->index, error->message);
|
||||
g_error_free (error);
|
||||
chup_fallback (task);
|
||||
return;
|
||||
}
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
call_hangup (MMBaseCall *self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
|
||||
/* Try to hangup the single call id */
|
||||
if (self->priv->index) {
|
||||
gchar *cmd;
|
||||
|
||||
cmd = g_strdup_printf ("+CHLD=1%u", self->priv->index);
|
||||
mm_base_modem_at_command (self->priv->modem,
|
||||
cmd,
|
||||
2,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)chld_hangup_ready,
|
||||
task);
|
||||
g_free (cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
/* otherwise terminate all */
|
||||
chup_fallback (task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Send DTMF tone to call */
|
||||
|
||||
static gboolean
|
||||
call_send_dtmf_finish (MMBaseCall *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
call_send_dtmf_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBaseCall *self;
|
||||
GError *error = NULL;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
|
||||
mm_base_modem_at_command_finish (modem, res, &error);
|
||||
if (error) {
|
||||
mm_obj_dbg (self, "couldn't send dtmf: %s", error->message);
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
call_send_dtmf (MMBaseCall *self,
|
||||
const gchar *dtmf,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GTask *task;
|
||||
gchar *cmd;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
|
||||
cmd = g_strdup_printf ("AT+VTS=%c", dtmf[0]);
|
||||
mm_base_modem_at_command (self->priv->modem,
|
||||
cmd,
|
||||
3,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)call_send_dtmf_ready,
|
||||
task);
|
||||
|
||||
g_free (cmd);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static gchar *
|
||||
@@ -1498,17 +1191,6 @@ 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->deflect = call_deflect;
|
||||
klass->deflect_finish = call_deflect_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;
|
||||
|
||||
properties[PROP_CONNECTION] =
|
||||
g_param_spec_object (MM_BASE_CALL_CONNECTION,
|
||||
"Connection",
|
||||
|
||||
+11
-10
@@ -50,6 +50,7 @@
|
||||
#include "mm-bearer-list.h"
|
||||
#include "mm-cbm-list.h"
|
||||
#include "mm-cbm-part.h"
|
||||
#include "mm-call-at.h"
|
||||
#include "mm-sms-list.h"
|
||||
#include "mm-sms-part-3gpp.h"
|
||||
#include "mm-sms-at.h"
|
||||
@@ -8902,16 +8903,16 @@ modem_voice_create_call (MMIfaceModemVoice *_self,
|
||||
{
|
||||
MMBroadbandModem *self = MM_BROADBAND_MODEM (_self);
|
||||
|
||||
return mm_base_call_new (MM_BASE_MODEM (self),
|
||||
G_OBJECT (self),
|
||||
direction,
|
||||
number,
|
||||
/* If +CLCC is supported, we want no incoming timeout.
|
||||
* Also, we're able to support detailed call state updates without
|
||||
* additional vendor-specific commands. */
|
||||
self->priv->clcc_supported, /* skip incoming timeout */
|
||||
self->priv->clcc_supported, /* dialing->ringing supported */
|
||||
self->priv->clcc_supported); /* ringing->active supported */
|
||||
return mm_call_at_new (MM_BASE_MODEM (self),
|
||||
G_OBJECT (self),
|
||||
direction,
|
||||
number,
|
||||
/* If +CLCC is supported, we want no incoming timeout.
|
||||
* Also, we're able to support detailed call state updates without
|
||||
* additional vendor-specific commands. */
|
||||
self->priv->clcc_supported, /* skip incoming timeout */
|
||||
self->priv->clcc_supported, /* dialing->ringing supported */
|
||||
self->priv->clcc_supported); /* ringing->active supported */
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -0,0 +1,422 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2015 Riccardo Vangelisti <riccardo.vangelisti@sadel.it>
|
||||
* Copyright (C) 2019 Aleksander Morgado <aleksander@aleksander.es>
|
||||
* Copyright (C) 2019 Purism SPC
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <ModemManager.h>
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-call-at.h"
|
||||
#include "mm-base-modem-at.h"
|
||||
#include "mm-base-modem.h"
|
||||
#include "mm-modem-helpers.h"
|
||||
#include "mm-error-helpers.h"
|
||||
#include "mm-log-object.h"
|
||||
#include "mm-bind.h"
|
||||
|
||||
G_DEFINE_TYPE (MMCallAt, mm_call_at, MM_TYPE_BASE_CALL)
|
||||
|
||||
struct _MMCallAtPrivate {
|
||||
/* The modem which owns this call */
|
||||
MMBaseModem *modem;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Start the CALL */
|
||||
|
||||
static gboolean
|
||||
call_start_finish (MMBaseCall *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
call_start_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
const gchar *response = NULL;
|
||||
|
||||
response = mm_base_modem_at_command_finish (modem, res, &error);
|
||||
|
||||
/* check response for error */
|
||||
if (response && response[0])
|
||||
error = g_error_new (MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Couldn't start the call: Unhandled response '%s'", response);
|
||||
|
||||
if (error)
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
call_start (MMBaseCall *_self,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMCallAt *self = MM_CALL_AT (_self);
|
||||
GError *error = NULL;
|
||||
GTask *task;
|
||||
gchar *cmd;
|
||||
MMIfacePortAt *port;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
|
||||
port = mm_base_modem_peek_best_at_port (self->priv->modem, &error);
|
||||
if (!port) {
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
cmd = g_strdup_printf ("ATD%s;", mm_gdbus_call_get_number (MM_GDBUS_CALL (self)));
|
||||
mm_base_modem_at_command_full (self->priv->modem,
|
||||
port,
|
||||
cmd,
|
||||
90,
|
||||
FALSE, /* no cached */
|
||||
FALSE, /* no raw */
|
||||
cancellable,
|
||||
(GAsyncReadyCallback)call_start_ready,
|
||||
task);
|
||||
g_free (cmd);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Accept the call */
|
||||
|
||||
static gboolean
|
||||
call_accept_finish (MMBaseCall *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
call_accept_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
const gchar *response;
|
||||
|
||||
response = mm_base_modem_at_command_finish (modem, res, &error);
|
||||
|
||||
/* check response for error */
|
||||
if (response && response[0])
|
||||
g_set_error (&error, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
|
||||
"Couldn't accept the call: Unhandled response '%s'", response);
|
||||
|
||||
if (error)
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
call_accept (MMBaseCall *_self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMCallAt *self = MM_CALL_AT (_self);
|
||||
GTask *task;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
mm_base_modem_at_command (self->priv->modem,
|
||||
"ATA",
|
||||
2,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)call_accept_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Deflect the call */
|
||||
|
||||
static gboolean
|
||||
call_deflect_finish (MMBaseCall *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
call_deflect_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
mm_base_modem_at_command_finish (modem, res, &error);
|
||||
if (error)
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
call_deflect (MMBaseCall *_self,
|
||||
const gchar *number,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMCallAt *self = MM_CALL_AT (_self);
|
||||
GTask *task;
|
||||
gchar *cmd;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
|
||||
cmd = g_strdup_printf ("+CTFR=%s", number);
|
||||
mm_base_modem_at_command (self->priv->modem,
|
||||
cmd,
|
||||
20,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)call_deflect_ready,
|
||||
task);
|
||||
g_free (cmd);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Hangup the call */
|
||||
|
||||
static gboolean
|
||||
call_hangup_finish (MMBaseCall *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
chup_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
mm_base_modem_at_command_finish (modem, res, &error);
|
||||
if (error)
|
||||
g_task_return_error (task, error);
|
||||
else
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
chup_fallback (GTask *task)
|
||||
{
|
||||
MMCallAt *self;
|
||||
|
||||
self = MM_CALL_AT (g_task_get_source_object (task));
|
||||
mm_base_modem_at_command (self->priv->modem,
|
||||
"+CHUP",
|
||||
2,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)chup_ready,
|
||||
task);
|
||||
}
|
||||
|
||||
static void
|
||||
chld_hangup_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBaseCall *self;
|
||||
GError *error = NULL;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
|
||||
mm_base_modem_at_command_finish (modem, res, &error);
|
||||
if (error) {
|
||||
mm_obj_warn (self, "couldn't hangup single call with call id '%u': %s",
|
||||
mm_base_call_get_index (MM_BASE_CALL (self)), error->message);
|
||||
g_error_free (error);
|
||||
chup_fallback (task);
|
||||
return;
|
||||
}
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
call_hangup (MMBaseCall *_self,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMCallAt *self = MM_CALL_AT (_self);
|
||||
GTask *task;
|
||||
guint index;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
|
||||
/* Try to hangup the single call id */
|
||||
index = mm_base_call_get_index (MM_BASE_CALL (self));
|
||||
if (index) {
|
||||
gchar *cmd;
|
||||
|
||||
cmd = g_strdup_printf ("+CHLD=1%u", index);
|
||||
mm_base_modem_at_command (self->priv->modem,
|
||||
cmd,
|
||||
2,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)chld_hangup_ready,
|
||||
task);
|
||||
g_free (cmd);
|
||||
return;
|
||||
}
|
||||
|
||||
/* otherwise terminate all */
|
||||
chup_fallback (task);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Send DTMF tone to call */
|
||||
|
||||
static gboolean
|
||||
call_send_dtmf_finish (MMBaseCall *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
return g_task_propagate_boolean (G_TASK (res), error);
|
||||
}
|
||||
|
||||
static void
|
||||
call_send_dtmf_ready (MMBaseModem *modem,
|
||||
GAsyncResult *res,
|
||||
GTask *task)
|
||||
{
|
||||
MMBaseCall *self;
|
||||
GError *error = NULL;
|
||||
|
||||
self = g_task_get_source_object (task);
|
||||
|
||||
mm_base_modem_at_command_finish (modem, res, &error);
|
||||
if (error) {
|
||||
mm_obj_dbg (self, "couldn't send dtmf: %s", error->message);
|
||||
g_task_return_error (task, error);
|
||||
g_object_unref (task);
|
||||
return;
|
||||
}
|
||||
|
||||
g_task_return_boolean (task, TRUE);
|
||||
g_object_unref (task);
|
||||
}
|
||||
|
||||
static void
|
||||
call_send_dtmf (MMBaseCall *_self,
|
||||
const gchar *dtmf,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
MMCallAt *self = MM_CALL_AT (_self);
|
||||
GTask *task;
|
||||
gchar *cmd;
|
||||
|
||||
task = g_task_new (self, NULL, callback, user_data);
|
||||
|
||||
cmd = g_strdup_printf ("AT+VTS=%c", dtmf[0]);
|
||||
mm_base_modem_at_command (self->priv->modem,
|
||||
cmd,
|
||||
3,
|
||||
FALSE,
|
||||
(GAsyncReadyCallback)call_send_dtmf_ready,
|
||||
task);
|
||||
|
||||
g_free (cmd);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
MMBaseCall *
|
||||
mm_call_at_new (MMBaseModem *modem,
|
||||
GObject *bind_to,
|
||||
MMCallDirection direction,
|
||||
const gchar *number,
|
||||
gboolean skip_incoming_timeout,
|
||||
gboolean supports_dialing_to_ringing,
|
||||
gboolean supports_ringing_to_active)
|
||||
{
|
||||
MMBaseCall *call;
|
||||
|
||||
call = MM_BASE_CALL (g_object_new (MM_TYPE_CALL_AT,
|
||||
MM_BASE_CALL_MODEM, modem,
|
||||
MM_BIND_TO, bind_to,
|
||||
"direction", direction,
|
||||
"number", number,
|
||||
MM_BASE_CALL_SKIP_INCOMING_TIMEOUT, skip_incoming_timeout,
|
||||
MM_BASE_CALL_SUPPORTS_DIALING_TO_RINGING, supports_dialing_to_ringing,
|
||||
MM_BASE_CALL_SUPPORTS_RINGING_TO_ACTIVE, supports_ringing_to_active,
|
||||
NULL));
|
||||
MM_CALL_AT (call)->priv->modem = g_object_ref (modem);
|
||||
return call;
|
||||
}
|
||||
|
||||
static void
|
||||
mm_call_at_init (MMCallAt *self)
|
||||
{
|
||||
/* Initialize private data */
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MM_TYPE_CALL_AT, MMCallAtPrivate);
|
||||
}
|
||||
|
||||
static void
|
||||
dispose (GObject *object)
|
||||
{
|
||||
MMCallAt *self = MM_CALL_AT (object);
|
||||
|
||||
g_clear_object (&self->priv->modem);
|
||||
|
||||
G_OBJECT_CLASS (mm_call_at_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
mm_call_at_class_init (MMCallAtClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
MMBaseCallClass *base_call_class = MM_BASE_CALL_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (object_class, sizeof (MMCallAtPrivate));
|
||||
|
||||
object_class->dispose = dispose;
|
||||
|
||||
base_call_class->start = call_start;
|
||||
base_call_class->start_finish = call_start_finish;
|
||||
base_call_class->accept = call_accept;
|
||||
base_call_class->accept_finish = call_accept_finish;
|
||||
base_call_class->deflect = call_deflect;
|
||||
base_call_class->deflect_finish = call_deflect_finish;
|
||||
base_call_class->hangup = call_hangup;
|
||||
base_call_class->hangup_finish = call_hangup_finish;
|
||||
base_call_class->send_dtmf = call_send_dtmf;
|
||||
base_call_class->send_dtmf_finish = call_send_dtmf_finish;
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details:
|
||||
*
|
||||
* Copyright (C) 2015 Riccardo Vangelisti <riccardo.vangelisti@sadel.it>
|
||||
* Copyright (C) 2019 Purism SPC
|
||||
*/
|
||||
|
||||
#ifndef MM_CALL_AT_H
|
||||
#define MM_CALL_AT_H
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-object.h>
|
||||
|
||||
#define _LIBMM_INSIDE_MM
|
||||
#include <libmm-glib.h>
|
||||
|
||||
#include "mm-base-call.h"
|
||||
#include "mm-base-modem.h"
|
||||
|
||||
#define MM_TYPE_CALL_AT (mm_call_at_get_type ())
|
||||
#define MM_CALL_AT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_CALL_AT, MMCallAt))
|
||||
#define MM_CALL_AT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_CALL_AT, MMCallAtClass))
|
||||
#define MM_IS_CALL_AT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MM_TYPE_CALL_AT))
|
||||
#define MM_IS_CALL_AT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MM_TYPE_CALL_AT))
|
||||
#define MM_CALL_AT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MM_TYPE_CALL_AT, MMCallAtClass))
|
||||
|
||||
typedef struct _MMCallAt MMCallAt;
|
||||
typedef struct _MMCallAtClass MMCallAtClass;
|
||||
typedef struct _MMCallAtPrivate MMCallAtPrivate;
|
||||
|
||||
struct _MMCallAt {
|
||||
MMBaseCall parent;
|
||||
MMCallAtPrivate *priv;
|
||||
};
|
||||
|
||||
struct _MMCallAtClass {
|
||||
MMBaseCallClass parent;
|
||||
};
|
||||
|
||||
GType mm_call_at_get_type (void);
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMCallAt, g_object_unref)
|
||||
|
||||
MMBaseCall *mm_call_at_new (MMBaseModem *modem,
|
||||
GObject *bind_to,
|
||||
MMCallDirection direction,
|
||||
const gchar *number,
|
||||
gboolean skip_incoming_timeout,
|
||||
gboolean supports_dialing_to_ringing,
|
||||
gboolean supports_ringing_to_active);
|
||||
|
||||
#endif /* MM_CALL_AT_H */
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "mm-base-modem-at.h"
|
||||
#include "mm-shared-cinterion.h"
|
||||
#include "mm-modem-helpers-cinterion.h"
|
||||
#include "mm-call-at.h"
|
||||
|
||||
G_DEFINE_INTERFACE (MMSharedCinterion, mm_shared_cinterion, MM_TYPE_IFACE_MODEM)
|
||||
|
||||
@@ -1005,15 +1006,15 @@ mm_shared_cinterion_create_call (MMIfaceModemVoice *self,
|
||||
priv = get_private (MM_SHARED_CINTERION (self));
|
||||
if (priv->slcc_support == FEATURE_SUPPORTED) {
|
||||
mm_obj_dbg (self, "created new call with ^SLCC support");
|
||||
return mm_base_call_new (MM_BASE_MODEM (self),
|
||||
G_OBJECT (self),
|
||||
direction,
|
||||
number,
|
||||
/* When SLCC is supported we have support for detailed
|
||||
* call list events via call list report URCs */
|
||||
TRUE, /* incoming timeout not required */
|
||||
TRUE, /* dialing->ringing supported */
|
||||
TRUE); /* ringing->active supported */
|
||||
return mm_call_at_new (MM_BASE_MODEM (self),
|
||||
G_OBJECT (self),
|
||||
direction,
|
||||
number,
|
||||
/* When SLCC is supported we have support for detailed
|
||||
* call list events via call list report URCs */
|
||||
TRUE, /* incoming timeout not required */
|
||||
TRUE, /* dialing->ringing supported */
|
||||
TRUE); /* ringing->active supported */
|
||||
}
|
||||
|
||||
/* otherwise, run parent's generic base call logic */
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
#include "mm-broadband-bearer.h"
|
||||
#include "mm-bearer-list.h"
|
||||
#include "mm-sim-huawei.h"
|
||||
#include "mm-call-at.h"
|
||||
|
||||
static void iface_modem_init (MMIfaceModemInterface *iface);
|
||||
static void iface_modem_3gpp_init (MMIfaceModem3gppInterface *iface);
|
||||
@@ -3880,13 +3881,13 @@ create_call (MMIfaceModemVoice *self,
|
||||
MMCallDirection direction,
|
||||
const gchar *number)
|
||||
{
|
||||
return mm_base_call_new (MM_BASE_MODEM (self),
|
||||
G_OBJECT (self),
|
||||
direction,
|
||||
number,
|
||||
TRUE, /* skip_incoming_timeout */
|
||||
TRUE, /* supports_dialing_to_ringing */
|
||||
TRUE); /* supports_ringing_to_active) */
|
||||
return mm_call_at_new (MM_BASE_MODEM (self),
|
||||
G_OBJECT (self),
|
||||
direction,
|
||||
number,
|
||||
TRUE, /* skip_incoming_timeout */
|
||||
TRUE, /* supports_dialing_to_ringing */
|
||||
TRUE); /* supports_ringing_to_active) */
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include "mm-sim-ublox.h"
|
||||
#include "mm-modem-helpers-ublox.h"
|
||||
#include "mm-ublox-enums-types.h"
|
||||
#include "mm-call-at.h"
|
||||
|
||||
static void iface_modem_init (MMIfaceModemInterface *iface);
|
||||
static void iface_modem_voice_init (MMIfaceModemVoiceInterface *iface);
|
||||
@@ -1505,13 +1506,13 @@ create_call (MMIfaceModemVoice *self,
|
||||
MMCallDirection direction,
|
||||
const gchar *number)
|
||||
{
|
||||
return mm_base_call_new (MM_BASE_MODEM (self),
|
||||
G_OBJECT (self),
|
||||
direction,
|
||||
number,
|
||||
TRUE, /* skip_incoming_timeout */
|
||||
TRUE, /* supports_dialing_to_ringing */
|
||||
TRUE); /* supports_ringing_to_active */
|
||||
return mm_call_at_new (MM_BASE_MODEM (self),
|
||||
G_OBJECT (self),
|
||||
direction,
|
||||
number,
|
||||
TRUE, /* skip_incoming_timeout */
|
||||
TRUE, /* supports_dialing_to_ringing */
|
||||
TRUE); /* supports_ringing_to_active */
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
Reference in New Issue
Block a user