consitencychecker: don't fail on multiple flush_start events
[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., 59 Temple Place - Suite 330,
21  * Boston, MA 02111-1307, USA.
22  */
23
24 /**
25  * SECTION:gstcheckconsistencychecker
26  * @short_description: Data flow consistency checker for GStreamer unit tests.
27  *
28  * These macros and functions are for internal use of the unit tests found
29  * inside the 'check' directories of various GStreamer packages.
30  *
31  * Since: 0.10.24
32  */
33
34 #include "gstconsistencychecker.h"
35
36 struct _GstStreamConsistency
37 {
38   /* FIXME: do we want to track some states per pad? */
39   volatile gboolean flushing;
40   volatile gboolean newsegment;
41   volatile gboolean eos;
42   volatile gboolean expect_flush;
43   GstObject *parent;
44   GList *pads;
45 };
46
47 typedef struct _GstStreamConsistencyProbe
48 {
49   GstPad *pad;
50   gulong probeid;
51 } GstStreamConsistencyProbe;
52
53
54 static gboolean
55 source_pad_data_cb (GstPad * pad, GstMiniObject * data,
56     GstStreamConsistency * consist)
57 {
58   GST_DEBUG_OBJECT (pad, "%p: %d %d %d %d", consist, consist->flushing,
59       consist->newsegment, consist->eos, consist->expect_flush);
60
61   if (GST_IS_BUFFER (data)) {
62     GST_DEBUG_OBJECT (pad, "Buffer %" GST_TIME_FORMAT,
63         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (GST_BUFFER (data))));
64     /* If an EOS went through, a buffer would be invalid */
65     fail_if (consist->eos, "Buffer received after EOS");
66     /* Buffers need to be preceded by a newsegment event */
67     fail_unless (consist->newsegment, "Buffer received without newsegment");
68   } else if (GST_IS_EVENT (data)) {
69     GstEvent *event = (GstEvent *) data;
70
71     GST_DEBUG_OBJECT (pad, "%s", GST_EVENT_TYPE_NAME (event));
72     switch (GST_EVENT_TYPE (event)) {
73       case GST_EVENT_FLUSH_START:
74         /* getting two flush_start in a row seems to be okay
75            fail_if (consist->flushing, "Received another FLUSH_START");
76          */
77         consist->flushing = TRUE;
78         break;
79       case GST_EVENT_FLUSH_STOP:
80         /* Receiving a flush-stop is only valid after receiving a flush-start */
81         fail_unless (consist->flushing,
82             "Received a FLUSH_STOP without a FLUSH_START");
83         fail_if (consist->eos, "Received a FLUSH_STOP after an EOS");
84         consist->flushing = consist->expect_flush = FALSE;
85         break;
86       case GST_EVENT_NEWSEGMENT:
87         fail_if ((consist->expect_flush && consist->flushing),
88             "Received NEWSEGMENT while in a flushing seek");
89         consist->newsegment = TRUE;
90         consist->eos = FALSE;
91         break;
92       case GST_EVENT_EOS:
93         /* FIXME : not 100% sure about whether two eos in a row is valid */
94         fail_if (consist->eos, "Received EOS just after another EOS");
95         consist->eos = TRUE;
96         consist->newsegment = FALSE;
97         break;
98       case GST_EVENT_TAG:
99         GST_DEBUG_OBJECT (pad, "tag %" GST_PTR_FORMAT, event->structure);
100         /* fall through */
101       default:
102         if (GST_EVENT_IS_SERIALIZED (event) && GST_EVENT_IS_DOWNSTREAM (event)) {
103           fail_if (consist->eos, "Event received after EOS");
104           fail_unless (consist->newsegment, "Event received before newsegment");
105         }
106         /* FIXME : Figure out what to do for other events */
107         break;
108     }
109   }
110
111   return TRUE;
112 }
113
114 static gboolean
115 sink_pad_data_cb (GstPad * pad, GstMiniObject * data,
116     GstStreamConsistency * consist)
117 {
118   GST_DEBUG_OBJECT (pad, "%p: %d %d %d %d", consist, consist->flushing,
119       consist->newsegment, consist->eos, consist->expect_flush);
120
121   if (GST_IS_BUFFER (data)) {
122     GST_DEBUG_OBJECT (pad, "Buffer %" GST_TIME_FORMAT,
123         GST_TIME_ARGS (GST_BUFFER_TIMESTAMP (GST_BUFFER (data))));
124     /* If an EOS went through, a buffer would be invalid */
125     fail_if (consist->eos, "Buffer received after EOS");
126     /* Buffers need to be preceded by a newsegment event */
127     fail_unless (consist->newsegment, "Buffer received without newsegment");
128   } else if (GST_IS_EVENT (data)) {
129     GstEvent *event = (GstEvent *) data;
130
131     GST_DEBUG_OBJECT (pad, "%s", GST_EVENT_TYPE_NAME (event));
132     switch (GST_EVENT_TYPE (event)) {
133       case GST_EVENT_SEEK:
134       {
135         GstSeekFlags flags;
136
137         gst_event_parse_seek (event, NULL, NULL, &flags, NULL, NULL, NULL,
138             NULL);
139         consist->expect_flush =
140             ((flags & GST_SEEK_FLAG_FLUSH) == GST_SEEK_FLAG_FLUSH);
141         break;
142       }
143       case GST_EVENT_NEWSEGMENT:
144         fail_if ((consist->expect_flush && consist->flushing),
145             "Received NEWSEGMENT while in a flushing seek");
146         consist->newsegment = TRUE;
147         consist->eos = FALSE;
148         break;
149       default:
150         /* FIXME : Figure out what to do for other events */
151         break;
152     }
153   }
154
155   return TRUE;
156 }
157
158 static void
159 add_pad (GstStreamConsistency * consist, GstPad * pad)
160 {
161   GstStreamConsistencyProbe *p;
162   GstPadDirection dir;
163
164   p = g_new0 (GstStreamConsistencyProbe, 1);
165   p->pad = g_object_ref (pad);
166   dir = gst_pad_get_direction (pad);
167   if (dir == GST_PAD_SRC) {
168     p->probeid =
169         gst_pad_add_data_probe (pad, (GCallback) source_pad_data_cb, consist);
170   } else if (dir == GST_PAD_SINK) {
171     p->probeid =
172         gst_pad_add_data_probe (pad, (GCallback) sink_pad_data_cb, consist);
173   }
174   consist->pads = g_list_prepend (consist->pads, p);
175 }
176
177 /**
178  * gst_consistency_checker_new:
179  * @pad: The #GstPad on which the dataflow will be checked.
180  *
181  * Sets up a data probe on the given pad which will raise assertions if the
182  * data flow is inconsistent.
183  *
184  * Returns: A #GstStreamConsistency structure used to track data flow.
185  *
186  * Since: 0.10.24
187  */
188 GstStreamConsistency *
189 gst_consistency_checker_new (GstPad * pad)
190 {
191   GstStreamConsistency *consist;
192
193   g_return_val_if_fail (pad != NULL, NULL);
194
195   consist = g_new0 (GstStreamConsistency, 1);
196
197   if (!consist->pads) {
198     consist->parent = GST_OBJECT_PARENT (pad);
199   }
200   add_pad (consist, pad);
201   return consist;
202 }
203
204 /**
205  * gst_consistency_checker_add_pad:
206  * @consist: The #GstStreamConsistency handle
207  * @pad: The #GstPad on which the dataflow will be checked.
208  *
209  * Sets up a data probe on the given pad which will raise assertions if the
210  * data flow is inconsistent.
211  *
212  * Returns: %TRUE if the pad was added
213  *
214  * Since: 0.10.37
215  */
216 gboolean
217 gst_consistency_checker_add_pad (GstStreamConsistency * consist, GstPad * pad)
218 {
219   g_return_val_if_fail (consist != NULL, FALSE);
220   g_return_val_if_fail (pad != NULL, FALSE);
221   g_return_val_if_fail (GST_OBJECT_PARENT (pad) == consist->parent, FALSE);
222
223   add_pad (consist, pad);
224   return TRUE;
225 }
226
227 /**
228  * gst_consistency_checker_reset:
229  * @consist: The #GstStreamConsistency to reset.
230  *
231  * Reset the stream checker's internal variables.
232  *
233  * Since: 0.10.24
234  */
235
236 void
237 gst_consistency_checker_reset (GstStreamConsistency * consist)
238 {
239   consist->eos = FALSE;
240   consist->flushing = FALSE;
241   consist->newsegment = FALSE;
242 }
243
244 /**
245  * gst_consistency_checker_free:
246  * @consist: The #GstStreamConsistency to free.
247  *
248  * Frees the allocated data and probes associated with @consist.
249  *
250  * Since: 0.10.24
251  */
252
253 void
254 gst_consistency_checker_free (GstStreamConsistency * consist)
255 {
256   GList *node;
257   GstStreamConsistencyProbe *p;
258
259   /* Remove the data probes */
260   for (node = consist->pads; node; node = g_list_next (node)) {
261     p = (GstStreamConsistencyProbe *) node->data;
262     gst_pad_remove_data_probe (p->pad, p->probeid);
263     g_object_unref (p->pad);
264     g_free (p);
265   }
266   g_list_free (consist->pads);
267   g_free (consist);
268 }