base-call,iface-modem-voice:: handle DTMF
This commit is contained in:

committed by
Aleksander Morgado

parent
8edead9193
commit
9874f10e1f
@@ -368,6 +368,111 @@ handle_hangup (MMBaseCall *self,
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/* Send tone (DBus call handling) */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MMBaseCall *self;
|
||||||
|
MMBaseModem *modem;
|
||||||
|
GDBusMethodInvocation *invocation;
|
||||||
|
gchar *tone;
|
||||||
|
} HandleSendToneContext;
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_send_tone_context_free (HandleSendToneContext *ctx)
|
||||||
|
{
|
||||||
|
g_object_unref (ctx->invocation);
|
||||||
|
g_object_unref (ctx->modem);
|
||||||
|
g_object_unref (ctx->self);
|
||||||
|
g_free(ctx->tone);
|
||||||
|
g_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_send_tone_ready (MMBaseCall *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
HandleSendToneContext *ctx)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (!MM_BASE_CALL_GET_CLASS (self)->send_tone_finish (self, res, &error)) {
|
||||||
|
g_dbus_method_invocation_take_error (ctx->invocation, error);
|
||||||
|
} else {
|
||||||
|
mm_gdbus_call_complete_send_tone (MM_GDBUS_CALL (ctx->self), ctx->invocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_send_tone_context_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
handle_send_tone_auth_ready (MMBaseModem *modem,
|
||||||
|
GAsyncResult *res,
|
||||||
|
HandleSendToneContext *ctx)
|
||||||
|
{
|
||||||
|
MMCallState state;
|
||||||
|
GError *error = NULL;
|
||||||
|
|
||||||
|
if (!mm_base_modem_authorize_finish (modem, res, &error)) {
|
||||||
|
g_dbus_method_invocation_take_error (ctx->invocation, error);
|
||||||
|
handle_send_tone_context_free (ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state = mm_gdbus_call_get_state (MM_GDBUS_CALL (ctx->self));
|
||||||
|
|
||||||
|
/* Check if we do support doing it */
|
||||||
|
if (!MM_BASE_CALL_GET_CLASS (ctx->self)->send_tone ||
|
||||||
|
!MM_BASE_CALL_GET_CLASS (ctx->self)->send_tone_finish) {
|
||||||
|
g_dbus_method_invocation_return_error (ctx->invocation,
|
||||||
|
MM_CORE_ERROR,
|
||||||
|
MM_CORE_ERROR_UNSUPPORTED,
|
||||||
|
"SendToneing call is not supported by this modem");
|
||||||
|
handle_send_tone_context_free (ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We can only send_tone when call is in ACTIVE state */
|
||||||
|
if (state != MM_CALL_STATE_ACTIVE ){
|
||||||
|
g_dbus_method_invocation_return_error (ctx->invocation,
|
||||||
|
MM_CORE_ERROR,
|
||||||
|
MM_CORE_ERROR_FAILED,
|
||||||
|
"This call was not active, cannot send_tone ");
|
||||||
|
handle_send_tone_context_free (ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mm_dbg("[%s:%d] Tone string: '%s'", __func__, __LINE__, ctx->tone);
|
||||||
|
MM_BASE_CALL_GET_CLASS (ctx->self)->send_tone (ctx->self, ctx->tone,
|
||||||
|
(GAsyncReadyCallback)handle_send_tone_ready,
|
||||||
|
ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
handle_send_tone (MMBaseCall *self,
|
||||||
|
GDBusMethodInvocation *invocation,
|
||||||
|
const gchar *tone)
|
||||||
|
{
|
||||||
|
HandleSendToneContext *ctx;
|
||||||
|
|
||||||
|
ctx = g_new0 (HandleSendToneContext, 1);
|
||||||
|
ctx->self = g_object_ref (self);
|
||||||
|
ctx->invocation = g_object_ref (invocation);
|
||||||
|
|
||||||
|
mm_dbg("[%s:%d] Tone string: '%s'", __func__, __LINE__, tone);
|
||||||
|
ctx->tone = g_strdup(tone);
|
||||||
|
g_object_get (self,
|
||||||
|
MM_BASE_CALL_MODEM, &ctx->modem,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
mm_base_modem_authorize (ctx->modem,
|
||||||
|
invocation,
|
||||||
|
MM_AUTHORIZATION_VOICE,
|
||||||
|
(GAsyncReadyCallback)handle_send_tone_auth_ready,
|
||||||
|
ctx);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
void
|
void
|
||||||
mm_base_call_export (MMBaseCall *self)
|
mm_base_call_export (MMBaseCall *self)
|
||||||
{
|
{
|
||||||
@@ -409,6 +514,10 @@ call_dbus_export (MMBaseCall *self)
|
|||||||
"handle-hangup",
|
"handle-hangup",
|
||||||
G_CALLBACK (handle_hangup),
|
G_CALLBACK (handle_hangup),
|
||||||
NULL);
|
NULL);
|
||||||
|
g_signal_connect (self,
|
||||||
|
"handle-send-tone",
|
||||||
|
G_CALLBACK (handle_send_tone),
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
|
||||||
if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self),
|
if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (self),
|
||||||
@@ -457,6 +566,11 @@ mm_base_call_change_state(MMBaseCall *self, MMCallState new_state, MMCallStateRe
|
|||||||
reason);
|
reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mm_base_call_received_dtmf (MMBaseCall *self, gchar *tone)
|
||||||
|
{
|
||||||
|
mm_gdbus_call_emit_tone_received(MM_GDBUS_CALL (self), tone);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
/* Start the CALL */
|
/* Start the CALL */
|
||||||
|
|
||||||
@@ -671,7 +785,6 @@ call_accept (MMBaseCall *self,
|
|||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
/* Hangup the CALL */
|
/* Hangup the CALL */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -759,6 +872,83 @@ call_hangup (MMBaseCall *self,
|
|||||||
g_free (cmd);
|
g_free (cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Send DTMF tone to call */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MMBaseCall *self;
|
||||||
|
MMBaseModem *modem;
|
||||||
|
GSimpleAsyncResult *result;
|
||||||
|
} CallSendToneContext;
|
||||||
|
|
||||||
|
static void
|
||||||
|
call_send_tone_context_complete_and_free (CallSendToneContext *ctx)
|
||||||
|
{
|
||||||
|
g_simple_async_result_complete_in_idle (ctx->result);
|
||||||
|
g_object_unref (ctx->result);
|
||||||
|
g_object_unref (ctx->modem);
|
||||||
|
g_object_unref (ctx->self);
|
||||||
|
g_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
call_send_tone_finish (MMBaseCall *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error)
|
||||||
|
{
|
||||||
|
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
call_send_tone_ready (MMBaseModem *modem,
|
||||||
|
GAsyncResult *res,
|
||||||
|
CallSendToneContext *ctx)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
const gchar *response = NULL;
|
||||||
|
|
||||||
|
response = mm_base_modem_at_command_finish (modem, res, &error);
|
||||||
|
if (error) {
|
||||||
|
mm_dbg ("Couldn't send_tone: '%s'", error->message);
|
||||||
|
g_simple_async_result_take_error (ctx->result, error);
|
||||||
|
call_send_tone_context_complete_and_free (ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_simple_async_result_set_op_res_gboolean (ctx->result, TRUE);
|
||||||
|
call_send_tone_context_complete_and_free (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
call_send_tone (MMBaseCall *self,
|
||||||
|
const gchar *tone,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
CallSendToneContext *ctx;
|
||||||
|
gchar *cmd;
|
||||||
|
|
||||||
|
/* Setup the context */
|
||||||
|
ctx = g_new0 (CallSendToneContext, 1);
|
||||||
|
ctx->result = g_simple_async_result_new (G_OBJECT (self),
|
||||||
|
callback,
|
||||||
|
user_data,
|
||||||
|
call_send_tone);
|
||||||
|
ctx->self = g_object_ref (self);
|
||||||
|
ctx->modem = g_object_ref (self->priv->modem);
|
||||||
|
|
||||||
|
mm_dbg("[%s:%d] Tone string: '%s'", __func__, __LINE__, tone);
|
||||||
|
cmd = g_strdup_printf ("AT+VTS=%c",tone[0]);
|
||||||
|
mm_base_modem_at_command (ctx->modem,
|
||||||
|
cmd,
|
||||||
|
3,
|
||||||
|
FALSE,
|
||||||
|
(GAsyncReadyCallback)call_send_tone_ready,
|
||||||
|
ctx);
|
||||||
|
|
||||||
|
g_free (cmd);
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
MMBaseCall *self;
|
MMBaseCall *self;
|
||||||
@@ -1018,6 +1208,8 @@ mm_base_call_class_init (MMBaseCallClass *klass)
|
|||||||
klass->hangup_finish = call_hangup_finish;
|
klass->hangup_finish = call_hangup_finish;
|
||||||
klass->delete = call_delete;
|
klass->delete = call_delete;
|
||||||
klass->delete_finish = call_delete_finish;
|
klass->delete_finish = call_delete_finish;
|
||||||
|
klass->send_tone = call_send_tone;
|
||||||
|
klass->send_tone_finish = call_send_tone_finish;
|
||||||
|
|
||||||
|
|
||||||
properties[PROP_CONNECTION] =
|
properties[PROP_CONNECTION] =
|
||||||
|
@@ -71,6 +71,15 @@ struct _MMBaseCallClass {
|
|||||||
GAsyncResult *res,
|
GAsyncResult *res,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
|
/* Send a DTMF tone */
|
||||||
|
void (* send_tone) (MMBaseCall *self,
|
||||||
|
const gchar *tone,
|
||||||
|
GAsyncReadyCallback callback,
|
||||||
|
gpointer user_data);
|
||||||
|
gboolean (* send_tone_finish) (MMBaseCall *self,
|
||||||
|
GAsyncResult *res,
|
||||||
|
GError **error);
|
||||||
|
|
||||||
/* Delete the call */
|
/* Delete the call */
|
||||||
void (* delete) (MMBaseCall *self,
|
void (* delete) (MMBaseCall *self,
|
||||||
GAsyncReadyCallback callback,
|
GAsyncReadyCallback callback,
|
||||||
@@ -88,10 +97,11 @@ MMBaseCall *mm_base_call_new_from_properties (MMBaseModem *modem,
|
|||||||
MMCallProperties *properties,
|
MMCallProperties *properties,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
void mm_base_call_export (MMBaseCall *self);
|
void mm_base_call_export (MMBaseCall *self);
|
||||||
void mm_base_call_unexport (MMBaseCall *self);
|
void mm_base_call_unexport (MMBaseCall *self);
|
||||||
const gchar *mm_base_call_get_path (MMBaseCall *self);
|
const gchar *mm_base_call_get_path (MMBaseCall *self);
|
||||||
void mm_base_call_change_state(MMBaseCall *self, MMCallState new_state, MMCallStateReason reason);
|
void mm_base_call_change_state (MMBaseCall *self, MMCallState new_state, MMCallStateReason reason);
|
||||||
|
void mm_base_call_received_dtmf (MMBaseCall *self, gchar *tone);
|
||||||
|
|
||||||
void mm_base_call_delete (MMBaseCall *self,
|
void mm_base_call_delete (MMBaseCall *self,
|
||||||
GAsyncReadyCallback callback,
|
GAsyncReadyCallback callback,
|
||||||
|
@@ -189,6 +189,29 @@ MMBaseCall* mm_call_list_get_first_non_terminated_call(MMCallList *self)
|
|||||||
return call;
|
return call;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean mm_call_list_send_dtmf_to_active_calls(MMCallList *self, gchar *tone)
|
||||||
|
{
|
||||||
|
gboolean signaled = FALSE;
|
||||||
|
GList *l;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
for (i = 0, l = self->priv->list; l; l = g_list_next (l)) {
|
||||||
|
|
||||||
|
MMCallState state;
|
||||||
|
|
||||||
|
g_object_get (MM_BASE_CALL (l->data),
|
||||||
|
"state" , &state,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if( state == MM_CALL_STATE_ACTIVE ) {
|
||||||
|
signaled = TRUE;
|
||||||
|
mm_base_call_received_dtmf(MM_BASE_CALL (l->data), tone);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return signaled;
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@@ -76,5 +76,7 @@ MMBaseCall* mm_call_list_get_new_incoming (MMCallList *self);
|
|||||||
MMBaseCall* mm_call_list_get_first_ringing_call (MMCallList *self);
|
MMBaseCall* mm_call_list_get_first_ringing_call (MMCallList *self);
|
||||||
MMBaseCall* mm_call_list_get_first_outgoing_dialing_call(MMCallList *self);
|
MMBaseCall* mm_call_list_get_first_outgoing_dialing_call(MMCallList *self);
|
||||||
MMBaseCall* mm_call_list_get_first_non_terminated_call (MMCallList *self);
|
MMBaseCall* mm_call_list_get_first_non_terminated_call (MMCallList *self);
|
||||||
|
gboolean mm_call_list_send_dtmf_to_active_calls (MMCallList *self,
|
||||||
|
gchar *tone);
|
||||||
|
|
||||||
#endif /* MM_CALL_LIST_H */
|
#endif /* MM_CALL_LIST_H */
|
||||||
|
@@ -46,7 +46,6 @@ mm_iface_modem_voice_create_call (MMIfaceModemVoice *self)
|
|||||||
return MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->create_call (self);
|
return MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->create_call (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
//BASCETTA:TODO: bisogna aggiungere la gestione degli errori.
|
|
||||||
MMBaseCall *
|
MMBaseCall *
|
||||||
mm_iface_modem_voice_create_incoming_call (MMIfaceModemVoice *self)
|
mm_iface_modem_voice_create_incoming_call (MMIfaceModemVoice *self)
|
||||||
{
|
{
|
||||||
@@ -192,6 +191,23 @@ gboolean mm_iface_modem_voice_network_hangup (MMIfaceModemVoice *self)
|
|||||||
|
|
||||||
return updated;
|
return updated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean mm_iface_modem_voice_received_dtmf (MMIfaceModemVoice *self, gchar *tone)
|
||||||
|
{
|
||||||
|
gboolean updated = FALSE;
|
||||||
|
MMCallList *list = NULL;
|
||||||
|
|
||||||
|
g_object_get (MM_BASE_MODEM (self),
|
||||||
|
MM_IFACE_MODEM_VOICE_CALL_LIST, &list,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
if( list ) {
|
||||||
|
updated = mm_call_list_send_dtmf_to_active_calls(list, tone);
|
||||||
|
}
|
||||||
|
|
||||||
|
return updated;
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@@ -126,6 +126,8 @@ gboolean mm_iface_modem_voice_update_incoming_call_number (MMIfaceModemVoi
|
|||||||
gboolean mm_iface_modem_voice_call_dialing_to_ringing (MMIfaceModemVoice *self);
|
gboolean mm_iface_modem_voice_call_dialing_to_ringing (MMIfaceModemVoice *self);
|
||||||
gboolean mm_iface_modem_voice_call_ringing_to_active (MMIfaceModemVoice *self);
|
gboolean mm_iface_modem_voice_call_ringing_to_active (MMIfaceModemVoice *self);
|
||||||
gboolean mm_iface_modem_voice_network_hangup (MMIfaceModemVoice *self);
|
gboolean mm_iface_modem_voice_network_hangup (MMIfaceModemVoice *self);
|
||||||
|
gboolean mm_iface_modem_voice_received_dtmf (MMIfaceModemVoice *self,
|
||||||
|
gchar *tone);
|
||||||
|
|
||||||
/* Look for a new valid multipart reference */
|
/* Look for a new valid multipart reference */
|
||||||
guint8 mm_iface_modem_voice_get_local_multipart_reference (MMIfaceModemVoice *self,
|
guint8 mm_iface_modem_voice_get_local_multipart_reference (MMIfaceModemVoice *self,
|
||||||
|
Reference in New Issue
Block a user