1 /* GStreamer
2 *
3 * unit test for clocksync
4 *
5 * Copyright (C) <2005> Thomas Vander Stichele <thomas at apestaart dot org>
6 * Copyright (C) <2015> Havard Graff <havard@pexip.com>
7 * Copyright (C) <2020> Jan Schmidt <jan@centricular.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the
21 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 */
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <gst/check/gstcheck.h>
29 #include <gst/check/gstharness.h>
30
GST_START_TEST(test_one_buffer)31 GST_START_TEST (test_one_buffer)
32 {
33 GstHarness *h = gst_harness_new_parse ("clocksync sync=false");
34 GstBuffer *buffer_in;
35 GstBuffer *buffer_out;
36
37 gst_harness_set_src_caps_str (h, "mycaps");
38
39 buffer_in = gst_buffer_new_and_alloc (4);
40 ASSERT_BUFFER_REFCOUNT (buffer_in, "buffer", 1);
41
42 gst_buffer_fill (buffer_in, 0, "data", 4);
43
44 /* pushing gives away my reference ... */
45 fail_unless_equals_int (GST_FLOW_OK, gst_harness_push (h, buffer_in));
46
47 /* ... but it should end up being collected on GstHarness queue */
48 fail_unless_equals_int (1, gst_harness_buffers_in_queue (h));
49 buffer_out = gst_harness_pull (h);
50
51 fail_unless (buffer_in == buffer_out);
52 ASSERT_BUFFER_REFCOUNT (buffer_out, "buffer", 1);
53
54 /* cleanup */
55 gst_buffer_unref (buffer_out);
56 gst_harness_teardown (h);
57 }
58
59 GST_END_TEST;
60
GST_START_TEST(test_sync_on_timestamp)61 GST_START_TEST (test_sync_on_timestamp)
62 {
63 /* the reason to use the queue in front of the clocksync element
64 is to effectively make gst_harness_push asynchronous, not locking
65 up the test, waiting for gst_clock_id_wait */
66 GstHarness *h = gst_harness_new_parse ("queue ! clocksync");
67 GstBuffer *buf;
68 GstClock *clock;
69 GstClockTime timestamp = 123456789;
70
71 /* use testclock */
72 gst_harness_use_testclock (h);
73 gst_harness_set_src_caps_str (h, "mycaps");
74
75 /* make a buffer and set the timestamp */
76 buf = gst_buffer_new ();
77 GST_BUFFER_PTS (buf) = timestamp;
78
79 /* push the buffer, and verify it does *not* make it through */
80 gst_harness_push (h, buf);
81 fail_unless_equals_int (0, gst_harness_buffers_in_queue (h));
82
83 /* verify the clocksync element has registered exactly one GstClockID */
84 fail_unless (gst_harness_wait_for_clock_id_waits (h, 1, 42));
85
86 /* crank the clock and pull the buffer */
87 gst_harness_crank_single_clock_wait (h);
88 buf = gst_harness_pull (h);
89
90 /* verify that the buffer has the right timestamp, and that the time on
91 the clock is equal to the timestamp */
92 fail_unless_equals_int64 (timestamp, GST_BUFFER_PTS (buf));
93 clock = gst_element_get_clock (h->element);
94 fail_unless_equals_int64 (timestamp, gst_clock_get_time (clock));
95
96 /* cleanup */
97 gst_object_unref (clock);
98 gst_buffer_unref (buf);
99 gst_harness_teardown (h);
100 }
101
102 GST_END_TEST;
103
GST_START_TEST(test_no_sync_on_timestamp)104 GST_START_TEST (test_no_sync_on_timestamp)
105 {
106 GstHarness *h = gst_harness_new_parse ("clocksync sync=false");
107 GstBuffer *buf;
108 GstClockTime timestamp = 123456789;
109
110 /* use testclock */
111 gst_harness_use_testclock (h);
112 gst_harness_set_src_caps_str (h, "mycaps");
113
114 /* make a buffer and set the timestamp */
115 buf = gst_buffer_new ();
116 GST_BUFFER_PTS (buf) = timestamp;
117
118 /* push the buffer, and verify it was forwarded immediately */
119 gst_harness_push (h, buf);
120 fail_unless_equals_int (1, gst_harness_buffers_in_queue (h));
121
122 buf = gst_harness_pull (h);
123 /* verify that the buffer has the right timestamp */
124 fail_unless_equals_int64 (timestamp, GST_BUFFER_PTS (buf));
125
126 /* cleanup */
127 gst_buffer_unref (buf);
128 gst_harness_teardown (h);
129 }
130
131 GST_END_TEST;
132
GST_START_TEST(test_stopping_element_unschedules_sync)133 GST_START_TEST (test_stopping_element_unschedules_sync)
134 {
135 /* the reason to use the queue in front of the clocksync element
136 is to effectively make gst_harness_push asynchronous, not locking
137 up the test, waiting for gst_clock_id_wait */
138 GstHarness *h = gst_harness_new_parse ("queue ! clocksync sync=true");
139 GstBuffer *buf;
140 GstClockTime timestamp = 123456789;
141
142 /* use testclock */
143 gst_harness_use_testclock (h);
144 gst_harness_set_src_caps_str (h, "mycaps");
145
146 /* make a buffer and set the timestamp */
147 buf = gst_buffer_new ();
148 GST_BUFFER_PTS (buf) = timestamp;
149
150 /* push the buffer, and verify it does *not* make it through */
151 gst_harness_push (h, buf);
152 fail_unless_equals_int (0, gst_harness_buffers_in_queue (h));
153
154 /* verify the clocksync element has registered exactly one GstClockID */
155 fail_unless (gst_harness_wait_for_clock_id_waits (h, 1, 42));
156
157 /* setting clocksync to READY should unschedule the sync */
158 gst_element_set_state (h->element, GST_STATE_READY);
159
160 /* verify the clocksync element no longer waits on the clock */
161 fail_unless (gst_harness_wait_for_clock_id_waits (h, 0, 42));
162
163 /* and that the waiting buffer was dropped */
164 fail_unless_equals_int (0, gst_harness_buffers_received (h));
165
166 gst_harness_teardown (h);
167 }
168
169 GST_END_TEST;
170
171 typedef struct
172 {
173 guint notify_count;
174 GstClockTimeDiff ts_offset;
175 } ClockSyncTestData;
176
177 static void
clock_sync_ts_offset_changed_cb(GstElement * clocksync,GParamSpec * pspec,ClockSyncTestData * data)178 clock_sync_ts_offset_changed_cb (GstElement * clocksync, GParamSpec * pspec,
179 ClockSyncTestData * data)
180 {
181 data->notify_count++;
182 g_object_get (clocksync, "ts-offset", &data->ts_offset, NULL);
183 }
184
GST_START_TEST(test_sync_to_first)185 GST_START_TEST (test_sync_to_first)
186 {
187 /* the reason to use the queue in front of the clocksync element
188 is to effectively make gst_harness_push asynchronous, not locking
189 up the test, waiting for gst_clock_id_wait */
190 GstHarness *h =
191 gst_harness_new_parse ("queue ! clocksync sync-to-first=true");
192 GstBuffer *buf;
193 GstClock *clock;
194 GstClockTime timestamp = 123456789;
195 GstElement *clocksync;
196 ClockSyncTestData data;
197 data.notify_count = 0;
198 data.ts_offset = 0;
199
200 clocksync = gst_harness_find_element (h, "clocksync");
201 g_signal_connect (clocksync, "notify::ts-offset",
202 G_CALLBACK (clock_sync_ts_offset_changed_cb), &data);
203 gst_object_unref (clocksync);
204
205 /* use testclock */
206 gst_harness_use_testclock (h);
207 gst_harness_set_src_caps_str (h, "mycaps");
208
209 /* make a buffer and set the timestamp */
210 buf = gst_buffer_new ();
211 GST_BUFFER_PTS (buf) = timestamp;
212
213 /* push the buffer, and verify it does *not* make it through */
214 gst_harness_push (h, buf);
215 fail_unless_equals_int (0, gst_harness_buffers_in_queue (h));
216
217 /* verify the clocksync element has registered exactly one GstClockID */
218 fail_unless (gst_harness_wait_for_clock_id_waits (h, 1, 42));
219
220 /* crank the clock and pull the buffer */
221 gst_harness_crank_single_clock_wait (h);
222 buf = gst_harness_pull (h);
223
224 /* verify that the buffer has the right timestamp, and that the time on
225 the clock is equal to the timestamp */
226 fail_unless_equals_int64 (timestamp, GST_BUFFER_PTS (buf));
227 clock = gst_element_get_clock (h->element);
228 /* this buffer must be pushed without clock waiting */
229 fail_unless_equals_int64 (gst_clock_get_time (clock), 0);
230 fail_unless_equals_int (data.notify_count, 1);
231 fail_unless_equals_int64 (data.ts_offset, -timestamp);
232
233 /* cleanup */
234 gst_object_unref (clock);
235 gst_buffer_unref (buf);
236 gst_harness_teardown (h);
237 }
238
239 GST_END_TEST;
240
241 static Suite *
clocksync_suite(void)242 clocksync_suite (void)
243 {
244 Suite *s = suite_create ("clocksync");
245 TCase *tc_chain = tcase_create ("general");
246
247 suite_add_tcase (s, tc_chain);
248 tcase_add_test (tc_chain, test_one_buffer);
249 tcase_add_test (tc_chain, test_sync_on_timestamp);
250 tcase_add_test (tc_chain, test_stopping_element_unschedules_sync);
251 tcase_add_test (tc_chain, test_no_sync_on_timestamp);
252 tcase_add_test (tc_chain, test_sync_to_first);
253
254
255 return s;
256 }
257
258 GST_CHECK_MAIN (clocksync);
259