gstreamer/ext/wpe/wpe-extension/gstwpebusmsgforwarder.c
Thibault Saunier 4dbfae0105 wpe: Relay messages from WPE internal pipelines
It is based on a tracer as it allows us to very easily get
every message that are posted on any bus inside the process.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2252>
2021-05-19 13:41:15 +00:00

175 lines
5.6 KiB
C

/* Copyright (C) <2021> Thibault Saunier <tsaunier@igalia.com>
*
* This library is free software; you can redistribute it and/or modify it under the terms of the
* GNU Library General Public License as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "gstwpeextension.h"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
GST_DEBUG_CATEGORY (wpe_bus_msg_forwarder_debug);
#define GST_CAT_DEFAULT wpe_bus_msg_forwarder_debug
struct _GstWpeBusMsgForwarder
{
GstTracer parent;
GCancellable *cancellable;
};
G_DEFINE_TYPE_WITH_CODE (GstWpeBusMsgForwarder, gst_wpe_bus_msg_forwarder,
GST_TYPE_TRACER, GST_DEBUG_CATEGORY_INIT (wpe_bus_msg_forwarder_debug,
"wpebusmsgforwarder", 0, "WPE message forwarder"););
static void
dispose (GObject * object)
{
GstWpeBusMsgForwarder *self = GST_WPE_BUS_MSG_FORWARDER (object);
g_clear_object (&self->cancellable);
}
static WebKitUserMessage *
create_gerror_bus_msg (GstElement * element, GstMessage * message)
{
GError *error;
gchar *debug_str, *details_structure, *src_path;
const GstStructure *details = NULL;
if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) {
gst_message_parse_error (message, &error, &debug_str);
gst_message_parse_error_details (message, &details);
} else if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_WARNING) {
gst_message_parse_warning (message, &error, &debug_str);
gst_message_parse_warning_details (message, &details);
} else {
gst_message_parse_info (message, &error, &debug_str);
gst_message_parse_info_details (message, &details);
}
details_structure =
details ? gst_structure_to_string (details) : g_strdup ("");
src_path = gst_object_get_path_string (GST_MESSAGE_SRC (message));
return webkit_user_message_new ("gstwpe.bus_gerror_message",
/* (message_type, src_path, error_domain, error_code, msg, debug_str, details_structure) */
g_variant_new ("(sssusss)",
gst_message_type_get_name (GST_MESSAGE_TYPE (message)),
src_path,
g_quark_to_string (error->domain),
error->code, error->message, debug_str, details_structure)
);
g_free (src_path);
}
/* Those types can't be deserialized on the receiver
* side, so we just ignore them for now */
#define IS_UNDESERIALIZABLE_TYPE(value) \
(g_type_is_a ((G_VALUE_TYPE (value)), G_TYPE_OBJECT) || \
g_type_is_a ((G_VALUE_TYPE (value)), G_TYPE_ERROR) || \
g_type_is_a ((G_VALUE_TYPE (value)), GST_TYPE_CONTEXT) || \
g_type_is_a ((G_VALUE_TYPE (value)), G_TYPE_POINTER))
static gboolean
cleanup_structure (GQuark field_id, GValue * value, gpointer self)
{
/* We need soome API in core to make that happen cleanly */
if (IS_UNDESERIALIZABLE_TYPE (value)) {
return FALSE;
}
if (GST_VALUE_HOLDS_LIST (value)) {
gint i;
for (i = 0; i < gst_value_list_get_size (value); i++) {
if (IS_UNDESERIALIZABLE_TYPE (gst_value_list_get_value (value, i)))
return FALSE;
}
}
if (GST_VALUE_HOLDS_ARRAY (value)) {
gint i;
for (i = 0; i < gst_value_array_get_size (value); i++) {
if (IS_UNDESERIALIZABLE_TYPE (gst_value_array_get_value (value, i)))
return FALSE;
}
}
return TRUE;
}
static void
gst_message_post_cb (GObject * object, GstClockTime ts, GstElement * element,
GstMessage * message)
{
gchar *str;
WebKitUserMessage *msg = NULL;
GstStructure *structure;
GstWpeBusMsgForwarder *self;
const GstStructure *message_struct;
if (!GST_IS_PIPELINE (element))
return;
self = GST_WPE_BUS_MSG_FORWARDER (object);
message_struct = gst_message_get_structure (message);
structure = message_struct ? gst_structure_copy (message_struct) : NULL;
if (structure) {
gst_structure_filter_and_map_in_place (structure, cleanup_structure, self);
str = gst_structure_to_string (structure);
} else {
str = g_strdup ("");
}
/* we special case error as gst can't serialize/de-serialize it */
if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR
|| GST_MESSAGE_TYPE (message) == GST_MESSAGE_WARNING
|| GST_MESSAGE_TYPE (message) == GST_MESSAGE_INFO) {
msg = create_gerror_bus_msg (element, message);
} else {
gchar *src_path = gst_object_get_path_string (GST_MESSAGE_SRC (message));
msg = webkit_user_message_new ("gstwpe.bus_message",
g_variant_new ("(sssss)",
gst_message_type_get_name (GST_MESSAGE_TYPE (message)),
GST_MESSAGE_SRC_NAME (message),
G_OBJECT_TYPE_NAME (GST_MESSAGE_SRC (message)), src_path, str));
g_free (src_path);
}
if (msg)
gst_wpe_extension_send_message (msg, self->cancellable, NULL, NULL);
g_free (str);
}
static void
constructed (GObject * object)
{
GstTracer *tracer = GST_TRACER (object);
gst_tracing_register_hook (tracer, "element-post-message-pre",
G_CALLBACK (gst_message_post_cb));
}
static void
gst_wpe_bus_msg_forwarder_init (GstWpeBusMsgForwarder * self)
{
self->cancellable = g_cancellable_new ();
}
static void
gst_wpe_bus_msg_forwarder_class_init (GstWpeBusMsgForwarderClass * klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = dispose;
object_class->constructed = constructed;
}