38 __author__ =
"Kipp Cannon <kipp.cannon@ligo.org>"
68 A function to nicely format a timestamp for printing
70 if timestamp
is None or timestamp == gst.CLOCK_TIME_NONE:
72 return "%d.%09d s" % (timestamp // gst.SECOND, timestamp % gst.SECOND)
77 A class representing a gstreamer element that will verify that the
78 timestamps agree with incoming buffers based on tracking the buffer offsets.
81 "Timestamp Checker Pass-Through Element",
83 "Checks that timestamps and offsets of audio streams advance as expected and remain synchronized to each other",
91 "Number of nanoseconds of timestamp<-->offset discrepancy to accept before reporting it. Timestamp<-->offset discrepancies of 1/2 a sample or more are always reported.",
94 0, 18446744073709551615L, 1,
95 gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT
100 "Only report errors.",
102 gobject.PARAM_READWRITE | gobject.PARAM_CONSTRUCT
107 gst.PadTemplate(
"sink",
110 gst.caps_from_string(
111 "audio/x-raw-float, " +
112 "rate = (int) [1, MAX], " +
113 "channels = (int) [1, MAX], " +
114 "endianness = (int) BYTE_ORDER, " +
115 "width = (int) {32, 64};" +
116 "audio/x-raw-complex, " +
117 "rate = (int) [1, MAX], " +
118 "channels = (int) [1, MAX], " +
119 "endianness = (int) BYTE_ORDER, " +
120 "width = (int) {64, 128};" +
121 "audio/x-raw-int, " +
122 "rate = (int) [1, MAX], " +
123 "channels = (int) [1, MAX], " +
124 "endianness = (int) BYTE_ORDER, " +
125 "width = (int) 16," +
126 "depth = (int) 16," +
127 "signed = (bool) {true, false}; " +
128 "audio/x-raw-int, " +
129 "rate = (int) [1, MAX], " +
130 "channels = (int) [1, MAX], " +
131 "endianness = (int) BYTE_ORDER, " +
132 "width = (int) 32," +
133 "depth = (int) 32," +
134 "signed = (bool) {true, false}; " +
135 "audio/x-raw-int, " +
136 "rate = (int) [1, MAX], " +
137 "channels = (int) [1, MAX], " +
138 "endianness = (int) BYTE_ORDER, " +
139 "width = (int) 64," +
140 "depth = (int) 64," +
141 "signed = (bool) {true, false}"
144 gst.PadTemplate(
"src",
147 gst.caps_from_string(
148 "audio/x-raw-float, " +
149 "rate = (int) [1, MAX], " +
150 "channels = (int) [1, MAX], " +
151 "endianness = (int) BYTE_ORDER, " +
152 "width = (int) {32, 64};" +
153 "audio/x-raw-complex, " +
154 "rate = (int) [1, MAX], " +
155 "channels = (int) [1, MAX], " +
156 "endianness = (int) BYTE_ORDER, " +
157 "width = (int) {64, 128};" +
158 "audio/x-raw-int, " +
159 "rate = (int) [1, MAX], " +
160 "channels = (int) [1, MAX], " +
161 "endianness = (int) BYTE_ORDER, " +
162 "width = (int) 16," +
163 "depth = (int) 16," +
164 "signed = (bool) {true, false}; " +
165 "audio/x-raw-int, " +
166 "rate = (int) [1, MAX], " +
167 "channels = (int) [1, MAX], " +
168 "endianness = (int) BYTE_ORDER, " +
169 "width = (int) 32," +
170 "depth = (int) 32," +
171 "signed = (bool) {true, false}; " +
172 "audio/x-raw-int, " +
173 "rate = (int) [1, MAX], " +
174 "channels = (int) [1, MAX], " +
175 "endianness = (int) BYTE_ORDER, " +
176 "width = (int) 64," +
177 "depth = (int) 64," +
178 "signed = (bool) {true, false}"
185 super(lal_checktimestamps, self).__init__()
186 self.set_passthrough(
True)
189 def do_set_property(self, prop, val):
190 if prop.name ==
"timestamp-fuzz":
192 elif prop.name ==
"silent":
196 def do_get_property(self, prop):
197 if prop.name ==
"timestamp-fuzz":
199 elif prop.name ==
"silent":
203 def do_set_caps(self, incaps, outcaps):
204 self.
unit_size = incaps[0][
"width"] // 8 * incaps[0][
"channels"]
217 def check_time_offset_mismatch(self, buf):
220 if buf.offset != expected_offset:
221 print >>sys.stderr,
"%s: timestamp/offset mismatch%s: got offset %d, buffer timestamp %s corresponds to offset %d (error = %d samples)" % (self.get_property(
"name"), (buf.flag_is_set(gst.BUFFER_FLAG_DISCONT)
and " at discontinuity" or ""), buf.offset,
printable_timestamp(buf.timestamp), expected_offset, buf.offset - expected_offset)
222 elif abs(buf.timestamp - expected_timestamp) > self.
timestamp_fuzz:
223 print >>sys.stderr,
"%s: timestamp/offset mismatch%s: got timestamp %s, buffer offset %d corresponds to timestamp %s (error = %d ns)" % (self.get_property(
"name"), (buf.flag_is_set(gst.BUFFER_FLAG_DISCONT)
and " at discontinuity" or ""),
printable_timestamp(buf.timestamp), buf.offset,
printable_timestamp(expected_timestamp), buf.timestamp - expected_timestamp)
226 def do_transform_ip(self, buf):
227 if self.
t0 is None or buf.flag_is_set(gst.BUFFER_FLAG_DISCONT):
230 print >>sys.stderr,
"%s: initial timestamp = %s, offset = %d" % (self.get_property(
"name"),
printable_timestamp(buf.timestamp), buf.offset)
231 elif buf.flag_is_set(gst.BUFFER_FLAG_DISCONT):
254 print >>sys.stderr,
"%s: got offset %d expected %d (discont flag is %s)" % (self.get_property(
"name"), buf.offset, self.
next_offset, buf.flag_is_set(gst.BUFFER_FLAG_DISCONT)
and "set" or "not set")
266 length = buf.offset_end - buf.offset
267 allowed_sizes = [length * self.
unit_size]
268 if buf.flag_is_set(gst.BUFFER_FLAG_GAP):
269 allowed_sizes.append(0)
270 if buf.size
not in allowed_sizes:
271 print >>sys.stderr,
"%s: got buffer size %d, buffer length %d corresponds to size %d" % (self.get_property(
"name"), buf.size, length, length * self.
unit_size)
292 gobject.type_register(lal_checktimestamps)
294 __gstelementfactory__ = (
295 lal_checktimestamps.__name__,