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.
This commit is contained in:
+50
-1
@@ -50,6 +50,7 @@ static Context *ctx;
|
||||
static gboolean list_flag;
|
||||
static gchar *create_str;
|
||||
static gchar *delete_str;
|
||||
static gboolean hangup_and_accept_flag;
|
||||
|
||||
static GOptionEntry entries[] = {
|
||||
{ "voice-list-calls", 0, 0, G_OPTION_ARG_NONE, &list_flag,
|
||||
@@ -64,6 +65,10 @@ static GOptionEntry entries[] = {
|
||||
"Delete a call from a given modem",
|
||||
"[PATH|INDEX]"
|
||||
},
|
||||
{ "voice-hangup-and-accept", 0, 0, G_OPTION_ARG_NONE, &hangup_and_accept_flag,
|
||||
"Hangs up all active calls and accepts the next waiting or held call",
|
||||
NULL
|
||||
},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
@@ -93,7 +98,8 @@ mmcli_modem_voice_options_enabled (void)
|
||||
|
||||
n_actions = (list_flag +
|
||||
!!create_str +
|
||||
!!delete_str);
|
||||
!!delete_str +
|
||||
hangup_and_accept_flag);
|
||||
|
||||
if (n_actions > 1) {
|
||||
g_printerr ("error: too many Voice actions requested\n");
|
||||
@@ -175,6 +181,31 @@ output_call_info (MMCall *call)
|
||||
g_free (extra);
|
||||
}
|
||||
|
||||
static void
|
||||
hangup_and_accept_process_reply (const GError *error)
|
||||
{
|
||||
if (error) {
|
||||
g_printerr ("error: couldn't hangup and accept: '%s'\n",
|
||||
error->message);
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
g_print ("operation successful\n");
|
||||
}
|
||||
|
||||
static void
|
||||
hangup_and_accept_ready (MMModemVoice *modem,
|
||||
GAsyncResult *result,
|
||||
gpointer nothing)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
mm_modem_voice_hangup_and_accept_finish (modem, result, &error);
|
||||
hangup_and_accept_process_reply (error);
|
||||
|
||||
mmcli_async_operation_done ();
|
||||
}
|
||||
|
||||
static void
|
||||
list_process_reply (GList *result,
|
||||
const GError *error)
|
||||
@@ -334,6 +365,16 @@ get_modem_ready (GObject *source,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Request to hangup and accept? */
|
||||
if (hangup_and_accept_flag) {
|
||||
g_debug ("Asynchronously hanging up and accepting next call...");
|
||||
mm_modem_voice_hangup_and_accept (ctx->modem_voice,
|
||||
ctx->cancellable,
|
||||
(GAsyncReadyCallback)hangup_and_accept_ready,
|
||||
NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
g_warn_if_reached ();
|
||||
}
|
||||
|
||||
@@ -430,5 +471,13 @@ mmcli_modem_voice_run_synchronous (GDBusConnection *connection)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Request to hangup and accept? */
|
||||
if (hangup_and_accept_flag) {
|
||||
g_debug ("Synchronously hanging up and accepting call...");
|
||||
mm_modem_voice_hangup_and_accept_sync (ctx->modem_voice, NULL, &error);
|
||||
hangup_and_accept_process_reply (error);
|
||||
return;
|
||||
}
|
||||
|
||||
g_warn_if_reached ();
|
||||
}
|
||||
|
||||
@@ -1012,6 +1012,9 @@ mm_modem_voice_delete_call_sync
|
||||
mm_modem_voice_list_calls
|
||||
mm_modem_voice_list_calls_finish
|
||||
mm_modem_voice_list_calls_sync
|
||||
mm_modem_voice_hangup_and_accept
|
||||
mm_modem_voice_hangup_and_accept_finish
|
||||
mm_modem_voice_hangup_and_accept_sync
|
||||
<SUBSECTION Standard>
|
||||
MMModemVoiceClass
|
||||
MMModemVoicePrivate
|
||||
@@ -2835,6 +2838,9 @@ mm_gdbus_modem_voice_call_delete_call_sync
|
||||
mm_gdbus_modem_voice_call_list_calls
|
||||
mm_gdbus_modem_voice_call_list_calls_finish
|
||||
mm_gdbus_modem_voice_call_list_calls_sync
|
||||
mm_gdbus_modem_voice_call_hangup_and_accept
|
||||
mm_gdbus_modem_voice_call_hangup_and_accept_finish
|
||||
mm_gdbus_modem_voice_call_hangup_and_accept_sync
|
||||
<SUBSECTION Private>
|
||||
mm_gdbus_modem_voice_set_calls
|
||||
mm_gdbus_modem_voice_emit_call_added
|
||||
@@ -2842,6 +2848,7 @@ mm_gdbus_modem_voice_emit_call_deleted
|
||||
mm_gdbus_modem_voice_complete_create_call
|
||||
mm_gdbus_modem_voice_complete_delete_call
|
||||
mm_gdbus_modem_voice_complete_list_calls
|
||||
mm_gdbus_modem_voice_complete_hangup_and_accept
|
||||
mm_gdbus_modem_voice_interface_info
|
||||
mm_gdbus_modem_voice_override_properties
|
||||
<SUBSECTION Standard>
|
||||
|
||||
@@ -63,6 +63,25 @@
|
||||
<arg name="path" type="o" direction="out" />
|
||||
</method>
|
||||
|
||||
<!--
|
||||
HangupAndAccept:
|
||||
|
||||
Hangup all active calls, if any, and accept the next call.
|
||||
|
||||
Waiting calls have preference over held calls, so the next
|
||||
call being active will be any waiting call, or otherwise,
|
||||
any held call.
|
||||
|
||||
The user should monitor the state of all available ongoing
|
||||
calls to be reported of which one becomes active.
|
||||
|
||||
No error is returned if there are no waiting or held calls.
|
||||
In this case, this method would be equivalent to calling
|
||||
<link linkend="gdbus-method-org-freedesktop-ModemManager1-Call.Hangup">Hangup()</link>
|
||||
on the active call.
|
||||
-->
|
||||
<method name="HangupAndAccept" />
|
||||
|
||||
<!--
|
||||
CallAdded:
|
||||
@path: Object path of the new call.
|
||||
|
||||
@@ -532,6 +532,85 @@ mm_modem_voice_delete_call_sync (MMModemVoice *self,
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* mm_modem_voice_hangup_and_accept_finish:
|
||||
* @self: A #MMModemVoice.
|
||||
* @res: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to mm_modem_voice_hangup_and_accept().
|
||||
* @error: Return location for error or %NULL.
|
||||
*
|
||||
* Finishes an operation started with mm_modem_voice_hangup_and_accept().
|
||||
*
|
||||
* Returns: %TRUE if the operation was successful, %FALSE if @error is set.
|
||||
* Since: 1.12
|
||||
*/
|
||||
gboolean
|
||||
mm_modem_voice_hangup_and_accept_finish (MMModemVoice *self,
|
||||
GAsyncResult *res,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (MM_IS_MODEM_VOICE (self), FALSE);
|
||||
|
||||
return mm_gdbus_modem_voice_call_hangup_and_accept_finish (MM_GDBUS_MODEM_VOICE (self), res, error);
|
||||
}
|
||||
|
||||
/**
|
||||
* mm_modem_voice_hangup_and_accept:
|
||||
* @self: A #MMModemVoice.
|
||||
* @cancellable: (allow-none): A #GCancellable or %NULL.
|
||||
* @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL.
|
||||
* @user_data: User data to pass to @callback.
|
||||
*
|
||||
* Asynchronously hangs up all active calls and accepts the next waiting or held call.
|
||||
*
|
||||
* When the operation is finished, @callback will be invoked in the <link linkend="g-main-context-push-thread-default">thread-default main loop</link> of the thread you are calling this method from.
|
||||
* You can then call mm_modem_voice_hangup_and_accept_finish() to get the result of the operation.
|
||||
*
|
||||
* See mm_modem_voice_hangup_and_accept_sync() for the synchronous, blocking version of this method.
|
||||
*
|
||||
* Since: 1.12
|
||||
*/
|
||||
void
|
||||
mm_modem_voice_hangup_and_accept (MMModemVoice *self,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_return_if_fail (MM_IS_MODEM_VOICE (self));
|
||||
|
||||
mm_gdbus_modem_voice_call_hangup_and_accept (MM_GDBUS_MODEM_VOICE (self),
|
||||
cancellable,
|
||||
callback,
|
||||
user_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* mm_modem_voice_hangup_and_accept_sync:
|
||||
* @self: A #MMModemVoice.
|
||||
* @cancellable: (allow-none): A #GCancellable or %NULL.
|
||||
* @error: Return location for error or %NULL.
|
||||
*
|
||||
* Synchronously hangs up all active calls and accepts the next waiting or held call.
|
||||
*
|
||||
* The calling thread is blocked until a reply is received. See mm_modem_voice_hangup_and_accept()
|
||||
* for the asynchronous version of this method.
|
||||
*
|
||||
* Returns: %TRUE if the operation was successful, %FALSE if @error is set.
|
||||
* Since: 1.12
|
||||
*/
|
||||
gboolean
|
||||
mm_modem_voice_hangup_and_accept_sync (MMModemVoice *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (MM_IS_MODEM_VOICE (self), FALSE);
|
||||
|
||||
return mm_gdbus_modem_voice_call_hangup_and_accept_sync (MM_GDBUS_MODEM_VOICE (self),
|
||||
cancellable,
|
||||
error);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
mm_modem_voice_init (MMModemVoice *self)
|
||||
{
|
||||
|
||||
@@ -110,6 +110,17 @@ gboolean mm_modem_voice_delete_call_sync (MMModemVoice *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
void mm_modem_voice_hangup_and_accept (MMModemVoice *self,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean mm_modem_voice_hangup_and_accept_finish (MMModemVoice *self,
|
||||
GAsyncResult *res,
|
||||
GError **error);
|
||||
gboolean mm_modem_voice_hangup_and_accept_sync (MMModemVoice *self,
|
||||
GCancellable *cancellable,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* _MM_MODEM_VOICE_H_ */
|
||||
|
||||
@@ -542,6 +542,148 @@ handle_list (MmGdbusModemVoice *skeleton,
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
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
|
||||
*
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user