gstbaseaudiosink.c 30.6 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/* GStreamer
 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
 *                    2005 Wim Taymans <wim@fluendo.com>
 *
 * gstbaseaudiosink.c: 
 *
 * 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

/* BaseAudioSink signals and args */
enum
{
  /* FILL ME */
  LAST_SIGNAL
};

49
/* we tollerate half a second diff before we start resyncing. This
50
 * should be enough to compensate for various rounding errors in the timestamp
51
52
53
 * and sample offset position. 
 * This is an emergency resync fallback since buffers marked as DISCONT will
 * always lock to the correct timestamp immediatly and buffers not marked as
54
 * DISCONT are contiguous by definition.
55
56
 */
#define DIFF_TOLERANCE  2
57

58
59
60
/* 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
61
#define DEFAULT_PROVIDE_CLOCK   TRUE
62

63
64
65
enum
{
  PROP_0,
66
67
  PROP_BUFFER_TIME,
  PROP_LATENCY_TIME,
68
  PROP_PROVIDE_CLOCK,
69
70
71
};

#define _do_init(bla) \
72
    GST_DEBUG_CATEGORY_INIT (gst_base_audio_sink_debug, "baseaudiosink", 0, "baseaudiosink element");
73

74
75
GST_BOILERPLATE_FULL (GstBaseAudioSink, gst_base_audio_sink, GstBaseSink,
    GST_TYPE_BASE_SINK, _do_init);
76

77
static void gst_base_audio_sink_dispose (GObject * object);
78

79
static void gst_base_audio_sink_set_property (GObject * object, guint prop_id,
80
    const GValue * value, GParamSpec * pspec);
81
static void gst_base_audio_sink_get_property (GObject * object, guint prop_id,
82
83
    GValue * value, GParamSpec * pspec);

84
85
static GstStateChangeReturn gst_base_audio_sink_async_play (GstBaseSink *
    basesink);
86
87
static GstStateChangeReturn gst_base_audio_sink_change_state (GstElement *
    element, GstStateChange transition);
88
89
static gboolean gst_base_audio_sink_activate_pull (GstBaseSink * basesink,
    gboolean active);
90

91
static GstClock *gst_base_audio_sink_provide_clock (GstElement * elem);
92
static GstClockTime gst_base_audio_sink_get_time (GstClock * clock,
93
    GstBaseAudioSink * sink);
94
95
static void gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data,
    guint len, gpointer user_data);
96

97
static GstFlowReturn gst_base_audio_sink_preroll (GstBaseSink * bsink,
98
    GstBuffer * buffer);
99
static GstFlowReturn gst_base_audio_sink_render (GstBaseSink * bsink,
100
    GstBuffer * buffer);
101
102
103
static gboolean gst_base_audio_sink_event (GstBaseSink * bsink,
    GstEvent * event);
static void gst_base_audio_sink_get_times (GstBaseSink * bsink,
104
    GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
105
106
static gboolean gst_base_audio_sink_setcaps (GstBaseSink * bsink,
    GstCaps * caps);
107
static void gst_base_audio_sink_fixate (GstBaseSink * bsink, GstCaps * caps);
108

109
/* static guint gst_base_audio_sink_signals[LAST_SIGNAL] = { 0 }; */
110
111

static void
112
gst_base_audio_sink_base_init (gpointer g_class)
113
114
115
116
{
}

static void
117
gst_base_audio_sink_class_init (GstBaseAudioSinkClass * klass)
118
119
120
121
122
123
124
125
126
127
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;
  GstBaseSinkClass *gstbasesink_class;

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

  gobject_class->set_property =
128
      GST_DEBUG_FUNCPTR (gst_base_audio_sink_set_property);
129
  gobject_class->get_property =
130
131
      GST_DEBUG_FUNCPTR (gst_base_audio_sink_get_property);
  gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_base_audio_sink_dispose);
132

133
  g_object_class_install_property (gobject_class, PROP_BUFFER_TIME,
134
135
      g_param_spec_int64 ("buffer-time", "Buffer Time",
          "Size of audio buffer in microseconds", 1,
136
          G_MAXINT64, DEFAULT_BUFFER_TIME, G_PARAM_READWRITE));
137

138
  g_object_class_install_property (gobject_class, PROP_LATENCY_TIME,
139
140
      g_param_spec_int64 ("latency-time", "Latency Time",
          "Audio latency in microseconds", 1,
141
          G_MAXINT64, DEFAULT_LATENCY_TIME, G_PARAM_READWRITE));
142

143
  g_object_class_install_property (gobject_class, PROP_PROVIDE_CLOCK,
144
145
146
      g_param_spec_boolean ("provide-clock", "Provide Clock",
          "Provide a clock to be used as the global pipeline clock",
          DEFAULT_PROVIDE_CLOCK, G_PARAM_READWRITE));
147
148

  gstelement_class->change_state =
149
      GST_DEBUG_FUNCPTR (gst_base_audio_sink_change_state);
150
151
  gstelement_class->provide_clock =
      GST_DEBUG_FUNCPTR (gst_base_audio_sink_provide_clock);
152

153
154
155
  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);
156
  gstbasesink_class->get_times =
157
158
      GST_DEBUG_FUNCPTR (gst_base_audio_sink_get_times);
  gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_base_audio_sink_setcaps);
159
  gstbasesink_class->fixate = GST_DEBUG_FUNCPTR (gst_base_audio_sink_fixate);
160
161
  gstbasesink_class->async_play =
      GST_DEBUG_FUNCPTR (gst_base_audio_sink_async_play);
162
163
  gstbasesink_class->activate_pull =
      GST_DEBUG_FUNCPTR (gst_base_audio_sink_activate_pull);
164
165
166
}

static void
167
168
gst_base_audio_sink_init (GstBaseAudioSink * baseaudiosink,
    GstBaseAudioSinkClass * g_class)
169
{
170
171
  baseaudiosink->buffer_time = DEFAULT_BUFFER_TIME;
  baseaudiosink->latency_time = DEFAULT_LATENCY_TIME;
172
  baseaudiosink->provide_clock = DEFAULT_PROVIDE_CLOCK;
173

174
  baseaudiosink->provided_clock = gst_audio_clock_new ("clock",
175
      (GstAudioClockGetTimeFunc) gst_base_audio_sink_get_time, baseaudiosink);
176
177
178

  GST_BASE_SINK (baseaudiosink)->can_activate_push = TRUE;
  GST_BASE_SINK (baseaudiosink)->can_activate_pull = TRUE;
179
180
}

181
static void
182
gst_base_audio_sink_dispose (GObject * object)
183
184
185
{
  GstBaseAudioSink *sink;

186
  sink = GST_BASE_AUDIO_SINK (object);
187

188
189
190
  if (sink->provided_clock)
    gst_object_unref (sink->provided_clock);
  sink->provided_clock = NULL;
191

192
193
194
195
  if (sink->ringbuffer) {
    gst_object_unparent (GST_OBJECT_CAST (sink->ringbuffer));
    sink->ringbuffer = NULL;
  }
196

197
198
199
  G_OBJECT_CLASS (parent_class)->dispose (object);
}

200
static GstClock *
201
gst_base_audio_sink_provide_clock (GstElement * elem)
202
203
{
  GstBaseAudioSink *sink;
204
  GstClock *clock;
205

206
  sink = GST_BASE_AUDIO_SINK (elem);
207

208
  /* we have no ringbuffer (must be NULL state) */
209
210
211
  if (sink->ringbuffer == NULL)
    goto wrong_state;

212
213
214
215
  if (!gst_ring_buffer_is_acquired (sink->ringbuffer))
    goto wrong_state;

  GST_OBJECT_LOCK (sink);
216
  if (!sink->provide_clock)
217
218
219
220
    goto clock_disabled;

  clock = GST_CLOCK_CAST (gst_object_ref (sink->provided_clock));
  GST_OBJECT_UNLOCK (sink);
221
222

  return clock;
223

224
  /* ERRORS */
225
226
227
228
229
230
231
232
233
234
235
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;
  }
236
237
238
}

static GstClockTime
239
gst_base_audio_sink_get_time (GstClock * clock, GstBaseAudioSink * sink)
240
{
241
242
  guint64 raw, samples;
  guint delay;
243
244
245
  GstClockTime result;

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

Wim Taymans's avatar
Wim Taymans committed
248
  /* our processed samples are always increasing */
249
250
251
252
253
254
255
256
257
258
  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;
259

260
261
  result = gst_util_uint64_scale_int (samples, GST_SECOND,
      sink->ringbuffer->spec.rate);
262

263
264
265
266
  GST_DEBUG_OBJECT (sink,
      "processed samples: raw %llu, delay %u, real %llu, time %"
      GST_TIME_FORMAT, raw, delay, samples, GST_TIME_ARGS (result));

267
  return result;
268
269
270
}

static void
271
gst_base_audio_sink_set_property (GObject * object, guint prop_id,
272
273
274
275
    const GValue * value, GParamSpec * pspec)
{
  GstBaseAudioSink *sink;

276
  sink = GST_BASE_AUDIO_SINK (object);
277
278

  switch (prop_id) {
279
280
    case PROP_BUFFER_TIME:
      sink->buffer_time = g_value_get_int64 (value);
281
      break;
282
283
    case PROP_LATENCY_TIME:
      sink->latency_time = g_value_get_int64 (value);
284
      break;
285
    case PROP_PROVIDE_CLOCK:
286
      GST_OBJECT_LOCK (sink);
287
      sink->provide_clock = g_value_get_boolean (value);
288
      GST_OBJECT_UNLOCK (sink);
289
      break;
290
291
292
293
294
295
296
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
297
298
gst_base_audio_sink_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
299
300
301
{
  GstBaseAudioSink *sink;

302
  sink = GST_BASE_AUDIO_SINK (object);
303
304

  switch (prop_id) {
305
306
    case PROP_BUFFER_TIME:
      g_value_set_int64 (value, sink->buffer_time);
307
      break;
308
309
    case PROP_LATENCY_TIME:
      g_value_set_int64 (value, sink->latency_time);
310
      break;
311
    case PROP_PROVIDE_CLOCK:
312
      GST_OBJECT_LOCK (sink);
313
      g_value_set_boolean (value, sink->provide_clock);
314
      GST_OBJECT_UNLOCK (sink);
315
      break;
316
317
318
319
320
321
322
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static gboolean
323
gst_base_audio_sink_setcaps (GstBaseSink * bsink, GstCaps * caps)
324
{
325
  GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (bsink);
326
327
  GstRingBufferSpec *spec;

328
329
330
  if (!sink->ringbuffer)
    return FALSE;

331
332
  spec = &sink->ringbuffer->spec;

333
  GST_DEBUG_OBJECT (sink, "release old ringbuffer");
334

Wim Taymans's avatar
Wim Taymans committed
335
  /* release old ringbuffer */
336
  gst_ring_buffer_release (sink->ringbuffer);
337

338
  GST_DEBUG_OBJECT (sink, "parse caps");
339
340
341
342

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

Wim Taymans's avatar
Wim Taymans committed
343
  /* parse new caps */
344
  if (!gst_ring_buffer_parse_caps (spec, caps))
Wim Taymans's avatar
Wim Taymans committed
345
    goto parse_error;
346

347
  gst_ring_buffer_debug_spec_buff (spec);
348

349
  GST_DEBUG_OBJECT (sink, "acquire new ringbuffer");
350

351
  if (!gst_ring_buffer_acquire (sink->ringbuffer, spec))
352
353
    goto acquire_error;

354
355
356
357
358
359
  /* calculate actual latency and buffer times. 
   * 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;
360

361
  gst_ring_buffer_debug_spec_buff (spec);
362
363

  return TRUE;
364
365
366
367

  /* ERRORS */
parse_error:
  {
368
369
    GST_DEBUG_OBJECT (sink, "could not parse caps");
    GST_ELEMENT_ERROR (sink, STREAM, FORMAT,
370
        (NULL), ("cannot parse audio format."));
371
372
373
374
    return FALSE;
  }
acquire_error:
  {
375
    GST_DEBUG_OBJECT (sink, "could not acquire ringbuffer");
376
377
    return FALSE;
  }
378
379
}

380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
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);
}

406
static void
407
gst_base_audio_sink_get_times (GstBaseSink * bsink, GstBuffer * buffer,
408
409
    GstClockTime * start, GstClockTime * end)
{
Wim Taymans's avatar
Wim Taymans committed
410
411
  /* our clock sync is a bit too much for the base class to handle so
   * we implement it ourselves. */
412
413
414
415
  *start = GST_CLOCK_TIME_NONE;
  *end = GST_CLOCK_TIME_NONE;
}

416
417
418
/* FIXME, this waits for the drain to happen but it cannot be
 * canceled.
 */
419
420
421
422
423
424
425
426
static gboolean
gst_base_audio_sink_drain (GstBaseAudioSink * sink)
{
  if (!sink->ringbuffer)
    return TRUE;
  if (!sink->ringbuffer->spec.rate)
    return TRUE;

427
428
429
430
431
432
  /* need to start playback before we can drain, but only when
   * we have successfully negotiated a format and thus aqcuired the
   * ringbuffer. */
  if (gst_ring_buffer_is_acquired (sink->ringbuffer))
    gst_ring_buffer_start (sink->ringbuffer);

433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
  if (sink->next_sample != -1) {
    GstClockTime time;
    GstClock *clock;

    time =
        gst_util_uint64_scale_int (sink->next_sample, GST_SECOND,
        sink->ringbuffer->spec.rate);

    GST_OBJECT_LOCK (sink);
    if ((clock = GST_ELEMENT_CLOCK (sink)) != NULL) {
      GstClockID id = gst_clock_new_single_shot_id (clock, time);

      GST_OBJECT_UNLOCK (sink);

      GST_DEBUG_OBJECT (sink, "waiting for last sample to play");
      gst_clock_id_wait (id, NULL);
449
450

      gst_clock_id_unref (id);
451
452
453
454
455
456
457
458
      sink->next_sample = -1;
    } else {
      GST_OBJECT_UNLOCK (sink);
    }
  }
  return TRUE;
}

459
static gboolean
460
gst_base_audio_sink_event (GstBaseSink * bsink, GstEvent * event)
461
{
462
  GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (bsink);
463
464

  switch (GST_EVENT_TYPE (event)) {
465
    case GST_EVENT_FLUSH_START:
466
467
      if (sink->ringbuffer)
        gst_ring_buffer_set_flushing (sink->ringbuffer, TRUE);
468
469
      break;
    case GST_EVENT_FLUSH_STOP:
470
471
      /* always resync on sample after a flush */
      sink->next_sample = -1;
472
473
      if (sink->ringbuffer)
        gst_ring_buffer_set_flushing (sink->ringbuffer, FALSE);
474
      break;
475
    case GST_EVENT_EOS:
476
      /* now wait till we played everything */
477
      gst_base_audio_sink_drain (sink);
478
      break;
479
480
481
482
483
484
485
486
    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);

487
      GST_DEBUG_OBJECT (sink, "new rate of %f", rate);
488
489
      break;
    }
490
491
492
    default:
      break;
  }
493
  return TRUE;
494
495
496
}

static GstFlowReturn
497
gst_base_audio_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
498
{
499
  GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (bsink);
Wim Taymans's avatar
Wim Taymans committed
500

501
  if (!gst_ring_buffer_is_acquired (sink->ringbuffer))
Wim Taymans's avatar
Wim Taymans committed
502
503
    goto wrong_state;

Wim Taymans's avatar
Wim Taymans committed
504
505
506
  /* we don't really do anything when prerolling. We could make a
   * property to play this buffer to have some sort of scrubbing
   * support. */
507
  return GST_FLOW_OK;
Wim Taymans's avatar
Wim Taymans committed
508
509
510

wrong_state:
  {
511
    GST_DEBUG_OBJECT (sink, "ringbuffer in wrong state");
512
    GST_ELEMENT_ERROR (sink, STREAM, FORMAT, (NULL), ("sink not negotiated."));
513
    return GST_FLOW_NOT_NEGOTIATED;
Wim Taymans's avatar
Wim Taymans committed
514
  }
515
516
}

517
518
519
520
521
522
523
524
525
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;
526
527
528
  /* no previous sample, try to insert at position 0 */
  if (sample == -1)
    sample = 0;
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549

  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;
}

550
static GstFlowReturn
551
gst_base_audio_sink_render (GstBaseSink * bsink, GstBuffer * buf)
552
{
553
554
  guint64 in_offset, clock_offset;
  GstClockTime time, stop, render_start, render_stop, sample_offset;
Wim Taymans's avatar
Wim Taymans committed
555
556
  GstBaseAudioSink *sink;
  GstRingBuffer *ringbuf;
557
  gint64 diff, align, ctime, cstop;
558
559
  guint8 *data;
  guint size;
560
  guint samples, written;
Wim Taymans's avatar
Wim Taymans committed
561
  gint bps;
562
  gint accum;
563
564
  GstClockTime crate_num;
  GstClockTime crate_denom;
565
  gint out_samples;
Wim Taymans's avatar
Wim Taymans committed
566
  GstClockTime cinternal, cexternal;
567
568
  GstClock *clock;
  gboolean sync;
Wim Taymans's avatar
Wim Taymans committed
569
570
571
572

  sink = GST_BASE_AUDIO_SINK (bsink);

  ringbuf = sink->ringbuffer;
573

Wim Taymans's avatar
Wim Taymans committed
574
  /* can't do anything when we don't have the device */
575
  if (G_UNLIKELY (!gst_ring_buffer_is_acquired (ringbuf)))
576
    goto wrong_state;
577

Wim Taymans's avatar
Wim Taymans committed
578
579
580
  bps = ringbuf->spec.bytes_per_sample;

  size = GST_BUFFER_SIZE (buf);
581
  if (G_UNLIKELY (size % bps) != 0)
Wim Taymans's avatar
Wim Taymans committed
582
583
584
    goto wrong_size;

  samples = size / bps;
585
  out_samples = samples;
Wim Taymans's avatar
Wim Taymans committed
586

Wim Taymans's avatar
Wim Taymans committed
587
588
  in_offset = GST_BUFFER_OFFSET (buf);
  time = GST_BUFFER_TIMESTAMP (buf);
589
590
  stop = time + gst_util_uint64_scale_int (samples, GST_SECOND,
      ringbuf->spec.rate);
Wim Taymans's avatar
Wim Taymans committed
591

592
  GST_DEBUG_OBJECT (sink,
593
594
595
      "time %" GST_TIME_FORMAT ", offset %llu, start %" GST_TIME_FORMAT
      ", samples %u", GST_TIME_ARGS (time), in_offset,
      GST_TIME_ARGS (bsink->segment.start), samples);
Wim Taymans's avatar
Wim Taymans committed
596

597
  data = GST_BUFFER_DATA (buf);
598

599
  /* if not valid timestamp or we can't clip or sync, try to play
600
   * sample ASAP */
601
  if (!GST_CLOCK_TIME_IS_VALID (time)) {
602
603
    render_start = gst_base_audio_sink_get_offset (sink);
    render_stop = render_start + samples;
604
    GST_DEBUG_OBJECT (sink,
605
606
        "Buffer of size %u has no time. Using render_start=%" G_GUINT64_FORMAT,
        GST_BUFFER_SIZE (buf), render_start);
Wim Taymans's avatar
Wim Taymans committed
607
608
609
    goto no_sync;
  }

Wim Taymans's avatar
Wim Taymans committed
610
  /* samples should be rendered based on their timestamp. All samples
611
612
613
   * arriving before the segment.start or after segment.stop are to be 
   * thrown away. All samples should also be clipped to the segment 
   * boundaries */
614
615
  /* let's calc stop based on the number of samples in the buffer instead
   * of trusting the DURATION */
616
617
  if (!gst_segment_clip (&bsink->segment, GST_FORMAT_TIME, time, stop, &ctime,
          &cstop))
Wim Taymans's avatar
Wim Taymans committed
618
    goto out_of_segment;
Wim Taymans's avatar
Wim Taymans committed
619

620
621
622
  /* see if some clipping happened */
  diff = ctime - time;
  if (diff > 0) {
623
    /* bring clipped time to samples */
624
625
626
627
    diff = gst_util_uint64_scale_int (diff, ringbuf->spec.rate, GST_SECOND);
    GST_DEBUG_OBJECT (sink, "clipping start to %" GST_TIME_FORMAT " %"
        G_GUINT64_FORMAT " samples", GST_TIME_ARGS (ctime), diff);
    samples -= diff;
628
    data += diff * bps;
629
630
631
632
    time = ctime;
  }
  diff = stop - cstop;
  if (diff > 0) {
633
    /* bring clipped time to samples */
634
635
636
637
638
639
640
    diff = gst_util_uint64_scale_int (diff, ringbuf->spec.rate, GST_SECOND);
    GST_DEBUG_OBJECT (sink, "clipping stop to %" GST_TIME_FORMAT " %"
        G_GUINT64_FORMAT " samples", GST_TIME_ARGS (cstop), diff);
    samples -= diff;
    stop = cstop;
  }

641
642
643
644
645
646
647
648
  /* figure out how to sync */
  if ((clock = GST_ELEMENT_CLOCK (bsink)))
    sync = bsink->sync;
  else
    sync = FALSE;

  if (!sync) {
    /* no sync needed, play sample ASAP */
649
650
    render_start = gst_base_audio_sink_get_offset (sink);
    render_stop = render_start + samples;
651
    GST_DEBUG_OBJECT (sink,
652
        "no sync needed. Using render_start=%" G_GUINT64_FORMAT, render_start);
653
654
655
    goto no_sync;
  }

656
657
  /* bring buffer start and stop times to running time */
  render_start =
658
      gst_segment_to_running_time (&bsink->segment, GST_FORMAT_TIME, time);
659
660
661
662
663
664
  render_stop =
      gst_segment_to_running_time (&bsink->segment, GST_FORMAT_TIME, stop);

  GST_DEBUG_OBJECT (sink,
      "running: start %" GST_TIME_FORMAT " - stop %" GST_TIME_FORMAT,
      GST_TIME_ARGS (render_start), GST_TIME_ARGS (render_stop));
665
666
667
668
669
670

  /* 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);

671
  clock_offset =
Wim Taymans's avatar
Wim Taymans committed
672
673
      (gst_element_get_base_time (GST_ELEMENT_CAST (bsink)) - cexternal) +
      cinternal;
674
675
676
677
678
679
680
681
682
683
684
685
686
687

  GST_DEBUG_OBJECT (sink, "clock offset %" GST_TIME_FORMAT " %" G_GUINT64_FORMAT
      "/%" G_GUINT64_FORMAT, GST_TIME_ARGS (clock_offset), crate_num,
      crate_denom);

  /* and bring the time to the rate corrected offset in the buffer */
  render_start = gst_util_uint64_scale_int (render_start + clock_offset,
      ringbuf->spec.rate, GST_SECOND);
  render_stop = gst_util_uint64_scale_int (render_stop + clock_offset,
      ringbuf->spec.rate, GST_SECOND);

  GST_DEBUG_OBJECT (sink,
      "render: start %" GST_TIME_FORMAT " - stop %" GST_TIME_FORMAT,
      GST_TIME_ARGS (render_start), GST_TIME_ARGS (render_stop));
688
689
690

  /* always resync after a discont */
  if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT))) {
691
    GST_DEBUG_OBJECT (sink, "resync after discont");
692
693
694
    goto no_align;
  }

695
696
697
698
699
700
  if (G_UNLIKELY (sink->next_sample == -1)) {
    GST_DEBUG_OBJECT (sink,
        "no align possible: no previous sample position known");
    goto no_align;
  }

701
702
703
704
705
  if (bsink->segment.rate >= 1.0)
    sample_offset = render_start;
  else
    sample_offset = render_stop;

706
  /* now try to align the sample to the previous one */
707
708
  if (sample_offset >= sink->next_sample)
    diff = sample_offset - sink->next_sample;
709
  else
710
    diff = sink->next_sample - sample_offset;
711
712
713
714
715

  /* we tollerate half a second diff before we start resyncing. This
   * should be enough to compensate for various rounding errors in the timestamp
   * and sample offset position. We always resync if we got a discont anyway and
   * non-discont should be aligned by definition. */
716
  if (G_LIKELY (diff < ringbuf->spec.rate / DIFF_TOLERANCE)) {
717
    GST_DEBUG_OBJECT (sink,
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
718
        "align with prev sample, %" G_GINT64_FORMAT " < %d", diff,
719
        ringbuf->spec.rate / DIFF_TOLERANCE);
720
721
    /* calc align with previous sample */
    align = sink->next_sample - sample_offset;
722
  } else {
723
724
    /* bring sample diff to seconds for error message */
    diff = gst_util_uint64_scale_int (diff, GST_SECOND, ringbuf->spec.rate);
725
726
    /* timestamps drifted apart from previous samples too much, we need to
     * resync. We log this as an element warning. */
Wim Taymans's avatar
Wim Taymans committed
727
728
729
730
731
    GST_ELEMENT_WARNING (sink, CORE, CLOCK,
        ("Compensating for audio synchronisation problems"),
        ("Unexpected discontinuity in audio timestamps of more "
            "than half a second (%" GST_TIME_FORMAT "), resyncing",
            GST_TIME_ARGS (diff)));
732
    align = 0;
733
  }
Wim Taymans's avatar
Wim Taymans committed
734

735
736
  /* apply alignment */
  render_start += align;
737

738
739
740
741
  /* only align stop if we are not slaved */
  if (clock != sink->provided_clock) {
    GST_DEBUG_OBJECT (sink, "no stop time align needed: we are slaved");
    goto no_align;
742
  }
743
  render_stop += align;
744

745
746
747
no_align:
  /* number of target samples is difference between start and stop */
  out_samples = render_stop - render_start;
748

749
750
751
no_sync:
  GST_DEBUG_OBJECT (sink, "rendering at %" G_GUINT64_FORMAT " %d/%d",
      sink->next_sample, samples, out_samples);
752

753
754
755
756
757
  /* we render the first or last sample first, depending on the rate */
  if (bsink->segment.rate >= 1.0)
    sample_offset = render_start;
  else
    sample_offset = render_stop;
Wim Taymans's avatar
Wim Taymans committed
758

759
760
  /* we need to accumulate over different runs for when we get interrupted */
  accum = 0;
761
  do {
762
    written =
763
764
        gst_ring_buffer_commit_full (ringbuf, &sample_offset, data, samples,
        out_samples, &accum);
765

766
    GST_DEBUG_OBJECT (sink, "wrote %u of %u", written, samples);
767
768
769
770
    /* if we wrote all, we're done */
    if (written == samples)
      break;

771
772
    /* else something interrupted us and we wait for preroll. */
    if (gst_base_sink_wait_preroll (bsink) != GST_FLOW_OK)
773
774
775
776
777
      goto stopping;

    samples -= written;
    data += written * bps;
  } while (TRUE);
Wim Taymans's avatar
Wim Taymans committed
778

779
780
  sink->next_sample = sample_offset;

781
782
783
  GST_DEBUG_OBJECT (sink, "next sample expected at %" G_GUINT64_FORMAT,
      sink->next_sample);

784
785
786
  if (GST_CLOCK_TIME_IS_VALID (stop) && stop >= bsink->segment.stop) {
    GST_DEBUG_OBJECT (sink,
        "start playback because we are at the end of segment");
Wim Taymans's avatar
Wim Taymans committed
787
788
    gst_ring_buffer_start (ringbuf);
  }
789
790

  return GST_FLOW_OK;
791

792
  /* SPECIAL cases */
Wim Taymans's avatar
Wim Taymans committed
793
794
out_of_segment:
  {
795
796
797
798
    GST_DEBUG_OBJECT (sink,
        "dropping sample out of segment time %" GST_TIME_FORMAT ", start %"
        GST_TIME_FORMAT, GST_TIME_ARGS (time),
        GST_TIME_ARGS (bsink->segment.start));
Wim Taymans's avatar
Wim Taymans committed
799
800
    return GST_FLOW_OK;
  }
801
  /* ERRORS */
802
803
wrong_state:
  {
804
    GST_DEBUG_OBJECT (sink, "ringbuffer not negotiated");
805
    GST_ELEMENT_ERROR (sink, STREAM, FORMAT, (NULL), ("sink not negotiated."));
806
    return GST_FLOW_NOT_NEGOTIATED;
807
  }
Wim Taymans's avatar
Wim Taymans committed
808
809
wrong_size:
  {
810
    GST_DEBUG_OBJECT (sink, "wrong size");
811
812
    GST_ELEMENT_ERROR (sink, STREAM, WRONG_TYPE,
        (NULL), ("sink received buffer of wrong size."));
Wim Taymans's avatar
Wim Taymans committed
813
814
    return GST_FLOW_ERROR;
  }
815
816
817
818
819
stopping:
  {
    GST_DEBUG_OBJECT (sink, "ringbuffer is stopping");
    return GST_FLOW_WRONG_STATE;
  }
820
821
}

Wim Taymans's avatar
Wim Taymans committed
822
823
824
825
826
827
828
829
830
831
/**
 * gst_base_audio_sink_create_ringbuffer:
 * @sink: a #GstBaseAudioSink.
 *
 * Create and return the #GstRingBuffer for @sink. This function will call the
 * ::create_ringbuffer vmethod and will set @sink as the parent of the returned
 * buffer (see gst_object_set_parent()).
 *
 * Returns: The new ringbuffer of @sink.
 */
832
GstRingBuffer *
833
gst_base_audio_sink_create_ringbuffer (GstBaseAudioSink * sink)
834
835
836
837
{
  GstBaseAudioSinkClass *bclass;
  GstRingBuffer *buffer = NULL;

838
  bclass = GST_BASE_AUDIO_SINK_GET_CLASS (sink);
839
840
841
  if (bclass->create_ringbuffer)
    buffer = bclass->create_ringbuffer (sink);

842
  if (buffer)
843
844
845
846
847
    gst_object_set_parent (GST_OBJECT (buffer), GST_OBJECT (sink));

  return buffer;
}

848
849
850
851
852
853
854
855
856
static gboolean
gst_base_audio_sink_activate_pull (GstBaseSink * basesink, gboolean active)
{
  gboolean ret;
  GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (basesink);

  if (active) {
    gst_ring_buffer_set_callback (sink->ringbuffer,
        gst_base_audio_sink_callback, sink);
857
    ret = gst_ring_buffer_start (sink->ringbuffer);
858
859
860
861
862
863
864
865
866
  } else {
    gst_ring_buffer_set_callback (sink->ringbuffer, NULL, NULL);
    /* stop thread */
    ret = gst_ring_buffer_release (sink->ringbuffer);
  }

  return ret;
}

867
static void
868
gst_base_audio_sink_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
869
    gpointer user_data)
870
{
871
872
873
874
875
  GstBaseSink *basesink;
  GstBaseAudioSink *sink;
  GstBuffer *buf;
  GstFlowReturn ret;

876
877
  basesink = GST_BASE_SINK (user_data);
  sink = GST_BASE_AUDIO_SINK (user_data);
878
879
880
881
882
883
884
885
886
887
888
889
890
891

  /* would be nice to arrange for pad_alloc_buffer to return data -- as it is we
     will copy twice, once into data, once into DMA */
  GST_LOG_OBJECT (basesink, "pulling %d bytes to fill audio buffer", len);
  ret = gst_pad_pull_range (basesink->sinkpad, basesink->offset, len, &buf);
  if (ret != GST_FLOW_OK)
    goto error;

  if (len != GST_BUFFER_SIZE (buf)) {
    GST_INFO_OBJECT (basesink, "short read pulling from sink pad: %d<%d",
        len, GST_BUFFER_SIZE (buf));
    len = MIN (GST_BUFFER_SIZE (buf), len);
  }

892
893
  basesink->offset += len;

894
895
896
897
898
899
900
901
902
903
  memcpy (data, GST_BUFFER_DATA (buf), len);

  return;

error:
  {
    GST_WARNING_OBJECT (basesink, "Got flow error but can't return it: %d",
        ret);
    return;
  }
904
905
}

906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
/* should be called with the LOCK */
static GstStateChangeReturn
gst_base_audio_sink_async_play (GstBaseSink * basesink)
{
  GstClock *clock;
  GstClockTime time, base;
  GstBaseAudioSink *sink;

  sink = GST_BASE_AUDIO_SINK (basesink);

  GST_DEBUG_OBJECT (sink, "ringbuffer may start now");
  gst_ring_buffer_may_start (sink->ringbuffer, TRUE);

  clock = GST_ELEMENT_CLOCK (sink);
  if (clock == NULL)
    goto no_clock;

  /* FIXME, only start slaving when we really start the ringbuffer */
  /* if we are slaved to a clock, we need to set the initial
   * calibration */
  if (clock != sink->provided_clock) {
    GstClockTime rate_num, rate_denom;

    base = GST_ELEMENT_CAST (sink)->base_time;
    time = gst_clock_get_internal_time (sink->provided_clock);

    GST_DEBUG_OBJECT (sink,
        "time: %" GST_TIME_FORMAT " base: %" GST_TIME_FORMAT,
        GST_TIME_ARGS (time), GST_TIME_ARGS (base));

    /* FIXME, this is not yet accurate enough for smooth playback */
    gst_clock_get_calibration (sink->provided_clock, NULL, NULL, &rate_num,
        &rate_denom);
    /* Does not work yet. */
    gst_clock_set_calibration (sink->provided_clock, time, base,
        rate_num, rate_denom);

    gst_clock_set_master (sink->provided_clock, clock);
  }

no_clock:
  return GST_STATE_CHANGE_SUCCESS;
}

static GstStateChangeReturn
gst_base_audio_sink_do_play (GstBaseAudioSink * sink)
{
  GstStateChangeReturn ret;

  GST_OBJECT_LOCK (sink);
  ret = gst_base_audio_sink_async_play (GST_BASE_SINK_CAST (sink));
  GST_OBJECT_UNLOCK (sink);

  return ret;
}

962
963
964
static GstStateChangeReturn
gst_base_audio_sink_change_state (GstElement * element,
    GstStateChange transition)
965
{
966
  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
967
  GstBaseAudioSink *sink = GST_BASE_AUDIO_SINK (element);
968
969

  switch (transition) {
970
    case GST_STATE_CHANGE_NULL_TO_READY:
971
972
973
      if (sink->ringbuffer == NULL) {
        sink->ringbuffer = gst_base_audio_sink_create_ringbuffer (sink);
      }
974
      if (!gst_ring_buffer_open_device (sink->ringbuffer))
975
        goto open_failed;
976
      break;
977
    case GST_STATE_CHANGE_READY_TO_PAUSED:
978
      sink->next_sample = -1;
979
980
      gst_ring_buffer_set_flushing (sink->ringbuffer, FALSE);
      gst_ring_buffer_may_start (sink->ringbuffer, FALSE);
981
      break;
982
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
983
      gst_base_audio_sink_do_play (sink);
Wim Taymans's avatar
Wim Taymans committed
984
      break;
985
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
986
987
988
      /* need to take the lock so we don't interfere with an
       * async play */
      GST_OBJECT_LOCK (sink);
989
990
      /* ringbuffer cannot start anymore */
      gst_ring_buffer_may_start (sink->ringbuffer, FALSE);
991
      gst_ring_buffer_pause (sink->ringbuffer);
992
      GST_OBJECT_UNLOCK (sink);
993
      break;
Wim Taymans's avatar
Wim Taymans committed
994
    case GST_STATE_CHANGE_PAUSED_TO_READY:
995
996
      /* make sure we unblock before calling the parent state change
       * so it can grab the STREAM_LOCK */
Wim Taymans's avatar
Wim Taymans committed
997
      gst_ring_buffer_set_flushing (sink->ringbuffer, TRUE);
998
999
1000
      break;
    default:
      break;
For faster browsing, not all history is shown. View entire blame