aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@aleksander.es>2019-06-27 12:02:36 +0200
committerAleksander Morgado <aleksander@aleksander.es>2019-07-11 23:20:59 +0200
commitd56d1b265625ba94c1308f6c0aa43201bab83db3 (patch)
tree6b888264418884202f083b2255fb9ca30b1f2847 /src
parentf994982cce641cb770d28c7172ecf09a8a25b124 (diff)
api,voice: new HangupAndAccept() method
This method will hangup the currently active call and right away accept the next available call. The user of the API does not need to specify explicitly which is the next call to accept, because that is decided automatically: * If there is any waiting call, it will accept it right away. * If there is no waiting call but there is a held call, it will make the held call active again.
Diffstat (limited to 'src')
-rw-r--r--src/mm-iface-modem-voice.c146
-rw-r--r--src/mm-iface-modem-voice.h8
2 files changed, 154 insertions, 0 deletions
diff --git a/src/mm-iface-modem-voice.c b/src/mm-iface-modem-voice.c
index 22582335..7d5afa4b 100644
--- a/src/mm-iface-modem-voice.c
+++ b/src/mm-iface-modem-voice.c
@@ -543,6 +543,148 @@ handle_list (MmGdbusModemVoice *skeleton,
}
/*****************************************************************************/
+
+typedef struct {
+ MmGdbusModemVoice *skeleton;
+ GDBusMethodInvocation *invocation;
+ MMIfaceModemVoice *self;
+ GList *active_calls;
+ MMBaseCall *next_call;
+} HandleHangupAndAcceptContext;
+
+static void
+handle_hangup_and_accept_context_free (HandleHangupAndAcceptContext *ctx)
+{
+ g_list_free_full (ctx->active_calls, g_object_unref);
+ g_clear_object (&ctx->next_call);
+ g_object_unref (ctx->skeleton);
+ g_object_unref (ctx->invocation);
+ g_object_unref (ctx->self);
+ g_slice_free (HandleHangupAndAcceptContext, ctx);
+}
+
+static void
+hangup_and_accept_ready (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ HandleHangupAndAcceptContext *ctx)
+{
+ GError *error = NULL;
+ GList *l;
+
+ if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->hangup_and_accept_finish (self, res, &error)) {
+ g_dbus_method_invocation_take_error (ctx->invocation, error);
+ handle_hangup_and_accept_context_free (ctx);
+ return;
+ }
+
+ for (l = ctx->active_calls; l; l = g_list_next (l))
+ mm_base_call_change_state (MM_BASE_CALL (l->data), MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_TERMINATED);
+ if (ctx->next_call)
+ mm_base_call_change_state (ctx->next_call, MM_CALL_STATE_ACTIVE, MM_CALL_STATE_REASON_ACCEPTED);
+
+ mm_gdbus_modem_voice_complete_hangup_and_accept (ctx->skeleton, ctx->invocation);
+ handle_hangup_and_accept_context_free (ctx);
+}
+
+static void
+prepare_hangup_and_accept_foreach (MMBaseCall *call,
+ HandleHangupAndAcceptContext *ctx)
+{
+ switch (mm_base_call_get_state (call)) {
+ case MM_CALL_STATE_ACTIVE:
+ ctx->active_calls = g_list_append (ctx->active_calls, g_object_ref (call));
+ break;
+ case MM_CALL_STATE_WAITING:
+ g_clear_object (&ctx->next_call);
+ ctx->next_call = g_object_ref (call);
+ break;
+ case MM_CALL_STATE_HELD:
+ if (!ctx->next_call)
+ ctx->next_call = g_object_ref (call);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+handle_hangup_and_accept_auth_ready (MMBaseModem *self,
+ GAsyncResult *res,
+ HandleHangupAndAcceptContext *ctx)
+{
+ MMModemState modem_state = MM_MODEM_STATE_UNKNOWN;
+ GError *error = NULL;
+ MMCallList *list = NULL;
+
+ if (!mm_base_modem_authorize_finish (self, res, &error)) {
+ g_dbus_method_invocation_take_error (ctx->invocation, error);
+ handle_hangup_and_accept_context_free (ctx);
+ return;
+ }
+
+ g_object_get (self,
+ MM_IFACE_MODEM_STATE, &modem_state,
+ NULL);
+
+ if (modem_state < MM_MODEM_STATE_ENABLED) {
+ g_dbus_method_invocation_return_error (ctx->invocation,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_WRONG_STATE,
+ "Cannot hangup and accept: device not yet enabled");
+ handle_hangup_and_accept_context_free (ctx);
+ return;
+ }
+
+ if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->hangup_and_accept ||
+ !MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->hangup_and_accept_finish) {
+ g_dbus_method_invocation_return_error (ctx->invocation,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_UNSUPPORTED,
+ "Cannot hangup and accept: unsupported");
+ handle_hangup_and_accept_context_free (ctx);
+ return;
+ }
+
+ g_object_get (self,
+ MM_IFACE_MODEM_VOICE_CALL_LIST, &list,
+ NULL);
+ if (!list) {
+ g_dbus_method_invocation_return_error (ctx->invocation,
+ MM_CORE_ERROR,
+ MM_CORE_ERROR_WRONG_STATE,
+ "Cannot hangup and accept: missing call list");
+ handle_hangup_and_accept_context_free (ctx);
+ return;
+ }
+ mm_call_list_foreach (list, (MMCallListForeachFunc)prepare_hangup_and_accept_foreach, ctx);
+ g_object_unref (list);
+
+ MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->hangup_and_accept (MM_IFACE_MODEM_VOICE (self),
+ (GAsyncReadyCallback)hangup_and_accept_ready,
+ ctx);
+}
+
+static gboolean
+handle_hangup_and_accept (MmGdbusModemVoice *skeleton,
+ GDBusMethodInvocation *invocation,
+ MMIfaceModemVoice *self)
+{
+ HandleHangupAndAcceptContext *ctx;
+
+ ctx = g_slice_new0 (HandleHangupAndAcceptContext);
+ ctx->skeleton = g_object_ref (skeleton);
+ ctx->invocation = g_object_ref (invocation);
+ ctx->self = g_object_ref (self);
+
+ mm_base_modem_authorize (MM_BASE_MODEM (self),
+ invocation,
+ MM_AUTHORIZATION_VOICE,
+ (GAsyncReadyCallback)handle_hangup_and_accept_auth_ready,
+ ctx);
+ return TRUE;
+}
+
+/*****************************************************************************/
/* Call list polling logic
*
* The call list polling is exclusively used to detect detailed call state
@@ -1224,6 +1366,10 @@ interface_initialization_step (GTask *task)
"handle-list-calls",
G_CALLBACK (handle_list),
self);
+ g_signal_connect (ctx->skeleton,
+ "handle-hangup-and-accept",
+ G_CALLBACK (handle_hangup_and_accept),
+ self);
/* Finally, export the new interface */
mm_gdbus_object_skeleton_set_modem_voice (MM_GDBUS_OBJECT_SKELETON (self),
diff --git a/src/mm-iface-modem-voice.h b/src/mm-iface-modem-voice.h
index f697937a..f65b63e0 100644
--- a/src/mm-iface-modem-voice.h
+++ b/src/mm-iface-modem-voice.h
@@ -91,6 +91,14 @@ struct _MMIfaceModemVoice {
MMBaseCall * (* create_call) (MMIfaceModemVoice *self,
MMCallDirection direction,
const gchar *number);
+
+ /* Hangup and accept */
+ void (* hangup_and_accept) (MMIfaceModemVoice *self,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+ gboolean (* hangup_and_accept_finish) (MMIfaceModemVoice *self,
+ GAsyncResult *res,
+ GError **error);
};
GType mm_iface_modem_voice_get_type (void);