From efb497e2e67d7eba213f6c2822e3f947219f6af4 Mon Sep 17 00:00:00 2001 From: Dylan Van Assche Date: Sat, 9 Jul 2022 21:10:37 +0200 Subject: mm-call-qmi: implement DTMF support Overwrite the base class with a QMI implementation to send DTMF characters during a call. Uses the continuous DTMF QMI messages to support both CDMA and 3GPP networks. --- src/mm-call-qmi.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) (limited to 'src/mm-call-qmi.c') diff --git a/src/mm-call-qmi.c b/src/mm-call-qmi.c index 38a2aa9e..8fad9584 100644 --- a/src/mm-call-qmi.c +++ b/src/mm-call-qmi.c @@ -329,6 +329,160 @@ call_hangup (MMBaseCall *self, qmi_message_voice_end_call_input_unref (input); } +/*****************************************************************************/ +/* Send DTMF character */ + +typedef struct { + QmiClient *client; + guint8 call_id; +} SendDtmfContext; + +static void +send_dtmf_context_free (SendDtmfContext *ctx) +{ + g_clear_object (&ctx->client); + g_slice_free (SendDtmfContext, ctx); +} + +static gboolean +call_send_dtmf_finish (MMBaseCall *self, + GAsyncResult *res, + GError **error) +{ + return g_task_propagate_boolean (G_TASK (res), error); +} + +static void +voice_stop_continuous_dtmf_ready (QmiClientVoice *client, + GAsyncResult *res, + GTask *task) +{ + g_autoptr (QmiMessageVoiceStopContinuousDtmfOutput) output = NULL; + GError *error = NULL; + + output = qmi_client_voice_stop_continuous_dtmf_finish (client, res, &error); + if (!output) { + g_prefix_error (&error, "QMI operation failed: "); + g_task_return_error (task, error); + } else if (!qmi_message_voice_stop_continuous_dtmf_output_get_result (output, &error)) { + g_prefix_error (&error, "Couldn't send DTMF character: "); + g_task_return_error (task, error); + } else { + g_task_return_boolean (task, TRUE); + } + + g_object_unref (task); +} + +static gboolean +voice_stop_continuous_dtmf (GTask *task) +{ + SendDtmfContext *ctx; + GError *error = NULL; + g_autoptr (QmiMessageVoiceStopContinuousDtmfInput) input = NULL; + + ctx = g_task_get_task_data (task); + + input = qmi_message_voice_stop_continuous_dtmf_input_new (); + qmi_message_voice_stop_continuous_dtmf_input_set_data (input, ctx->call_id, &error); + + qmi_client_voice_stop_continuous_dtmf (QMI_CLIENT_VOICE (ctx->client), + input, + 5, + NULL, + (GAsyncReadyCallback) voice_stop_continuous_dtmf_ready, + task); + + return G_SOURCE_REMOVE; +} + +static void +voice_start_continuous_dtmf_ready (QmiClientVoice *client, + GAsyncResult *res, + GTask *task) +{ + g_autoptr(QmiMessageVoiceStartContinuousDtmfOutput) output = NULL; + GError *error = NULL; + + output = qmi_client_voice_start_continuous_dtmf_finish (client, res, &error); + if (!output) { + g_prefix_error (&error, "QMI operation failed: "); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + if (!qmi_message_voice_start_continuous_dtmf_output_get_result (output, &error)) { + g_prefix_error (&error, "Couldn't send DTMF character: "); + g_task_return_error (task, error); + g_object_unref (task); + return; + } + + /* Disable DTMF press after 500 ms */ + g_timeout_add (500, (GSourceFunc) voice_stop_continuous_dtmf, task); +} + +static void +call_send_dtmf (MMBaseCall *self, + const gchar *dtmf, + GAsyncReadyCallback callback, + gpointer user_data) +{ + GTask *task; + GError *error = NULL; + SendDtmfContext *ctx; + QmiClient *client = NULL; + guint8 call_id; + g_autoptr (QmiMessageVoiceStartContinuousDtmfInput) input = NULL; + + /* Ensure Voice client */ + if (!ensure_qmi_client (MM_CALL_QMI (self), + QMI_SERVICE_VOICE, &client, + callback, user_data)) + return; + + task = g_task_new (self, NULL, callback, user_data); + + call_id = mm_base_call_get_index (self); + if (call_id == 0) { + g_task_return_new_error (task, + MM_CORE_ERROR, + MM_CORE_ERROR_INVALID_ARGS, + "Invalid call index"); + g_object_unref (task); + return; + } + + ctx = g_slice_new0 (SendDtmfContext); + ctx->client = g_object_ref (client); + ctx->call_id = call_id; + + g_task_set_task_data (task, ctx, (GDestroyNotify) send_dtmf_context_free); + + /* Send DTMF character as ASCII number */ + input = qmi_message_voice_start_continuous_dtmf_input_new (); + qmi_message_voice_start_continuous_dtmf_input_set_data (input, + call_id, + (guint8) dtmf[0], + &error); + if (error) { + g_task_return_new_error (task, + MM_CORE_ERROR, + MM_CORE_ERROR_INVALID_ARGS, + "DTMF data build failed"); + g_object_unref (task); + return; + } + + qmi_client_voice_start_continuous_dtmf (QMI_CLIENT_VOICE (client), + input, + 5, + NULL, + (GAsyncReadyCallback) voice_start_continuous_dtmf_ready, + task); +} + /*****************************************************************************/ MMBaseCall * @@ -362,4 +516,6 @@ mm_call_qmi_class_init (MMCallQmiClass *klass) base_call_class->accept_finish = call_accept_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; } -- cgit v1.2.3-70-g09d2