Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / gst-libs / gst / audio / gstbaseaudiosink.c
index fea7a8e..6d09d12 100644 (file)
@@ -57,7 +57,6 @@ struct _GstBaseAudioSinkPrivate
 
   GstClockTime eos_time;
 
-  gboolean do_time_offset;
   /* number of microseconds we alow timestamps or clock slaving to drift
    * before resyncing */
   guint64 drift_tolerance;
@@ -119,10 +118,10 @@ gst_base_audio_sink_slave_method_get_type (void)
 }
 
 
-#define _do_init(bla) \
+#define _do_init \
     GST_DEBUG_CATEGORY_INIT (gst_base_audio_sink_debug, "baseaudiosink", 0, "baseaudiosink element");
-
-GST_BOILERPLATE_FULL (GstBaseAudioSink, gst_base_audio_sink, GstBaseSink,
+#define gst_base_audio_sink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstBaseAudioSink, gst_base_audio_sink,
     GST_TYPE_BASE_SINK, _do_init);
 
 static void gst_base_audio_sink_dispose (GObject * object);
@@ -132,8 +131,10 @@ static void gst_base_audio_sink_set_property (GObject * object, guint prop_id,
 static void gst_base_audio_sink_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 
+#if 0
 static GstStateChangeReturn gst_base_audio_sink_async_play (GstBaseSink *
     basesink);
+#endif
 static GstStateChangeReturn gst_base_audio_sink_change_state (GstElement *
     element, GstStateChange transition);
 static gboolean gst_base_audio_sink_activate_pull (GstBaseSink * basesink,
@@ -165,11 +166,6 @@ static gboolean gst_base_audio_sink_query_pad (GstPad * pad, GstQuery * query);
 /* static guint gst_base_audio_sink_signals[LAST_SIGNAL] = { 0 }; */
 
 static void
-gst_base_audio_sink_base_init (gpointer g_class)
-{
-}
-
-static void
 gst_base_audio_sink_class_init (GstBaseAudioSinkClass * klass)
 {
   GObjectClass *gobject_class;
@@ -240,8 +236,10 @@ gst_base_audio_sink_class_init (GstBaseAudioSinkClass * klass)
       GST_DEBUG_FUNCPTR (gst_base_audio_sink_get_times);
   gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_base_audio_sink_setcaps);
   gstbasesink_class->fixate = GST_DEBUG_FUNCPTR (gst_base_audio_sink_fixate);
+#if 0
   gstbasesink_class->async_play =
       GST_DEBUG_FUNCPTR (gst_base_audio_sink_async_play);
+#endif
   gstbasesink_class->activate_pull =
       GST_DEBUG_FUNCPTR (gst_base_audio_sink_activate_pull);
 
@@ -253,10 +251,8 @@ gst_base_audio_sink_class_init (GstBaseAudioSinkClass * klass)
 }
 
 static void
-gst_base_audio_sink_init (GstBaseAudioSink * baseaudiosink,
-    GstBaseAudioSinkClass * g_class)
+gst_base_audio_sink_init (GstBaseAudioSink * baseaudiosink)
 {
-  GstPluginFeature *feature;
   GstBaseSink *basesink;
 
   baseaudiosink->priv = GST_BASE_AUDIO_SINK_GET_PRIVATE (baseaudiosink);
@@ -279,25 +275,6 @@ gst_base_audio_sink_init (GstBaseAudioSink * baseaudiosink,
   /* install some custom pad_query functions */
   gst_pad_set_query_function (GST_BASE_SINK_PAD (baseaudiosink),
       GST_DEBUG_FUNCPTR (gst_base_audio_sink_query_pad));
-
-  baseaudiosink->priv->do_time_offset = TRUE;
-
-  /* check the factory, pulsesink < 0.10.17 does the timestamp offset itself so
-   * we should not do ourselves */
-  feature =
-      GST_PLUGIN_FEATURE_CAST (GST_ELEMENT_CLASS (g_class)->elementfactory);
-  GST_DEBUG ("created from factory %p", feature);
-
-  /* HACK for old pulsesink that did the time_offset themselves */
-  if (feature) {
-    if (strcmp (gst_plugin_feature_get_name (feature), "pulsesink") == 0) {
-      if (!gst_plugin_feature_check_version (feature, 0, 10, 17)) {
-        /* we're dealing with an old pulsesink, we need to disable time corection */
-        GST_DEBUG ("disable time offset");
-        baseaudiosink->priv->do_time_offset = FALSE;
-      }
-    }
-  }
 }
 
 static void
@@ -736,7 +713,10 @@ gst_base_audio_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
 
   GST_DEBUG_OBJECT (sink, "release old ringbuffer");
 
-  /* get current time, updates the last_time */
+  /* get current time, updates the last_time. When the subclass has a clock that
+   * restarts from 0 when a new format is negotiated, it will call
+   * gst_audio_clock_reset() which will use this last_time to create an offset
+   * so that time from the clock keeps on increasing monotonically. */
   now = gst_clock_get_time (sink->provided_clock);
 
   GST_DEBUG_OBJECT (sink, "time was %" GST_TIME_FORMAT, GST_TIME_ARGS (now));
@@ -891,17 +871,6 @@ gst_base_audio_sink_event (GstBaseSink * bsink, GstEvent * event)
       /* now wait till we played everything */
       gst_base_audio_sink_drain (sink);
       break;
-    case GST_EVENT_NEWSEGMENT:
-    {
-      gdouble rate;
-
-      /* we only need the rate */
-      gst_event_parse_new_segment_full (event, NULL, &rate, NULL, NULL,
-          NULL, NULL, NULL);
-
-      GST_DEBUG_OBJECT (sink, "new segment rate of %f", rate);
-      break;
-    }
     default:
       break;
   }
@@ -1364,8 +1333,8 @@ gst_base_audio_sink_get_alignment (GstBaseAudioSink * sink,
         G_GINT64_FORMAT, align, maxdrift);
   } else {
     /* calculate sample diff in seconds for error message */
-    gint64 diff_s = gst_util_uint64_scale_int (diff, GST_SECOND,
-        ringbuf->spec.rate);
+    gint64 diff_s =
+        gst_util_uint64_scale_int (diff, GST_SECOND, ringbuf->spec.rate);
     /* timestamps drifted apart from previous samples too much, we need to
      * resync. We log this as an element warning. */
     GST_WARNING_OBJECT (sink,
@@ -1387,9 +1356,11 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
   GstBaseAudioSinkClass *bclass;
   GstBaseAudioSink *sink;
   GstRingBuffer *ringbuf;
-  gint64 diff, align, ctime, cstop;
+  gint64 diff, align;
+  guint64 ctime, cstop;
+  gsize offset;
   guint8 *data;
-  guint size;
+  gsize size;
   guint samples, written;
   gint bps;
   gint accum;
@@ -1440,7 +1411,7 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
 
   bps = ringbuf->spec.bytes_per_sample;
 
-  size = GST_BUFFER_SIZE (buf);
+  size = gst_buffer_get_size (buf);
   if (G_UNLIKELY (size % bps) != 0)
     goto wrong_size;
 
@@ -1455,7 +1426,7 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
       GST_TIME_FORMAT ", samples %u", GST_TIME_ARGS (time), in_offset,
       GST_TIME_ARGS (bsink->segment.start), samples);
 
-  data = GST_BUFFER_DATA (buf);
+  offset = 0;
 
   /* if not valid timestamp or we can't clip or sync, try to play
    * sample ASAP */
@@ -1464,7 +1435,7 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
     render_stop = render_start + samples;
     GST_DEBUG_OBJECT (sink,
         "Buffer of size %u has no time. Using render_start=%" G_GUINT64_FORMAT,
-        GST_BUFFER_SIZE (buf), render_start);
+        size, render_start);
     /* we don't have a start so we don't know stop either */
     stop = -1;
     goto no_sync;
@@ -1518,7 +1489,7 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
     GST_DEBUG_OBJECT (sink, "clipping start to %" GST_TIME_FORMAT " %"
         G_GUINT64_FORMAT " samples", GST_TIME_ARGS (ctime), diff);
     samples -= diff;
-    data += diff * bps;
+    offset += diff * bps;
     time = ctime;
   }
   diff = stop - cstop;
@@ -1599,20 +1570,18 @@ gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
       GST_TIME_ARGS (render_start), GST_TIME_ARGS (render_stop));
 
   /* bring to position in the ringbuffer */
-  if (sink->priv->do_time_offset) {
-    time_offset =
-        GST_AUDIO_CLOCK_CAST (sink->provided_clock)->abidata.ABI.time_offset;
-    GST_DEBUG_OBJECT (sink,
-        "time offset %" GST_TIME_FORMAT, GST_TIME_ARGS (time_offset));
-    if (render_start > time_offset)
-      render_start -= time_offset;
-    else
-      render_start = 0;
-    if (render_stop > time_offset)
-      render_stop -= time_offset;
-    else
-      render_stop = 0;
-  }
+  time_offset =
+      GST_AUDIO_CLOCK_CAST (sink->provided_clock)->abidata.ABI.time_offset;
+  GST_DEBUG_OBJECT (sink,
+      "time offset %" GST_TIME_FORMAT, GST_TIME_ARGS (time_offset));
+  if (render_start > time_offset)
+    render_start -= time_offset;
+  else
+    render_start = 0;
+  if (render_stop > time_offset)
+    render_stop -= time_offset;
+  else
+    render_stop = 0;
 
   /* and bring the time to the rate corrected offset in the buffer */
   render_start = gst_util_uint64_scale_int (render_start,
@@ -1676,10 +1645,11 @@ no_sync:
   /* we need to accumulate over different runs for when we get interrupted */
   accum = 0;
   align_next = TRUE;
+  data = gst_buffer_map (buf, &size, NULL, GST_MAP_READ);
   do {
     written =
-        gst_ring_buffer_commit_full (ringbuf, &sample_offset, data, samples,
-        out_samples, &accum);
+        gst_ring_buffer_commit_full (ringbuf, &sample_offset, data + offset,
+        samples, out_samples, &accum);
 
     GST_DEBUG_OBJECT (sink, "wrote %u of %u", written, samples);
     /* if we wrote all, we're done */
@@ -1703,8 +1673,9 @@ no_sync:
       break;
 
     samples -= written;
-    data += written * bps;
+    offset += written * bps;
   } while (TRUE);
+  gst_buffer_unmap (buf, data, size);
 
   if (align_next)
     sink->next_sample = sample_offset;
@@ -1764,6 +1735,7 @@ stopping:
   {
     GST_DEBUG_OBJECT (sink, "preroll got interrupted: %d (%s)", ret,
         gst_flow_get_name (ret));
+    gst_buffer_unmap (buf, data, size);
     goto done;
   }
 sync_latency_failed:
@@ -1807,6 +1779,7 @@ gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
   GstBaseAudioSink *sink;
   GstBuffer *buf;
   GstFlowReturn ret;
+  gsize size;
 
   basesink = GST_BASE_SINK (user_data);
   sink = GST_BASE_AUDIO_SINK (user_data);
@@ -1818,7 +1791,7 @@ gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
   GST_LOG_OBJECT (basesink, "pulling %d bytes offset %" G_GUINT64_FORMAT
       " to fill audio buffer", len, basesink->offset);
   ret =
-      gst_pad_pull_range (basesink->sinkpad, basesink->segment.last_stop, len,
+      gst_pad_pull_range (basesink->sinkpad, basesink->segment.position, len,
       &buf);
 
   if (ret != GST_FLOW_OK) {
@@ -1828,7 +1801,7 @@ gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
       goto error;
   }
 
-  GST_PAD_PREROLL_LOCK (basesink->sinkpad);
+  GST_BASE_SINK_PREROLL_LOCK (basesink);
   if (basesink->flushing)
     goto flushing;
 
@@ -1837,17 +1810,18 @@ gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
   if (ret != GST_FLOW_OK)
     goto preroll_error;
 
-  if (len != GST_BUFFER_SIZE (buf)) {
+  size = gst_buffer_get_size (buf);
+
+  if (len != size) {
     GST_INFO_OBJECT (basesink,
-        "got different size than requested from sink pad: %u != %u", len,
-        GST_BUFFER_SIZE (buf));
-    len = MIN (GST_BUFFER_SIZE (buf), len);
+        "got different size than requested from sink pad: %u != %u", len, size);
+    len = MIN (size, len);
   }
 
-  basesink->segment.last_stop += len;
+  basesink->segment.position += len;
 
-  memcpy (data, GST_BUFFER_DATA (buf), len);
-  GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+  gst_buffer_extract (buf, 0, data, len);
+  GST_BASE_SINK_PREROLL_UNLOCK (basesink);
 
   GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
 
@@ -1877,7 +1851,7 @@ flushing:
   {
     GST_DEBUG_OBJECT (sink, "we are flushing");
     gst_ring_buffer_pause (rbuf);
-    GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+    GST_BASE_SINK_PREROLL_UNLOCK (basesink);
     GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
     return;
   }
@@ -1885,7 +1859,7 @@ preroll_error:
   {
     GST_DEBUG_OBJECT (sink, "error %s", gst_flow_get_name (ret));
     gst_ring_buffer_pause (rbuf);
-    GST_PAD_PREROLL_UNLOCK (basesink->sinkpad);
+    GST_BASE_SINK_PREROLL_UNLOCK (basesink);
     GST_PAD_STREAM_UNLOCK (basesink->sinkpad);
     return;
   }
@@ -1913,6 +1887,7 @@ gst_base_audio_sink_activate_pull (GstBaseSink * basesink, gboolean active)
   return ret;
 }
 
+#if 0
 /* should be called with the LOCK */
 static GstStateChangeReturn
 gst_base_audio_sink_async_play (GstBaseSink * basesink)
@@ -1931,6 +1906,7 @@ gst_base_audio_sink_async_play (GstBaseSink * basesink)
 
   return GST_STATE_CHANGE_SUCCESS;
 }
+#endif
 
 static GstStateChangeReturn
 gst_base_audio_sink_change_state (GstElement * element,