api,voice: new HangupAll() method

This method will terminate all ongoing calls.
This commit is contained in:
Aleksander Morgado
2019-06-27 14:25:14 +02:00
parent f065105f17
commit efcc4c60fe
7 changed files with 326 additions and 1 deletions

View File

@@ -52,6 +52,7 @@ static gchar *create_str;
static gchar *delete_str; static gchar *delete_str;
static gboolean hold_and_accept_flag; static gboolean hold_and_accept_flag;
static gboolean hangup_and_accept_flag; static gboolean hangup_and_accept_flag;
static gboolean hangup_all_flag;
static GOptionEntry entries[] = { static GOptionEntry entries[] = {
{ "voice-list-calls", 0, 0, G_OPTION_ARG_NONE, &list_flag, { "voice-list-calls", 0, 0, G_OPTION_ARG_NONE, &list_flag,
@@ -74,6 +75,10 @@ static GOptionEntry entries[] = {
"Hangs up all active calls and accepts the next waiting or held call", "Hangs up all active calls and accepts the next waiting or held call",
NULL NULL
}, },
{ "voice-hangup-all", 0, 0, G_OPTION_ARG_NONE, &hangup_all_flag,
"Hangs up all ongoing (active, waiting, held) calls",
NULL
},
{ NULL } { NULL }
}; };
@@ -105,7 +110,8 @@ mmcli_modem_voice_options_enabled (void)
!!create_str + !!create_str +
!!delete_str + !!delete_str +
hold_and_accept_flag + hold_and_accept_flag +
hangup_and_accept_flag); hangup_and_accept_flag +
hangup_all_flag);
if (n_actions > 1) { if (n_actions > 1) {
g_printerr ("error: too many Voice actions requested\n"); g_printerr ("error: too many Voice actions requested\n");
@@ -187,6 +193,31 @@ output_call_info (MMCall *call)
g_free (extra); g_free (extra);
} }
static void
hangup_all_process_reply (const GError *error)
{
if (error) {
g_printerr ("error: couldn't hangup all: '%s'\n",
error->message);
exit (EXIT_FAILURE);
}
g_print ("operation successful\n");
}
static void
hangup_all_ready (MMModemVoice *modem,
GAsyncResult *result,
gpointer nothing)
{
GError *error = NULL;
mm_modem_voice_hangup_all_finish (modem, result, &error);
hangup_all_process_reply (error);
mmcli_async_operation_done ();
}
static void static void
hangup_and_accept_process_reply (const GError *error) hangup_and_accept_process_reply (const GError *error)
{ {
@@ -416,6 +447,16 @@ get_modem_ready (GObject *source,
return; return;
} }
/* Request to hangup all? */
if (hangup_all_flag) {
g_debug ("Asynchronously hanging up all calls...");
mm_modem_voice_hangup_all (ctx->modem_voice,
ctx->cancellable,
(GAsyncReadyCallback)hangup_all_ready,
NULL);
return;
}
g_warn_if_reached (); g_warn_if_reached ();
} }
@@ -528,5 +569,13 @@ mmcli_modem_voice_run_synchronous (GDBusConnection *connection)
return; return;
} }
/* Request to hangup all? */
if (hangup_all_flag) {
g_debug ("Synchronously hanging up all calls...");
mm_modem_voice_hangup_all_sync (ctx->modem_voice, NULL, &error);
hangup_all_process_reply (error);
return;
}
g_warn_if_reached (); g_warn_if_reached ();
} }

View File

@@ -1018,6 +1018,9 @@ mm_modem_voice_hangup_and_accept_sync
mm_modem_voice_hold_and_accept mm_modem_voice_hold_and_accept
mm_modem_voice_hold_and_accept_finish mm_modem_voice_hold_and_accept_finish
mm_modem_voice_hold_and_accept_sync mm_modem_voice_hold_and_accept_sync
mm_modem_voice_hangup_all
mm_modem_voice_hangup_all_finish
mm_modem_voice_hangup_all_sync
<SUBSECTION Standard> <SUBSECTION Standard>
MMModemVoiceClass MMModemVoiceClass
MMModemVoicePrivate MMModemVoicePrivate
@@ -2847,6 +2850,9 @@ mm_gdbus_modem_voice_call_hangup_and_accept_sync
mm_gdbus_modem_voice_call_hold_and_accept mm_gdbus_modem_voice_call_hold_and_accept
mm_gdbus_modem_voice_call_hold_and_accept_finish mm_gdbus_modem_voice_call_hold_and_accept_finish
mm_gdbus_modem_voice_call_hold_and_accept_sync mm_gdbus_modem_voice_call_hold_and_accept_sync
mm_gdbus_modem_voice_call_hangup_all
mm_gdbus_modem_voice_call_hangup_all_finish
mm_gdbus_modem_voice_call_hangup_all_sync
<SUBSECTION Private> <SUBSECTION Private>
mm_gdbus_modem_voice_set_calls mm_gdbus_modem_voice_set_calls
mm_gdbus_modem_voice_emit_call_added mm_gdbus_modem_voice_emit_call_added
@@ -2856,6 +2862,7 @@ mm_gdbus_modem_voice_complete_delete_call
mm_gdbus_modem_voice_complete_list_calls mm_gdbus_modem_voice_complete_list_calls
mm_gdbus_modem_voice_complete_hangup_and_accept mm_gdbus_modem_voice_complete_hangup_and_accept
mm_gdbus_modem_voice_complete_hold_and_accept mm_gdbus_modem_voice_complete_hold_and_accept
mm_gdbus_modem_voice_complete_hangup_all
mm_gdbus_modem_voice_interface_info mm_gdbus_modem_voice_interface_info
mm_gdbus_modem_voice_override_properties mm_gdbus_modem_voice_override_properties
<SUBSECTION Standard> <SUBSECTION Standard>

View File

@@ -99,6 +99,18 @@
--> -->
<method name="HangupAndAccept" /> <method name="HangupAndAccept" />
<!--
HangupAll:
Hangup all active calls.
Depending on how the device implements the action, calls on
hold or in waiting state may also be terminated.
No error is returned if there are no ongoing calls.
-->
<method name="HangupAll" />
<!-- <!--
CallAdded: CallAdded:
@path: Object path of the new call. @path: Object path of the new call.

View File

@@ -690,6 +690,85 @@ mm_modem_voice_hangup_and_accept_sync (MMModemVoice *self,
/*****************************************************************************/ /*****************************************************************************/
/**
* mm_modem_voice_hangup_all_finish:
* @self: A #MMModemVoice.
* @res: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to mm_modem_voice_hangup_all().
* @error: Return location for error or %NULL.
*
* Finishes an operation started with mm_modem_voice_hangup_all().
*
* Returns: %TRUE if the operation was successful, %FALSE if @error is set.
* Since: 1.12
*/
gboolean
mm_modem_voice_hangup_all_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_all_finish (MM_GDBUS_MODEM_VOICE (self), res, error);
}
/**
* mm_modem_voice_hangup_all:
* @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 ongoing (active, waiting, held) calls.
*
* 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_all_finish() to get the result of the operation.
*
* See mm_modem_voice_hangup_all_sync() for the synchronous, blocking version of this method.
*
* Since: 1.12
*/
void
mm_modem_voice_hangup_all (MMModemVoice *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data)
{
g_return_if_fail (MM_IS_MODEM_VOICE (self));
mm_gdbus_modem_voice_call_hangup_all (MM_GDBUS_MODEM_VOICE (self),
cancellable,
callback,
user_data);
}
/**
* mm_modem_voice_hangup_all_sync:
* @self: A #MMModemVoice.
* @cancellable: (allow-none): A #GCancellable or %NULL.
* @error: Return location for error or %NULL.
*
* Synchronously hangs up all ongoing (active, waiting, held) calls.
*
* The calling thread is blocked until a reply is received. See mm_modem_voice_hangup_all()
* 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_all_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_all_sync (MM_GDBUS_MODEM_VOICE (self),
cancellable,
error);
}
/*****************************************************************************/
static void static void
mm_modem_voice_init (MMModemVoice *self) mm_modem_voice_init (MMModemVoice *self)
{ {

View File

@@ -132,6 +132,17 @@ gboolean mm_modem_voice_hangup_and_accept_sync (MMModemVoice *self,
GCancellable *cancellable, GCancellable *cancellable,
GError **error); GError **error);
void mm_modem_voice_hangup_all (MMModemVoice *self,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean mm_modem_voice_hangup_all_finish (MMModemVoice *self,
GAsyncResult *res,
GError **error);
gboolean mm_modem_voice_hangup_all_sync (MMModemVoice *self,
GCancellable *cancellable,
GError **error);
G_END_DECLS G_END_DECLS
#endif /* _MM_MODEM_VOICE_H_ */ #endif /* _MM_MODEM_VOICE_H_ */

View File

@@ -826,6 +826,161 @@ handle_hangup_and_accept (MmGdbusModemVoice *skeleton,
return TRUE; return TRUE;
} }
/*****************************************************************************/
typedef struct {
MmGdbusModemVoice *skeleton;
GDBusMethodInvocation *invocation;
MMIfaceModemVoice *self;
GList *calls;
} HandleHangupAllContext;
static void
handle_hangup_all_context_free (HandleHangupAllContext *ctx)
{
g_list_free_full (ctx->calls, g_object_unref);
g_object_unref (ctx->skeleton);
g_object_unref (ctx->invocation);
g_object_unref (ctx->self);
g_slice_free (HandleHangupAllContext, ctx);
}
static void
hangup_all_ready (MMIfaceModemVoice *self,
GAsyncResult *res,
HandleHangupAllContext *ctx)
{
GError *error = NULL;
GList *l;
if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->hangup_all_finish (self, res, &error)) {
g_dbus_method_invocation_take_error (ctx->invocation, error);
handle_hangup_all_context_free (ctx);
return;
}
for (l = ctx->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);
mm_gdbus_modem_voice_complete_hangup_all (ctx->skeleton, ctx->invocation);
handle_hangup_all_context_free (ctx);
}
static void
prepare_hangup_all_foreach (MMBaseCall *call,
HandleHangupAllContext *ctx)
{
/* The implementation of this operation will usually be done with +CHUP, and we
* know that +CHUP is implemented in different ways by different manufacturers.
*
* The 3GPP TS27.007 spec for +CHUP states that the "Execution command causes
* the TA to hangup the current call of the MT." This sentence leaves a bit of open
* interpretation to the implementors, because a current call can be considered only
* the active ones, or otherwise any call (active, held or waiting).
*
* And so, the u-blox TOBY-L4 takes one interpretation and "In case of multiple
* calls, all active calls will be released, while waiting and held calls are not".
*
* And the Cinterion PLS-8 takes a different interpretation and cancels all calls,
* including the waiting and held ones.
*
* In this logic, we're going to terminate exclusively the ACTIVE calls only, and we
* will leave the possible termination of waiting/held calls to be reported via
* call state updates, e.g. +CLCC polling or other plugin-specific method. In the
* case of the Cinterion PLS-8, we'll detect the termination of the waiting and
* held calls via ^SLCC URCs.
*/
switch (mm_base_call_get_state (call)) {
case MM_CALL_STATE_DIALING:
case MM_CALL_STATE_RINGING_OUT:
case MM_CALL_STATE_RINGING_IN:
case MM_CALL_STATE_ACTIVE:
ctx->calls = g_list_append (ctx->calls, g_object_ref (call));
break;
case MM_CALL_STATE_WAITING:
case MM_CALL_STATE_HELD:
default:
break;
}
}
static void
handle_hangup_all_auth_ready (MMBaseModem *self,
GAsyncResult *res,
HandleHangupAllContext *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_all_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 all: device not yet enabled");
handle_hangup_all_context_free (ctx);
return;
}
if (!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->hangup_all ||
!MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->hangup_all_finish) {
g_dbus_method_invocation_return_error (ctx->invocation,
MM_CORE_ERROR,
MM_CORE_ERROR_UNSUPPORTED,
"Cannot hangup all: unsupported");
handle_hangup_all_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 all: missing call list");
handle_hangup_all_context_free (ctx);
return;
}
mm_call_list_foreach (list, (MMCallListForeachFunc)prepare_hangup_all_foreach, ctx);
g_object_unref (list);
MM_IFACE_MODEM_VOICE_GET_INTERFACE (self)->hangup_all (MM_IFACE_MODEM_VOICE (self),
(GAsyncReadyCallback)hangup_all_ready,
ctx);
}
static gboolean
handle_hangup_all (MmGdbusModemVoice *skeleton,
GDBusMethodInvocation *invocation,
MMIfaceModemVoice *self)
{
HandleHangupAllContext *ctx;
ctx = g_slice_new0 (HandleHangupAllContext);
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_all_auth_ready,
ctx);
return TRUE;
}
/*****************************************************************************/ /*****************************************************************************/
/* Call list polling logic /* Call list polling logic
* *
@@ -1516,6 +1671,10 @@ interface_initialization_step (GTask *task)
"handle-hold-and-accept", "handle-hold-and-accept",
G_CALLBACK (handle_hold_and_accept), G_CALLBACK (handle_hold_and_accept),
self); self);
g_signal_connect (ctx->skeleton,
"handle-hangup-all",
G_CALLBACK (handle_hangup_all),
self);
/* Finally, export the new interface */ /* Finally, export the new interface */
mm_gdbus_object_skeleton_set_modem_voice (MM_GDBUS_OBJECT_SKELETON (self), mm_gdbus_object_skeleton_set_modem_voice (MM_GDBUS_OBJECT_SKELETON (self),

View File

@@ -107,6 +107,14 @@ struct _MMIfaceModemVoice {
gboolean (* hangup_and_accept_finish) (MMIfaceModemVoice *self, gboolean (* hangup_and_accept_finish) (MMIfaceModemVoice *self,
GAsyncResult *res, GAsyncResult *res,
GError **error); GError **error);
/* Hangup all */
void (* hangup_all) (MMIfaceModemVoice *self,
GAsyncReadyCallback callback,
gpointer user_data);
gboolean (* hangup_all_finish) (MMIfaceModemVoice *self,
GAsyncResult *res,
GError **error);
}; };
GType mm_iface_modem_voice_get_type (void); GType mm_iface_modem_voice_get_type (void);