gstbaseaudiosink.c 61.6 KB
Newer Older
1
2
3
4
/* GStreamer
 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
 *                    2005 Wim Taymans <wim@fluendo.com>
 *
5
 * gstbaseaudiosink.c:
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

Wim Taymans's avatar
Wim Taymans committed
23
24
25
26
27
28
29
30
31
32
33
34
/**
 * SECTION:gstbaseaudiosink
 * @short_description: Base class for audio sinks
 * @see_also: #GstAudioSink, #GstRingBuffer.
 *
 * This is the base class for audio sinks. Subclasses need to implement the
 * ::create_ringbuffer vmethod. This base class will then take care of
 * writing samples to the ringbuffer, synchronisation, clipping and flushing.
 *
 * Last reviewed on 2006-09-27 (0.10.12)
 */

35
36
#include <string.h>

37
38
#include "gstbaseaudiosink.h"

39
40
GST_DEBUG_CATEGORY_STATIC (gst_base_audio_sink_debug);
#define GST_CAT_DEFAULT gst_base_audio_sink_debug
41

42
43
44
45
46
47
48
49
50
51
52
#define GST_BASE_AUDIO_SINK_GET_PRIVATE(obj)  \
   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_AUDIO_SINK, GstBaseAudioSinkPrivate))

struct _GstBaseAudioSinkPrivate
{
  /* upstream latency */
  GstClockTime us_latency;
  /* the clock slaving algorithm in use */
  GstBaseAudioSinkSlaveMethod slave_method;
  /* running average of clock skew */
  GstClockTimeDiff avg_skew;
53
54
  /* the number of samples we aligned last time */
  gint64 last_align;
55
56

  gboolean sync_latency;
57
58

  GstClockTime eos_time;
59
  gint eos_rendering;
60
61

  gboolean do_time_offset;
62
63
64
  /* number of microseconds we alow timestamps or clock slaving to drift
   * before resyncing */
  guint64 drift_tolerance;
65
66
};

67
68
69
70
71
72
73
/* BaseAudioSink signals and args */
enum
{
  /* FILL ME */
  LAST_SIGNAL
};

74
/* we tollerate half a second diff before we start resyncing. This
75
 * should be enough to compensate for various rounding errors in the timestamp
76
 * and sample offset position.
77
78
 * This is an emergency resync fallback since buffers marked as DISCONT will
 * always lock to the correct timestamp immediatly and buffers not marked as
79
 * DISCONT are contiguous by definition.
80
81
 */
#define DIFF_TOLERANCE  2
82

83
84
85
/* FIXME: 0.11, store the buffer_time and latency_time in nanoseconds */
#define DEFAULT_BUFFER_TIME     ((200 * GST_MSECOND) / GST_USECOND)
#define DEFAULT_LATENCY_TIME    ((10 * GST_MSECOND) / GST_USECOND)
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
86
#define DEFAULT_PROVIDE_CLOCK   TRUE
87
#define DEFAULT_SLAVE_METHOD    GST_BASE_AUDIO_SINK_SLAVE_SKEW
88

89
90
91
/* FIXME, enable pull mode when clock slaving and trick modes are figured out */
#define DEFAULT_CAN_ACTIVATE_PULL FALSE

92
/* when timestamps or clock slaving drift for more than 20ms we resync. This is
93
 * a reasonable default */
94
#define DEFAULT_DRIFT_TOLERANCE   ((40 * GST_MSECOND) / GST_USECOND)
95

96
97
98
enum
{
  PROP_0,
99

100
101
  PROP_BUFFER_TIME,
  PROP_LATENCY_TIME,
102
  PROP_PROVIDE_CLOCK,
103
  PROP_SLAVE_METHOD,
104
105
106
107
  PROP_CAN_ACTIVATE_PULL,
  PROP_DRIFT_TOLERANCE,

  PROP_LAST
108
109
};

110
111
GType
gst_base_audio_sink_slave_method_get_type (void)
112
113
114
115
116
{
  static GType slave_method_type = 0;
  static const GEnumValue slave_method[] = {
    {GST_BASE_AUDIO_SINK_SLAVE_RESAMPLE, "Resampling slaving", "resample"},
    {GST_BASE_AUDIO_SINK_SLAVE_SKEW, "Skew slaving", "skew"},
117
    {GST_BASE_AUDIO_SINK_SLAVE_NONE, "No slaving", "none"},
118
119
120
121
122
123
124
125
126
127
128
    {0, NULL, NULL},
  };

  if (!slave_method_type) {
    slave_method_type =
        g_enum_register_static ("GstBaseAudioSinkSlaveMethod", slave_method);
  }
  return slave_method_type;
}


129
#define _do_init(bla) \
130
    GST_DEBUG_CATEGORY_INIT (gst_base_audio_sink_debug, "baseaudiosink", 0, "baseaudiosink element");
131

132
133
GST_BOILERPLATE_FULL (GstBaseAudioSink, gst_base_audio_sink, GstBaseSink,
    GST_TYPE_BASE_SINK, _do_init);
134

135
static void gst_base_audio_sink_dispose (GObject * object);
136

137
static void gst_base_audio_sink_set_property (GObject * object, guint prop_id,
138
    const GValue * value, GParamSpec * pspec);
139
static void gst_base_audio_sink_get_property (GObject * object, guint prop_id,
140
141
    GValue * value, GParamSpec * pspec);

142
143
static GstStateChangeReturn gst_base_audio_sink_async_play (GstBaseSink *
    basesink);
144
145
static GstStateChangeReturn gst_base_audio_sink_change_state (GstElement *
    element, GstStateChange transition);
146
147
static gboolean gst_base_audio_sink_activate_pull (GstBaseSink * basesink,
    gboolean active);
148
149
static gboolean gst_base_audio_sink_query (GstElement * element, GstQuery *
    query);
150

151
static GstClock *gst_base_audio_sink_provide_clock (GstElement * elem);
152
static GstClockTime gst_base_audio_sink_get_time (GstClock * clock,
153
    GstBaseAudioSink * sink);
154
155
static void gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data,
    guint len, gpointer user_data);
156

157
static GstFlowReturn gst_base_audio_sink_preroll (GstBaseSink * bsink,
158
    GstBuffer * buffer);
159
static GstFlowReturn gst_base_audio_sink_render (GstBaseSink * bsink,
160
    GstBuffer * buffer);
161
162
163
static gboolean gst_base_audio_sink_event (GstBaseSink * bsink,
    GstEvent * event);
static void gst_base_audio_sink_get_times (GstBaseSink * bsink,
164
    GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
165
166
static gboolean gst_base_audio_sink_setcaps (GstBaseSink * bsink,
    GstCaps * caps);
167
static void gst_base_audio_sink_fixate (GstBaseSink * bsink, GstCaps * caps);
168

169
170
171
static gboolean gst_base_audio_sink_query_pad (GstPad * pad, GstQuery * query);


172
/* static guint gst_base_audio_sink_signals[LAST_SIGNAL] = { 0 }; */
173
174

static void
175
gst_base_audio_sink_base_init (gpointer g_class)
176
177
178
179
{
}

static void
180
gst_base_audio_sink_class_init (GstBaseAudioSinkClass * klass)
181
182
183
184
185
186
187
188
189
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;
  GstBaseSinkClass *gstbasesink_class;

  gobject_class = (GObjectClass *) klass;
  gstelement_class = (GstElementClass *) klass;
  gstbasesink_class = (GstBaseSinkClass *) klass;

190
191
  g_type_class_add_private (klass, sizeof (GstBaseAudioSinkPrivate));

192
193
194
  gobject_class->set_property = gst_base_audio_sink_set_property;
  gobject_class->get_property = gst_base_audio_sink_get_property;
  gobject_class->dispose = gst_base_audio_sink_dispose;
195

196
  g_object_class_install_property (gobject_class, PROP_BUFFER_TIME,
197
198
      g_param_spec_int64 ("buffer-time", "Buffer Time",
          "Size of audio buffer in microseconds", 1,
199
200
          G_MAXINT64, DEFAULT_BUFFER_TIME,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
201

202
  g_object_class_install_property (gobject_class, PROP_LATENCY_TIME,
203
204
      g_param_spec_int64 ("latency-time", "Latency Time",
          "Audio latency in microseconds", 1,
205
206
          G_MAXINT64, DEFAULT_LATENCY_TIME,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
207

208
  g_object_class_install_property (gobject_class, PROP_PROVIDE_CLOCK,
209
210
      g_param_spec_boolean ("provide-clock", "Provide Clock",
          "Provide a clock to be used as the global pipeline clock",
211
          DEFAULT_PROVIDE_CLOCK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
212

213
214
215
  g_object_class_install_property (gobject_class, PROP_SLAVE_METHOD,
      g_param_spec_enum ("slave-method", "Slave Method",
          "Algorithm to use to match the rate of the masterclock",
216
          GST_TYPE_BASE_AUDIO_SINK_SLAVE_METHOD, DEFAULT_SLAVE_METHOD,
217
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
218

219
220
221
222
  g_object_class_install_property (gobject_class, PROP_CAN_ACTIVATE_PULL,
      g_param_spec_boolean ("can-activate-pull", "Allow Pull Scheduling",
          "Allow pull-based scheduling", DEFAULT_CAN_ACTIVATE_PULL,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
223
224
225
226
227
228
229
230
231
232
233
234
235
  /**
   * GstBaseAudioSink:drift-tolerance
   *
   * Controls the amount of time in milliseconds that timestamps or clocks are allowed
   * to drift before resynchronisation happens.
   *
   * Since: 0.10.26
   */
  g_object_class_install_property (gobject_class, PROP_DRIFT_TOLERANCE,
      g_param_spec_int64 ("drift-tolerance", "Drift Tolerance",
          "Tolerance for timestamp and clock drift in microseconds", 1,
          G_MAXINT64, DEFAULT_DRIFT_TOLERANCE,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
236

237
  gstelement_class->change_state =
238
      GST_DEBUG_FUNCPTR (gst_base_audio_sink_change_state);
239
240
  gstelement_class->provide_clock =
      GST_DEBUG_FUNCPTR (gst_base_audio_sink_provide_clock);
241
  gstelement_class->query = GST_DEBUG_FUNCPTR (gst_base_audio_sink_query);
242

243
244
245
  gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_base_audio_sink_event);
  gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_base_audio_sink_preroll);
  gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_base_audio_sink_render);
246
  gstbasesink_class->get_times =
247
248
      GST_DEBUG_FUNCPTR (gst_base_audio_sink_get_times);
  gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_base_audio_sink_setcaps);
249
  gstbasesink_class->fixate = GST_DEBUG_FUNCPTR (gst_base_audio_sink_fixate);
250
251
  gstbasesink_class->async_play =
      GST_DEBUG_FUNCPTR (gst_base_audio_sink_async_play);
252
253
  gstbasesink_class->activate_pull =
      GST_DEBUG_FUNCPTR (gst_base_audio_sink_activate_pull);
254
255
256
257

  /* ref class from a thread-safe context to work around missing bit of
   * thread-safety in GObject */
  g_type_class_ref (GST_TYPE_AUDIO_CLOCK);
258
  g_type_class_ref (GST_TYPE_RING_BUFFER);
259

260
261
262
}

static void
263
264
gst_base_audio_sink_init (GstBaseAudioSink * baseaudiosink,
    GstBaseAudioSinkClass * g_class)
265
{
266
267
  GstPluginFeature *feature;

268
269
  baseaudiosink->priv = GST_BASE_AUDIO_SINK_GET_PRIVATE (baseaudiosink);

270
271
  baseaudiosink->buffer_time = DEFAULT_BUFFER_TIME;
  baseaudiosink->latency_time = DEFAULT_LATENCY_TIME;
272
  baseaudiosink->provide_clock = DEFAULT_PROVIDE_CLOCK;
273
  baseaudiosink->priv->slave_method = DEFAULT_SLAVE_METHOD;
274

275
276
  baseaudiosink->provided_clock = gst_audio_clock_new ("GstAudioSinkClock",
      (GstAudioClockGetTimeFunc) gst_base_audio_sink_get_time, baseaudiosink);
277

278
  GST_BASE_SINK (baseaudiosink)->can_activate_push = TRUE;
279
  GST_BASE_SINK (baseaudiosink)->can_activate_pull = DEFAULT_CAN_ACTIVATE_PULL;
280
  baseaudiosink->priv->drift_tolerance = DEFAULT_DRIFT_TOLERANCE;
281
282
283
284

  /* 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));
285
286
287
288
289
290
291
292
293
294
295
296
297
298

  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 */
299
        GST_DEBUG ("disable time offset");
300
301
302
303
        baseaudiosink->priv->do_time_offset = FALSE;
      }
    }
  }
304
305
}

306
static void
307
gst_base_audio_sink_dispose (GObject * object)
308
309
310
{
  GstBaseAudioSink *sink;

311
  sink = GST_BASE_AUDIO_SINK (object);
312

313
314
  if (sink->provided_clock) {
    gst_audio_clock_invalidate (sink->provided_clock);
315
    gst_object_unref (sink->provided_clock);
316
317
    sink->provided_clock = NULL;
  }
318

319
320
321
322
  if (sink->ringbuffer) {
    gst_object_unparent (GST_OBJECT_CAST (sink->ringbuffer));
    sink->ringbuffer = NULL;
  }
323

324
325
326
  G_OBJECT_CLASS (parent_class)->dispose (object);
}

327

328
static GstClock *
329
gst_base_audio_sink_provide_clock (GstElement * elem)
330
331
{
  GstBaseAudioSink *sink;
332
  GstClock *clock;
333

334
  sink = GST_BASE_AUDIO_SINK (elem);
335

336
  /* we have no ringbuffer (must be NULL state) */
337
338
339
  if (sink->ringbuffer == NULL)
    goto wrong_state;

340
341
342
343
  if (!gst_ring_buffer_is_acquired (sink->ringbuffer))
    goto wrong_state;

  GST_OBJECT_LOCK (sink);
344
  if (!sink->provide_clock)
345
346
347
348
    goto clock_disabled;

  clock = GST_CLOCK_CAST (gst_object_ref (sink->provided_clock));
  GST_OBJECT_UNLOCK (sink);
349
350

  return clock;
351

352
  /* ERRORS */
353
354
355
356
357
358
359
360
361
362
363
wrong_state:
  {
    GST_DEBUG_OBJECT (sink, "ringbuffer not acquired");
    return NULL;
  }
clock_disabled:
  {
    GST_DEBUG_OBJECT (sink, "clock provide disabled");
    GST_OBJECT_UNLOCK (sink);
    return NULL;
  }
364
365
}

366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
static gboolean
gst_base_audio_sink_query_pad (GstPad * pad, GstQuery * query)
{
  gboolean res = FALSE;
  GstBaseAudioSink *basesink;

  basesink = GST_BASE_AUDIO_SINK (gst_pad_get_parent (pad));

  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_CONVERT:
    {
      GstFormat src_fmt, dest_fmt;
      gint64 src_val, dest_val;

      GST_LOG_OBJECT (pad, "query convert");

      if (basesink->ringbuffer) {
        gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, NULL);
        res = gst_ring_buffer_convert (basesink->ringbuffer, src_fmt, src_val,
            dest_fmt, &dest_val);
        if (res) {
          gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
        }
      }
      break;
    }
    default:
      break;
  }

  gst_object_unref (basesink);

  return res;
}

401
402
403
404
static gboolean
gst_base_audio_sink_query (GstElement * element, GstQuery * query)
{
  gboolean res = FALSE;
405
  GstBaseAudioSink *basesink;
406

407
  basesink = GST_BASE_AUDIO_SINK (element);
408
409
410
411
412
413
414
415
416

  switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_LATENCY:
    {
      gboolean live, us_live;
      GstClockTime min_l, max_l;

      GST_DEBUG_OBJECT (basesink, "latency query");

417
418
419
420
421
422
423
      if (!basesink->ringbuffer || !basesink->ringbuffer->spec.rate) {
        GST_DEBUG_OBJECT (basesink,
            "we are not yet negotiated, can't report latency yet");
        res = FALSE;
        goto done;
      }

424
425
426
427
428
429
430
      /* ask parent first, it will do an upstream query for us. */
      if ((res =
              gst_base_sink_query_latency (GST_BASE_SINK_CAST (basesink), &live,
                  &us_live, &min_l, &max_l))) {
        GstClockTime min_latency, max_latency;

        /* we and upstream are both live, adjust the min_latency */
431
        if (live && us_live) {
432
433
434
435
          GstRingBufferSpec *spec;

          spec = &basesink->ringbuffer->spec;

436
437
          basesink->priv->us_latency = min_l;

438
          min_latency =
439
              gst_util_uint64_scale_int (spec->seglatency * spec->segsize,
440
              GST_SECOND, spec->rate * spec->bytes_per_sample);
441
442
443

          /* we cannot go lower than the buffer size and the min peer latency */
          min_latency = min_latency + min_l;
444
445
          /* the max latency is the max of the peer, we can delay an infinite
           * amount of time. */
446
          max_latency = min_latency + (max_l == -1 ? 0 : max_l);
447
448
449
450
451
452
453
454

          GST_DEBUG_OBJECT (basesink,
              "peer min %" GST_TIME_FORMAT ", our min latency: %"
              GST_TIME_FORMAT, GST_TIME_ARGS (min_l),
              GST_TIME_ARGS (min_latency));
        } else {
          GST_DEBUG_OBJECT (basesink,
              "peer or we are not live, don't care about latency");
455
456
          min_latency = min_l;
          max_latency = max_l;
457
458
459
460
461
        }
        gst_query_set_latency (query, live, min_latency, max_latency);
      }
      break;
    }
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
    case GST_QUERY_CONVERT:
    {
      GstFormat src_fmt, dest_fmt;
      gint64 src_val, dest_val;

      GST_LOG_OBJECT (basesink, "query convert");

      if (basesink->ringbuffer) {
        gst_query_parse_convert (query, &src_fmt, &src_val, &dest_fmt, NULL);
        res = gst_ring_buffer_convert (basesink->ringbuffer, src_fmt, src_val,
            dest_fmt, &dest_val);
        if (res) {
          gst_query_set_convert (query, src_fmt, src_val, dest_fmt, dest_val);
        }
      }
      break;
    }
479
480
481
482
483
    default:
      res = GST_ELEMENT_CLASS (parent_class)->query (element, query);
      break;
  }

484
done:
485
486
487
488
  return res;
}


489
static GstClockTime
490
gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink)
491
{
492
493
  guint64 raw, samples;
  guint delay;
494
  GstClockTime result;
495
496

  if (sink->ringbuffer == NULL || sink->ringbuffer->spec.rate == 0)
497
    return GST_CLOCK_TIME_NONE;
498

Wim Taymans's avatar
Wim Taymans committed
499
  /* our processed samples are always increasing */
500
501
502
503
504
505
506
507
508
509
  raw = samples = gst_ring_buffer_samples_done (sink->ringbuffer);

  /* the number of samples not yet processed, this is still queued in the
   * device (not played for playback). */
  delay = gst_ring_buffer_delay (sink->ringbuffer);

  if (G_LIKELY (samples >= delay))
    samples -= delay;
  else
    samples = 0;
510

511
512
  result = gst_util_uint64_scale_int (samples, GST_SECOND,
      sink->ringbuffer->spec.rate);
513

514
  GST_DEBUG_OBJECT (sink,
515
516
517
      "processed samples: raw %" G_GUINT64_FORMAT ", delay %u, real %"
      G_GUINT64_FORMAT ", time %" GST_TIME_FORMAT,
      raw, delay, samples, GST_TIME_ARGS (result));
518

519
  return result;
520
521
}

522
523
524
525
526
/**
 * gst_base_audio_sink_set_provide_clock:
 * @sink: a #GstBaseAudioSink
 * @provide: new state
 *
527
 * Controls whether @sink will provide a clock or not. If @provide is %TRUE,
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
 * gst_element_provide_clock() will return a clock that reflects the datarate
 * of @sink. If @provide is %FALSE, gst_element_provide_clock() will return NULL.
 *
 * Since: 0.10.16
 */
void
gst_base_audio_sink_set_provide_clock (GstBaseAudioSink * sink,
    gboolean provide)
{
  g_return_if_fail (GST_IS_BASE_AUDIO_SINK (sink));

  GST_OBJECT_LOCK (sink);
  sink->provide_clock = provide;
  GST_OBJECT_UNLOCK (sink);
}

/**
 * gst_base_audio_sink_get_provide_clock:
 * @sink: a #GstBaseAudioSink
 *
 * Queries whether @sink will provide a clock or not. See also
 * gst_base_audio_sink_set_provide_clock.
 *
 * Returns: %TRUE if @sink will provide a clock.
 *
 * Since: 0.10.16
 */
gboolean
gst_base_audio_sink_get_provide_clock (GstBaseAudioSink * sink)
{
  gboolean result;

  g_return_val_if_fail (GST_IS_BASE_AUDIO_SINK (sink), FALSE);

  GST_OBJECT_LOCK (sink);
  result = sink->provide_clock;
  GST_OBJECT_UNLOCK (sink);

  return result;
}

/**
 * gst_base_audio_sink_set_slave_method:
 * @sink: a #GstBaseAudioSink
 * @method: the new slave method
 *
574
 * Controls how clock slaving will be performed in @sink.
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
 *
 * Since: 0.10.16
 */
void
gst_base_audio_sink_set_slave_method (GstBaseAudioSink * sink,
    GstBaseAudioSinkSlaveMethod method)
{
  g_return_if_fail (GST_IS_BASE_AUDIO_SINK (sink));

  GST_OBJECT_LOCK (sink);
  sink->priv->slave_method = method;
  GST_OBJECT_UNLOCK (sink);
}

/**
 * gst_base_audio_sink_get_slave_method:
 * @sink: a #GstBaseAudioSink
 *
 * Get the current slave method used by @sink.
 *
 * Returns: The current slave method used by @sink.
 *
 * Since: 0.10.16
 */
GstBaseAudioSinkSlaveMethod
gst_base_audio_sink_get_slave_method (GstBaseAudioSink * sink)
{
  GstBaseAudioSinkSlaveMethod result;

  g_return_val_if_fail (GST_IS_BASE_AUDIO_SINK (sink), -1);

  GST_OBJECT_LOCK (sink);
  result = sink->priv->slave_method;
  GST_OBJECT_UNLOCK (sink);

  return result;
}

613
614
615
616
617
618

/**
 * gst_base_audio_sink_set_drift_tolerance:
 * @sink: a #GstBaseAudioSink
 * @drift_tolerance: the new drift tolerance in microseconds
 *
Wim Taymans's avatar
Wim Taymans committed
619
620
621
 * Controls the sink's drift tolerance.
 *
 * Since: 0.10.31
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
 */
void
gst_base_audio_sink_set_drift_tolerance (GstBaseAudioSink * sink,
    gint64 drift_tolerance)
{
  g_return_if_fail (GST_IS_BASE_AUDIO_SINK (sink));

  GST_OBJECT_LOCK (sink);
  sink->priv->drift_tolerance = drift_tolerance;
  GST_OBJECT_UNLOCK (sink);
}

/**
 * gst_base_audio_sink_get_drift_tolerance
 * @sink: a #GstBaseAudioSink
 *
 * Get the current drift tolerance, in microseconds, used by @sink.
 *
 * Returns: The current drift tolerance used by @sink.
Wim Taymans's avatar
Wim Taymans committed
641
642
 *
 * Since: 0.10.31
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
 */
gint64
gst_base_audio_sink_get_drift_tolerance (GstBaseAudioSink * sink)
{
  gint64 result;

  g_return_val_if_fail (GST_IS_BASE_AUDIO_SINK (sink), -1);

  GST_OBJECT_LOCK (sink);
  result = sink->priv->drift_tolerance;
  GST_OBJECT_UNLOCK (sink);

  return result;
}

658
static void
659
gst_base_audio_sink_set_property (GObject * object, guint prop_id,
660
661
662
663
    const GValue * value, GParamSpec * pspec)
{
  GstBaseAudioSink *sink;

664
  sink = GST_BASE_AUDIO_SINK (object);
665
666

  switch (prop_id) {
667
668
    case PROP_BUFFER_TIME:
      sink->buffer_time = g_value_get_int64 (value);
669
      break;
670
671
    case PROP_LATENCY_TIME:
      sink->latency_time = g_value_get_int64 (value);
672
      break;
673
    case PROP_PROVIDE_CLOCK:
674
      gst_base_audio_sink_set_provide_clock (sink, g_value_get_boolean (value));
675
      break;
676
    case PROP_SLAVE_METHOD:
677
      gst_base_audio_sink_set_slave_method (sink, g_value_get_enum (value));
678
      break;
679
680
681
    case PROP_CAN_ACTIVATE_PULL:
      GST_BASE_SINK (sink)->can_activate_pull = g_value_get_boolean (value);
      break;
682
    case PROP_DRIFT_TOLERANCE:
683
      gst_base_audio_sink_set_drift_tolerance (sink, g_value_get_int64 (value));
684
      break;
685
686
687
688
689
690
691
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
692
693
gst_base_audio_sink_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
694
695
696
{
  GstBaseAudioSink *sink;

697
  sink = GST_BASE_AUDIO_SINK (object);
698
699

  switch (prop_id) {
700
701
    case PROP_BUFFER_TIME:
      g_value_set_int64 (value, sink->buffer_time);
702
      break;
703
704
    case PROP_LATENCY_TIME:
      g_value_set_int64 (value, sink->latency_time);
705
      break;
706
    case PROP_PROVIDE_CLOCK:
707
      g_value_set_boolean (value, gst_base_audio_sink_get_provide_clock (sink));
708
      break;
709
    case PROP_SLAVE_METHOD:
710
      g_value_set_enum (value, gst_base_audio_sink_get_slave_method (sink));
711
      break;
712
713
714
    case PROP_CAN_ACTIVATE_PULL:
      g_value_set_boolean (value, GST_BASE_SINK (sink)->can_activate_pull);
      break;
715
    case PROP_DRIFT_TOLERANCE:
716
      g_value_set_int64 (value, gst_base_audio_sink_get_drift_tolerance (sink));
717
      break;
718
719
720
721
722
723
724
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static gboolean
725
gst_base_audio_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
726
{
727
  GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (bsink);
728
  GstRingBufferSpec *spec;
729
  GstClockTime now;
730

731
732
733
  if (!sink->ringbuffer)
    return FALSE;

734
735
  spec = &sink->ringbuffer->spec;

736
  GST_DEBUG_OBJECT (sink, "release old ringbuffer");
737

738
739
740
741
742
  /* get current time, updates the last_time */
  now = gst_clock_get_time (sink->provided_clock);

  GST_DEBUG_OBJECT (sink, "time was %" GST_TIME_FORMAT, GST_TIME_ARGS (now));

Wim Taymans's avatar
Wim Taymans committed
743
  /* release old ringbuffer */
744
  gst_ring_buffer_pause (sink->ringbuffer);
745
  gst_ring_buffer_activate (sink->ringbuffer, FALSE);
746
  gst_ring_buffer_release (sink->ringbuffer);
747

748
  GST_DEBUG_OBJECT (sink, "parse caps");
749
750
751
752

  spec->buffer_time = sink->buffer_time;
  spec->latency_time = sink->latency_time;

Wim Taymans's avatar
Wim Taymans committed
753
  /* parse new caps */
754
  if (!gst_ring_buffer_parse_caps (spec, caps))
Wim Taymans's avatar
Wim Taymans committed
755
    goto parse_error;
756

757
  gst_ring_buffer_debug_spec_buff (spec);
758

759
  GST_DEBUG_OBJECT (sink, "acquire ringbuffer");
760
  if (!gst_ring_buffer_acquire (sink->ringbuffer, spec))
761
762
    goto acquire_error;

763
764
765
766
767
  if (bsink->pad_mode == GST_ACTIVATE_PUSH) {
    GST_DEBUG_OBJECT (sink, "activate ringbuffer");
    gst_ring_buffer_activate (sink->ringbuffer, TRUE);
  }

768
  /* calculate actual latency and buffer times.
769
770
771
772
773
   * FIXME: In 0.11, store the latency_time internally in ns */
  spec->latency_time = gst_util_uint64_scale (spec->segsize,
      (GST_SECOND / GST_USECOND), spec->rate * spec->bytes_per_sample);

  spec->buffer_time = spec->segtotal * spec->latency_time;
774

775
  gst_ring_buffer_debug_spec_buff (spec);
776
777

  return TRUE;
778
779
780
781

  /* ERRORS */
parse_error:
  {
782
783
    GST_DEBUG_OBJECT (sink, "could not parse caps");
    GST_ELEMENT_ERROR (sink, STREAM, FORMAT,
784
        (NULL), ("cannot parse audio format."));
785
786
787
788
    return FALSE;
  }
acquire_error:
  {
789
    GST_DEBUG_OBJECT (sink, "could not acquire ringbuffer");
790
791
    return FALSE;
  }
792
793
}

794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
static void
gst_base_audio_sink_fixate (GstBaseSink * bsink, GstCaps * caps)
{
  GstStructure *s;
  gint width, depth;

  s = gst_caps_get_structure (caps, 0);

  /* fields for all formats */
  gst_structure_fixate_field_nearest_int (s, "rate", 44100);
  gst_structure_fixate_field_nearest_int (s, "channels", 2);
  gst_structure_fixate_field_nearest_int (s, "width", 16);

  /* fields for int */
  if (gst_structure_has_field (s, "depth")) {
    gst_structure_get_int (s, "width", &width);
    /* round width to nearest multiple of 8 for the depth */
    depth = GST_ROUND_UP_8 (width);
    gst_structure_fixate_field_nearest_int (s, "depth", depth);
  }
  if (gst_structure_has_field (s, "signed"))
    gst_structure_fixate_field_boolean (s, "signed", TRUE);
  if (gst_structure_has_field (s, "endianness"))
    gst_structure_fixate_field_nearest_int (s, "endianness", G_BYTE_ORDER);
}

820
static void
821
gst_base_audio_sink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
822
823
    GstClockTime * start, GstClockTime * end)
{
Wim Taymans's avatar
Wim Taymans committed
824
825
  /* our clock sync is a bit too much for the base class to handle so
   * we implement it ourselves. */
826
827
828
829
  *start = GST_CLOCK_TIME_NONE;
  *end = GST_CLOCK_TIME_NONE;
}

830
/* This waits for the drain to happen and can be canceled */
831
832
833
834
835
836
837
838
static gboolean
gst_base_audio_sink_drain (GstBaseAudioSink * sink)
{
  if (!sink->ringbuffer)
    return TRUE;
  if (!sink->ringbuffer->spec.rate)
    return TRUE;

839
840
841
842
  /* if PLAYING is interrupted,
   * arrange to have clock running when going to PLAYING again */
  g_atomic_int_set (&sink->priv->eos_rendering, 1);

843
  /* need to start playback before we can drain, but only when
844
   * we have successfully negotiated a format and thus acquired the
845
846
847
848
   * ringbuffer. */
  if (gst_ring_buffer_is_acquired (sink->ringbuffer))
    gst_ring_buffer_start (sink->ringbuffer);

849
  if (sink->priv->eos_time != -1) {
850
    GST_DEBUG_OBJECT (sink,
851
852
        "last sample time %" GST_TIME_FORMAT,
        GST_TIME_ARGS (sink->priv->eos_time));
853

854
855
    /* wait for the EOS time to be reached, this is the time when the last
     * sample is played. */
856
    gst_base_sink_wait_eos (GST_BASE_SINK (sink), sink->priv->eos_time, NULL);
857

858
    GST_DEBUG_OBJECT (sink, "drained audio");
859
  }
860
  g_atomic_int_set (&sink->priv->eos_rendering, 0);
861
862
863
  return TRUE;
}

864
static gboolean
865
gst_base_audio_sink_event (GstBaseSink * bsink, GstEvent * event)
866
{
867
  GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (bsink);
868
869

  switch (GST_EVENT_TYPE (event)) {
870
    case GST_EVENT_FLUSH_START:
871
872
      if (sink->ringbuffer)
        gst_ring_buffer_set_flushing (sink->ringbuffer, TRUE);
873
874
      break;
    case GST_EVENT_FLUSH_STOP:
875
      /* always resync on sample after a flush */
876
      sink->priv->avg_skew = -1;
877
      sink->next_sample = -1;
878
      sink->priv->eos_time = -1;
879
880
      if (sink->ringbuffer)
        gst_ring_buffer_set_flushing (sink->ringbuffer, FALSE);
881
      break;
882
    case GST_EVENT_EOS:
883
      /* now wait till we played everything */
884
      gst_base_audio_sink_drain (sink);
885
      break;
886
887
888
889
890
891
892
893
    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);

894
      GST_DEBUG_OBJECT (sink, "new segment rate of %f", rate);
895
896
      break;
    }
897
898
899
    default:
      break;
  }
900
  return TRUE;
901
902
903
}

static GstFlowReturn
904
gst_base_audio_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
905
{
906
  GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (bsink);
Wim Taymans's avatar
Wim Taymans committed
907

908
  if (!gst_ring_buffer_is_acquired (sink->ringbuffer))
Wim Taymans's avatar
Wim Taymans committed
909
910
    goto wrong_state;

Wim Taymans's avatar
Wim Taymans committed
911
912
913
  /* we don't really do anything when prerolling. We could make a
   * property to play this buffer to have some sort of scrubbing
   * support. */
914
  return GST_FLOW_OK;
Wim Taymans's avatar
Wim Taymans committed
915
916
917

wrong_state:
  {
918
    GST_DEBUG_OBJECT (sink, "ringbuffer in wrong state");
919
    GST_ELEMENT_ERROR (sink, STREAM, FORMAT, (NULL), ("sink not negotiated."));
920
    return GST_FLOW_NOT_NEGOTIATED;
Wim Taymans's avatar
Wim Taymans committed
921
  }
922
923
}

924
925
926
927
928
929
930
931
932
static guint64
gst_base_audio_sink_get_offset (GstBaseAudioSink * sink)
{
  guint64 sample;
  gint writeseg, segdone, sps;
  gint diff;

  /* assume we can append to the previous sample */
  sample = sink->next_sample;
933
934
935
  /* no previous sample, try to insert at position 0 */
  if (sample == -1)
    sample = 0;
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956

  sps = sink->ringbuffer->samples_per_seg;

  /* figure out the segment and the offset inside the segment where
   * the sample should be written. */
  writeseg = sample / sps;

  /* get the currently processed segment */
  segdone = g_atomic_int_get (&sink->ringbuffer->segdone)
      - sink->ringbuffer->segbase;

  /* see how far away it is from the write segment */
  diff = writeseg - segdone;
  if (diff < 0) {
    /* sample would be dropped, position to next playable position */
    sample = (segdone + 1) * sps;
  }

  return sample;
}

957
958
static GstClockTime
clock_convert_external (GstClockTime external, GstClockTime cinternal,
959
    GstClockTime cexternal, GstClockTime crate_num, GstClockTime crate_denom)
960
961
962
963
964
965
966
{
  /* adjust for rate and speed */
  if (external >= cexternal) {
    external =
        gst_util_uint64_scale (external - cexternal, crate_denom, crate_num);
    external += cinternal;
  } else {
967
968
    external =
        gst_util_uint64_scale (cexternal - external, crate_denom, crate_num);
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
    if (cinternal > external)
      external = cinternal - external;
    else
      external = 0;
  }
  return external;
}

/* algorithm to calculate sample positions that will result in resampling to
 * match the clock rate of the master */
static void
gst_base_audio_sink_resample_slaving (GstBaseAudioSink * sink,
    GstClockTime render_start, GstClockTime render_stop,
    GstClockTime * srender_start, GstClockTime * srender_stop)
{
  GstClockTime cinternal, cexternal;
  GstClockTime crate_num, crate_denom;

987
988
989
990
991
992
993
994
995
996
  /* FIXME, we can sample and add observations here or use the timeouts on the
   * clock. No idea which one is better or more stable. The timeout seems more
   * arbitrary but this one seems more demanding and does not work when there is
   * no data comming in to the sink. */
#if 0
  GstClockTime etime, itime;
  gdouble r_squared;

  /* sample clocks and figure out clock skew */
  etime = gst_clock_get_time (GST_ELEMENT_CLOCK (sink));
997
  itime = gst_audio_clock_get_time (sink->provided_clock);
998
999
1000
1001
1002

  /* add new observation */
  gst_clock_add_observation (sink->provided_clock, itime, etime, &r_squared);
#endif

1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
  /* get calibration parameters to compensate for speed and offset differences
   * when we are slaved */
  gst_clock_get_calibration (sink->provided_clock, &cinternal, &cexternal,
      &crate_num, &crate_denom);

  GST_DEBUG_OBJECT (sink, "internal %" GST_TIME_FORMAT " external %"
      GST_TIME_FORMAT " %" G_GUINT64_FORMAT "/%" G_GUINT64_FORMAT " = %f",
      GST_TIME_ARGS (cinternal), GST_TIME_ARGS (cexternal), crate_num,
      crate_denom, gst_guint64_to_gdouble (crate_num) /
      gst_guint64_to_gdouble (crate_denom));

  if (crate_num == 0)
    crate_denom = crate_num = 1;

  /* bring external time to internal time */
  render_start = clock_convert_external (render_start, cinternal, cexternal,
1019
      crate_num, crate_denom);
1020
  render_stop = clock_convert_external (render_stop, cinternal, cexternal,
1021
      crate_num, crate_denom);
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039

  GST_DEBUG_OBJECT (sink,
      "after slaving: start %" GST_TIME_FORMAT " - stop %" GST_TIME_FORMAT,
      GST_TIME_ARGS (render_start), GST_TIME_ARGS (render_stop));

  *srender_start = render_start;
  *srender_stop = render_stop;
}

/* algorithm to calculate sample positions that will result in changing the
 * playout pointer to match the clock rate of the master */
static void
gst_base_audio_sink_skew_slaving (GstBaseAudioSink * sink,
    GstClockTime render_start, GstClockTime render_stop,
    GstClockTime * srender_start, GstClockTime * srender_stop)
{
  GstClockTime cinternal, cexternal, crate_num, crate_denom;
  GstClockTime etime, itime;
1040
1041
  GstClockTimeDiff skew, mdrift, mdrift2;
  gint driftsamples;
1042
  gint64 last_align;
1043
1044
1045
1046
1047
1048
1049

  /* get calibration parameters to compensate for offsets */
  gst_clock_get_calibration (sink->provided_clock, &cinternal, &cexternal,
      &crate_num, &crate_denom);

  /* sample clocks and figure out clock skew */
  etime = gst_clock_get_time (GST_ELEMENT_CLOCK (sink));
1050
  itime = gst_audio_clock_get_time (sink->provided_clock);
1051
  itime = gst_audio_clock_adjust (sink->provided_clock, itime);
1052

1053
1054
1055
1056
1057
1058
  GST_DEBUG_OBJECT (sink,
      "internal %" GST_TIME_FORMAT " external %" GST_TIME_FORMAT
      " cinternal %" GST_TIME_FORMAT " cexternal %" GST_TIME_FORMAT,
      GST_TIME_ARGS (itime), GST_TIME_ARGS (etime),
      GST_TIME_ARGS (cinternal), GST_TIME_ARGS (cexternal));

1059
1060
1061
  /* make sure we never go below 0 */
  etime = etime > cexternal ? etime - cexternal : 0;
  itime = itime > cinternal ? itime - cinternal : 0;
1062

1063
1064
1065
  /* do itime - etime.
   * positive value means external clock goes slower
   * negative value means external clock goes faster */
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
  skew = GST_CLOCK_DIFF (etime, itime);
  if (sink->priv->avg_skew == -1) {
    /* first observation */
    sink->priv->avg_skew = skew;
  } else {
    /* next observations use a moving average */
    sink->priv->avg_skew = (31 * sink->priv->avg_skew + skew) / 32;
  }

  GST_DEBUG_OBJECT (sink, "internal %" GST_TIME_FORMAT " external %"
      GST_TIME_FORMAT " skew %" G_GINT64_FORMAT " avg %" G_GINT64_FORMAT,
      GST_TIME_ARGS (itime), GST_TIME_ARGS (etime), skew, sink->priv->avg_skew);

1079
1080
1081
  /* the max drift we allow */
  mdrift = sink->priv->drift_tolerance * 1000;
  mdrift2 = mdrift / 2;
1082
1083

  /* adjust playout pointer based on skew */
1084
  if (sink->priv->avg_skew > mdrift2) {
1085
    /* master is running slower, move internal time forward */
1086
1087
    GST_WARNING_OBJECT (sink,
        "correct clock skew %" G_GINT64_FORMAT " > %" G_GINT64_FORMAT,
1088
1089
1090
        sink->priv->avg_skew, mdrift2);
    cexternal = cexternal > mdrift ? cexternal - mdrift : 0;
    sink->priv->avg_skew -= mdrift;
1091

1092
    driftsamples = (sink->ringbuffer->spec.rate * mdrift) / GST_SECOND;
1093
1094
1095
1096
    last_align = sink->priv->last_align;

    /* if we were aligning in the wrong direction or we aligned more than what we
     * will correct, resync */
1097
    if (last_align < 0 || last_align > driftsamples)
1098
1099
1100
      sink->next_sample = -1;

    GST_DEBUG_OBJECT (sink,
1101
1102
        "last_align %" G_GINT64_FORMAT " driftsamples %u, next %"
        G_GUINT64_FORMAT, last_align, driftsamples, sink->next_sample);
1103

1104
1105
    gst_clock_set_calibration (sink->provided_clock, cinternal, cexternal,
        crate_num, crate_denom);
1106
  } else if (sink->priv->avg_skew < -mdrift2) {
1107
    /* master is running faster, move external time forwards */
1108
1109
    GST_WARNING_OBJECT (sink,
        "correct clock skew %" G_GINT64_FORMAT " < %" G_GINT64_FORMAT,
1110
1111
1112
        sink->priv->avg_skew, -mdrift2);
    cexternal += mdrift;
    sink->priv->avg_skew += mdrift;
1113

1114
    driftsamples = (sink->ringbuffer->spec.rate * mdrift) / GST_SECOND;
1115
1116
1117
1118
    last_align = sink->priv->last_align;

    /* if we were aligning in the wrong direction or we aligned more than what we
     * will correct, resync */
1119
    if (last_align > 0 || -last_align > driftsamples)
1120
1121
1122
      sink->next_sample = -1;

    GST_DEBUG_OBJECT (sink,
1123
1124
        "last_align %" G_GINT64_FORMAT " driftsamples %u, next %"
        G_GUINT64_FORMAT, last_align, driftsamples, sink->next_sample);
1125

1126
1127
1128
1129
1130
1131
    gst_clock_set_calibration (sink->provided_clock, cinternal, cexternal,
        crate_num, crate_denom);
  }

  /* convert, ignoring speed */
  render_start = clock_convert_external (render_start, cinternal, cexternal,
1132
      crate_num, crate_denom);
1133
  render_stop = clock_convert_external (render_stop, cinternal, cexternal,
1134
      crate_num, crate_denom);