call: allow setting DTMF tone duration at call creation time

Instead of hard-coding a 500ms DTMF tone duration, let applications
use a specific duration at call setup time.

Signed-off-by: Dan Williams <dan@ioncontrol.co>
This commit is contained in:
Dan Williams
2025-05-30 07:59:58 -05:00
parent 28b1954654
commit 5448a85a2b
19 changed files with 253 additions and 39 deletions
+14
View File
@@ -922,6 +922,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.
+9
View File
@@ -37,6 +37,10 @@ typedef struct _MMBaseCall MMBaseCall;
typedef struct _MMBaseCallClass MMBaseCallClass;
typedef struct _MMBaseCallPrivate MMBaseCallPrivate;
#define MM_CALL_DIRECTION "direction"
#define MM_CALL_NUMBER "number"
#define MM_CALL_DTMF_TONE_DURATION "dtmf-tone-duration"
#define MM_BASE_CALL_PATH "call-path"
#define MM_BASE_CALL_CONNECTION "call-connection"
#define MM_BASE_CALL_IFACE_MODEM_VOICE "call-iface-modem-voice"
@@ -129,4 +133,9 @@ void mm_base_call_received_dtmf (MMBaseCall *self,
void mm_base_call_incoming_refresh (MMBaseCall *self);
guint mm_base_call_get_dtmf_tone_duration (MMBaseCall *self);
void mm_base_call_set_dtmf_tone_duration (MMBaseCall *self,
guint duration_ms);
#endif /* MM_BASE_CALL_H */
+4 -2
View File
@@ -12190,11 +12190,13 @@ modem_voice_load_call_list (MMIfaceModemVoice *self,
static MMBaseCall *
modem_voice_create_call (MMIfaceModemVoice *self,
MMCallDirection direction,
const gchar *number)
const gchar *number,
const guint dtmf_tone_duration)
{
return mm_call_qmi_new (MM_BASE_MODEM (self),
direction,
number);
number,
dtmf_tone_duration);
}
/*****************************************************************************/
+3 -1
View File
@@ -8899,7 +8899,8 @@ modem_voice_disable_unsolicited_events (MMIfaceModemVoice *self,
static MMBaseCall *
modem_voice_create_call (MMIfaceModemVoice *_self,
MMCallDirection direction,
const gchar *number)
const gchar *number,
const guint dtmf_tone_duration)
{
MMBroadbandModem *self = MM_BROADBAND_MODEM (_self);
@@ -8907,6 +8908,7 @@ modem_voice_create_call (MMIfaceModemVoice *_self,
G_OBJECT (self),
direction,
number,
dtmf_tone_duration,
/* If +CLCC is supported, we want no incoming timeout.
* Also, we're able to support detailed call state updates without
* additional vendor-specific commands. */
+66 -15
View File
@@ -36,9 +36,18 @@
G_DEFINE_TYPE (MMCallAt, mm_call_at, MM_TYPE_BASE_CALL)
typedef enum {
FEATURE_SUPPORT_UNKNOWN,
FEATURE_NOT_SUPPORTED,
FEATURE_SUPPORTED,
} FeatureSupport;
struct _MMCallAtPrivate {
/* The modem which owns this call */
MMBaseModem *modem;
/* DTMF support */
FeatureSupport vtd_supported;
};
/*****************************************************************************/
@@ -334,26 +343,66 @@ call_send_dtmf_ready (MMBaseModem *modem,
}
static void
call_send_dtmf (MMBaseCall *_self,
const gchar *dtmf,
GAsyncReadyCallback callback,
gpointer user_data)
send_dtmf_digit (MMCallAt *self,
GTask *task,
const gchar dtmf_digit)
{
MMCallAt *self = MM_CALL_AT (_self);
GTask *task;
gchar *cmd;
g_autofree gchar *cmd = NULL;
task = g_task_new (self, NULL, callback, user_data);
cmd = g_strdup_printf ("AT+VTS=%c", dtmf[0]);
cmd = g_strdup_printf ("AT+VTS=%c", dtmf_digit);
mm_base_modem_at_command (self->priv->modem,
cmd,
3,
FALSE,
(GAsyncReadyCallback)call_send_dtmf_ready,
task);
}
g_free (cmd);
static void
call_dtmf_vtd_ready (MMBaseModem *modem,
GAsyncResult *res,
GTask *task)
{
MMCallAt *self;
g_autoptr(GError) error = NULL;
gchar dtmf_digit;
self = g_task_get_source_object (task);
mm_base_modem_at_command_finish (modem, res, &error);
self->priv->vtd_supported = error ? FEATURE_NOT_SUPPORTED : FEATURE_SUPPORTED;
dtmf_digit = (gchar) GPOINTER_TO_UINT (g_task_get_task_data (task));
send_dtmf_digit (self, task, dtmf_digit);
}
static void
call_send_dtmf (MMBaseCall *_self,
const gchar *dtmf,
GAsyncReadyCallback callback,
gpointer user_data)
{
MMCallAt *self = MM_CALL_AT (_self);
GTask *task;
g_autofree gchar *cmd = NULL;
task = g_task_new (self, NULL, callback, user_data);
if (self->priv->vtd_supported == FEATURE_NOT_SUPPORTED) {
send_dtmf_digit (self, task, dtmf[0]);
return;
}
g_task_set_task_data (task, GUINT_TO_POINTER (dtmf[0]), NULL);
/* Otherwise try to set duration */
cmd = g_strdup_printf ("AT+VTD=%u", mm_base_call_get_dtmf_tone_duration (_self));
mm_base_modem_at_command (self->priv->modem,
cmd,
3,
FALSE,
(GAsyncReadyCallback)call_dtmf_vtd_ready,
task);
}
/*****************************************************************************/
@@ -363,6 +412,7 @@ mm_call_at_new (MMBaseModem *modem,
GObject *bind_to,
MMCallDirection direction,
const gchar *number,
const guint dtmf_tone_duration,
gboolean skip_incoming_timeout,
gboolean supports_dialing_to_ringing,
gboolean supports_ringing_to_active)
@@ -370,10 +420,11 @@ mm_call_at_new (MMBaseModem *modem,
MMBaseCall *call;
call = MM_BASE_CALL (g_object_new (MM_TYPE_CALL_AT,
MM_BASE_CALL_IFACE_MODEM_VOICE, modem,
MM_BIND_TO, bind_to,
"direction", direction,
"number", number,
MM_BASE_CALL_IFACE_MODEM_VOICE, modem,
MM_BIND_TO, bind_to,
MM_CALL_DIRECTION, direction,
MM_CALL_NUMBER, number,
MM_CALL_DTMF_TONE_DURATION, dtmf_tone_duration,
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,
+1
View File
@@ -53,6 +53,7 @@ MMBaseCall *mm_call_at_new (MMBaseModem *modem,
GObject *bind_to,
MMCallDirection direction,
const gchar *number,
const guint dtmf_tone_duration,
gboolean skip_incoming_timeout,
gboolean supports_dialing_to_ringing,
gboolean supports_ringing_to_active);
+14 -7
View File
@@ -402,9 +402,12 @@ voice_start_continuous_dtmf_ready (QmiClientVoice *client,
GAsyncResult *res,
GTask *task)
{
MMCallQmi *self;
g_autoptr(QmiMessageVoiceStartContinuousDtmfOutput) output = NULL;
GError *error = NULL;
self = g_task_get_source_object (task);
output = qmi_client_voice_start_continuous_dtmf_finish (client, res, &error);
if (!output) {
g_prefix_error (&error, "QMI operation failed: ");
@@ -420,8 +423,10 @@ voice_start_continuous_dtmf_ready (QmiClientVoice *client,
return;
}
/* Disable DTMF press after 500 ms */
g_timeout_add (500, (GSourceFunc) voice_stop_continuous_dtmf, task);
/* Disable DTMF press after DTMF tone duration elapses */
g_timeout_add (mm_base_call_get_dtmf_tone_duration (MM_BASE_CALL (self)),
(GSourceFunc) voice_stop_continuous_dtmf,
task);
}
static void
@@ -489,15 +494,17 @@ call_send_dtmf (MMBaseCall *self,
MMBaseCall *
mm_call_qmi_new (MMBaseModem *modem,
MMCallDirection direction,
const gchar *number)
const gchar *number,
const guint dtmf_tone_duration)
{
MMBaseCall *call;
call = MM_BASE_CALL (g_object_new (MM_TYPE_CALL_QMI,
MM_BASE_CALL_IFACE_MODEM_VOICE, modem,
MM_BIND_TO, modem,
"direction", direction,
"number", number,
MM_BASE_CALL_IFACE_MODEM_VOICE, modem,
MM_BIND_TO, modem,
MM_CALL_DIRECTION, direction,
MM_CALL_NUMBER, number,
MM_CALL_DTMF_TONE_DURATION, dtmf_tone_duration,
MM_BASE_CALL_SKIP_INCOMING_TIMEOUT, TRUE,
MM_BASE_CALL_SUPPORTS_DIALING_TO_RINGING, TRUE,
MM_BASE_CALL_SUPPORTS_RINGING_TO_ACTIVE, TRUE,
+2 -1
View File
@@ -49,6 +49,7 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (MMCallQmi, g_object_unref)
MMBaseCall *mm_call_qmi_new (MMBaseModem *modem,
MMCallDirection direction,
const gchar *number);
const gchar *number,
const guint dtmf_tone_duration);
#endif /* MM_CALL_QMI_H */
+8 -2
View File
@@ -161,7 +161,7 @@ create_incoming_call (MMIfaceModemVoice *self,
g_assert (MM_IFACE_MODEM_VOICE_GET_IFACE (self)->create_call != NULL);
call = MM_IFACE_MODEM_VOICE_GET_IFACE (self)->create_call (self, MM_CALL_DIRECTION_INCOMING, number);
call = MM_IFACE_MODEM_VOICE_GET_IFACE (self)->create_call (self, MM_CALL_DIRECTION_INCOMING, number, 0);
update_audio_settings_in_call (self, call);
return call;
}
@@ -173,6 +173,7 @@ create_outgoing_call_from_properties (MMIfaceModemVoice *self,
{
MMBaseCall *call;
const gchar *number;
guint dtmf_tone_duration;
/* Don't create CALL from properties if either number is missing */
number = mm_call_properties_get_number (properties) ;
@@ -184,9 +185,14 @@ create_outgoing_call_from_properties (MMIfaceModemVoice *self,
return NULL;
}
dtmf_tone_duration = mm_call_properties_get_dtmf_tone_duration (properties) ;
/* Create a call object as defined by the interface */
g_assert (MM_IFACE_MODEM_VOICE_GET_IFACE (self)->create_call != NULL);
call = MM_IFACE_MODEM_VOICE_GET_IFACE (self)->create_call (self, MM_CALL_DIRECTION_OUTGOING, number);
call = MM_IFACE_MODEM_VOICE_GET_IFACE (self)->create_call (self,
MM_CALL_DIRECTION_OUTGOING,
number,
dtmf_tone_duration);
update_audio_settings_in_call (self, call);
return call;
}
+2 -1
View File
@@ -123,7 +123,8 @@ struct _MMIfaceModemVoiceInterface {
/* Create call objects */
MMBaseCall * (* create_call) (MMIfaceModemVoice *self,
MMCallDirection direction,
const gchar *number);
const gchar *number,
const guint dtmf_tone_duration);
/* Hold and accept */
void (* hold_and_accept) (MMIfaceModemVoice *self,
+16
View File
@@ -5871,3 +5871,19 @@ mm_parse_cpin_response (const gchar *response,
return MM_MODEM_LOCK_UNKNOWN;
}
/*****************************************************************************/
guint
mm_dtmf_duration_normalize (guint duration_ms)
{
/* Default to 500ms */
if (duration_ms == 0)
return 500;
/* round to next highest 100ms */
if (duration_ms % 100)
duration_ms = ((duration_ms + 100) / 100) * 100;
return CLAMP (duration_ms, 100, 1000);
}
+5
View File
@@ -643,4 +643,9 @@ guint mm_string_uint_map_lookup (const MMStringUintMap *map,
MMModemLock mm_parse_cpin_response (const gchar *response,
gboolean expect_cpin_prefix);
/*****************************************************************************/
/* Helper to clamp duration and round to next 100ms */
guint mm_dtmf_duration_normalize (guint duration_ms);
#endif /* MM_MODEM_HELPERS_H */
+4 -2
View File
@@ -998,7 +998,8 @@ mm_shared_cinterion_enable_location_gathering (MMIfaceModemLocation *self,
MMBaseCall *
mm_shared_cinterion_create_call (MMIfaceModemVoice *self,
MMCallDirection direction,
const gchar *number)
const gchar *number,
const guint dtmf_tone_duration)
{
Private *priv;
@@ -1010,6 +1011,7 @@ mm_shared_cinterion_create_call (MMIfaceModemVoice *self,
G_OBJECT (self),
direction,
number,
dtmf_tone_duration,
/* When SLCC is supported we have support for detailed
* call list events via call list report URCs */
TRUE, /* incoming timeout not required */
@@ -1020,7 +1022,7 @@ mm_shared_cinterion_create_call (MMIfaceModemVoice *self,
/* otherwise, run parent's generic base call logic */
g_assert (priv->iface_modem_voice_parent);
g_assert (priv->iface_modem_voice_parent->create_call);
return priv->iface_modem_voice_parent->create_call (self, direction, number);
return priv->iface_modem_voice_parent->create_call (self, direction, number, dtmf_tone_duration);
}
/*****************************************************************************/
+2 -1
View File
@@ -105,7 +105,8 @@ gboolean mm_shared_cinterion_disable_location_gathering_finish (MMI
MMBaseCall *mm_shared_cinterion_create_call (MMIfaceModemVoice *self,
MMCallDirection direction,
const gchar *number);
const gchar *number,
const guint dtmf_tone_duration);
void mm_shared_cinterion_voice_check_support (MMIfaceModemVoice *self,
GAsyncReadyCallback callback,
@@ -3879,12 +3879,14 @@ modem_voice_disable_unsolicited_events (MMIfaceModemVoice *self,
static MMBaseCall *
create_call (MMIfaceModemVoice *self,
MMCallDirection direction,
const gchar *number)
const gchar *number,
const guint dtmf_tone_duration)
{
return mm_call_at_new (MM_BASE_MODEM (self),
G_OBJECT (self),
direction,
number,
dtmf_tone_duration,
TRUE, /* skip_incoming_timeout */
TRUE, /* supports_dialing_to_ringing */
TRUE); /* supports_ringing_to_active) */
+3 -1
View File
@@ -1504,12 +1504,14 @@ modem_voice_setup_unsolicited_events (MMIfaceModemVoice *self,
static MMBaseCall *
create_call (MMIfaceModemVoice *self,
MMCallDirection direction,
const gchar *number)
const gchar *number,
const guint dtmf_tone_duration)
{
return mm_call_at_new (MM_BASE_MODEM (self),
G_OBJECT (self),
direction,
number,
dtmf_tone_duration,
TRUE, /* skip_incoming_timeout */
TRUE, /* supports_dialing_to_ringing */
TRUE); /* supports_ringing_to_active */