Commit c5f08156 authored by Stepan Salenikovich's avatar Stepan Salenikovich
Browse files

gnome: fix frameUpdate crash

add a missing disconnect from the frameUpdate signal
also prevent potential crash when leaving call view
or hanging up as the video renderer is starting

Refs #68820

Change-Id: I64cab0951a26cb99a077de8a3f5d876314cd8cec
parent 7ff4796f
......@@ -59,12 +59,18 @@ struct _CurrentCallViewPrivate
GtkWidget *video_widget;
GtkWidget *button_hangup;
Video::Renderer *remote_renderer;
Video::Renderer *local_renderer;
/* new renderers should be put into the queue for processing by a g_idle
* functions whose id should be saved into renderer_idle_source;
* this way when the CurrentCallView object is destroyed, we do not try
* to process any new renderers by stoping the g_idle function.
*/
guint renderer_idle_source;
GAsyncQueue *new_renderer_queue;
QMetaObject::Connection state_change_connection;
QMetaObject::Connection call_details_connection;
QMetaObject::Connection renderer_connection;
QMetaObject::Connection local_renderer_connection;
QMetaObject::Connection remote_renderer_connection;
};
G_DEFINE_TYPE_WITH_PRIVATE(CurrentCallView, current_call_view, GTK_TYPE_BOX);
......@@ -82,15 +88,56 @@ current_call_view_dispose(GObject *object)
QObject::disconnect(priv->state_change_connection);
QObject::disconnect(priv->call_details_connection);
QObject::disconnect(priv->renderer_connection);
QObject::disconnect(priv->local_renderer_connection);
QObject::disconnect(priv->remote_renderer_connection);
/* dispose may be called multiple times, make sure
* not to call g_source_remove more than once */
if (priv->renderer_idle_source) {
g_source_remove(priv->renderer_idle_source);
priv->renderer_idle_source = 0;
}
if (priv->new_renderer_queue) {
g_async_queue_unref(priv->new_renderer_queue);
priv->new_renderer_queue = NULL;
}
G_OBJECT_CLASS(current_call_view_parent_class)->dispose(object);
}
static gboolean
check_renderer_queue(CurrentCallView *self)
{
g_return_val_if_fail(IS_CURRENT_CALL_VIEW(self), FALSE);
CurrentCallViewPrivate *priv = CURRENT_CALL_VIEW_GET_PRIVATE(self);
/* get all the renderers in the queue */
gpointer new_video_renderer = g_async_queue_try_pop(priv->new_renderer_queue);
while (new_video_renderer) {
video_widget_add_renderer(VIDEO_WIDGET(priv->video_widget), (const VideoRenderer *)new_video_renderer);
g_free(new_video_renderer);
new_video_renderer = g_async_queue_try_pop(priv->new_renderer_queue);
}
return TRUE; /* keep going */
}
static void
current_call_view_init(CurrentCallView *view)
{
gtk_widget_init_template(GTK_WIDGET(view));
CurrentCallViewPrivate *priv = CURRENT_CALL_VIEW_GET_PRIVATE(view);
/* init new renderer queue */
priv->new_renderer_queue = g_async_queue_new_full((GDestroyNotify)g_free);
/* check new render queue when idle */
priv->renderer_idle_source = g_idle_add_full(
G_PRIORITY_DEFAULT_IDLE,
(GSourceFunc)check_renderer_queue,
view,
NULL);
}
static void
......@@ -188,28 +235,18 @@ update_details(CurrentCallView *view, Call *call)
gtk_label_set_text(GTK_LABEL(priv->label_duration), ba_length.constData());
}
static gboolean
set_remote_renderer(CurrentCallView *view)
{
g_return_val_if_fail(IS_CURRENT_CALL_VIEW(view), FALSE);
CurrentCallViewPrivate *priv = CURRENT_CALL_VIEW_GET_PRIVATE(view);
video_widget_set_remote_renderer(VIDEO_WIDGET(priv->video_widget), priv->remote_renderer);
return FALSE; /* do not call again */
}
static gboolean
set_local_renderer(CurrentCallView *view)
static void
push_new_renderer(CurrentCallView *self, Video::Renderer *renderer, VideoRendererType type)
{
g_return_val_if_fail(IS_CURRENT_CALL_VIEW(view), FALSE);
g_return_if_fail(IS_CURRENT_CALL_VIEW(self));
CurrentCallViewPrivate *priv = CURRENT_CALL_VIEW_GET_PRIVATE(view);
CurrentCallViewPrivate *priv = CURRENT_CALL_VIEW_GET_PRIVATE(self);
video_widget_set_local_renderer(VIDEO_WIDGET(priv->video_widget), priv->local_renderer);
VideoRenderer *new_video_renderer = g_new0(VideoRenderer, 1);
new_video_renderer->renderer = renderer;
new_video_renderer->type = type;
return FALSE; /* do not call again */
g_async_queue_push(priv->new_renderer_queue, new_video_renderer);
}
static void
......@@ -321,38 +358,26 @@ current_call_view_set_call_info(CurrentCallView *view, const QModelIndex& idx) {
gtk_widget_show_all(priv->frame_video);
/* check if we already have a renderer */
priv->remote_renderer = call->videoRenderer();
set_remote_renderer(view);
push_new_renderer(view, call->videoRenderer(), VIDEO_RENDERER_REMOTE);
/* callback for remote renderer */
priv->renderer_connection = QObject::connect(
priv->remote_renderer_connection = QObject::connect(
call,
&Call::videoStarted,
[=](Video::Renderer *renderer) {
priv->remote_renderer = renderer;
g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
(GSourceFunc)set_remote_renderer,
view,
NULL);
push_new_renderer(view, renderer, VIDEO_RENDERER_REMOTE);
}
);
/* local renderer */
priv->local_renderer = Video::PreviewManager::instance()->previewRenderer();
set_local_renderer(view);
push_new_renderer(view, Video::PreviewManager::instance()->previewRenderer(), VIDEO_RENDERER_LOCAL);
/* callback for local renderer */
priv->renderer_connection = QObject::connect(
priv->local_renderer_connection = QObject::connect(
Video::PreviewManager::instance(),
&Video::PreviewManager::previewStarted,
[=](Video::Renderer *renderer) {
priv->local_renderer = renderer;
g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
(GSourceFunc)set_local_renderer,
view,
NULL);
push_new_renderer(view, renderer, VIDEO_RENDERER_LOCAL);
}
);
......
......@@ -357,10 +357,13 @@ static void
renderer_start(VideoWidgetRenderer *renderer)
{
g_return_if_fail(CLUTTER_IS_ACTOR(renderer->actor));
QObject::disconnect(renderer->frame_update);
renderer->frame_update = QObject::connect(
renderer->renderer,
&Video::Renderer::frameUpdated,
[=]() {
if (!renderer->renderer->isRendering())
g_warning("got frame but not rendering!");
/* this callback comes from another thread;
* rendering must be done in the main loop;
......@@ -415,27 +418,25 @@ video_widget_new(void)
}
void
video_widget_set_remote_renderer(VideoWidget *self, Video::Renderer *renderer_remote_new)
video_widget_add_renderer(VideoWidget *self, const VideoRenderer *new_renderer)
{
g_return_if_fail(IS_VIDEO_WIDGET(self));
if (renderer_remote_new == NULL) return;
if (new_renderer == NULL || new_renderer->renderer == NULL)
return;
VideoWidgetPrivate *priv = VIDEO_WIDGET_GET_PRIVATE(self);
/* update the renderer */
priv->remote->renderer = renderer_remote_new;
video_widget_set_renderer(priv->remote);
}
void
video_widget_set_local_renderer(VideoWidget *self, Video::Renderer *renderer_local_new)
{
g_return_if_fail(IS_VIDEO_WIDGET(self));
if (renderer_local_new == NULL) return;
VideoWidgetPrivate *priv = VIDEO_WIDGET_GET_PRIVATE(self);
/* update the renderer */
priv->local->renderer = renderer_local_new;
video_widget_set_renderer(priv->local);
switch(new_renderer->type) {
case VIDEO_RENDERER_REMOTE:
priv->remote->renderer = new_renderer->renderer;
video_widget_set_renderer(priv->remote);
break;
case VIDEO_RENDERER_LOCAL:
priv->local->renderer = new_renderer->renderer;
video_widget_set_renderer(priv->local);
break;
case VIDEO_RENDERER_COUNT:
break;
}
}
......@@ -45,12 +45,25 @@ G_BEGIN_DECLS
typedef struct _VideoWidgetClass VideoWidgetClass;
typedef struct _VideoWidget VideoWidget;
typedef struct _VideoRenderer VideoRenderer;
typedef enum {
VIDEO_RENDERER_REMOTE,
VIDEO_RENDERER_LOCAL,
VIDEO_RENDERER_COUNT
} VideoRendererType;
struct _VideoRenderer
{
VideoRendererType type;
Video::Renderer *renderer;
};
/* Public interface */
GType video_widget_get_type (void) G_GNUC_CONST;
GtkWidget* video_widget_new (void);
void video_widget_set_remote_renderer(VideoWidget *self, Video::Renderer *renderer_remote_new);
void video_widget_set_local_renderer (VideoWidget *self, Video::Renderer *renderer_local_new);
GType video_widget_get_type (void) G_GNUC_CONST;
GtkWidget* video_widget_new (void);
void video_widget_add_renderer(VideoWidget *self, const VideoRenderer *new_renderer);
G_END_DECLS
#endif /* __VIDEO_WIDGET_H__ */
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment