• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) <2021> Thibault Saunier <tsaunier@igalia.com>
2  *
3  * This library is free software; you can redistribute it and/or modify it under the terms of the
4  * GNU Library General Public License as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
8  * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
9  * Library General Public License for more details.
10  *
11  * You should have received a copy of the GNU Library General Public License along with this
12  * library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
13  * Boston, MA 02110-1301, USA.
14  */
15 #include "gstwpeextension.h"
16 
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20 
21 GST_DEBUG_CATEGORY (wpe_bus_msg_forwarder_debug);
22 #define GST_CAT_DEFAULT wpe_bus_msg_forwarder_debug
23 
24 struct _GstWpeBusMsgForwarder
25 {
26   GstTracer parent;
27   GCancellable *cancellable;
28 };
29 
30 G_DEFINE_TYPE_WITH_CODE (GstWpeBusMsgForwarder, gst_wpe_bus_msg_forwarder,
31     GST_TYPE_TRACER, GST_DEBUG_CATEGORY_INIT (wpe_bus_msg_forwarder_debug,
32         "wpebusmsgforwarder", 0, "WPE message forwarder"););
33 
34 static void
dispose(GObject * object)35 dispose (GObject * object)
36 {
37   GstWpeBusMsgForwarder *self = GST_WPE_BUS_MSG_FORWARDER (object);
38 
39   g_clear_object (&self->cancellable);
40 }
41 
42 static WebKitUserMessage *
create_gerror_bus_msg(GstElement * element,GstMessage * message)43 create_gerror_bus_msg (GstElement * element, GstMessage * message)
44 {
45   GError *error;
46   gchar *debug_str, *details_structure, *src_path;
47   WebKitUserMessage *msg;
48   const GstStructure *details = NULL;
49 
50   if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR) {
51     gst_message_parse_error (message, &error, &debug_str);
52     gst_message_parse_error_details (message, &details);
53   } else if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_WARNING) {
54     gst_message_parse_warning (message, &error, &debug_str);
55     gst_message_parse_warning_details (message, &details);
56   } else {
57     gst_message_parse_info (message, &error, &debug_str);
58     gst_message_parse_info_details (message, &details);
59   }
60 
61   details_structure =
62       details ? gst_structure_to_string (details) : g_strdup ("");
63   src_path = gst_object_get_path_string (GST_MESSAGE_SRC (message));
64 
65   msg = webkit_user_message_new ("gstwpe.bus_gerror_message",
66       /* (message_type, src_path, error_domain, error_code, msg, debug_str, details_structure) */
67       g_variant_new ("(issssusss)",
68           GST_MESSAGE_TYPE (message),
69           GST_MESSAGE_SRC_NAME (message),
70           G_OBJECT_TYPE_NAME (GST_MESSAGE_SRC (message)),
71           src_path,
72           g_quark_to_string (error->domain),
73           error->code, error->message, debug_str, details_structure)
74       );
75   g_free (src_path);
76 
77   return msg;
78 }
79 
80 /* Those types can't be deserialized on the receiver
81  * side, so we just ignore them for now */
82 #define IS_NOT_DESERIALIZABLE_TYPE(value) \
83   (g_type_is_a ((G_VALUE_TYPE (value)), G_TYPE_OBJECT)  || \
84    g_type_is_a ((G_VALUE_TYPE (value)), G_TYPE_ERROR) || \
85    g_type_is_a ((G_VALUE_TYPE (value)), GST_TYPE_CONTEXT) || \
86    g_type_is_a ((G_VALUE_TYPE (value)), G_TYPE_POINTER))
87 
88 static gboolean
cleanup_structure(GQuark field_id,GValue * value,gpointer self)89 cleanup_structure (GQuark field_id, GValue * value, gpointer self)
90 {
91   /* We need soome API in core to make that happen cleanly */
92   if (IS_NOT_DESERIALIZABLE_TYPE (value)) {
93     return FALSE;
94   }
95 
96   if (GST_VALUE_HOLDS_LIST (value)) {
97     gint i;
98 
99     for (i = 0; i < gst_value_list_get_size (value); i++) {
100       if (IS_NOT_DESERIALIZABLE_TYPE (gst_value_list_get_value (value, i)))
101         return FALSE;
102     }
103   }
104 
105   if (GST_VALUE_HOLDS_ARRAY (value)) {
106     gint i;
107 
108     for (i = 0; i < gst_value_array_get_size (value); i++) {
109       if (IS_NOT_DESERIALIZABLE_TYPE (gst_value_array_get_value (value, i)))
110         return FALSE;
111     }
112   }
113 
114   return TRUE;
115 }
116 
117 static void
gst_message_post_cb(GObject * object,GstClockTime ts,GstElement * element,GstMessage * message)118 gst_message_post_cb (GObject * object, GstClockTime ts, GstElement * element,
119     GstMessage * message)
120 {
121   gchar *str;
122   WebKitUserMessage *msg = NULL;
123   GstStructure *structure;
124   GstWpeBusMsgForwarder *self;
125   const GstStructure *message_struct;
126 
127   if (!GST_IS_PIPELINE (element))
128     return;
129 
130   self = GST_WPE_BUS_MSG_FORWARDER (object);
131   message_struct = gst_message_get_structure (message);
132   structure = message_struct ? gst_structure_copy (message_struct) : NULL;
133 
134   if (structure) {
135     gst_structure_filter_and_map_in_place (structure, cleanup_structure, self);
136     str = gst_structure_to_string (structure);
137   } else {
138     str = g_strdup ("");
139   }
140 
141   /* we special case error as gst can't serialize/de-serialize it */
142   if (GST_MESSAGE_TYPE (message) == GST_MESSAGE_ERROR
143       || GST_MESSAGE_TYPE (message) == GST_MESSAGE_WARNING
144       || GST_MESSAGE_TYPE (message) == GST_MESSAGE_INFO) {
145     msg = create_gerror_bus_msg (element, message);
146   } else {
147     gchar *src_path = gst_object_get_path_string (GST_MESSAGE_SRC (message));
148     msg = webkit_user_message_new ("gstwpe.bus_message",
149         g_variant_new ("(issss)",
150             GST_MESSAGE_TYPE (message),
151             GST_MESSAGE_SRC_NAME (message),
152             G_OBJECT_TYPE_NAME (GST_MESSAGE_SRC (message)), src_path, str));
153     g_free (src_path);
154   }
155   if (msg)
156     gst_wpe_extension_send_message (msg, self->cancellable, NULL, NULL);
157   g_free (str);
158 }
159 
160 static void
constructed(GObject * object)161 constructed (GObject * object)
162 {
163   GstTracer *tracer = GST_TRACER (object);
164   gst_tracing_register_hook (tracer, "element-post-message-pre",
165       G_CALLBACK (gst_message_post_cb));
166 }
167 
168 static void
gst_wpe_bus_msg_forwarder_init(GstWpeBusMsgForwarder * self)169 gst_wpe_bus_msg_forwarder_init (GstWpeBusMsgForwarder * self)
170 {
171   self->cancellable = g_cancellable_new ();
172 }
173 
174 static void
gst_wpe_bus_msg_forwarder_class_init(GstWpeBusMsgForwarderClass * klass)175 gst_wpe_bus_msg_forwarder_class_init (GstWpeBusMsgForwarderClass * klass)
176 {
177   GObjectClass *object_class = G_OBJECT_CLASS (klass);
178 
179   object_class->dispose = dispose;
180   object_class->constructed = constructed;
181 }
182