audiolatency: Handle audio buffers with invalid duration
authorNirbheek Chauhan <nirbheek@centricular.com>
Wed, 21 Jul 2021 14:10:17 +0000 (19:40 +0530)
committerNirbheek Chauhan <nirbheek@centricular.com>
Fri, 23 Jul 2021 12:19:33 +0000 (12:19 +0000)
pipewiresrc outputs audio buffers without a valid duration, so we need
to calculate it manually in that case.

Upstream issue: https://gitlab.freedesktop.org/pipewire/pipewire/-/issues/1438

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/2419>

gst/audiolatency/gstaudiolatency.c

index e4b6fe0..4ea491a 100644 (file)
@@ -292,7 +292,7 @@ buffer_has_wave (GstBuffer * buffer, GstPad * pad)
   GstMapInfo minfo;
   guint64 duration;
   gint64 offset;
-  gint ii, channels, fsize;
+  gint ii, channels, fsize, rate;
   gfloat *fdata;
   gboolean ret;
   GstMemory *memory = NULL;
@@ -317,18 +317,26 @@ buffer_has_wave (GstBuffer * buffer, GstPad * pad)
 
   caps = gst_pad_get_current_caps (pad);
   s = gst_caps_get_structure (caps, 0);
-  ret = gst_structure_get_int (s, "channels", &channels);
+  /* channels and rate are required in caps, so will always be present */
+  gst_structure_get_int (s, "channels", &channels);
+  gst_structure_get_int (s, "rate", &rate);
   gst_caps_unref (caps);
-  if (!ret) {
-    GST_WARNING_OBJECT (pad, "unknown number of channels, can't detect wave");
-    return -1;
-  }
 
   fdata = (gfloat *) minfo.data;
   fsize = minfo.size / sizeof (gfloat);
 
   offset = -1;
-  duration = GST_BUFFER_DURATION (buffer);
+  if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
+    duration = GST_BUFFER_DURATION (buffer);
+  } else {
+    /* Cannot do a rounding-accurate duration calculation here because in the
+     * case when the duration is invalid, the pts might also be invalid */
+    duration = gst_util_uint64_scale_int_round (GST_SECOND, fsize / channels,
+        rate);
+    GST_LOG_OBJECT (pad, "buffer duration is invalid, calculated likely "
+        "duration as %" G_GINT64_FORMAT "us", duration / GST_USECOND);
+  }
+
   /* Read only one channel */
   for (ii = 1; ii < fsize; ii += channels) {
     if (ABS (fdata[ii]) > 0.7) {
@@ -420,8 +428,9 @@ gst_audiolatency_sink_chain (GstPad * pad, GstObject * parent,
   latency = (self->recv_pts - self->send_pts);
   gst_audiolatency_set_latency (self, latency);
 
-  GST_INFO ("recv pts: %" G_GINT64_FORMAT "us, latency: %" G_GINT64_FORMAT "ms",
-      self->recv_pts, latency / 1000);
+  GST_INFO ("recv pts: %" G_GINT64_FORMAT "us, latency: %" G_GINT64_FORMAT
+      "ms, offset: %" G_GINT64_FORMAT "ms", self->recv_pts, latency / 1000,
+      offset / 1000);
 
 out:
   gst_buffer_unref (buffer);