ab2c82c2a0fb05bce3a09c64425174aea1907e6f
[platform/upstream/gstreamer.git] / validate / gst / validate / gst-validate-bin-monitor.c
1 /* GStreamer
2  *
3  * Copyright (C) 2013 Collabora Ltd.
4  *  Author: Thiago Sousa Santos <thiago.sousa.santos@collabora.com>
5  *
6  * gst-validate-bin-monitor.c - Validate BinMonitor class
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public
19  * License along with this library; if not, write to the
20  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "gst-validate-internal.h"
29 #include "gst-validate-bin-monitor.h"
30 #include "gst-validate-monitor-factory.h"
31
32 #define PRINT_POSITION_TIMEOUT 250
33
34 /**
35  * SECTION:gst-validate-bin-monitor
36  * @short_description: Class that wraps a #GstBin for Validate checks
37  *
38  * TODO
39  */
40
41 enum
42 {
43   PROP_0,
44   PROP_HANDLES_STATE,
45   PROP_LAST
46 };
47
48 #define gst_validate_bin_monitor_parent_class parent_class
49 G_DEFINE_TYPE (GstValidateBinMonitor, gst_validate_bin_monitor,
50     GST_TYPE_VALIDATE_ELEMENT_MONITOR);
51
52 static void
53 gst_validate_bin_monitor_get_property (GObject * object, guint prop_id,
54     GValue * value, GParamSpec * pspec);
55 static void
56 gst_validate_bin_monitor_set_property (GObject * object, guint prop_id,
57     const GValue * value, GParamSpec * pspec);
58 static void
59 gst_validate_bin_monitor_wrap_element (GstValidateBinMonitor * monitor,
60     GstElement * element);
61 static gboolean gst_validate_bin_monitor_setup (GstValidateMonitor * monitor);
62
63 static void
64 _validate_bin_element_added (GstBin * bin, GstElement * pad,
65     GstValidateBinMonitor * monitor);
66
67 static void
68 _validate_bin_element_removed (GstBin * bin, GstElement * element,
69     GstValidateBinMonitor * monitor);
70
71 static void
72 gst_validate_bin_set_media_descriptor (GstValidateMonitor * monitor,
73     GstValidateMediaDescriptor * media_descriptor)
74 {
75   GList *tmp;
76
77   GST_VALIDATE_MONITOR_LOCK (monitor);
78   for (tmp = GST_VALIDATE_BIN_MONITOR_CAST (monitor)->element_monitors; tmp;
79       tmp = tmp->next) {
80     GstValidateMonitor *sub_monitor = (GstValidateMonitor *) tmp->data;
81     gst_validate_monitor_set_media_descriptor (sub_monitor, media_descriptor);
82   }
83   GST_VALIDATE_MONITOR_UNLOCK (monitor);
84
85   GST_VALIDATE_MONITOR_CLASS (parent_class)->set_media_descriptor (monitor,
86       media_descriptor);
87 }
88
89 static void
90 gst_validate_bin_monitor_set_property (GObject * object, guint prop_id,
91     const GValue * value, GParamSpec * pspec)
92 {
93   switch (prop_id) {
94     case PROP_HANDLES_STATE:
95       g_assert_not_reached ();
96       break;
97     default:
98       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
99       break;
100   }
101 }
102
103 static void
104 gst_validate_bin_monitor_get_property (GObject * object, guint prop_id,
105     GValue * value, GParamSpec * pspec)
106 {
107   GstValidateBinMonitor *monitor;
108
109   monitor = GST_VALIDATE_BIN_MONITOR_CAST (object);
110
111   switch (prop_id) {
112     case PROP_HANDLES_STATE:
113       if (monitor->scenario == NULL)
114         g_value_set_boolean (value, FALSE);
115       else
116         g_object_get_property (G_OBJECT (monitor->scenario), "handles-states",
117             value);
118       break;
119     default:
120       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
121       break;
122   }
123 }
124
125 static void
126 purge_and_unref_reporter (gpointer data)
127 {
128   GstValidateReporter *reporter = data;
129
130   gst_validate_reporter_purge_reports (reporter);
131   g_object_unref (reporter);
132 }
133
134 static void
135 gst_validate_bin_monitor_dispose (GObject * object)
136 {
137   GstValidateBinMonitor *monitor = GST_VALIDATE_BIN_MONITOR_CAST (object);
138   GstElement *bin =
139       GST_ELEMENT (gst_validate_monitor_get_target (GST_VALIDATE_MONITOR_CAST
140           (monitor)));
141
142   if (bin) {
143     if (monitor->element_added_id)
144       g_signal_handler_disconnect (bin, monitor->element_added_id);
145     if (monitor->element_removed_id)
146       g_signal_handler_disconnect (bin, monitor->element_removed_id);
147     gst_object_unref (bin);
148   }
149
150   if (monitor->scenario) {
151     gst_validate_reporter_purge_reports (GST_VALIDATE_REPORTER
152         (monitor->scenario));
153     gst_clear_object (&monitor->scenario);
154   }
155
156   g_list_free_full (monitor->element_monitors, purge_and_unref_reporter);
157
158   G_OBJECT_CLASS (parent_class)->dispose (object);
159 }
160
161
162 static void
163 gst_validate_bin_monitor_class_init (GstValidateBinMonitorClass * klass)
164 {
165   GObjectClass *gobject_class;
166   GstValidateMonitorClass *validatemonitor_class;
167
168   gobject_class = G_OBJECT_CLASS (klass);
169   validatemonitor_class = GST_VALIDATE_MONITOR_CLASS_CAST (klass);
170
171   gobject_class->get_property = gst_validate_bin_monitor_get_property;
172   gobject_class->set_property = gst_validate_bin_monitor_set_property;
173   gobject_class->dispose = gst_validate_bin_monitor_dispose;
174
175   g_object_class_install_property (gobject_class, PROP_HANDLES_STATE,
176       g_param_spec_boolean ("handles-states", "Handles state",
177           "True if the application should not set handle the first state change "
178           " False if it is application responsibility",
179           FALSE, G_PARAM_READABLE));
180
181   validatemonitor_class->setup = gst_validate_bin_monitor_setup;
182   validatemonitor_class->set_media_descriptor =
183       gst_validate_bin_set_media_descriptor;
184 }
185
186 static void
187 gst_validate_bin_monitor_init (GstValidateBinMonitor * bin_monitor)
188 {
189 }
190
191 /**
192  * gst_validate_bin_monitor_new:
193  * @bin: (transfer none): a #GstBin to run Validate on
194  */
195 GstValidateBinMonitor *
196 gst_validate_bin_monitor_new (GstBin * bin, GstValidateRunner * runner,
197     GstValidateMonitor * parent)
198 {
199   GstValidateBinMonitor *monitor =
200       g_object_new (GST_TYPE_VALIDATE_BIN_MONITOR, "object",
201       bin, "validate-runner", runner, "validate-parent", parent, NULL);
202   GstObject *target =
203       gst_validate_monitor_get_target (GST_VALIDATE_MONITOR (monitor));
204
205   if (target == NULL) {
206     g_object_unref (monitor);
207     return NULL;
208   }
209   gst_object_unref (target);
210
211   return monitor;
212 }
213
214 static void
215 gst_validate_bin_child_added_overrides (GstValidateMonitor * monitor,
216     GstElement * element)
217 {
218   GList *iter;
219
220   GST_VALIDATE_MONITOR_OVERRIDES_LOCK (monitor);
221   for (iter = GST_VALIDATE_MONITOR_OVERRIDES (monitor).head; iter;
222       iter = g_list_next (iter)) {
223     GstValidateOverride *override = iter->data;
224
225     gst_validate_override_element_added_handler (override, monitor, element);
226   }
227   GST_VALIDATE_MONITOR_OVERRIDES_UNLOCK (monitor);
228 }
229
230 static gboolean
231 gst_validate_bin_monitor_setup (GstValidateMonitor * monitor)
232 {
233   GstIterator *iterator;
234   gboolean done;
235   GstElement *element;
236   GstValidateBinMonitor *bin_monitor = GST_VALIDATE_BIN_MONITOR_CAST (monitor);
237   GstBin *bin = GST_BIN_CAST (gst_validate_monitor_get_target (monitor));
238
239   if (!GST_IS_BIN (bin)) {
240     GST_WARNING_OBJECT (monitor, "Trying to create bin monitor with other "
241         "type of object");
242     goto fail;
243   }
244
245   GST_DEBUG_OBJECT (bin_monitor, "Setting up monitor for bin %" GST_PTR_FORMAT,
246       bin);
247
248   if (g_object_get_data ((GObject *) bin, "validate-monitor")) {
249     GST_DEBUG_OBJECT (bin_monitor,
250         "Bin already has a validate-monitor associated");
251     goto fail;
252   }
253
254   bin_monitor->element_added_id =
255       g_signal_connect (bin, "element-added",
256       G_CALLBACK (_validate_bin_element_added), monitor);
257
258   bin_monitor->element_removed_id =
259       g_signal_connect (bin, "element-removed",
260       G_CALLBACK (_validate_bin_element_removed), monitor);
261
262   iterator = gst_bin_iterate_elements (bin);
263   done = FALSE;
264   while (!done) {
265     GValue value = { 0, };
266
267     switch (gst_iterator_next (iterator, &value)) {
268       case GST_ITERATOR_OK:
269         element = g_value_get_object (&value);
270         gst_validate_bin_monitor_wrap_element (bin_monitor, element);
271         g_value_reset (&value);
272         break;
273       case GST_ITERATOR_RESYNC:
274         /* TODO how to handle this? */
275         gst_iterator_resync (iterator);
276         break;
277       case GST_ITERATOR_ERROR:
278         done = TRUE;
279         break;
280       case GST_ITERATOR_DONE:
281         done = TRUE;
282         break;
283     }
284   }
285   gst_iterator_free (iterator);
286   gst_object_unref (bin);
287
288   return GST_VALIDATE_MONITOR_CLASS (parent_class)->setup (monitor);
289
290 fail:
291   if (bin)
292     gst_object_unref (bin);
293   return FALSE;
294 }
295
296 static void
297 gst_validate_bin_monitor_wrap_element (GstValidateBinMonitor * monitor,
298     GstElement * element)
299 {
300   GstValidateElementMonitor *element_monitor;
301   GstValidateRunner *runner =
302       gst_validate_reporter_get_runner (GST_VALIDATE_REPORTER (monitor));
303
304   GST_DEBUG_OBJECT (monitor, "Wrapping element %s", GST_ELEMENT_NAME (element));
305
306   element_monitor =
307       GST_VALIDATE_ELEMENT_MONITOR_CAST (gst_validate_monitor_factory_create
308       (GST_OBJECT_CAST (element), runner, GST_VALIDATE_MONITOR_CAST (monitor)));
309   g_return_if_fail (element_monitor != NULL);
310
311   GST_VALIDATE_MONITOR_CAST (element_monitor)->verbosity =
312       GST_VALIDATE_MONITOR_CAST (monitor)->verbosity;
313   gst_validate_bin_child_added_overrides (GST_VALIDATE_MONITOR (monitor),
314       element);
315
316   if (GST_VALIDATE_MONITOR_CAST (monitor)->verbosity &
317       GST_VALIDATE_VERBOSITY_NEW_ELEMENTS)
318     gst_validate_printf (NULL, "(element-added) %s added to %s\n",
319         GST_ELEMENT_NAME (element),
320         gst_validate_reporter_get_name (GST_VALIDATE_REPORTER (monitor)));
321
322   GST_VALIDATE_MONITOR_LOCK (monitor);
323   monitor->element_monitors = g_list_prepend (monitor->element_monitors,
324       element_monitor);
325   GST_VALIDATE_MONITOR_UNLOCK (monitor);
326
327   gst_object_unref (runner);
328 }
329
330 static void
331 _validate_bin_element_added (GstBin * bin, GstElement * element,
332     GstValidateBinMonitor * monitor)
333 {
334   GstObject *target =
335       gst_validate_monitor_get_target (GST_VALIDATE_MONITOR (monitor));
336
337   g_return_if_fail (GST_ELEMENT_CAST (target) == GST_ELEMENT_CAST (bin));
338
339   gst_object_unref (target);
340   gst_validate_bin_monitor_wrap_element (monitor, element);
341 }
342
343 static void
344 _validate_bin_element_removed (GstBin * bin, GstElement * element,
345     GstValidateBinMonitor * monitor)
346 {
347   if (GST_VALIDATE_MONITOR_CAST (monitor)->verbosity &
348       GST_VALIDATE_VERBOSITY_NEW_ELEMENTS)
349     gst_validate_printf (NULL, "(element-removed) %s removed from %s\n",
350         GST_ELEMENT_NAME (element),
351         gst_validate_reporter_get_name (GST_VALIDATE_REPORTER (monitor)));
352 }
353
354 /**
355  * gst_validate_bin_monitor_get_scenario:
356  * @monitor: A #GstValidateBinMonitor
357  *
358  * Returns: (transfer full) (nullable): The #GstValidateScenario being executed
359  * under @monitor watch
360  *
361  * Since: 1.20
362  */
363 GstValidateScenario *
364 gst_validate_bin_monitor_get_scenario (GstValidateBinMonitor * monitor)
365 {
366   if (monitor->scenario)
367     return gst_object_ref (monitor->scenario);
368
369   return NULL;
370 }