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.
This commit is contained in:

committed by
Aleksander Morgado

parent
ea3f5ccad8
commit
efb497e2e6
@@ -422,7 +422,7 @@ dnl-----------------------------------------------------------------------------
|
||||
dnl QMI support (enabled by default)
|
||||
dnl
|
||||
|
||||
LIBQMI_VERSION=1.31.8
|
||||
LIBQMI_VERSION=1.31.9
|
||||
|
||||
AC_ARG_WITH(qmi, AS_HELP_STRING([--without-qmi], [Build without QMI support]), [], [with_qmi=yes])
|
||||
AM_CONDITIONAL(WITH_QMI, test "x$with_qmi" = "xyes")
|
||||
|
@@ -247,7 +247,7 @@ config_h.set('WITH_MBIM', enable_mbim)
|
||||
# QMI support (enabled by default)
|
||||
enable_qmi = get_option('qmi')
|
||||
if enable_qmi
|
||||
qmi_glib_dep = dependency('qmi-glib', version: '>= 1.31.8')
|
||||
qmi_glib_dep = dependency('qmi-glib', version: '>= 1.31.9')
|
||||
endif
|
||||
config_h.set('WITH_QMI', enable_qmi)
|
||||
|
||||
|
@@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user