gst_plugins_base/gst-libs/gst/audio/gstbaseaudiosink.c
changeset 0 0e761a78d257
child 7 567bb019e3e3
equal deleted inserted replaced
-1:000000000000 0:0e761a78d257
       
     1 /* GStreamer
       
     2  * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
       
     3  *                    2005 Wim Taymans <wim@fluendo.com>
       
     4  *
       
     5  * gstbaseaudiosink.c: 
       
     6  *
       
     7  * This library is free software; you can redistribute it and/or
       
     8  * modify it under the terms of the GNU Library General Public
       
     9  * License as published by the Free Software Foundation; either
       
    10  * version 2 of the License, or (at your option) any later version.
       
    11  *
       
    12  * This library is distributed in the hope that it will be useful,
       
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
       
    15  * Library General Public License for more details.
       
    16  *
       
    17  * You should have received a copy of the GNU Library General Public
       
    18  * License along with this library; if not, write to the
       
    19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
       
    20  * Boston, MA 02111-1307, USA.
       
    21  */
       
    22 
       
    23 /**
       
    24  * SECTION:gstbaseaudiosink
       
    25  * @short_description: Base class for audio sinks
       
    26  * @see_also: #GstAudioSink, #GstRingBuffer.
       
    27  *
       
    28  * This is the base class for audio sinks. Subclasses need to implement the
       
    29  * ::create_ringbuffer vmethod. This base class will then take care of
       
    30  * writing samples to the ringbuffer, synchronisation, clipping and flushing.
       
    31  *
       
    32  * Last reviewed on 2006-09-27 (0.10.12)
       
    33  */
       
    34 
       
    35 #include <string.h>
       
    36 
       
    37 #include "gstbaseaudiosink.h"
       
    38 
       
    39 #ifdef __SYMBIAN32__
       
    40 #include <glib_global.h>
       
    41 #endif
       
    42 
       
    43 GST_DEBUG_CATEGORY_STATIC (gst_base_audio_sink_debug);
       
    44 #define GST_CAT_DEFAULT gst_base_audio_sink_debug
       
    45 
       
    46 #define GST_BASE_AUDIO_SINK_GET_PRIVATE(obj)  \
       
    47    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_AUDIO_SINK, GstBaseAudioSinkPrivate))
       
    48 
       
    49 struct _GstBaseAudioSinkPrivate
       
    50 {
       
    51   /* upstream latency */
       
    52   GstClockTime us_latency;
       
    53   /* the clock slaving algorithm in use */
       
    54   GstBaseAudioSinkSlaveMethod slave_method;
       
    55   /* running average of clock skew */
       
    56   GstClockTimeDiff avg_skew;
       
    57   /* the number of samples we aligned last time */
       
    58   gint64 last_align;
       
    59 };
       
    60 
       
    61 /* BaseAudioSink signals and args */
       
    62 enum
       
    63 {
       
    64   /* FILL ME */
       
    65   LAST_SIGNAL
       
    66 };
       
    67 
       
    68 /* we tollerate half a second diff before we start resyncing. This
       
    69  * should be enough to compensate for various rounding errors in the timestamp
       
    70  * and sample offset position. 
       
    71  * This is an emergency resync fallback since buffers marked as DISCONT will
       
    72  * always lock to the correct timestamp immediatly and buffers not marked as
       
    73  * DISCONT are contiguous by definition.
       
    74  */
       
    75 #define DIFF_TOLERANCE  2
       
    76 
       
    77 /* FIXME: 0.11, store the buffer_time and latency_time in nanoseconds */
       
    78 #define DEFAULT_BUFFER_TIME     ((200 * GST_MSECOND) / GST_USECOND)
       
    79 #define DEFAULT_LATENCY_TIME    ((10 * GST_MSECOND) / GST_USECOND)
       
    80 #define DEFAULT_PROVIDE_CLOCK   TRUE
       
    81 #define DEFAULT_SLAVE_METHOD    GST_BASE_AUDIO_SINK_SLAVE_SKEW
       
    82 
       
    83 enum
       
    84 {
       
    85   PROP_0,
       
    86   PROP_BUFFER_TIME,
       
    87   PROP_LATENCY_TIME,
       
    88   PROP_PROVIDE_CLOCK,
       
    89   PROP_SLAVE_METHOD
       
    90 };
       
    91 
       
    92 #define GST_TYPE_SLAVE_METHOD (slave_method_get_type ())
       
    93 
       
    94 static GType
       
    95 slave_method_get_type (void)
       
    96 {
       
    97   static GType slave_method_type = 0;
       
    98   static const GEnumValue slave_method[] = {
       
    99     {GST_BASE_AUDIO_SINK_SLAVE_RESAMPLE, "Resampling slaving", "resample"},
       
   100     {GST_BASE_AUDIO_SINK_SLAVE_SKEW, "Skew slaving", "skew"},
       
   101     {GST_BASE_AUDIO_SINK_SLAVE_NONE, "No slaving", "none"},
       
   102     {0, NULL, NULL},
       
   103   };
       
   104 
       
   105   if (!slave_method_type) {
       
   106     slave_method_type =
       
   107         g_enum_register_static ("GstBaseAudioSinkSlaveMethod", slave_method);
       
   108   }
       
   109   return slave_method_type;
       
   110 }
       
   111 
       
   112 
       
   113 #define _do_init(bla) \
       
   114     GST_DEBUG_CATEGORY_INIT (gst_base_audio_sink_debug, "baseaudiosink", 0, "baseaudiosink element");
       
   115 
       
   116 GST_BOILERPLATE_FULL (GstBaseAudioSink, gst_base_audio_sink, GstBaseSink,
       
   117     GST_TYPE_BASE_SINK, _do_init);
       
   118 
       
   119 static void gst_base_audio_sink_dispose (GObject * object);
       
   120 
       
   121 static void gst_base_audio_sink_set_property (GObject * object, guint prop_id,
       
   122     const GValue * value, GParamSpec * pspec);
       
   123 static void gst_base_audio_sink_get_property (GObject * object, guint prop_id,
       
   124     GValue * value, GParamSpec * pspec);
       
   125 
       
   126 static GstStateChangeReturn gst_base_audio_sink_async_play (GstBaseSink *
       
   127     basesink);
       
   128 static GstStateChangeReturn gst_base_audio_sink_change_state (GstElement *
       
   129     element, GstStateChange transition);
       
   130 static gboolean gst_base_audio_sink_activate_pull (GstBaseSink * basesink,
       
   131     gboolean active);
       
   132 static gboolean gst_base_audio_sink_query (GstElement * element, GstQuery *
       
   133     query);
       
   134 
       
   135 static GstClock *gst_base_audio_sink_provide_clock (GstElement * elem);
       
   136 static GstClockTime gst_base_audio_sink_get_time (GstClock * clock,
       
   137     GstBaseAudioSink * sink);
       
   138 static void gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data,
       
   139     guint len, gpointer user_data);
       
   140 
       
   141 static GstFlowReturn gst_base_audio_sink_preroll (GstBaseSink * bsink,
       
   142     GstBuffer * buffer);
       
   143 static GstFlowReturn gst_base_audio_sink_render (GstBaseSink * bsink,
       
   144     GstBuffer * buffer);
       
   145 static gboolean gst_base_audio_sink_event (GstBaseSink * bsink,
       
   146     GstEvent * event);
       
   147 static void gst_base_audio_sink_get_times (GstBaseSink * bsink,
       
   148     GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
       
   149 static gboolean gst_base_audio_sink_setcaps (GstBaseSink * bsink,
       
   150     GstCaps * caps);
       
   151 static void gst_base_audio_sink_fixate (GstBaseSink * bsink, GstCaps * caps);
       
   152 
       
   153 /* static guint gst_base_audio_sink_signals[LAST_SIGNAL] = { 0 }; */
       
   154 
       
   155 static void
       
   156 gst_base_audio_sink_base_init (gpointer g_class)
       
   157 {
       
   158 }
       
   159 
       
   160 static void
       
   161 gst_base_audio_sink_class_init (GstBaseAudioSinkClass * klass)
       
   162 {
       
   163   GObjectClass *gobject_class;
       
   164   GstElementClass *gstelement_class;
       
   165   GstBaseSinkClass *gstbasesink_class;
       
   166 
       
   167   gobject_class = (GObjectClass *) klass;
       
   168   gstelement_class = (GstElementClass *) klass;
       
   169   gstbasesink_class = (GstBaseSinkClass *) klass;
       
   170 
       
   171   g_type_class_add_private (klass, sizeof (GstBaseAudioSinkPrivate));
       
   172 
       
   173   gobject_class->set_property =
       
   174       GST_DEBUG_FUNCPTR (gst_base_audio_sink_set_property);
       
   175   gobject_class->get_property =
       
   176       GST_DEBUG_FUNCPTR (gst_base_audio_sink_get_property);
       
   177   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_base_audio_sink_dispose);
       
   178 
       
   179   g_object_class_install_property (gobject_class, PROP_BUFFER_TIME,
       
   180       g_param_spec_int64 ("buffer-time", "Buffer Time",
       
   181           "Size of audio buffer in microseconds", 1,
       
   182           G_MAXINT64, DEFAULT_BUFFER_TIME, G_PARAM_READWRITE));
       
   183 
       
   184   g_object_class_install_property (gobject_class, PROP_LATENCY_TIME,
       
   185       g_param_spec_int64 ("latency-time", "Latency Time",
       
   186           "Audio latency in microseconds", 1,
       
   187           G_MAXINT64, DEFAULT_LATENCY_TIME, G_PARAM_READWRITE));
       
   188 
       
   189   g_object_class_install_property (gobject_class, PROP_PROVIDE_CLOCK,
       
   190       g_param_spec_boolean ("provide-clock", "Provide Clock",
       
   191           "Provide a clock to be used as the global pipeline clock",
       
   192           DEFAULT_PROVIDE_CLOCK, G_PARAM_READWRITE));
       
   193 
       
   194   g_object_class_install_property (gobject_class, PROP_SLAVE_METHOD,
       
   195       g_param_spec_enum ("slave-method", "Slave Method",
       
   196           "Algorithm to use to match the rate of the masterclock",
       
   197           GST_TYPE_SLAVE_METHOD, DEFAULT_SLAVE_METHOD, G_PARAM_READWRITE));
       
   198 
       
   199   gstelement_class->change_state =
       
   200       GST_DEBUG_FUNCPTR (gst_base_audio_sink_change_state);
       
   201   gstelement_class->provide_clock =
       
   202       GST_DEBUG_FUNCPTR (gst_base_audio_sink_provide_clock);
       
   203   gstelement_class->query = GST_DEBUG_FUNCPTR (gst_base_audio_sink_query);
       
   204 
       
   205   gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_base_audio_sink_event);
       
   206   gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_base_audio_sink_preroll);
       
   207   gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_base_audio_sink_render);
       
   208   gstbasesink_class->get_times =
       
   209       GST_DEBUG_FUNCPTR (gst_base_audio_sink_get_times);
       
   210   gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_base_audio_sink_setcaps);
       
   211   gstbasesink_class->fixate = GST_DEBUG_FUNCPTR (gst_base_audio_sink_fixate);
       
   212   gstbasesink_class->async_play =
       
   213       GST_DEBUG_FUNCPTR (gst_base_audio_sink_async_play);
       
   214   gstbasesink_class->activate_pull =
       
   215       GST_DEBUG_FUNCPTR (gst_base_audio_sink_activate_pull);
       
   216 
       
   217   /* ref class from a thread-safe context to work around missing bit of
       
   218    * thread-safety in GObject */
       
   219   g_type_class_ref (GST_TYPE_AUDIO_CLOCK);
       
   220 }
       
   221 
       
   222 static void
       
   223 gst_base_audio_sink_init (GstBaseAudioSink * baseaudiosink,
       
   224     GstBaseAudioSinkClass * g_class)
       
   225 {
       
   226   baseaudiosink->priv = GST_BASE_AUDIO_SINK_GET_PRIVATE (baseaudiosink);
       
   227 
       
   228   baseaudiosink->buffer_time = DEFAULT_BUFFER_TIME;
       
   229   baseaudiosink->latency_time = DEFAULT_LATENCY_TIME;
       
   230   baseaudiosink->provide_clock = DEFAULT_PROVIDE_CLOCK;
       
   231   baseaudiosink->priv->slave_method = DEFAULT_SLAVE_METHOD;
       
   232 
       
   233   baseaudiosink->provided_clock = gst_audio_clock_new ("GstAudioSinkClock",
       
   234       (GstAudioClockGetTimeFunc) gst_base_audio_sink_get_time, baseaudiosink);
       
   235 
       
   236   GST_BASE_SINK (baseaudiosink)->can_activate_push = TRUE;
       
   237   /* FIXME, enable pull mode when segments, latency, state changes, negotiation
       
   238    * and clock slaving are figured out */
       
   239   GST_BASE_SINK (baseaudiosink)->can_activate_pull = FALSE;
       
   240 }
       
   241 
       
   242 static void
       
   243 gst_base_audio_sink_dispose (GObject * object)
       
   244 {
       
   245   GstBaseAudioSink *sink;
       
   246 
       
   247   sink = GST_BASE_AUDIO_SINK (object);
       
   248 
       
   249   if (sink->provided_clock)
       
   250     gst_object_unref (sink->provided_clock);
       
   251   sink->provided_clock = NULL;
       
   252 
       
   253   if (sink->ringbuffer) {
       
   254     gst_object_unparent (GST_OBJECT_CAST (sink->ringbuffer));
       
   255     sink->ringbuffer = NULL;
       
   256   }
       
   257 
       
   258   G_OBJECT_CLASS (parent_class)->dispose (object);
       
   259 }
       
   260 
       
   261 static GstClock *
       
   262 gst_base_audio_sink_provide_clock (GstElement * elem)
       
   263 {
       
   264   GstBaseAudioSink *sink;
       
   265   GstClock *clock;
       
   266 
       
   267   sink = GST_BASE_AUDIO_SINK (elem);
       
   268 
       
   269   /* we have no ringbuffer (must be NULL state) */
       
   270   if (sink->ringbuffer == NULL)
       
   271     goto wrong_state;
       
   272 
       
   273   if (!gst_ring_buffer_is_acquired (sink->ringbuffer))
       
   274     goto wrong_state;
       
   275 
       
   276   GST_OBJECT_LOCK (sink);
       
   277   if (!sink->provide_clock)
       
   278     goto clock_disabled;
       
   279 
       
   280   clock = GST_CLOCK_CAST (gst_object_ref (sink->provided_clock));
       
   281   GST_OBJECT_UNLOCK (sink);
       
   282 
       
   283   return clock;
       
   284 
       
   285   /* ERRORS */
       
   286 wrong_state:
       
   287   {
       
   288     GST_DEBUG_OBJECT (sink, "ringbuffer not acquired");
       
   289     return NULL;
       
   290   }
       
   291 clock_disabled:
       
   292   {
       
   293     GST_DEBUG_OBJECT (sink, "clock provide disabled");
       
   294     GST_OBJECT_UNLOCK (sink);
       
   295     return NULL;
       
   296   }
       
   297 }
       
   298 
       
   299 static gboolean
       
   300 gst_base_audio_sink_query (GstElement * element, GstQuery * query)
       
   301 {
       
   302   gboolean res = FALSE;
       
   303 
       
   304   GstBaseAudioSink *basesink = GST_BASE_AUDIO_SINK (element);
       
   305 
       
   306   switch (GST_QUERY_TYPE (query)) {
       
   307     case GST_QUERY_LATENCY:
       
   308     {
       
   309       gboolean live, us_live;
       
   310       GstClockTime min_l, max_l;
       
   311 
       
   312       GST_DEBUG_OBJECT (basesink, "latency query");
       
   313 
       
   314       if (!basesink->ringbuffer || !basesink->ringbuffer->spec.rate) {
       
   315         GST_DEBUG_OBJECT (basesink,
       
   316             "we are not yet negotiated, can't report latency yet");
       
   317         res = FALSE;
       
   318         goto done;
       
   319       }
       
   320 
       
   321       /* ask parent first, it will do an upstream query for us. */
       
   322       if ((res =
       
   323               gst_base_sink_query_latency (GST_BASE_SINK_CAST (basesink), &live,
       
   324                   &us_live, &min_l, &max_l))) {
       
   325         GstClockTime min_latency, max_latency;
       
   326 
       
   327         /* we and upstream are both live, adjust the min_latency */
       
   328         if (live && us_live) {
       
   329           GstRingBufferSpec *spec;
       
   330 
       
   331           spec = &basesink->ringbuffer->spec;
       
   332 
       
   333           basesink->priv->us_latency = min_l;
       
   334 
       
   335           min_latency =
       
   336               gst_util_uint64_scale_int (spec->segtotal * spec->segsize,
       
   337               GST_SECOND, spec->rate * spec->bytes_per_sample);
       
   338 
       
   339           /* we cannot go lower than the buffer size and the min peer latency */
       
   340           min_latency = min_latency + min_l;
       
   341           /* the max latency is the max of the peer, we can delay an infinite
       
   342            * amount of time. */
       
   343           max_latency = min_latency + (max_l == -1 ? 0 : max_l);
       
   344 
       
   345           GST_DEBUG_OBJECT (basesink,
       
   346               "peer min %" GST_TIME_FORMAT ", our min latency: %"
       
   347               GST_TIME_FORMAT, GST_TIME_ARGS (min_l),
       
   348               GST_TIME_ARGS (min_latency));
       
   349         } else {
       
   350           GST_DEBUG_OBJECT (basesink,
       
   351               "peer or we are not live, don't care about latency");
       
   352           min_latency = 0;
       
   353           max_latency = -1;
       
   354         }
       
   355         gst_query_set_latency (query, live, min_latency, max_latency);
       
   356       }
       
   357       break;
       
   358     }
       
   359     default:
       
   360       res = GST_ELEMENT_CLASS (parent_class)->query (element, query);
       
   361       break;
       
   362   }
       
   363 
       
   364 done:
       
   365   return res;
       
   366 }
       
   367 
       
   368 
       
   369 static GstClockTime
       
   370 gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink)
       
   371 {
       
   372   guint64 raw, samples;
       
   373   guint delay;
       
   374   GstClockTime result, us_latency;
       
   375 
       
   376   if (sink->ringbuffer == NULL || sink->ringbuffer->spec.rate == 0)
       
   377     return GST_CLOCK_TIME_NONE;
       
   378 
       
   379   /* our processed samples are always increasing */
       
   380   raw = samples = gst_ring_buffer_samples_done (sink->ringbuffer);
       
   381 
       
   382   /* the number of samples not yet processed, this is still queued in the
       
   383    * device (not played for playback). */
       
   384   delay = gst_ring_buffer_delay (sink->ringbuffer);
       
   385 
       
   386   if (G_LIKELY (samples >= delay))
       
   387     samples -= delay;
       
   388   else
       
   389     samples = 0;
       
   390 
       
   391   result = gst_util_uint64_scale_int (samples, GST_SECOND,
       
   392       sink->ringbuffer->spec.rate);
       
   393 
       
   394   /* latency before starting the clock */
       
   395   us_latency = sink->priv->us_latency;
       
   396 
       
   397   result += us_latency;
       
   398 
       
   399   GST_DEBUG_OBJECT (sink,
       
   400       "processed samples: raw %llu, delay %u, real %llu, time %"
       
   401       GST_TIME_FORMAT ", upstream latency %" GST_TIME_FORMAT, raw, delay,
       
   402       samples, GST_TIME_ARGS (result), GST_TIME_ARGS (us_latency));
       
   403 
       
   404   return result;
       
   405 }
       
   406 
       
   407 /**
       
   408  * gst_base_audio_sink_set_provide_clock:
       
   409  * @sink: a #GstBaseAudioSink
       
   410  * @provide: new state
       
   411  *
       
   412  * Controls whether @sink will provide a clock or not. If @provide is %TRUE, 
       
   413  * gst_element_provide_clock() will return a clock that reflects the datarate
       
   414  * of @sink. If @provide is %FALSE, gst_element_provide_clock() will return NULL.
       
   415  *
       
   416  * Since: 0.10.16
       
   417  */
       
   418 #ifdef __SYMBIAN32__
       
   419 EXPORT_C
       
   420 #endif
       
   421 
       
   422 void
       
   423 gst_base_audio_sink_set_provide_clock (GstBaseAudioSink * sink,
       
   424     gboolean provide)
       
   425 {
       
   426   g_return_if_fail (GST_IS_BASE_AUDIO_SINK (sink));
       
   427 
       
   428   GST_OBJECT_LOCK (sink);
       
   429   sink->provide_clock = provide;
       
   430   GST_OBJECT_UNLOCK (sink);
       
   431 }
       
   432 
       
   433 /**
       
   434  * gst_base_audio_sink_get_provide_clock:
       
   435  * @sink: a #GstBaseAudioSink
       
   436  *
       
   437  * Queries whether @sink will provide a clock or not. See also
       
   438  * gst_base_audio_sink_set_provide_clock.
       
   439  *
       
   440  * Returns: %TRUE if @sink will provide a clock.
       
   441  *
       
   442  * Since: 0.10.16
       
   443  */
       
   444 #ifdef __SYMBIAN32__
       
   445 EXPORT_C
       
   446 #endif
       
   447 
       
   448 gboolean
       
   449 gst_base_audio_sink_get_provide_clock (GstBaseAudioSink * sink)
       
   450 {
       
   451   gboolean result;
       
   452 
       
   453   g_return_val_if_fail (GST_IS_BASE_AUDIO_SINK (sink), FALSE);
       
   454 
       
   455   GST_OBJECT_LOCK (sink);
       
   456   result = sink->provide_clock;
       
   457   GST_OBJECT_UNLOCK (sink);
       
   458 
       
   459   return result;
       
   460 }
       
   461 
       
   462 /**
       
   463  * gst_base_audio_sink_set_slave_method:
       
   464  * @sink: a #GstBaseAudioSink
       
   465  * @method: the new slave method
       
   466  *
       
   467  * Controls how clock slaving will be performed in @sink. 
       
   468  *
       
   469  * Since: 0.10.16
       
   470  */
       
   471 #ifdef __SYMBIAN32__
       
   472 EXPORT_C
       
   473 #endif
       
   474 
       
   475 void
       
   476 gst_base_audio_sink_set_slave_method (GstBaseAudioSink * sink,
       
   477     GstBaseAudioSinkSlaveMethod method)
       
   478 {
       
   479   g_return_if_fail (GST_IS_BASE_AUDIO_SINK (sink));
       
   480 
       
   481   GST_OBJECT_LOCK (sink);
       
   482   sink->priv->slave_method = method;
       
   483   GST_OBJECT_UNLOCK (sink);
       
   484 }
       
   485 
       
   486 /**
       
   487  * gst_base_audio_sink_get_slave_method:
       
   488  * @sink: a #GstBaseAudioSink
       
   489  *
       
   490  * Get the current slave method used by @sink.
       
   491  *
       
   492  * Returns: The current slave method used by @sink.
       
   493  *
       
   494  * Since: 0.10.16
       
   495  */
       
   496 #ifdef __SYMBIAN32__
       
   497 EXPORT_C
       
   498 #endif
       
   499 
       
   500 GstBaseAudioSinkSlaveMethod
       
   501 gst_base_audio_sink_get_slave_method (GstBaseAudioSink * sink)
       
   502 {
       
   503   GstBaseAudioSinkSlaveMethod result;
       
   504 
       
   505   g_return_val_if_fail (GST_IS_BASE_AUDIO_SINK (sink), -1);
       
   506 
       
   507   GST_OBJECT_LOCK (sink);
       
   508   result = sink->priv->slave_method;
       
   509   GST_OBJECT_UNLOCK (sink);
       
   510 
       
   511   return result;
       
   512 }
       
   513 
       
   514 static void
       
   515 gst_base_audio_sink_set_property (GObject * object, guint prop_id,
       
   516     const GValue * value, GParamSpec * pspec)
       
   517 {
       
   518   GstBaseAudioSink *sink;
       
   519 
       
   520   sink = GST_BASE_AUDIO_SINK (object);
       
   521 
       
   522   switch (prop_id) {
       
   523     case PROP_BUFFER_TIME:
       
   524       sink->buffer_time = g_value_get_int64 (value);
       
   525       break;
       
   526     case PROP_LATENCY_TIME:
       
   527       sink->latency_time = g_value_get_int64 (value);
       
   528       break;
       
   529     case PROP_PROVIDE_CLOCK:
       
   530       gst_base_audio_sink_set_provide_clock (sink, g_value_get_boolean (value));
       
   531       break;
       
   532     case PROP_SLAVE_METHOD:
       
   533       gst_base_audio_sink_set_slave_method (sink, g_value_get_enum (value));
       
   534       break;
       
   535     default:
       
   536       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   537       break;
       
   538   }
       
   539 }
       
   540 
       
   541 static void
       
   542 gst_base_audio_sink_get_property (GObject * object, guint prop_id,
       
   543     GValue * value, GParamSpec * pspec)
       
   544 {
       
   545   GstBaseAudioSink *sink;
       
   546 
       
   547   sink = GST_BASE_AUDIO_SINK (object);
       
   548 
       
   549   switch (prop_id) {
       
   550     case PROP_BUFFER_TIME:
       
   551       g_value_set_int64 (value, sink->buffer_time);
       
   552       break;
       
   553     case PROP_LATENCY_TIME:
       
   554       g_value_set_int64 (value, sink->latency_time);
       
   555       break;
       
   556     case PROP_PROVIDE_CLOCK:
       
   557       g_value_set_boolean (value, gst_base_audio_sink_get_provide_clock (sink));
       
   558       break;
       
   559     case PROP_SLAVE_METHOD:
       
   560       g_value_set_enum (value, gst_base_audio_sink_get_slave_method (sink));
       
   561       break;
       
   562     default:
       
   563       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       
   564       break;
       
   565   }
       
   566 }
       
   567 
       
   568 static gboolean
       
   569 gst_base_audio_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
       
   570 {
       
   571   GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (bsink);
       
   572   GstRingBufferSpec *spec;
       
   573 
       
   574   if (!sink->ringbuffer)
       
   575     return FALSE;
       
   576 
       
   577   spec = &sink->ringbuffer->spec;
       
   578 
       
   579   GST_DEBUG_OBJECT (sink, "release old ringbuffer");
       
   580 
       
   581   /* release old ringbuffer */
       
   582   gst_ring_buffer_release (sink->ringbuffer);
       
   583 
       
   584   GST_DEBUG_OBJECT (sink, "parse caps");
       
   585 
       
   586   spec->buffer_time = sink->buffer_time;
       
   587   spec->latency_time = sink->latency_time;
       
   588 
       
   589   /* parse new caps */
       
   590   if (!gst_ring_buffer_parse_caps (spec, caps))
       
   591     goto parse_error;
       
   592 
       
   593   gst_ring_buffer_debug_spec_buff (spec);
       
   594 
       
   595   GST_DEBUG_OBJECT (sink, "acquire new ringbuffer");
       
   596 
       
   597   if (!gst_ring_buffer_acquire (sink->ringbuffer, spec))
       
   598     goto acquire_error;
       
   599 
       
   600   /* calculate actual latency and buffer times. 
       
   601    * FIXME: In 0.11, store the latency_time internally in ns */
       
   602   spec->latency_time = gst_util_uint64_scale (spec->segsize,
       
   603       (GST_SECOND / GST_USECOND), spec->rate * spec->bytes_per_sample);
       
   604 
       
   605   spec->buffer_time = spec->segtotal * spec->latency_time;
       
   606 
       
   607   gst_ring_buffer_debug_spec_buff (spec);
       
   608 
       
   609   return TRUE;
       
   610 
       
   611   /* ERRORS */
       
   612 parse_error:
       
   613   {
       
   614     GST_DEBUG_OBJECT (sink, "could not parse caps");
       
   615     GST_ELEMENT_ERROR (sink, STREAM, FORMAT,
       
   616         (NULL), ("cannot parse audio format."));
       
   617     return FALSE;
       
   618   }
       
   619 acquire_error:
       
   620   {
       
   621     GST_DEBUG_OBJECT (sink, "could not acquire ringbuffer");
       
   622     return FALSE;
       
   623   }
       
   624 }
       
   625 
       
   626 static void
       
   627 gst_base_audio_sink_fixate (GstBaseSink * bsink, GstCaps * caps)
       
   628 {
       
   629   GstStructure *s;
       
   630   gint width, depth;
       
   631 
       
   632   s = gst_caps_get_structure (caps, 0);
       
   633 
       
   634   /* fields for all formats */
       
   635   gst_structure_fixate_field_nearest_int (s, "rate", 44100);
       
   636   gst_structure_fixate_field_nearest_int (s, "channels", 2);
       
   637   gst_structure_fixate_field_nearest_int (s, "width", 16);
       
   638 
       
   639   /* fields for int */
       
   640   if (gst_structure_has_field (s, "depth")) {
       
   641     gst_structure_get_int (s, "width", &width);
       
   642     /* round width to nearest multiple of 8 for the depth */
       
   643     depth = GST_ROUND_UP_8 (width);
       
   644     gst_structure_fixate_field_nearest_int (s, "depth", depth);
       
   645   }
       
   646   if (gst_structure_has_field (s, "signed"))
       
   647     gst_structure_fixate_field_boolean (s, "signed", TRUE);
       
   648   if (gst_structure_has_field (s, "endianness"))
       
   649     gst_structure_fixate_field_nearest_int (s, "endianness", G_BYTE_ORDER);
       
   650 }
       
   651 
       
   652 static void
       
   653 gst_base_audio_sink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
       
   654     GstClockTime * start, GstClockTime * end)
       
   655 {
       
   656   /* our clock sync is a bit too much for the base class to handle so
       
   657    * we implement it ourselves. */
       
   658   *start = GST_CLOCK_TIME_NONE;
       
   659   *end = GST_CLOCK_TIME_NONE;
       
   660 }
       
   661 
       
   662 /* This waits for the drain to happen and can be canceled */
       
   663 static gboolean
       
   664 gst_base_audio_sink_drain (GstBaseAudioSink * sink)
       
   665 {
       
   666   GstClockTime base_time;
       
   667 
       
   668   if (!sink->ringbuffer)
       
   669     return TRUE;
       
   670   if (!sink->ringbuffer->spec.rate)
       
   671     return TRUE;
       
   672 
       
   673   /* need to start playback before we can drain, but only when
       
   674    * we have successfully negotiated a format and thus acquired the
       
   675    * ringbuffer. */
       
   676   if (gst_ring_buffer_is_acquired (sink->ringbuffer))
       
   677     gst_ring_buffer_start (sink->ringbuffer);
       
   678 
       
   679   if (sink->next_sample != -1) {
       
   680     GstClockTime time;
       
   681 
       
   682     /* convert next expected sample to time */
       
   683     time =
       
   684         gst_util_uint64_scale_int (sink->next_sample, GST_SECOND,
       
   685         sink->ringbuffer->spec.rate);
       
   686 
       
   687     GST_DEBUG_OBJECT (sink,
       
   688         "last sample %" G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT,
       
   689         sink->next_sample, GST_TIME_ARGS (time));
       
   690 
       
   691     /* our time already includes the base_time, _wait_eos() wants a running_time
       
   692      * so we have to subtract the base_time again here. FIXME, store an
       
   693      * unadjusted EOS time so that we don't have to do this. */
       
   694     GST_OBJECT_LOCK (sink);
       
   695     base_time = GST_ELEMENT_CAST (sink)->base_time;
       
   696     GST_OBJECT_UNLOCK (sink);
       
   697 
       
   698     if (time > base_time)
       
   699       time -= base_time;
       
   700     else
       
   701       time = 0;
       
   702 
       
   703     /* wait for the EOS time to be reached, this is the time when the last
       
   704      * sample is played. */
       
   705     gst_base_sink_wait_eos (GST_BASE_SINK (sink), time, NULL);
       
   706 
       
   707     sink->next_sample = -1;
       
   708   }
       
   709   return TRUE;
       
   710 }
       
   711 
       
   712 static gboolean
       
   713 gst_base_audio_sink_event (GstBaseSink * bsink, GstEvent * event)
       
   714 {
       
   715   GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (bsink);
       
   716 
       
   717   switch (GST_EVENT_TYPE (event)) {
       
   718     case GST_EVENT_FLUSH_START:
       
   719       if (sink->ringbuffer)
       
   720         gst_ring_buffer_set_flushing (sink->ringbuffer, TRUE);
       
   721       break;
       
   722     case GST_EVENT_FLUSH_STOP:
       
   723       /* always resync on sample after a flush */
       
   724       sink->priv->avg_skew = -1;
       
   725       sink->next_sample = -1;
       
   726       if (sink->ringbuffer)
       
   727         gst_ring_buffer_set_flushing (sink->ringbuffer, FALSE);
       
   728       break;
       
   729     case GST_EVENT_EOS:
       
   730       /* now wait till we played everything */
       
   731       gst_base_audio_sink_drain (sink);
       
   732       break;
       
   733     case GST_EVENT_NEWSEGMENT:
       
   734     {
       
   735       gdouble rate;
       
   736 
       
   737       /* we only need the rate */
       
   738       gst_event_parse_new_segment_full (event, NULL, &rate, NULL, NULL,
       
   739           NULL, NULL, NULL);
       
   740 
       
   741       GST_DEBUG_OBJECT (sink, "new segment rate of %f", rate);
       
   742       break;
       
   743     }
       
   744     default:
       
   745       break;
       
   746   }
       
   747   return TRUE;
       
   748 }
       
   749 
       
   750 static GstFlowReturn
       
   751 gst_base_audio_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
       
   752 {
       
   753   GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (bsink);
       
   754 
       
   755   if (!gst_ring_buffer_is_acquired (sink->ringbuffer))
       
   756     goto wrong_state;
       
   757 
       
   758   /* we don't really do anything when prerolling. We could make a
       
   759    * property to play this buffer to have some sort of scrubbing
       
   760    * support. */
       
   761   return GST_FLOW_OK;
       
   762 
       
   763 wrong_state:
       
   764   {
       
   765     GST_DEBUG_OBJECT (sink, "ringbuffer in wrong state");
       
   766     GST_ELEMENT_ERROR (sink, STREAM, FORMAT, (NULL), ("sink not negotiated."));
       
   767     return GST_FLOW_NOT_NEGOTIATED;
       
   768   }
       
   769 }
       
   770 
       
   771 static guint64
       
   772 gst_base_audio_sink_get_offset (GstBaseAudioSink * sink)
       
   773 {
       
   774   guint64 sample;
       
   775   gint writeseg, segdone, sps;
       
   776   gint diff;
       
   777 
       
   778   /* assume we can append to the previous sample */
       
   779   sample = sink->next_sample;
       
   780   /* no previous sample, try to insert at position 0 */
       
   781   if (sample == -1)
       
   782     sample = 0;
       
   783 
       
   784   sps = sink->ringbuffer->samples_per_seg;
       
   785 
       
   786   /* figure out the segment and the offset inside the segment where
       
   787    * the sample should be written. */
       
   788   writeseg = sample / sps;
       
   789 
       
   790   /* get the currently processed segment */
       
   791   segdone = g_atomic_int_get (&sink->ringbuffer->segdone)
       
   792       - sink->ringbuffer->segbase;
       
   793 
       
   794   /* see how far away it is from the write segment */
       
   795   diff = writeseg - segdone;
       
   796   if (diff < 0) {
       
   797     /* sample would be dropped, position to next playable position */
       
   798     sample = (segdone + 1) * sps;
       
   799   }
       
   800 
       
   801   return sample;
       
   802 }
       
   803 
       
   804 static GstClockTime
       
   805 clock_convert_external (GstClockTime external, GstClockTime cinternal,
       
   806     GstClockTime cexternal, GstClockTime crate_num, GstClockTime crate_denom,
       
   807     GstClockTime us_latency)
       
   808 {
       
   809   /* adjust for rate and speed */
       
   810   if (external >= cexternal) {
       
   811     external =
       
   812         gst_util_uint64_scale (external - cexternal, crate_denom, crate_num);
       
   813     external += cinternal;
       
   814   } else {
       
   815     external = gst_util_uint64_scale (cexternal - external,
       
   816         crate_denom, crate_num);
       
   817     if (cinternal > external)
       
   818       external = cinternal - external;
       
   819     else
       
   820       external = 0;
       
   821   }
       
   822   /* adjust for offset when slaving started */
       
   823   if (external > us_latency)
       
   824     external -= us_latency;
       
   825   else
       
   826     external = 0;
       
   827 
       
   828   return external;
       
   829 }
       
   830 
       
   831 /* algorithm to calculate sample positions that will result in resampling to
       
   832  * match the clock rate of the master */
       
   833 static void
       
   834 gst_base_audio_sink_resample_slaving (GstBaseAudioSink * sink,
       
   835     GstClockTime render_start, GstClockTime render_stop,
       
   836     GstClockTime * srender_start, GstClockTime * srender_stop)
       
   837 {
       
   838   GstClockTime cinternal, cexternal;
       
   839   GstClockTime crate_num, crate_denom;
       
   840 
       
   841   /* get calibration parameters to compensate for speed and offset differences
       
   842    * when we are slaved */
       
   843   gst_clock_get_calibration (sink->provided_clock, &cinternal, &cexternal,
       
   844       &crate_num, &crate_denom);
       
   845 
       
   846   GST_DEBUG_OBJECT (sink, "internal %" GST_TIME_FORMAT " external %"
       
   847       GST_TIME_FORMAT " %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " = %f",
       
   848       GST_TIME_ARGS (cinternal), GST_TIME_ARGS (cexternal), crate_num,
       
   849       crate_denom, gst_guint64_to_gdouble (crate_num) /
       
   850       gst_guint64_to_gdouble (crate_denom));
       
   851 
       
   852   if (crate_num == 0)
       
   853     crate_denom = crate_num = 1;
       
   854 
       
   855   /* bring external time to internal time */
       
   856   render_start = clock_convert_external (render_start, cinternal, cexternal,
       
   857       crate_num, crate_denom, sink->priv->us_latency);
       
   858   render_stop = clock_convert_external (render_stop, cinternal, cexternal,
       
   859       crate_num, crate_denom, sink->priv->us_latency);
       
   860 
       
   861   GST_DEBUG_OBJECT (sink,
       
   862       "after slaving: start %" GST_TIME_FORMAT " - stop %" GST_TIME_FORMAT,
       
   863       GST_TIME_ARGS (render_start), GST_TIME_ARGS (render_stop));
       
   864 
       
   865   *srender_start = render_start;
       
   866   *srender_stop = render_stop;
       
   867 }
       
   868 
       
   869 /* algorithm to calculate sample positions that will result in changing the
       
   870  * playout pointer to match the clock rate of the master */
       
   871 static void
       
   872 gst_base_audio_sink_skew_slaving (GstBaseAudioSink * sink,
       
   873     GstClockTime render_start, GstClockTime render_stop,
       
   874     GstClockTime * srender_start, GstClockTime * srender_stop)
       
   875 {
       
   876   GstClockTime cinternal, cexternal, crate_num, crate_denom;
       
   877   GstClockTime etime, itime;
       
   878   GstClockTimeDiff skew, segtime, segtime2;
       
   879   gint segsamples;
       
   880   gint64 last_align;
       
   881 
       
   882   /* get calibration parameters to compensate for offsets */
       
   883   gst_clock_get_calibration (sink->provided_clock, &cinternal, &cexternal,
       
   884       &crate_num, &crate_denom);
       
   885 
       
   886   /* sample clocks and figure out clock skew */
       
   887   etime = gst_clock_get_time (GST_ELEMENT_CLOCK (sink));
       
   888   itime = gst_clock_get_internal_time (sink->provided_clock);
       
   889 
       
   890   etime -= cexternal;
       
   891   itime -= cinternal;
       
   892 
       
   893   skew = GST_CLOCK_DIFF (etime, itime);
       
   894   if (sink->priv->avg_skew == -1) {
       
   895     /* first observation */
       
   896     sink->priv->avg_skew = skew;
       
   897   } else {
       
   898     /* next observations use a moving average */
       
   899     sink->priv->avg_skew = (31 * sink->priv->avg_skew + skew) / 32;
       
   900   }
       
   901 
       
   902   GST_DEBUG_OBJECT (sink, "internal %" GST_TIME_FORMAT " external %"
       
   903       GST_TIME_FORMAT " skew %" G_GINT64_FORMAT " avg %" G_GINT64_FORMAT,
       
   904       GST_TIME_ARGS (itime), GST_TIME_ARGS (etime), skew, sink->priv->avg_skew);
       
   905 
       
   906   /* the max drift we allow is the length of a segment */
       
   907   segtime = sink->ringbuffer->spec.latency_time * 1000;
       
   908   segtime2 = segtime / 2;
       
   909 
       
   910   /* adjust playout pointer based on skew */
       
   911   if (sink->priv->avg_skew > segtime2) {
       
   912     /* master is running slower, move internal time forward */
       
   913     GST_WARNING_OBJECT (sink,
       
   914         "correct clock skew %" G_GINT64_FORMAT " > %" G_GINT64_FORMAT,
       
   915         sink->priv->avg_skew, segtime2);
       
   916     cinternal += segtime;
       
   917     sink->priv->avg_skew -= segtime;
       
   918 
       
   919     segsamples =
       
   920         sink->ringbuffer->spec.segsize /
       
   921         sink->ringbuffer->spec.bytes_per_sample;
       
   922     last_align = sink->priv->last_align;
       
   923 
       
   924     /* if we were aligning in the wrong direction or we aligned more than what we
       
   925      * will correct, resync */
       
   926     if (last_align < 0 || last_align > segsamples)
       
   927       sink->next_sample = -1;
       
   928 
       
   929     GST_DEBUG_OBJECT (sink,
       
   930         "last_align %" G_GINT64_FORMAT " segsamples %u, next %"
       
   931         G_GUINT64_FORMAT, last_align, segsamples, sink->next_sample);
       
   932 
       
   933     gst_clock_set_calibration (sink->provided_clock, cinternal, cexternal,
       
   934         crate_num, crate_denom);
       
   935   } else if (sink->priv->avg_skew < -segtime2) {
       
   936     /* master is running faster, move external time forwards */
       
   937     GST_WARNING_OBJECT (sink,
       
   938         "correct clock skew %" G_GINT64_FORMAT " < %" G_GINT64_FORMAT,
       
   939         sink->priv->avg_skew, -segtime2);
       
   940     cexternal += segtime;
       
   941     sink->priv->avg_skew += segtime;
       
   942 
       
   943     segsamples =
       
   944         sink->ringbuffer->spec.segsize /
       
   945         sink->ringbuffer->spec.bytes_per_sample;
       
   946     last_align = sink->priv->last_align;
       
   947 
       
   948     /* if we were aligning in the wrong direction or we aligned more than what we
       
   949      * will correct, resync */
       
   950     if (last_align > 0 || -last_align > segsamples)
       
   951       sink->next_sample = -1;
       
   952 
       
   953     GST_DEBUG_OBJECT (sink,
       
   954         "last_align %" G_GINT64_FORMAT " segsamples %u, next %"
       
   955         G_GUINT64_FORMAT, last_align, segsamples, sink->next_sample);
       
   956 
       
   957     gst_clock_set_calibration (sink->provided_clock, cinternal, cexternal,
       
   958         crate_num, crate_denom);
       
   959   }
       
   960 
       
   961   /* convert, ignoring speed */
       
   962   render_start = clock_convert_external (render_start, cinternal, cexternal,
       
   963       crate_num, crate_denom, sink->priv->us_latency);
       
   964   render_stop = clock_convert_external (render_stop, cinternal, cexternal,
       
   965       crate_num, crate_denom, sink->priv->us_latency);
       
   966 
       
   967   *srender_start = render_start;
       
   968   *srender_stop = render_stop;
       
   969 }
       
   970 
       
   971 /* apply the clock offset but do no slaving otherwise */
       
   972 static void
       
   973 gst_base_audio_sink_none_slaving (GstBaseAudioSink * sink,
       
   974     GstClockTime render_start, GstClockTime render_stop,
       
   975     GstClockTime * srender_start, GstClockTime * srender_stop)
       
   976 {
       
   977   GstClockTime cinternal, cexternal, crate_num, crate_denom;
       
   978 
       
   979   /* get calibration parameters to compensate for offsets */
       
   980   gst_clock_get_calibration (sink->provided_clock, &cinternal, &cexternal,
       
   981       &crate_num, &crate_denom);
       
   982 
       
   983   /* convert, ignoring speed */
       
   984   render_start = clock_convert_external (render_start, cinternal, cexternal,
       
   985       crate_num, crate_denom, sink->priv->us_latency);
       
   986   render_stop = clock_convert_external (render_stop, cinternal, cexternal,
       
   987       crate_num, crate_denom, sink->priv->us_latency);
       
   988 
       
   989   *srender_start = render_start;
       
   990   *srender_stop = render_stop;
       
   991 }
       
   992 
       
   993 /* converts render_start and render_stop to their slaved values */
       
   994 static void
       
   995 gst_base_audio_sink_handle_slaving (GstBaseAudioSink * sink,
       
   996     GstClockTime render_start, GstClockTime render_stop,
       
   997     GstClockTime * srender_start, GstClockTime * srender_stop)
       
   998 {
       
   999   switch (sink->priv->slave_method) {
       
  1000     case GST_BASE_AUDIO_SINK_SLAVE_RESAMPLE:
       
  1001       gst_base_audio_sink_resample_slaving (sink, render_start, render_stop,
       
  1002           srender_start, srender_stop);
       
  1003       break;
       
  1004     case GST_BASE_AUDIO_SINK_SLAVE_SKEW:
       
  1005       gst_base_audio_sink_skew_slaving (sink, render_start, render_stop,
       
  1006           srender_start, srender_stop);
       
  1007       break;
       
  1008     case GST_BASE_AUDIO_SINK_SLAVE_NONE:
       
  1009       gst_base_audio_sink_none_slaving (sink, render_start, render_stop,
       
  1010           srender_start, srender_stop);
       
  1011       break;
       
  1012     default:
       
  1013       g_warning ("unknown slaving method %d", sink->priv->slave_method);
       
  1014       break;
       
  1015   }
       
  1016 }
       
  1017 
       
  1018 static GstFlowReturn
       
  1019 gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
       
  1020 {
       
  1021   guint64 in_offset;
       
  1022   GstClockTime time, stop, render_start, render_stop, sample_offset;
       
  1023   GstBaseAudioSink *sink;
       
  1024   GstRingBuffer *ringbuf;
       
  1025   gint64 diff, align, ctime, cstop;
       
  1026   guint8 *data;
       
  1027   guint size;
       
  1028   guint samples, written;
       
  1029   gint bps;
       
  1030   gint accum;
       
  1031   gint out_samples;
       
  1032   GstClockTime base_time = GST_CLOCK_TIME_NONE, latency;
       
  1033   GstClock *clock;
       
  1034   gboolean sync, slaved, align_next;
       
  1035 
       
  1036   sink = GST_BASE_AUDIO_SINK (bsink);
       
  1037 
       
  1038   ringbuf = sink->ringbuffer;
       
  1039 
       
  1040   /* can't do anything when we don't have the device */
       
  1041   if (G_UNLIKELY (!gst_ring_buffer_is_acquired (ringbuf)))
       
  1042     goto wrong_state;
       
  1043 
       
  1044   bps = ringbuf->spec.bytes_per_sample;
       
  1045 
       
  1046   size = GST_BUFFER_SIZE (buf);
       
  1047   if (G_UNLIKELY (size % bps) != 0)
       
  1048     goto wrong_size;
       
  1049 
       
  1050   samples = size / bps;
       
  1051   out_samples = samples;
       
  1052 
       
  1053   in_offset = GST_BUFFER_OFFSET (buf);
       
  1054   time = GST_BUFFER_TIMESTAMP (buf);
       
  1055   stop = time + gst_util_uint64_scale_int (samples, GST_SECOND,
       
  1056       ringbuf->spec.rate);
       
  1057 
       
  1058   GST_DEBUG_OBJECT (sink,
       
  1059       "time %" GST_TIME_FORMAT ", offset %llu, start %" GST_TIME_FORMAT
       
  1060       ", samples %u", GST_TIME_ARGS (time), in_offset,
       
  1061       GST_TIME_ARGS (bsink->segment.start), samples);
       
  1062 
       
  1063   data = GST_BUFFER_DATA (buf);
       
  1064 
       
  1065   /* if not valid timestamp or we can't clip or sync, try to play
       
  1066    * sample ASAP */
       
  1067   if (!GST_CLOCK_TIME_IS_VALID (time)) {
       
  1068     render_start = gst_base_audio_sink_get_offset (sink);
       
  1069     render_stop = render_start + samples;
       
  1070     GST_DEBUG_OBJECT (sink,
       
  1071         "Buffer of size %u has no time. Using render_start=%" G_GUINT64_FORMAT,
       
  1072         GST_BUFFER_SIZE (buf), render_start);
       
  1073     goto no_sync;
       
  1074   }
       
  1075 
       
  1076   /* samples should be rendered based on their timestamp. All samples
       
  1077    * arriving before the segment.start or after segment.stop are to be 
       
  1078    * thrown away. All samples should also be clipped to the segment 
       
  1079    * boundaries */
       
  1080   /* let's calc stop based on the number of samples in the buffer instead
       
  1081    * of trusting the DURATION */
       
  1082   if (!gst_segment_clip (&bsink->segment, GST_FORMAT_TIME, time, stop, &ctime,
       
  1083           &cstop))
       
  1084     goto out_of_segment;
       
  1085 
       
  1086   /* see if some clipping happened */
       
  1087   diff = ctime - time;
       
  1088   if (diff > 0) {
       
  1089     /* bring clipped time to samples */
       
  1090     diff = gst_util_uint64_scale_int (diff, ringbuf->spec.rate, GST_SECOND);
       
  1091     GST_DEBUG_OBJECT (sink, "clipping start to %" GST_TIME_FORMAT " %"
       
  1092         G_GUINT64_FORMAT " samples", GST_TIME_ARGS (ctime), diff);
       
  1093     samples -= diff;
       
  1094     data += diff * bps;
       
  1095     time = ctime;
       
  1096   }
       
  1097   diff = stop - cstop;
       
  1098   if (diff > 0) {
       
  1099     /* bring clipped time to samples */
       
  1100     diff = gst_util_uint64_scale_int (diff, ringbuf->spec.rate, GST_SECOND);
       
  1101     GST_DEBUG_OBJECT (sink, "clipping stop to %" GST_TIME_FORMAT " %"
       
  1102         G_GUINT64_FORMAT " samples", GST_TIME_ARGS (cstop), diff);
       
  1103     samples -= diff;
       
  1104     stop = cstop;
       
  1105   }
       
  1106 
       
  1107   /* figure out how to sync */
       
  1108   if ((clock = GST_ELEMENT_CLOCK (bsink)))
       
  1109     sync = bsink->sync;
       
  1110   else
       
  1111     sync = FALSE;
       
  1112 
       
  1113   if (!sync) {
       
  1114     /* no sync needed, play sample ASAP */
       
  1115     render_start = gst_base_audio_sink_get_offset (sink);
       
  1116     render_stop = render_start + samples;
       
  1117     GST_DEBUG_OBJECT (sink,
       
  1118         "no sync needed. Using render_start=%" G_GUINT64_FORMAT, render_start);
       
  1119     goto no_sync;
       
  1120   }
       
  1121 
       
  1122   /* bring buffer start and stop times to running time */
       
  1123   render_start =
       
  1124       gst_segment_to_running_time (&bsink->segment, GST_FORMAT_TIME, time);
       
  1125   render_stop =
       
  1126       gst_segment_to_running_time (&bsink->segment, GST_FORMAT_TIME, stop);
       
  1127 
       
  1128   GST_DEBUG_OBJECT (sink,
       
  1129       "running: start %" GST_TIME_FORMAT " - stop %" GST_TIME_FORMAT,
       
  1130       GST_TIME_ARGS (render_start), GST_TIME_ARGS (render_stop));
       
  1131 
       
  1132   base_time = gst_element_get_base_time (GST_ELEMENT_CAST (bsink));
       
  1133 
       
  1134   GST_DEBUG_OBJECT (sink, "base_time %" GST_TIME_FORMAT,
       
  1135       GST_TIME_ARGS (base_time));
       
  1136 
       
  1137   /* add base time to sync against the clock */
       
  1138   render_start += base_time;
       
  1139   render_stop += base_time;
       
  1140 
       
  1141   /* compensate for latency */
       
  1142   latency = gst_base_sink_get_latency (bsink);
       
  1143   GST_DEBUG_OBJECT (sink,
       
  1144       "compensating for latency %" GST_TIME_FORMAT, GST_TIME_ARGS (latency));
       
  1145 
       
  1146   /* add latency to get the timestamp to sync against the pipeline clock */
       
  1147   render_start += latency;
       
  1148   render_stop += latency;
       
  1149 
       
  1150   GST_DEBUG_OBJECT (sink,
       
  1151       "after latency: start %" GST_TIME_FORMAT " - stop %" GST_TIME_FORMAT,
       
  1152       GST_TIME_ARGS (render_start), GST_TIME_ARGS (render_stop));
       
  1153 
       
  1154   if ((slaved = clock != sink->provided_clock)) {
       
  1155     /* handle clock slaving */
       
  1156     gst_base_audio_sink_handle_slaving (sink, render_start, render_stop,
       
  1157         &render_start, &render_stop);
       
  1158   }
       
  1159 
       
  1160   /* and bring the time to the rate corrected offset in the buffer */
       
  1161   render_start = gst_util_uint64_scale_int (render_start,
       
  1162       ringbuf->spec.rate, GST_SECOND);
       
  1163   render_stop = gst_util_uint64_scale_int (render_stop,
       
  1164       ringbuf->spec.rate, GST_SECOND);
       
  1165 
       
  1166   /* always resync after a discont */
       
  1167   if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT))) {
       
  1168     GST_DEBUG_OBJECT (sink, "resync after discont");
       
  1169     goto no_align;
       
  1170   }
       
  1171 
       
  1172   if (G_UNLIKELY (sink->next_sample == -1)) {
       
  1173     GST_DEBUG_OBJECT (sink,
       
  1174         "no align possible: no previous sample position known");
       
  1175     goto no_align;
       
  1176   }
       
  1177 
       
  1178   /* positive playback rate, first sample is render_start, negative rate, first
       
  1179    * sample is render_stop */
       
  1180   if (bsink->segment.rate >= 1.0)
       
  1181     sample_offset = render_start;
       
  1182   else
       
  1183     sample_offset = render_stop;
       
  1184 
       
  1185   /* now try to align the sample to the previous one */
       
  1186   if (sample_offset >= sink->next_sample)
       
  1187     diff = sample_offset - sink->next_sample;
       
  1188   else
       
  1189     diff = sink->next_sample - sample_offset;
       
  1190 
       
  1191   /* we tollerate half a second diff before we start resyncing. This
       
  1192    * should be enough to compensate for various rounding errors in the timestamp
       
  1193    * and sample offset position. We always resync if we got a discont anyway and
       
  1194    * non-discont should be aligned by definition. */
       
  1195   if (G_LIKELY (diff < ringbuf->spec.rate / DIFF_TOLERANCE)) {
       
  1196     /* calc align with previous sample */
       
  1197     align = sink->next_sample - sample_offset;
       
  1198     GST_DEBUG_OBJECT (sink,
       
  1199         "align with prev sample, ABS (%" G_GINT64_FORMAT ") < %d", align,
       
  1200         ringbuf->spec.rate / DIFF_TOLERANCE);
       
  1201   } else {
       
  1202     /* bring sample diff to seconds for error message */
       
  1203     diff = gst_util_uint64_scale_int (diff, GST_SECOND, ringbuf->spec.rate);
       
  1204     /* timestamps drifted apart from previous samples too much, we need to
       
  1205      * resync. We log this as an element warning. */
       
  1206     GST_ELEMENT_WARNING (sink, CORE, CLOCK,
       
  1207         ("Compensating for audio synchronisation problems"),
       
  1208         ("Unexpected discontinuity in audio timestamps of more "
       
  1209             "than half a second (%" GST_TIME_FORMAT "), resyncing",
       
  1210             GST_TIME_ARGS (diff)));
       
  1211     align = 0;
       
  1212   }
       
  1213   sink->priv->last_align = align;
       
  1214 
       
  1215   /* apply alignment */
       
  1216   render_start += align;
       
  1217 
       
  1218   /* only align stop if we are not slaved to resample */
       
  1219   if (slaved && sink->priv->slave_method == GST_BASE_AUDIO_SINK_SLAVE_RESAMPLE) {
       
  1220     GST_DEBUG_OBJECT (sink, "no stop time align needed: we are slaved");
       
  1221     goto no_align;
       
  1222   }
       
  1223   render_stop += align;
       
  1224 
       
  1225 no_align:
       
  1226   /* number of target samples is difference between start and stop */
       
  1227   out_samples = render_stop - render_start;
       
  1228 
       
  1229 no_sync:
       
  1230   /* we render the first or last sample first, depending on the rate */
       
  1231   if (bsink->segment.rate >= 1.0)
       
  1232     sample_offset = render_start;
       
  1233   else
       
  1234     sample_offset = render_stop;
       
  1235 
       
  1236   GST_DEBUG_OBJECT (sink, "rendering at %" G_GUINT64_FORMAT " %d/%d",
       
  1237       sample_offset, samples, out_samples);
       
  1238 
       
  1239   /* we need to accumulate over different runs for when we get interrupted */
       
  1240   accum = 0;
       
  1241   align_next = TRUE;
       
  1242   do {
       
  1243     written =
       
  1244         gst_ring_buffer_commit_full (ringbuf, &sample_offset, data, samples,
       
  1245         out_samples, &accum);
       
  1246 
       
  1247     GST_DEBUG_OBJECT (sink, "wrote %u of %u", written, samples);
       
  1248     /* if we wrote all, we're done */
       
  1249     if (written == samples)
       
  1250       break;
       
  1251 
       
  1252     /* else something interrupted us and we wait for preroll. */
       
  1253     if (gst_base_sink_wait_preroll (bsink) != GST_FLOW_OK)
       
  1254       goto stopping;
       
  1255 
       
  1256     /* if we got interrupted, we cannot assume that the next sample should
       
  1257      * be aligned to this one */
       
  1258     align_next = FALSE;
       
  1259 
       
  1260     samples -= written;
       
  1261     data += written * bps;
       
  1262   } while (TRUE);
       
  1263 
       
  1264   if (align_next)
       
  1265     sink->next_sample = sample_offset;
       
  1266   else
       
  1267     sink->next_sample = -1;
       
  1268 
       
  1269   GST_DEBUG_OBJECT (sink, "next sample expected at %" G_GUINT64_FORMAT,
       
  1270       sink->next_sample);
       
  1271 
       
  1272   if (GST_CLOCK_TIME_IS_VALID (stop) && stop >= bsink->segment.stop) {
       
  1273     GST_DEBUG_OBJECT (sink,
       
  1274         "start playback because we are at the end of segment");
       
  1275     gst_ring_buffer_start (ringbuf);
       
  1276   }
       
  1277 
       
  1278   return GST_FLOW_OK;
       
  1279 
       
  1280   /* SPECIAL cases */
       
  1281 out_of_segment:
       
  1282   {
       
  1283     GST_DEBUG_OBJECT (sink,
       
  1284         "dropping sample out of segment time %" GST_TIME_FORMAT ", start %"
       
  1285         GST_TIME_FORMAT, GST_TIME_ARGS (time),
       
  1286         GST_TIME_ARGS (bsink->segment.start));
       
  1287     return GST_FLOW_OK;
       
  1288   }
       
  1289   /* ERRORS */
       
  1290 wrong_state:
       
  1291   {
       
  1292     GST_DEBUG_OBJECT (sink, "ringbuffer not negotiated");
       
  1293     GST_ELEMENT_ERROR (sink, STREAM, FORMAT, (NULL), ("sink not negotiated."));
       
  1294     return GST_FLOW_NOT_NEGOTIATED;
       
  1295   }
       
  1296 wrong_size:
       
  1297   {
       
  1298     GST_DEBUG_OBJECT (sink, "wrong size");
       
  1299     GST_ELEMENT_ERROR (sink, STREAM, WRONG_TYPE,
       
  1300         (NULL), ("sink received buffer of wrong size."));
       
  1301     return GST_FLOW_ERROR;
       
  1302   }
       
  1303 stopping:
       
  1304   {
       
  1305     GST_DEBUG_OBJECT (sink, "ringbuffer is stopping");
       
  1306     return GST_FLOW_WRONG_STATE;
       
  1307   }
       
  1308 }
       
  1309 
       
  1310 /**
       
  1311  * gst_base_audio_sink_create_ringbuffer:
       
  1312  * @sink: a #GstBaseAudioSink.
       
  1313  *
       
  1314  * Create and return the #GstRingBuffer for @sink. This function will call the
       
  1315  * ::create_ringbuffer vmethod and will set @sink as the parent of the returned
       
  1316  * buffer (see gst_object_set_parent()).
       
  1317  *
       
  1318  * Returns: The new ringbuffer of @sink.
       
  1319  */
       
  1320 #ifdef __SYMBIAN32__
       
  1321 EXPORT_C
       
  1322 #endif
       
  1323 
       
  1324 GstRingBuffer *
       
  1325 gst_base_audio_sink_create_ringbuffer (GstBaseAudioSink * sink)
       
  1326 {
       
  1327   GstBaseAudioSinkClass *bclass;
       
  1328   GstRingBuffer *buffer = NULL;
       
  1329 
       
  1330   bclass = GST_BASE_AUDIO_SINK_GET_CLASS (sink);
       
  1331   if (bclass->create_ringbuffer)
       
  1332     buffer = bclass->create_ringbuffer (sink);
       
  1333 
       
  1334   if (buffer)
       
  1335     gst_object_set_parent (GST_OBJECT (buffer), GST_OBJECT (sink));
       
  1336 
       
  1337   return buffer;
       
  1338 }
       
  1339 
       
  1340 static gboolean
       
  1341 gst_base_audio_sink_activate_pull (GstBaseSink * basesink, gboolean active)
       
  1342 {
       
  1343   gboolean ret;
       
  1344   GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (basesink);
       
  1345 
       
  1346   if (active) {
       
  1347     gst_ring_buffer_set_callback (sink->ringbuffer,
       
  1348         gst_base_audio_sink_callback, sink);
       
  1349     ret = gst_ring_buffer_start (sink->ringbuffer);
       
  1350   } else {
       
  1351     gst_ring_buffer_set_callback (sink->ringbuffer, NULL, NULL);
       
  1352     /* stop thread */
       
  1353     ret = gst_ring_buffer_release (sink->ringbuffer);
       
  1354   }
       
  1355 
       
  1356   return ret;
       
  1357 }
       
  1358 
       
  1359 static void
       
  1360 gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
       
  1361     gpointer user_data)
       
  1362 {
       
  1363   GstBaseSink *basesink;
       
  1364   GstBaseAudioSink *sink;
       
  1365   GstBuffer *buf;
       
  1366   GstFlowReturn ret;
       
  1367 
       
  1368   basesink = GST_BASE_SINK (user_data);
       
  1369   sink = GST_BASE_AUDIO_SINK (user_data);
       
  1370 
       
  1371   /* would be nice to arrange for pad_alloc_buffer to return data -- as it is we
       
  1372      will copy twice, once into data, once into DMA */
       
  1373   GST_LOG_OBJECT (basesink, "pulling %d bytes offset %" G_GUINT64_FORMAT
       
  1374       " to fill audio buffer", len, basesink->offset);
       
  1375   ret = gst_pad_pull_range (basesink->sinkpad, basesink->offset, len, &buf);
       
  1376 
       
  1377   if (ret != GST_FLOW_OK) {
       
  1378     if (ret == GST_FLOW_UNEXPECTED)
       
  1379       goto eos;
       
  1380     else
       
  1381       goto error;
       
  1382   }
       
  1383 
       
  1384   if (len != GST_BUFFER_SIZE (buf)) {
       
  1385     GST_INFO_OBJECT (basesink, "short read pulling from sink pad: %d<%d",
       
  1386         len, GST_BUFFER_SIZE (buf));
       
  1387     len = MIN (GST_BUFFER_SIZE (buf), len);
       
  1388   }
       
  1389 
       
  1390   basesink->offset += len;
       
  1391 
       
  1392   memcpy (data, GST_BUFFER_DATA (buf), len);
       
  1393 
       
  1394   return;
       
  1395 
       
  1396 error:
       
  1397   {
       
  1398     GST_WARNING_OBJECT (basesink, "Got flow error but can't return it: %d",
       
  1399         ret);
       
  1400     return;
       
  1401   }
       
  1402 eos:
       
  1403   {
       
  1404     /* FIXME: this is not quite correct; we'll be called endlessly until
       
  1405      * the sink gets shut down; maybe we should set a flag somewhere, or
       
  1406      * set segment.stop and segment.duration to the last sample or so */
       
  1407     GST_DEBUG_OBJECT (sink, "EOS");
       
  1408     gst_element_post_message (GST_ELEMENT_CAST (sink),
       
  1409         gst_message_new_eos (GST_OBJECT_CAST (sink)));
       
  1410     gst_base_audio_sink_drain (sink);
       
  1411   }
       
  1412 }
       
  1413 
       
  1414 /* should be called with the LOCK */
       
  1415 static GstStateChangeReturn
       
  1416 gst_base_audio_sink_async_play (GstBaseSink * basesink)
       
  1417 {
       
  1418   GstClock *clock;
       
  1419   GstBaseAudioSink *sink;
       
  1420   GstClockTime itime, etime;
       
  1421   GstClockTime rate_num, rate_denom;
       
  1422 
       
  1423   sink = GST_BASE_AUDIO_SINK (basesink);
       
  1424 
       
  1425   GST_DEBUG_OBJECT (sink, "ringbuffer may start now");
       
  1426   gst_ring_buffer_may_start (sink->ringbuffer, TRUE);
       
  1427 
       
  1428   clock = GST_ELEMENT_CLOCK (sink);
       
  1429   if (clock == NULL)
       
  1430     goto done;
       
  1431 
       
  1432   /* we provided the global clock, don't need to do anything special */
       
  1433   if (clock == sink->provided_clock)
       
  1434     goto done;
       
  1435 
       
  1436   /* if we are slaved to a clock, we need to set the initial
       
  1437    * calibration */
       
  1438   /* get external and internal time to set as calibration params */
       
  1439   etime = gst_clock_get_time (clock);
       
  1440   itime = gst_clock_get_internal_time (sink->provided_clock);
       
  1441 
       
  1442   sink->priv->avg_skew = -1;
       
  1443   sink->next_sample = -1;
       
  1444 
       
  1445   GST_DEBUG_OBJECT (sink,
       
  1446       "internal time: %" GST_TIME_FORMAT " external time: %" GST_TIME_FORMAT,
       
  1447       GST_TIME_ARGS (itime), GST_TIME_ARGS (etime));
       
  1448 
       
  1449   gst_clock_get_calibration (sink->provided_clock, NULL, NULL, &rate_num,
       
  1450       &rate_denom);
       
  1451   gst_clock_set_calibration (sink->provided_clock, itime, etime,
       
  1452       rate_num, rate_denom);
       
  1453 
       
  1454   switch (sink->priv->slave_method) {
       
  1455     case GST_BASE_AUDIO_SINK_SLAVE_RESAMPLE:
       
  1456       /* only set as master if we need to resample */
       
  1457       GST_DEBUG_OBJECT (sink, "Setting clock as master");
       
  1458       gst_clock_set_master (sink->provided_clock, clock);
       
  1459       break;
       
  1460     default:
       
  1461       break;
       
  1462   }
       
  1463 
       
  1464   /* start ringbuffer so we can start slaving right away when we need to */
       
  1465   gst_ring_buffer_start (sink->ringbuffer);
       
  1466 
       
  1467 done:
       
  1468   return GST_STATE_CHANGE_SUCCESS;
       
  1469 }
       
  1470 
       
  1471 static GstStateChangeReturn
       
  1472 gst_base_audio_sink_do_play (GstBaseAudioSink * sink)
       
  1473 {
       
  1474   GstStateChangeReturn ret;
       
  1475 
       
  1476   GST_OBJECT_LOCK (sink);
       
  1477   ret = gst_base_audio_sink_async_play (GST_BASE_SINK_CAST (sink));
       
  1478   GST_OBJECT_UNLOCK (sink);
       
  1479 
       
  1480   return ret;
       
  1481 }
       
  1482 
       
  1483 static GstStateChangeReturn
       
  1484 gst_base_audio_sink_change_state (GstElement * element,
       
  1485     GstStateChange transition)
       
  1486 {
       
  1487   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
       
  1488   GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (element);
       
  1489 
       
  1490   switch (transition) {
       
  1491     case GST_STATE_CHANGE_NULL_TO_READY:
       
  1492       if (sink->ringbuffer == NULL) {
       
  1493         sink->ringbuffer = gst_base_audio_sink_create_ringbuffer (sink);
       
  1494       }
       
  1495       if (!gst_ring_buffer_open_device (sink->ringbuffer))
       
  1496         goto open_failed;
       
  1497       break;
       
  1498     case GST_STATE_CHANGE_READY_TO_PAUSED:
       
  1499       sink->next_sample = -1;
       
  1500       sink->priv->last_align = -1;
       
  1501       gst_ring_buffer_set_flushing (sink->ringbuffer, FALSE);
       
  1502       gst_ring_buffer_may_start (sink->ringbuffer, FALSE);
       
  1503       break;
       
  1504     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
       
  1505       gst_base_audio_sink_do_play (sink);
       
  1506       break;
       
  1507     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
       
  1508       /* need to take the lock so we don't interfere with an
       
  1509        * async play */
       
  1510       GST_OBJECT_LOCK (sink);
       
  1511       /* ringbuffer cannot start anymore */
       
  1512       gst_ring_buffer_may_start (sink->ringbuffer, FALSE);
       
  1513       gst_ring_buffer_pause (sink->ringbuffer);
       
  1514       GST_OBJECT_UNLOCK (sink);
       
  1515       break;
       
  1516     case GST_STATE_CHANGE_PAUSED_TO_READY:
       
  1517       /* make sure we unblock before calling the parent state change
       
  1518        * so it can grab the STREAM_LOCK */
       
  1519       gst_ring_buffer_set_flushing (sink->ringbuffer, TRUE);
       
  1520       break;
       
  1521     default:
       
  1522       break;
       
  1523   }
       
  1524 
       
  1525   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
       
  1526 
       
  1527   switch (transition) {
       
  1528     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
       
  1529       /* stop slaving ourselves to the master, if any */
       
  1530       gst_clock_set_master (sink->provided_clock, NULL);
       
  1531       break;
       
  1532     case GST_STATE_CHANGE_PAUSED_TO_READY:
       
  1533       gst_ring_buffer_release (sink->ringbuffer);
       
  1534       break;
       
  1535     case GST_STATE_CHANGE_READY_TO_NULL:
       
  1536       /* we release again here because the aqcuire happens when setting the
       
  1537        * caps, which happens before we commit the state to PAUSED and thus the
       
  1538        * PAUSED->READY state change (see above, where we release the ringbuffer)
       
  1539        * might not be called when we get here. */
       
  1540       gst_ring_buffer_release (sink->ringbuffer);
       
  1541       gst_ring_buffer_close_device (sink->ringbuffer);
       
  1542       break;
       
  1543     default:
       
  1544       break;
       
  1545   }
       
  1546 
       
  1547   return ret;
       
  1548 
       
  1549   /* ERRORS */
       
  1550 open_failed:
       
  1551   {
       
  1552     /* subclass must post a meaningfull error message */
       
  1553     GST_DEBUG_OBJECT (sink, "open failed");
       
  1554     return GST_STATE_CHANGE_FAILURE;
       
  1555   }
       
  1556 }