Port gtk-doc comments to their equivalent markdown syntax
[platform/upstream/gstreamer.git] / libs / gst / check / gstconsistencychecker.c
1 /* GStreamer
2  *
3  * unit testing helper lib
4  *
5  * Copyright (C) 2009 Edward Hervey <bilboed@bilboed.com>
6  * Copyright (C) 2012 Stefan Sauer <ensonic@users.sf.net>
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 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., 51 Franklin St, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23
24 /**
25  * SECTION:gstcheckconsistencychecker
26  * @title: GstStreamConsistencyChecker
27  * @short_description: Data flow consistency checker for GStreamer unit tests.
28  *
29  * These macros and functions are for internal use of the unit tests found
30  * inside the 'check' directories of various GStreamer packages.
31  */
32
33 #include "gstconsistencychecker.h"
34
35 struct _GstStreamConsistency
36 {
37   /* FIXME: do we want to track some states per pad? */
38   volatile gboolean flushing;
39   volatile gboolean segment;
40   volatile gboolean eos;
41   volatile gboolean expect_flush;
42   volatile gboolean saw_serialized_event;
43   volatile gboolean saw_stream_start;
44   GstObject *parent;
45   GList *pads;
46 };
47
48 typedef struct _GstStreamConsistencyProbe
49 {
50   GstPad *pad;
51   gulong probeid;
52 } GstStreamConsistencyProbe;
53
54 static gboolean
55 source_pad_data_cb (GstPad * pad, GstPadProbeInfo * info,
56     GstStreamConsistency * consist)
57 {
58   GstMiniObject *data = GST_PAD_PROBE_INFO_DATA (info);
59
60   GST_DEBUG_OBJECT (pad, "%p: %d %d %d %d", consist, consist->flushing,
61       consist->segment, consist->eos, consist->expect_flush);
62
63   if (GST_IS_BUFFER (data)) {
64     GST_DEBUG_OBJECT (pad,
65         "Buffer pts %" GST_TIME_FORMAT ", dts %" GST_TIME_FORMAT,
66         GST_TIME_ARGS (GST_BUFFER_PTS (GST_BUFFER_CAST (data))),
67         GST_TIME_ARGS (GST_BUFFER_DTS (GST_BUFFER_CAST (data))));
68     /* If an EOS went through, a buffer would be invalid */
69     fail_if (consist->eos, "Buffer received after EOS on pad %s:%s",
70         GST_DEBUG_PAD_NAME (pad));
71     /* Buffers need to be preceded by a segment event */
72     fail_unless (consist->segment, "Buffer received without segment "
73         "on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
74   } else if (GST_IS_EVENT (data)) {
75     GstEvent *event = (GstEvent *) data;
76
77     GST_DEBUG_OBJECT (pad, "Event : %s", GST_EVENT_TYPE_NAME (event));
78     switch (GST_EVENT_TYPE (event)) {
79       case GST_EVENT_FLUSH_START:
80         /* getting two flush_start in a row seems to be okay
81            fail_if (consist->flushing, "Received another FLUSH_START");
82          */
83         consist->flushing = TRUE;
84         break;
85       case GST_EVENT_FLUSH_STOP:
86         /* Receiving a flush-stop is only valid after receiving a flush-start */
87         fail_unless (consist->flushing,
88             "Received a FLUSH_STOP without a FLUSH_START on pad %s:%s",
89             GST_DEBUG_PAD_NAME (pad));
90         fail_if (consist->eos, "Received a FLUSH_STOP after an EOS on "
91             "pad %s:%s", GST_DEBUG_PAD_NAME (pad));
92         consist->flushing = consist->expect_flush = FALSE;
93         break;
94       case GST_EVENT_STREAM_START:
95         fail_if (consist->saw_serialized_event && !consist->saw_stream_start,
96             "Got a STREAM_START event after a serialized event on pad %s:%s",
97             GST_DEBUG_PAD_NAME (pad));
98         consist->saw_stream_start = TRUE;
99         break;
100       case GST_EVENT_CAPS:
101         /* ok to have these before segment event */
102         /* FIXME check order more precisely, if so spec'ed somehow ? */
103         break;
104       case GST_EVENT_SEGMENT:
105         fail_if ((consist->expect_flush && consist->flushing),
106             "Received SEGMENT while in a flushing seek on pad %s:%s",
107             GST_DEBUG_PAD_NAME (pad));
108         consist->segment = TRUE;
109         consist->eos = FALSE;
110         break;
111       case GST_EVENT_EOS:
112         /* FIXME : not 100% sure about whether two eos in a row is valid */
113         fail_if (consist->eos, "Received EOS just after another EOS on "
114             "pad %s:%s", GST_DEBUG_PAD_NAME (pad));
115         consist->eos = TRUE;
116         consist->segment = FALSE;
117         break;
118       case GST_EVENT_TAG:
119         GST_DEBUG_OBJECT (pad, "tag %" GST_PTR_FORMAT,
120             gst_event_get_structure (event));
121         /* fall through */
122       default:
123         if (GST_EVENT_IS_SERIALIZED (event) && GST_EVENT_IS_DOWNSTREAM (event)) {
124           fail_if (consist->eos, "Event received after EOS");
125           fail_unless (consist->segment, "Event %s received before segment "
126               "on pad %s:%s", GST_EVENT_TYPE_NAME (event),
127               GST_DEBUG_PAD_NAME (pad));
128         }
129         /* FIXME : Figure out what to do for other events */
130         break;
131     }
132     if (GST_EVENT_IS_SERIALIZED (event)) {
133       fail_if (!consist->saw_stream_start
134           && GST_EVENT_TYPE (event) != GST_EVENT_STREAM_START,
135           "Got a serialized event (%s) before a STREAM_START on pad %s:%s",
136           GST_EVENT_TYPE_NAME (event), GST_DEBUG_PAD_NAME (pad));
137       consist->saw_serialized_event = TRUE;
138     }
139   }
140
141   return TRUE;
142 }
143
144 static gboolean
145 sink_pad_data_cb (GstPad * pad, GstPadProbeInfo * info,
146     GstStreamConsistency * consist)
147 {
148   GstMiniObject *data = GST_PAD_PROBE_INFO_DATA (info);
149
150   GST_DEBUG_OBJECT (pad, "%p: %d %d %d %d", consist, consist->flushing,
151       consist->segment, consist->eos, consist->expect_flush);
152
153   if (GST_IS_BUFFER (data)) {
154     GST_DEBUG_OBJECT (pad, "Buffer %" GST_TIME_FORMAT,
155         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (GST_BUFFER (data))));
156     /* If an EOS went through, a buffer would be invalid */
157     fail_if (consist->eos, "Buffer received after EOS on pad %s:%s",
158         GST_DEBUG_PAD_NAME (pad));
159     /* Buffers need to be preceded by a segment event */
160     fail_unless (consist->segment, "Buffer received without segment "
161         "on pad %s:%s", GST_DEBUG_PAD_NAME (pad));
162   } else if (GST_IS_EVENT (data)) {
163     GstEvent *event = (GstEvent *) data;
164
165     GST_DEBUG_OBJECT (pad, "%s", GST_EVENT_TYPE_NAME (event));
166     switch (GST_EVENT_TYPE (event)) {
167       case GST_EVENT_SEEK:
168       {
169         GstSeekFlags flags;
170
171         gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL,
172             NULL);
173         consist->expect_flush =
174             ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
175         break;
176       }
177       case GST_EVENT_SEGMENT:
178         fail_if ((consist->expect_flush && consist->flushing),
179             "Received SEGMENT while in a flushing seek on pad %s:%s",
180             GST_DEBUG_PAD_NAME (pad));
181         consist->segment = TRUE;
182         consist->eos = FALSE;
183         break;
184       default:
185         /* FIXME : Figure out what to do for other events */
186         break;
187     }
188   }
189
190   return TRUE;
191 }
192
193 static void
194 add_pad (GstStreamConsistency * consist, GstPad * pad)
195 {
196   GstStreamConsistencyProbe *p;
197   GstPadDirection dir;
198
199   p = g_new0 (GstStreamConsistencyProbe, 1);
200   p->pad = g_object_ref (pad);
201   dir = gst_pad_get_direction (pad);
202   if (dir == GST_PAD_SRC) {
203
204     p->probeid =
205         gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
206         (GstPadProbeCallback) source_pad_data_cb, consist, NULL);
207
208   } else if (dir == GST_PAD_SINK) {
209     p->probeid =
210         gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_DATA_DOWNSTREAM,
211         (GstPadProbeCallback) sink_pad_data_cb, consist, NULL);
212   }
213   consist->pads = g_list_prepend (consist->pads, p);
214 }
215
216 /**
217  * gst_consistency_checker_new: (skip)
218  * @pad: The #GstPad on which the dataflow will be checked.
219  *
220  * Sets up a data probe on the given pad which will raise assertions if the
221  * data flow is inconsistent.
222  *
223  * Returns: A #GstStreamConsistency structure used to track data flow.
224  */
225 GstStreamConsistency *
226 gst_consistency_checker_new (GstPad * pad)
227 {
228   GstStreamConsistency *consist;
229
230   g_return_val_if_fail (pad != NULL, NULL);
231
232   consist = g_new0 (GstStreamConsistency, 1);
233
234   if (!consist->pads) {
235     consist->parent = GST_OBJECT_PARENT (pad);
236   }
237   add_pad (consist, pad);
238   return consist;
239 }
240
241 /**
242  * gst_consistency_checker_add_pad:
243  * @consist: The #GstStreamConsistency handle
244  * @pad: The #GstPad on which the dataflow will be checked.
245  *
246  * Sets up a data probe on the given pad which will raise assertions if the
247  * data flow is inconsistent.
248  *
249  * Returns: %TRUE if the pad was added
250  */
251 gboolean
252 gst_consistency_checker_add_pad (GstStreamConsistency * consist, GstPad * pad)
253 {
254   g_return_val_if_fail (consist != NULL, FALSE);
255   g_return_val_if_fail (pad != NULL, FALSE);
256   g_return_val_if_fail (GST_OBJECT_PARENT (pad) == consist->parent, FALSE);
257
258   add_pad (consist, pad);
259   return TRUE;
260 }
261
262 /**
263  * gst_consistency_checker_reset:
264  * @consist: The #GstStreamConsistency to reset.
265  *
266  * Reset the stream checker's internal variables.
267  */
268
269 void
270 gst_consistency_checker_reset (GstStreamConsistency * consist)
271 {
272   consist->flushing = FALSE;
273   consist->segment = FALSE;
274   consist->eos = FALSE;
275   consist->expect_flush = FALSE;
276   consist->saw_serialized_event = FALSE;
277   consist->saw_stream_start = FALSE;
278 }
279
280 /**
281  * gst_consistency_checker_free:
282  * @consist: The #GstStreamConsistency to free.
283  *
284  * Frees the allocated data and probes associated with @consist.
285  */
286
287 void
288 gst_consistency_checker_free (GstStreamConsistency * consist)
289 {
290   GList *node;
291   GstStreamConsistencyProbe *p;
292
293   /* Remove the data probes */
294   for (node = consist->pads; node; node = g_list_next (node)) {
295     p = (GstStreamConsistencyProbe *) node->data;
296     gst_pad_remove_probe (p->pad, p->probeid);
297     gst_object_unref (p->pad);
298     g_free (p);
299   }
300   g_list_free (consist->pads);
301   g_free (consist);
302 }