aboutsummaryrefslogtreecommitdiff
path: root/src/mm-base-call.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mm-base-call.c')
-rw-r--r--src/mm-base-call.c727
1 files changed, 357 insertions, 370 deletions
diff --git a/src/mm-base-call.c b/src/mm-base-call.c
index 6308fd18..e011c448 100644
--- a/src/mm-base-call.c
+++ b/src/mm-base-call.c
@@ -28,10 +28,8 @@
#include "mm-base-call.h"
#include "mm-broadband-modem.h"
-#include "mm-iface-modem.h"
+#include "mm-auth-provider.h"
#include "mm-iface-modem-voice.h"
-#include "mm-base-modem-at.h"
-#include "mm-base-modem.h"
#include "mm-log-object.h"
#include "mm-modem-helpers.h"
#include "mm-error-helpers.h"
@@ -49,7 +47,7 @@ enum {
PROP_PATH,
PROP_CONNECTION,
PROP_BIND_TO,
- PROP_MODEM,
+ PROP_IFACE_MODEM_VOICE,
PROP_SKIP_INCOMING_TIMEOUT,
PROP_SUPPORTS_DIALING_TO_RINGING,
PROP_SUPPORTS_RINGING_TO_ACTIVE,
@@ -70,8 +68,8 @@ struct _MMBaseCallPrivate {
/* The object this Call is bound to */
GObject *bind_to;
- /* The modem which owns this call */
- MMBaseModem *modem;
+ /* The voice interface which owns this call */
+ MMIfaceModemVoice *iface;
/* The path where the call object is exported */
gchar *path;
/* Features */
@@ -91,6 +89,9 @@ struct _MMBaseCallPrivate {
* 'terminated' is coming asynchronously (e.g. via in-call state
* update notifications) */
GCancellable *start_cancellable;
+
+ /* DTMF support */
+ GQueue *dtmf_queue;
};
/*****************************************************************************/
@@ -239,7 +240,7 @@ handle_start_auth_ready (MMAuthProvider *authp,
mm_obj_info (ctx->self, "processing user request to start voice call...");
/* Disallow non-emergency calls when in emergency-only state */
- if (!mm_iface_modem_voice_authorize_outgoing_call (MM_IFACE_MODEM_VOICE (ctx->self->priv->modem), ctx->self, &error)) {
+ if (!mm_iface_modem_voice_authorize_outgoing_call (ctx->self->priv->iface, ctx->self, &error)) {
mm_base_call_change_state (ctx->self, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_UNKNOWN);
mm_dbus_method_invocation_take_error (ctx->invocation, error);
handle_start_context_free (ctx);
@@ -534,7 +535,7 @@ handle_join_multiparty_auth_ready (MMAuthProvider *authp,
/* This action is provided in the Call API, but implemented in the Modem.Voice interface
* logic, because the action affects not only one call object, but all call objects that
* are part of the multiparty call. */
- mm_iface_modem_voice_join_multiparty (MM_IFACE_MODEM_VOICE (ctx->self->priv->modem),
+ mm_iface_modem_voice_join_multiparty (ctx->self->priv->iface,
ctx->self,
(GAsyncReadyCallback)modem_voice_join_multiparty_ready,
ctx);
@@ -608,7 +609,7 @@ handle_leave_multiparty_auth_ready (MMAuthProvider *authp,
/* This action is provided in the Call API, but implemented in the Modem.Voice interface
* logic, because the action affects not only one call object, but all call objects that
* are part of the multiparty call. */
- mm_iface_modem_voice_leave_multiparty (MM_IFACE_MODEM_VOICE (ctx->self->priv->modem),
+ mm_iface_modem_voice_leave_multiparty (ctx->self->priv->iface,
ctx->self,
(GAsyncReadyCallback)modem_voice_leave_multiparty_ready,
ctx);
@@ -730,6 +731,283 @@ handle_hangup (MMBaseCall *self,
/*****************************************************************************/
/* Send dtmf (DBus call handling) */
+typedef enum {
+ DTMF_STEP_FIRST,
+ DTMF_STEP_START,
+ DTMF_STEP_TIMEOUT,
+ DTMF_STEP_STOP,
+ DTMF_STEP_NEXT,
+ DTMF_STEP_LAST,
+} DtmfStep;
+
+typedef struct {
+ DtmfStep step;
+ GError *saved_error;
+ guint8 call_id;
+ /* Array of DTMF runs; split by pauses */
+ GPtrArray *dtmfs;
+ /* index into dtmfs */
+ guint cur_dtmf;
+ /* index into cur dtmf run string */
+ gchar *cur_tone;
+ guint timeout_id;
+} SendDtmfContext;
+
+static void
+send_dtmf_context_clear_timeout (SendDtmfContext *ctx)
+{
+ if (ctx->timeout_id) {
+ g_source_remove (ctx->timeout_id);
+ ctx->timeout_id = 0;
+ }
+}
+
+static void
+send_dtmf_context_free (SendDtmfContext *ctx)
+{
+ send_dtmf_context_clear_timeout (ctx);
+ g_ptr_array_foreach (ctx->dtmfs, (GFunc) g_free, NULL);
+ g_ptr_array_free (ctx->dtmfs, TRUE);
+ g_assert (!ctx->saved_error);
+ g_slice_free (SendDtmfContext, ctx);
+}
+
+static void send_dtmf_task_step_next (GTask *task);
+
+static void
+stop_dtmf_ignore_ready (MMBaseCall *self,
+ GAsyncResult *res,
+ gpointer unused)
+{
+ /* Ignore the result and error */
+ MM_BASE_CALL_GET_CLASS (self)->stop_dtmf_finish (self, res, NULL);
+}
+
+static void
+send_dtmf_task_cancel (GTask *task)
+{
+ MMBaseCall *self;
+ SendDtmfContext *ctx;
+
+ ctx = g_task_get_task_data (task);
+ self = g_task_get_source_object (task);
+
+ send_dtmf_context_clear_timeout (ctx);
+ if (ctx->step > DTMF_STEP_FIRST && ctx->step < DTMF_STEP_STOP) {
+ if (MM_BASE_CALL_GET_CLASS (self)->stop_dtmf) {
+ MM_BASE_CALL_GET_CLASS (self)->stop_dtmf (self,
+ (GAsyncReadyCallback)stop_dtmf_ignore_ready,
+ NULL);
+ }
+ }
+ g_assert (ctx->step != DTMF_STEP_LAST);
+ ctx->step = DTMF_STEP_LAST;
+ send_dtmf_task_step_next (task);
+}
+
+static void
+stop_dtmf_ready (MMBaseCall *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ SendDtmfContext *ctx;
+ GError *error = NULL;
+ gboolean success;
+
+ ctx = g_task_get_task_data (task);
+
+ success = MM_BASE_CALL_GET_CLASS (self)->stop_dtmf_finish (self, res, &error);
+ if (ctx->step == DTMF_STEP_STOP) {
+ if (!success) {
+ g_propagate_error (&ctx->saved_error, error);
+ ctx->step = DTMF_STEP_LAST;
+ } else
+ ctx->step++;
+
+ send_dtmf_task_step_next (task);
+ }
+
+ /* Balance stop_dtmf() */
+ g_object_unref (task);
+}
+
+static gboolean
+dtmf_timeout (GTask *task)
+{
+ SendDtmfContext *ctx;
+
+ ctx = g_task_get_task_data (task);
+
+ /* If this was a pause character; move past it */
+ if (ctx->cur_tone[0] == MM_CALL_DTMF_PAUSE_CHAR)
+ ctx->cur_tone++;
+
+ send_dtmf_context_clear_timeout (ctx);
+ ctx->step++;
+ send_dtmf_task_step_next (task);
+
+ return G_SOURCE_REMOVE;
+}
+
+static void
+send_dtmf_ready (MMBaseCall *self,
+ GAsyncResult *res,
+ GTask *task)
+{
+ SendDtmfContext *ctx;
+ GError *error = NULL;
+ gssize num_sent;
+
+ ctx = g_task_get_task_data (task);
+
+ num_sent = MM_BASE_CALL_GET_CLASS (self)->send_dtmf_finish (self, res, &error);
+ if (ctx->step == DTMF_STEP_START) {
+ if (num_sent < 0) {
+ g_propagate_error (&ctx->saved_error, error);
+ ctx->step = DTMF_STEP_LAST;
+ } else {
+ g_assert (num_sent > 0);
+ g_assert ((guint) num_sent <= strlen (ctx->cur_tone));
+ ctx->cur_tone += num_sent;
+ ctx->step++;
+ }
+
+ send_dtmf_task_step_next (task);
+ }
+
+ /* Balance send_dtmf() */
+ g_object_unref (task);
+}
+
+static void
+send_dtmf_task_step_next (GTask *task)
+{
+ SendDtmfContext *ctx;
+ gboolean need_stop;
+ MMBaseCall *self;
+ gboolean is_pause;
+
+ self = g_task_get_source_object (task);
+ ctx = g_task_get_task_data (task);
+
+ is_pause = (ctx->cur_tone[0] == MM_CALL_DTMF_PAUSE_CHAR);
+ need_stop = MM_BASE_CALL_GET_CLASS (self)->stop_dtmf &&
+ MM_BASE_CALL_GET_CLASS (self)->stop_dtmf_finish;
+
+ switch (ctx->step) {
+ case DTMF_STEP_FIRST:
+ ctx->step++;
+ /* Fall through */
+ case DTMF_STEP_START:
+ if (!is_pause) {
+ MM_BASE_CALL_GET_CLASS (self)->send_dtmf (self,
+ ctx->cur_tone,
+ (GAsyncReadyCallback)send_dtmf_ready,
+ g_object_ref (task));
+ return;
+ }
+ /* Fall through */
+ case DTMF_STEP_TIMEOUT:
+ if (need_stop || is_pause) {
+ guint duration;
+
+ duration = is_pause ? 2000 : mm_base_call_get_dtmf_tone_duration (self);
+
+ /* Disable DTMF press after DTMF tone duration elapses */
+ ctx->timeout_id = g_timeout_add (duration,
+ (GSourceFunc) dtmf_timeout,
+ task);
+ return;
+ }
+ /* Fall through */
+ case DTMF_STEP_STOP:
+ send_dtmf_context_clear_timeout (ctx);
+ if (need_stop && !is_pause) {
+ MM_BASE_CALL_GET_CLASS (self)->stop_dtmf (self,
+ (GAsyncReadyCallback)stop_dtmf_ready,
+ g_object_ref (task));
+ return;
+ }
+ /* Fall through */
+ case DTMF_STEP_NEXT:
+ /* Advance to next DTMF run? */
+ if (ctx->cur_tone[0] == '\0') {
+ ctx->cur_dtmf++;
+ if (ctx->cur_dtmf < ctx->dtmfs->len)
+ ctx->cur_tone = g_ptr_array_index (ctx->dtmfs, ctx->cur_dtmf);
+ }
+
+ /* More to send? */
+ if (ctx->cur_tone[0]) {
+ ctx->step = DTMF_STEP_START;
+ send_dtmf_task_step_next (task);
+ return;
+ }
+ /* no more DTMF characters to send */
+ /* Fall through */
+ case DTMF_STEP_LAST:
+ send_dtmf_context_clear_timeout (ctx);
+ if (ctx->saved_error)
+ g_task_return_error (task, g_steal_pointer (&ctx->saved_error));
+ else
+ g_task_return_boolean (task, TRUE);
+ g_object_unref (task);
+
+ /* Start the next tone if any are queued */
+ g_queue_remove (self->priv->dtmf_queue, task);
+ task = g_queue_peek_head (self->priv->dtmf_queue);
+ if (task)
+ send_dtmf_task_step_next (task);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static gboolean
+send_dtmf_task_finish (MMBaseCall *self,
+ GAsyncResult *res,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (res), error);
+}
+
+static GTask *
+send_dtmf_task_new (MMBaseCall *self,
+ const gchar *dtmf,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ GError **error)
+{
+ GTask *task;
+ SendDtmfContext *ctx;
+ guint8 call_id;
+
+ call_id = mm_base_call_get_index (self);
+ if (call_id == 0) {
+ g_set_error (error,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_INVALID_ARGS,
+ "Invalid call index");
+ return NULL;
+ }
+
+ task = g_task_new (self, NULL, callback, user_data);
+
+ ctx = g_slice_new0 (SendDtmfContext);
+ ctx->call_id = call_id;
+ /* Split DTMF into runs of DTMF characters interrupted by pauses */
+ ctx->dtmfs = mm_dtmf_split (dtmf);
+ g_assert (ctx->dtmfs->len > 0);
+ ctx->cur_tone = g_ptr_array_index (ctx->dtmfs, ctx->cur_dtmf);
+ g_task_set_task_data (task, ctx, (GDestroyNotify) send_dtmf_context_free);
+
+ return task;
+}
+
+/*****************************************************************************/
+/* Send DTMF D-Bus request handling */
+
typedef struct {
MMBaseCall *self;
GDBusMethodInvocation *invocation;
@@ -752,7 +1030,7 @@ handle_send_dtmf_ready (MMBaseCall *self,
{
GError *error = NULL;
- if (!MM_BASE_CALL_GET_CLASS (self)->send_dtmf_finish (self, res, &error)) {
+ if (!send_dtmf_task_finish (self, res, &error)) {
mm_dbus_method_invocation_take_error (ctx->invocation, error);
} else {
mm_gdbus_call_complete_send_dtmf (MM_GDBUS_CALL (ctx->self), ctx->invocation);
@@ -766,8 +1044,9 @@ handle_send_dtmf_auth_ready (MMAuthProvider *authp,
GAsyncResult *res,
HandleSendDtmfContext *ctx)
{
- MMCallState state;
- GError *error = NULL;
+ MMCallState state;
+ GError *error = NULL;
+ GTask *task;
if (!mm_auth_provider_authorize_finish (authp, res, &error)) {
mm_dbus_method_invocation_take_error (ctx->invocation, error);
@@ -777,7 +1056,23 @@ handle_send_dtmf_auth_ready (MMAuthProvider *authp,
state = mm_gdbus_call_get_state (MM_GDBUS_CALL (ctx->self));
- /* Check if we do support doing it */
+ /* Ensure there are DTMF characters to send */
+ if (!ctx->dtmf || !ctx->dtmf[0]) {
+ mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
+ "No DTMF characters given");
+ handle_send_dtmf_context_free (ctx);
+ return;
+ }
+
+ /* And that there aren't too many */
+ if (strlen (ctx->dtmf) > 50) {
+ mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_INVALID_ARGS,
+ "Too many DTMF characters");
+ handle_send_dtmf_context_free (ctx);
+ return;
+ }
+
+ /* Check if we do support doing DTMF at all */
if (!MM_BASE_CALL_GET_CLASS (ctx->self)->send_dtmf ||
!MM_BASE_CALL_GET_CLASS (ctx->self)->send_dtmf_finish) {
mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_UNSUPPORTED,
@@ -787,7 +1082,7 @@ handle_send_dtmf_auth_ready (MMAuthProvider *authp,
}
/* We can only send_dtmf when call is in ACTIVE state */
- if (state != MM_CALL_STATE_ACTIVE ){
+ if (state != MM_CALL_STATE_ACTIVE) {
mm_dbus_method_invocation_return_error_literal (ctx->invocation, MM_CORE_ERROR, MM_CORE_ERROR_FAILED,
"This call was not active, cannot send dtmf");
handle_send_dtmf_context_free (ctx);
@@ -795,9 +1090,20 @@ handle_send_dtmf_auth_ready (MMAuthProvider *authp,
}
mm_obj_info (ctx->self, "processing user request to send DTMF...");
- MM_BASE_CALL_GET_CLASS (ctx->self)->send_dtmf (ctx->self, ctx->dtmf,
- (GAsyncReadyCallback)handle_send_dtmf_ready,
- ctx);
+ task = send_dtmf_task_new (ctx->self,
+ ctx->dtmf,
+ (GAsyncReadyCallback)handle_send_dtmf_ready,
+ ctx,
+ &error);
+ if (!task) {
+ mm_dbus_method_invocation_take_error (ctx->invocation, error);
+ handle_send_dtmf_context_free (ctx);
+ return;
+ }
+
+ g_queue_push_tail (ctx->self->priv->dtmf_queue, task);
+ if (g_queue_get_length (ctx->self->priv->dtmf_queue) == 1)
+ send_dtmf_task_step_next (task);
}
static gboolean
@@ -924,6 +1230,20 @@ mm_base_call_set_multiparty (MMBaseCall *self,
return mm_gdbus_call_set_multiparty (MM_GDBUS_CALL (self), multiparty);
}
+guint
+mm_base_call_get_dtmf_tone_duration (MMBaseCall *self)
+{
+ return mm_dtmf_duration_normalize (mm_gdbus_call_get_dtmf_tone_duration (MM_GDBUS_CALL (self)));
+}
+
+void
+mm_base_call_set_dtmf_tone_duration (MMBaseCall *self,
+ guint duration_ms)
+{
+ return mm_gdbus_call_set_dtmf_tone_duration (MM_GDBUS_CALL (self),
+ mm_dtmf_duration_normalize (duration_ms));
+}
+
/*****************************************************************************/
/* Current call index, only applicable while the call is ongoing
* See 3GPP TS 22.030 [27], subclause 6.5.5.1.
@@ -989,314 +1309,6 @@ mm_base_call_received_dtmf (MMBaseCall *self,
}
/*****************************************************************************/
-/* 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 *
log_object_build_id (MMLogObject *_self)
@@ -1309,28 +1321,6 @@ log_object_build_id (MMLogObject *_self)
/*****************************************************************************/
-MMBaseCall *
-mm_base_call_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)
-{
- return MM_BASE_CALL (g_object_new (MM_TYPE_BASE_CALL,
- 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));
-}
-
-/*****************************************************************************/
-
static void
set_property (GObject *object,
guint prop_id,
@@ -1365,9 +1355,9 @@ set_property (GObject *object,
self->priv->bind_to = g_value_dup_object (value);
mm_bind_to (MM_BIND (self), MM_BASE_CALL_CONNECTION, self->priv->bind_to);
break;
- case PROP_MODEM:
- g_clear_object (&self->priv->modem);
- self->priv->modem = g_value_dup_object (value);
+ case PROP_IFACE_MODEM_VOICE:
+ g_clear_object (&self->priv->iface);
+ self->priv->iface = g_value_dup_object (value);
break;
case PROP_SKIP_INCOMING_TIMEOUT:
self->priv->skip_incoming_timeout = g_value_get_boolean (value);
@@ -1402,8 +1392,8 @@ get_property (GObject *object,
case PROP_BIND_TO:
g_value_set_object (value, self->priv->bind_to);
break;
- case PROP_MODEM:
- g_value_set_object (value, self->priv->modem);
+ case PROP_IFACE_MODEM_VOICE:
+ g_value_set_object (value, self->priv->iface);
break;
case PROP_SKIP_INCOMING_TIMEOUT:
g_value_set_boolean (value, self->priv->skip_incoming_timeout);
@@ -1434,6 +1424,8 @@ mm_base_call_init (MMBaseCall *self)
/* Setup authorization provider */
self->priv->authp = mm_auth_provider_get ();
self->priv->authp_cancellable = g_cancellable_new ();
+
+ self->priv->dtmf_queue = g_queue_new ();
}
static void
@@ -1441,6 +1433,9 @@ finalize (GObject *object)
{
MMBaseCall *self = MM_BASE_CALL (object);
+ g_assert (g_queue_get_length (self->priv->dtmf_queue) == 0);
+ g_queue_free (g_steal_pointer (&self->priv->dtmf_queue));
+
g_assert (!self->priv->start_cancellable);
g_free (self->priv->path);
@@ -1466,11 +1461,14 @@ dispose (GObject *object)
g_clear_object (&self->priv->connection);
}
- g_clear_object (&self->priv->modem);
+ g_clear_object (&self->priv->iface);
g_clear_object (&self->priv->bind_to);
g_cancellable_cancel (self->priv->authp_cancellable);
g_clear_object (&self->priv->authp_cancellable);
+ g_queue_foreach (self->priv->dtmf_queue, (GFunc) send_dtmf_task_cancel, NULL);
+ g_queue_clear (self->priv->dtmf_queue);
+
G_OBJECT_CLASS (mm_base_call_parent_class)->dispose (object);
}
@@ -1498,17 +1496,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",
@@ -1527,13 +1514,13 @@ mm_base_call_class_init (MMBaseCallClass *klass)
g_object_class_override_property (object_class, PROP_BIND_TO, MM_BIND_TO);
- properties[PROP_MODEM] =
- g_param_spec_object (MM_BASE_CALL_MODEM,
- "Modem",
- "The Modem which owns this call",
- MM_TYPE_BASE_MODEM,
+ properties[PROP_IFACE_MODEM_VOICE] =
+ g_param_spec_object (MM_BASE_CALL_IFACE_MODEM_VOICE,
+ "Modem Voice Interface",
+ "The Modem voice interface which owns this call",
+ MM_TYPE_IFACE_MODEM_VOICE,
G_PARAM_READWRITE);
- g_object_class_install_property (object_class, PROP_MODEM, properties[PROP_MODEM]);
+ g_object_class_install_property (object_class, PROP_IFACE_MODEM_VOICE, properties[PROP_IFACE_MODEM_VOICE]);
properties[PROP_SKIP_INCOMING_TIMEOUT] =
g_param_spec_boolean (MM_BASE_CALL_SKIP_INCOMING_TIMEOUT,