base-call: implement generic audio channel setup/cleanup handlers
Modems that require specific commands to setup or cleanup the audio channel as soon as a call is ongoing can subclass these two new methods. The setup() method is considered part of the call start/accept process, and so if it fails, the whole operation will fail. The failures in the cleanup() method will be reported in the log, but otherwise ignored, as this operation may be executed without any user intervention (e.g. if the remote party hangs up).
This commit is contained in:

committed by
Dan Williams

parent
17c511ec69
commit
329caff84f
@@ -60,6 +60,9 @@ struct _MMBaseCallPrivate {
|
||||
|
||||
guint incoming_timeout;
|
||||
GRegex *in_call_events;
|
||||
|
||||
/* The port used for audio while call is ongoing, if known */
|
||||
MMPort *audio_port;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
@@ -163,6 +166,27 @@ mm_base_call_incoming_refresh (MMBaseCall *self)
|
||||
self->priv->incoming_timeout = g_timeout_add_seconds (INCOMING_TIMEOUT_SECS, (GSourceFunc)incoming_timeout_cb, self);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Update audio settings */
|
||||
|
||||
static void
|
||||
update_audio_settings (MMBaseCall *self,
|
||||
MMPort *audio_port,
|
||||
MMCallAudioFormat *audio_format)
|
||||
{
|
||||
if (!audio_port && self->priv->audio_port && mm_port_get_connected (self->priv->audio_port))
|
||||
mm_port_set_connected (self->priv->audio_port, FALSE);
|
||||
g_clear_object (&self->priv->audio_port);
|
||||
|
||||
if (audio_port) {
|
||||
self->priv->audio_port = g_object_ref (audio_port);
|
||||
mm_port_set_connected (self->priv->audio_port, TRUE);
|
||||
}
|
||||
|
||||
mm_gdbus_call_set_audio_port (MM_GDBUS_CALL (self), audio_port ? mm_port_get_device (audio_port) : NULL);
|
||||
mm_gdbus_call_set_audio_format (MM_GDBUS_CALL (self), mm_call_audio_format_get_dictionary (audio_format));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Start call (DBus call handling) */
|
||||
|
||||
@@ -182,8 +206,52 @@ handle_start_context_free (HandleStartContext *ctx)
|
||||
}
|
||||
|
||||
static void
|
||||
handle_start_ready (MMBaseCall *self,
|
||||
GAsyncResult *res,
|
||||
call_started (HandleStartContext *ctx)
|
||||
{
|
||||
mm_info ("call is started");
|
||||
|
||||
/* If dialing to ringing supported, leave it dialing */
|
||||
if (!ctx->self->priv->supports_dialing_to_ringing) {
|
||||
/* If ringing to active supported, set it ringing */
|
||||
if (ctx->self->priv->supports_ringing_to_active)
|
||||
mm_base_call_change_state (ctx->self, MM_CALL_STATE_RINGING_OUT, MM_CALL_STATE_REASON_OUTGOING_STARTED);
|
||||
else
|
||||
/* Otherwise, active right away */
|
||||
mm_base_call_change_state (ctx->self, MM_CALL_STATE_ACTIVE, MM_CALL_STATE_REASON_OUTGOING_STARTED);
|
||||
}
|
||||
mm_gdbus_call_complete_start (MM_GDBUS_CALL (ctx->self), ctx->invocation);
|
||||
handle_start_context_free (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
start_setup_audio_channel_ready (MMBaseCall *self,
|
||||
GAsyncResult *res,
|
||||
HandleStartContext *ctx)
|
||||
{
|
||||
MMPort *audio_port = NULL;
|
||||
MMCallAudioFormat *audio_format = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!MM_BASE_CALL_GET_CLASS (self)->setup_audio_channel_finish (self, res, &audio_port, &audio_format, &error)) {
|
||||
mm_warn ("Couldn't setup audio channel: '%s'", error->message);
|
||||
mm_base_call_change_state (self, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_AUDIO_SETUP_FAILED);
|
||||
g_dbus_method_invocation_take_error (ctx->invocation, error);
|
||||
handle_start_context_free (ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (audio_port || audio_format) {
|
||||
update_audio_settings (self, audio_port, audio_format);
|
||||
g_clear_object (&audio_port);
|
||||
g_clear_object (&audio_format);
|
||||
}
|
||||
|
||||
call_started (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_start_ready (MMBaseCall *self,
|
||||
GAsyncResult *res,
|
||||
HandleStartContext *ctx)
|
||||
{
|
||||
GError *error = NULL;
|
||||
@@ -200,19 +268,21 @@ handle_start_ready (MMBaseCall *self,
|
||||
else
|
||||
mm_base_call_change_state (self, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_UNKNOWN);
|
||||
g_dbus_method_invocation_take_error (ctx->invocation, error);
|
||||
} else {
|
||||
/* If dialing to ringing supported, leave it dialing */
|
||||
if (!self->priv->supports_dialing_to_ringing) {
|
||||
/* If ringing to active supported, set it ringing */
|
||||
if (self->priv->supports_ringing_to_active)
|
||||
mm_base_call_change_state (self, MM_CALL_STATE_RINGING_OUT, MM_CALL_STATE_REASON_OUTGOING_STARTED);
|
||||
else
|
||||
/* Otherwise, active right away */
|
||||
mm_base_call_change_state (self, MM_CALL_STATE_ACTIVE, MM_CALL_STATE_REASON_OUTGOING_STARTED);
|
||||
}
|
||||
mm_gdbus_call_complete_start (MM_GDBUS_CALL (ctx->self), ctx->invocation);
|
||||
handle_start_context_free (ctx);
|
||||
return;
|
||||
}
|
||||
handle_start_context_free (ctx);
|
||||
|
||||
/* If there is an audio setup method, run it now */
|
||||
if (MM_BASE_CALL_GET_CLASS (self)->setup_audio_channel) {
|
||||
mm_info ("setting up audio channel...");
|
||||
MM_BASE_CALL_GET_CLASS (self)->setup_audio_channel (self,
|
||||
(GAsyncReadyCallback) start_setup_audio_channel_ready,
|
||||
ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, we're done */
|
||||
call_started (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -300,6 +370,46 @@ handle_accept_context_free (HandleAcceptContext *ctx)
|
||||
g_free (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
call_accepted (HandleAcceptContext *ctx)
|
||||
{
|
||||
mm_info ("call is accepted");
|
||||
|
||||
if (ctx->self->priv->incoming_timeout) {
|
||||
g_source_remove (ctx->self->priv->incoming_timeout);
|
||||
ctx->self->priv->incoming_timeout = 0;
|
||||
}
|
||||
mm_base_call_change_state (ctx->self, MM_CALL_STATE_ACTIVE, MM_CALL_STATE_REASON_ACCEPTED);
|
||||
mm_gdbus_call_complete_accept (MM_GDBUS_CALL (ctx->self), ctx->invocation);
|
||||
handle_accept_context_free (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
accept_setup_audio_channel_ready (MMBaseCall *self,
|
||||
GAsyncResult *res,
|
||||
HandleAcceptContext *ctx)
|
||||
{
|
||||
MMPort *audio_port = NULL;
|
||||
MMCallAudioFormat *audio_format = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!MM_BASE_CALL_GET_CLASS (self)->setup_audio_channel_finish (self, res, &audio_port, &audio_format, &error)) {
|
||||
mm_warn ("Couldn't setup audio channel: '%s'", error->message);
|
||||
mm_base_call_change_state (self, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_AUDIO_SETUP_FAILED);
|
||||
g_dbus_method_invocation_take_error (ctx->invocation, error);
|
||||
handle_accept_context_free (ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
if (audio_port || audio_format) {
|
||||
update_audio_settings (self, audio_port, audio_format);
|
||||
g_clear_object (&audio_port);
|
||||
g_clear_object (&audio_format);
|
||||
}
|
||||
|
||||
call_accepted (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
handle_accept_ready (MMBaseCall *self,
|
||||
GAsyncResult *res,
|
||||
@@ -310,15 +420,21 @@ handle_accept_ready (MMBaseCall *self,
|
||||
if (!MM_BASE_CALL_GET_CLASS (self)->accept_finish (self, res, &error)) {
|
||||
mm_base_call_change_state (self, MM_CALL_STATE_TERMINATED, MM_CALL_STATE_REASON_ERROR);
|
||||
g_dbus_method_invocation_take_error (ctx->invocation, error);
|
||||
} else {
|
||||
if (ctx->self->priv->incoming_timeout) {
|
||||
g_source_remove (ctx->self->priv->incoming_timeout);
|
||||
ctx->self->priv->incoming_timeout = 0;
|
||||
}
|
||||
mm_base_call_change_state (self, MM_CALL_STATE_ACTIVE, MM_CALL_STATE_REASON_ACCEPTED);
|
||||
mm_gdbus_call_complete_accept (MM_GDBUS_CALL (ctx->self), ctx->invocation);
|
||||
handle_accept_context_free (ctx);
|
||||
return;
|
||||
}
|
||||
handle_accept_context_free (ctx);
|
||||
|
||||
/* If there is an audio setup method, run it now */
|
||||
if (MM_BASE_CALL_GET_CLASS (self)->setup_audio_channel) {
|
||||
mm_info ("setting up audio channel...");
|
||||
MM_BASE_CALL_GET_CLASS (self)->setup_audio_channel (self,
|
||||
(GAsyncReadyCallback) accept_setup_audio_channel_ready,
|
||||
ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Otherwise, we're done */
|
||||
call_accepted (ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -677,6 +793,18 @@ mm_base_call_get_path (MMBaseCall *self)
|
||||
state == MM_CALL_STATE_RINGING_OUT || \
|
||||
state == MM_CALL_STATE_ACTIVE)
|
||||
|
||||
static void
|
||||
cleanup_audio_channel_ready (MMBaseCall *self,
|
||||
GAsyncResult *res)
|
||||
{
|
||||
GError *error = NULL;
|
||||
|
||||
if (!MM_BASE_CALL_GET_CLASS (self)->cleanup_audio_channel_finish (self, res, &error)) {
|
||||
mm_warn ("audio channel cleanup failed: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
mm_base_call_change_state (MMBaseCall *self,
|
||||
MMCallState new_state,
|
||||
@@ -710,6 +838,13 @@ mm_base_call_change_state (MMBaseCall *self,
|
||||
mm_warn ("Couldn't cleanup in-call unsolicited events: %s", error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
if (MM_BASE_CALL_GET_CLASS (self)->cleanup_audio_channel) {
|
||||
mm_info ("cleaning up audio channel...");
|
||||
update_audio_settings (self, NULL, NULL);
|
||||
MM_BASE_CALL_GET_CLASS (self)->cleanup_audio_channel (self,
|
||||
(GAsyncReadyCallback) cleanup_audio_channel_ready,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
mm_gdbus_call_set_state (MM_GDBUS_CALL (self), new_state);
|
||||
@@ -724,21 +859,6 @@ mm_base_call_received_dtmf (MMBaseCall *self,
|
||||
mm_gdbus_call_emit_dtmf_received (MM_GDBUS_CALL (self), dtmf);
|
||||
}
|
||||
|
||||
void
|
||||
mm_base_call_set_audio_port (MMBaseCall *self, const gchar *port)
|
||||
{
|
||||
mm_gdbus_call_set_audio_port (MM_GDBUS_CALL (self), port);
|
||||
}
|
||||
|
||||
void
|
||||
mm_base_call_set_audio_format (MMBaseCall *self,
|
||||
MMCallAudioFormat *audio_format)
|
||||
{
|
||||
mm_gdbus_call_set_audio_format (
|
||||
MM_GDBUS_CALL (self),
|
||||
mm_call_audio_format_get_dictionary (audio_format));
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Start the CALL */
|
||||
|
||||
@@ -1067,6 +1187,8 @@ dispose (GObject *object)
|
||||
{
|
||||
MMBaseCall *self = MM_BASE_CALL (object);
|
||||
|
||||
g_clear_object (&self->priv->audio_port);
|
||||
|
||||
if (self->priv->incoming_timeout) {
|
||||
g_source_remove (self->priv->incoming_timeout);
|
||||
self->priv->incoming_timeout = 0;
|
||||
|
Reference in New Issue
Block a user