diff options
author | Marco Bascetta <marco.bascetta@sadel.it> | 2015-05-11 13:40:46 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@aleksander.es> | 2015-08-02 10:39:47 +0200 |
commit | 9874f10e1f27509219b6fe6b0a5374d04d1a3e3b (patch) | |
tree | 2b0b7715451408d90997a011941e94fa8eb84c5c /src | |
parent | 8edead919343809d7c4bd7732a15c1a6c3912cba (diff) |
base-call,iface-modem-voice:: handle DTMF
Diffstat (limited to 'src')
-rw-r--r-- | src/mm-base-call.c | 194 | ||||
-rw-r--r-- | src/mm-base-call.h | 20 | ||||
-rw-r--r-- | src/mm-call-list.c | 23 | ||||
-rw-r--r-- | src/mm-call-list.h | 2 | ||||
-rw-r--r-- | src/mm-iface-modem-voice.c | 18 | ||||
-rw-r--r-- | src/mm-iface-modem-voice.h | 2 |
6 files changed, 252 insertions, 7 deletions
diff --git a/src/mm-base-call.c b/src/mm-base-call.c index bc4f0311..32f1e8fb 100644 --- a/src/mm-base-call.c +++ b/src/mm-base-call.c @@ -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 mm_base_call_export (MMBaseCall *self) { @@ -409,6 +514,10 @@ call_dbus_export (MMBaseCall *self) "handle-hangup", G_CALLBACK (handle_hangup), 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), @@ -457,6 +566,11 @@ mm_base_call_change_state(MMBaseCall *self, MMCallState new_state, MMCallStateRe 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 */ @@ -671,7 +785,6 @@ call_accept (MMBaseCall *self, /*****************************************************************************/ - /* Hangup the CALL */ typedef struct { @@ -760,6 +873,83 @@ call_hangup (MMBaseCall *self, } /*****************************************************************************/ +/* 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 { MMBaseCall *self; MMBaseModem *modem; @@ -1018,6 +1208,8 @@ mm_base_call_class_init (MMBaseCallClass *klass) klass->hangup_finish = call_hangup_finish; klass->delete = call_delete; klass->delete_finish = call_delete_finish; + klass->send_tone = call_send_tone; + klass->send_tone_finish = call_send_tone_finish; properties[PROP_CONNECTION] = diff --git a/src/mm-base-call.h b/src/mm-base-call.h index de9fe2ca..37bb9110 100644 --- a/src/mm-base-call.h +++ b/src/mm-base-call.h @@ -70,7 +70,16 @@ struct _MMBaseCallClass { gboolean (* hangup_finish) (MMBaseCall *self, GAsyncResult *res, 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 */ void (* delete) (MMBaseCall *self, GAsyncReadyCallback callback, @@ -88,10 +97,11 @@ MMBaseCall *mm_base_call_new_from_properties (MMBaseModem *modem, MMCallProperties *properties, GError **error); -void mm_base_call_export (MMBaseCall *self); -void mm_base_call_unexport (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_export (MMBaseCall *self); +void mm_base_call_unexport (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_received_dtmf (MMBaseCall *self, gchar *tone); void mm_base_call_delete (MMBaseCall *self, GAsyncReadyCallback callback, diff --git a/src/mm-call-list.c b/src/mm-call-list.c index c241a0be..d15db686 100644 --- a/src/mm-call-list.c +++ b/src/mm-call-list.c @@ -189,6 +189,29 @@ MMBaseCall* mm_call_list_get_first_non_terminated_call(MMCallList *self) 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 { diff --git a/src/mm-call-list.h b/src/mm-call-list.h index 197bb592..1a63b934 100644 --- a/src/mm-call-list.h +++ b/src/mm-call-list.h @@ -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_outgoing_dialing_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 */ diff --git a/src/mm-iface-modem-voice.c b/src/mm-iface-modem-voice.c index 36cb82f7..817f8c32 100644 --- a/src/mm-iface-modem-voice.c +++ b/src/mm-iface-modem-voice.c @@ -46,7 +46,6 @@ mm_iface_modem_voice_create_call (MMIfaceModemVoice *self) return MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->create_call (self); } -//BASCETTA:TODO: bisogna aggiungere la gestione degli errori. MMBaseCall * mm_iface_modem_voice_create_incoming_call (MMIfaceModemVoice *self) { @@ -192,6 +191,23 @@ gboolean mm_iface_modem_voice_network_hangup (MMIfaceModemVoice *self) 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 { diff --git a/src/mm-iface-modem-voice.h b/src/mm-iface-modem-voice.h index c3b2f1e5..d2aa8a3a 100644 --- a/src/mm-iface-modem-voice.h +++ b/src/mm-iface-modem-voice.h @@ -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_ringing_to_active (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 */ guint8 mm_iface_modem_voice_get_local_multipart_reference (MMIfaceModemVoice *self, |