gstringbuffer.c 35.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/* GStreamer
 * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
 *
 * 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.
 */
19

20
21
22
/**
 * SECTION:gstringbuffer
 * @short_description: Base class for audio ringbuffer implementations
23
 * @see_also: gstbaseaudiosink
24
 *
25
26
 * <refsect2>
 * <para>
27
28
 * This object is the base class for audio ringbuffers used by the base
 * audio source and sink classes.
29
30
31
 * </para>
 * <para>
 * The ringbuffer abstracts a circular buffer of data. One reader and
32
 * one writer can operate on the data from different threads in a lockfree
33
 * manner. The base class is sufficiently flexible to be used as an
34
 * abstraction for DMA based ringbuffers as well as a pure software
35
36
37
38
39
 * implementations.
 * </para>
 * </refsect2>
 *
 * Last reviewed on 2006-02-02 (0.10.4)
40
 */
41
42
43
44
45

#include <string.h>

#include "gstringbuffer.h"

46
47
GST_DEBUG_CATEGORY_STATIC (gst_ring_buffer_debug);
#define GST_CAT_DEFAULT gst_ring_buffer_debug
48

49
50
51
52
static void gst_ring_buffer_class_init (GstRingBufferClass * klass);
static void gst_ring_buffer_init (GstRingBuffer * ringbuffer);
static void gst_ring_buffer_dispose (GObject * object);
static void gst_ring_buffer_finalize (GObject * object);
53

54
55
static gboolean gst_ring_buffer_pause_unlocked (GstRingBuffer * buf);

56
57
58
59
static GstObjectClass *parent_class = NULL;

/* ringbuffer abstract base class */
GType
60
gst_ring_buffer_get_type (void)
61
62
63
{
  static GType ringbuffer_type = 0;

64
  if (G_UNLIKELY (!ringbuffer_type)) {
65
66
67
68
    static const GTypeInfo ringbuffer_info = {
      sizeof (GstRingBufferClass),
      NULL,
      NULL,
69
      (GClassInitFunc) gst_ring_buffer_class_init,
70
71
72
73
      NULL,
      NULL,
      sizeof (GstRingBuffer),
      0,
74
      (GInstanceInitFunc) gst_ring_buffer_init,
75
76
77
78
79
      NULL
    };

    ringbuffer_type = g_type_register_static (GST_TYPE_OBJECT, "GstRingBuffer",
        &ringbuffer_info, G_TYPE_FLAG_ABSTRACT);
80

81
    GST_DEBUG_CATEGORY_INIT (gst_ring_buffer_debug, "ringbuffer", 0,
82
        "ringbuffer class");
83
84
85
86
87
  }
  return ringbuffer_type;
}

static void
88
gst_ring_buffer_class_init (GstRingBufferClass * klass)
89
90
91
92
93
94
95
{
  GObjectClass *gobject_class;
  GstObjectClass *gstobject_class;

  gobject_class = (GObjectClass *) klass;
  gstobject_class = (GstObjectClass *) klass;

96
  parent_class = g_type_class_peek_parent (klass);
97

98
99
  gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_ring_buffer_dispose);
  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_ring_buffer_finalize);
100
101
102
}

static void
103
gst_ring_buffer_init (GstRingBuffer * ringbuffer)
104
{
105
  ringbuffer->open = FALSE;
106
  ringbuffer->acquired = FALSE;
107
  ringbuffer->state = GST_RING_BUFFER_STATE_STOPPED;
108
  ringbuffer->cond = g_cond_new ();
109
110
  ringbuffer->waiting = 0;
  ringbuffer->empty_seg = NULL;
111
  ringbuffer->abidata.ABI.flushing = TRUE;
112
113
114
}

static void
115
gst_ring_buffer_dispose (GObject * object)
116
{
117
  GstRingBuffer *ringbuffer = GST_RING_BUFFER (object);
118

119
120
  gst_caps_replace (&ringbuffer->spec.caps, NULL);

121
122
123
124
  G_OBJECT_CLASS (parent_class)->dispose (G_OBJECT (ringbuffer));
}

static void
125
gst_ring_buffer_finalize (GObject * object)
126
{
127
  GstRingBuffer *ringbuffer = GST_RING_BUFFER (object);
128
129

  g_cond_free (ringbuffer->cond);
130
  g_free (ringbuffer->empty_seg);
131
132
133
134

  G_OBJECT_CLASS (parent_class)->finalize (G_OBJECT (ringbuffer));
}

135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
static const int linear_formats[4 * 2 * 2] = {
  GST_S8,
  GST_S8,
  GST_U8,
  GST_U8,
  GST_S16_LE,
  GST_S16_BE,
  GST_U16_LE,
  GST_U16_BE,
  GST_S24_LE,
  GST_S24_BE,
  GST_U24_LE,
  GST_U24_BE,
  GST_S32_LE,
  GST_S32_BE,
  GST_U32_LE,
  GST_U32_BE
Wim Taymans's avatar
Wim Taymans committed
152
153
};

154
155
156
157
158
159
160
161
162
163
164
165
166
static const int linear24_formats[3 * 2 * 2] = {
  GST_S24_3LE,
  GST_S24_3BE,
  GST_U24_3LE,
  GST_U24_3BE,
  GST_S20_3LE,
  GST_S20_3BE,
  GST_U20_3LE,
  GST_U20_3BE,
  GST_S18_3LE,
  GST_S18_3BE,
  GST_U18_3LE,
  GST_U18_3BE,
Wim Taymans's avatar
Wim Taymans committed
167
168
};

169
static GstBufferFormat
Wim Taymans's avatar
Wim Taymans committed
170
171
build_linear_format (int depth, int width, int unsignd, int big_endian)
{
172
  const gint *formats;
173

Wim Taymans's avatar
Wim Taymans committed
174
175
176
  if (width == 24) {
    switch (depth) {
      case 24:
177
        formats = &linear24_formats[0];
Wim Taymans's avatar
Wim Taymans committed
178
179
        break;
      case 20:
180
        formats = &linear24_formats[4];
Wim Taymans's avatar
Wim Taymans committed
181
182
        break;
      case 18:
183
        formats = &linear24_formats[8];
Wim Taymans's avatar
Wim Taymans committed
184
185
186
187
188
189
190
        break;
      default:
        return GST_UNKNOWN;
    }
  } else {
    switch (depth) {
      case 8:
191
        formats = &linear_formats[0];
Wim Taymans's avatar
Wim Taymans committed
192
193
        break;
      case 16:
194
        formats = &linear_formats[4];
Wim Taymans's avatar
Wim Taymans committed
195
196
        break;
      case 24:
197
        formats = &linear_formats[8];
Wim Taymans's avatar
Wim Taymans committed
198
199
        break;
      case 32:
200
        formats = &linear_formats[12];
Wim Taymans's avatar
Wim Taymans committed
201
202
203
204
205
        break;
      default:
        return GST_UNKNOWN;
    }
  }
206
207
208
209
  if (unsignd)
    formats += 2;
  if (big_endian)
    formats += 1;
210
  return (GstBufferFormat) * formats;
Wim Taymans's avatar
Wim Taymans committed
211
212
}

213
214
215
216
217
218
/**
 * gst_ring_buffer_debug_spec_caps:
 * @spec: the spec to debug
 *
 * Print debug info about the parsed caps in @spec to the debug log.
 */
Wim Taymans's avatar
Wim Taymans committed
219
void
220
gst_ring_buffer_debug_spec_caps (GstRingBufferSpec * spec)
Wim Taymans's avatar
Wim Taymans committed
221
222
223
224
225
226
227
228
229
230
231
232
233
{
  GST_DEBUG ("spec caps: %p %" GST_PTR_FORMAT, spec->caps, spec->caps);
  GST_DEBUG ("parsed caps: type:         %d", spec->type);
  GST_DEBUG ("parsed caps: format:       %d", spec->format);
  GST_DEBUG ("parsed caps: width:        %d", spec->width);
  GST_DEBUG ("parsed caps: depth:        %d", spec->depth);
  GST_DEBUG ("parsed caps: sign:         %d", spec->sign);
  GST_DEBUG ("parsed caps: bigend:       %d", spec->bigend);
  GST_DEBUG ("parsed caps: rate:         %d", spec->rate);
  GST_DEBUG ("parsed caps: channels:     %d", spec->channels);
  GST_DEBUG ("parsed caps: sample bytes: %d", spec->bytes_per_sample);
}

234
235
236
237
238
239
/**
 * gst_ring_buffer_debug_spec_buff:
 * @spec: the spec to debug
 *
 * Print debug info about the buffer sized in @spec to the debug log.
 */
Wim Taymans's avatar
Wim Taymans committed
240
void
241
gst_ring_buffer_debug_spec_buff (GstRingBufferSpec * spec)
Wim Taymans's avatar
Wim Taymans committed
242
243
244
245
246
247
248
249
250
251
252
253
254
{
  GST_DEBUG ("acquire ringbuffer: buffer time: %" G_GINT64_FORMAT " usec",
      spec->buffer_time);
  GST_DEBUG ("acquire ringbuffer: latency time: %" G_GINT64_FORMAT " usec",
      spec->latency_time);
  GST_DEBUG ("acquire ringbuffer: total segments: %d", spec->segtotal);
  GST_DEBUG ("acquire ringbuffer: segment size: %d bytes = %d samples",
      spec->segsize, spec->segsize / spec->bytes_per_sample);
  GST_DEBUG ("acquire ringbuffer: buffer size: %d bytes = %d samples",
      spec->segsize * spec->segtotal,
      spec->segsize * spec->segtotal / spec->bytes_per_sample);
}

255
256
257
258
259
260
261
262
263
/**
 * gst_ring_buffer_parse_caps:
 * @spec: a spec
 * @caps: a #GstCaps
 *
 * Parse @caps into @spec.
 *
 * Returns: TRUE if the caps could be parsed.
 */
Wim Taymans's avatar
Wim Taymans committed
264
gboolean
265
gst_ring_buffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps)
Wim Taymans's avatar
Wim Taymans committed
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
{
  const gchar *mimetype;
  GstStructure *structure;

  structure = gst_caps_get_structure (caps, 0);

  /* we have to differentiate between int and float formats */
  mimetype = gst_structure_get_name (structure);

  if (!strncmp (mimetype, "audio/x-raw-int", 15)) {
    gint endianness;

    spec->type = GST_BUFTYPE_LINEAR;

    /* extract the needed information from the cap */
    if (!(gst_structure_get_int (structure, "width", &spec->width) &&
            gst_structure_get_int (structure, "depth", &spec->depth) &&
            gst_structure_get_boolean (structure, "signed", &spec->sign)))
      goto parse_error;

    /* extract endianness if needed */
    if (spec->width > 8) {
      if (!gst_structure_get_int (structure, "endianness", &endianness))
        goto parse_error;
    } else {
      endianness = G_BYTE_ORDER;
    }

    spec->bigend = endianness == G_LITTLE_ENDIAN ? FALSE : TRUE;

296
297
    spec->format =
        build_linear_format (spec->depth, spec->width, spec->sign ? 0 : 1,
Wim Taymans's avatar
Wim Taymans committed
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
        spec->bigend ? 1 : 0);
  } else if (!strncmp (mimetype, "audio/x-raw-float", 17)) {

    spec->type = GST_BUFTYPE_FLOAT;

    /* get layout */
    if (!gst_structure_get_int (structure, "width", &spec->width))
      goto parse_error;

    /* match layout to format wrt to endianness */
    switch (spec->width) {
      case 32:
        spec->format =
            G_BYTE_ORDER == G_LITTLE_ENDIAN ? GST_FLOAT32_LE : GST_FLOAT32_BE;
        break;
      case 64:
        spec->format =
            G_BYTE_ORDER == G_LITTLE_ENDIAN ? GST_FLOAT64_LE : GST_FLOAT64_BE;
        break;
      default:
        goto parse_error;
    }
  } else if (!strncmp (mimetype, "audio/x-alaw", 12)) {
    spec->type = GST_BUFTYPE_A_LAW;
    spec->format = GST_A_LAW;
323
324
    spec->width = 8;
    spec->depth = 8;
Wim Taymans's avatar
Wim Taymans committed
325
326
327
  } else if (!strncmp (mimetype, "audio/x-mulaw", 13)) {
    spec->type = GST_BUFTYPE_MU_LAW;
    spec->format = GST_MU_LAW;
328
329
    spec->width = 8;
    spec->depth = 8;
Wim Taymans's avatar
Wim Taymans committed
330
331
332
333
  } else {
    goto parse_error;
  }

334
335
336
337
338
  /* get rate and channels */
  if (!(gst_structure_get_int (structure, "rate", &spec->rate) &&
          gst_structure_get_int (structure, "channels", &spec->channels)))
    goto parse_error;

Wim Taymans's avatar
Wim Taymans committed
339
340
341
342
343
344
  spec->bytes_per_sample = (spec->width >> 3) * spec->channels;

  gst_caps_replace (&spec->caps, caps);

  g_return_val_if_fail (spec->latency_time != 0, FALSE);

345
346
347
348
349
350
351
352
  /* calculate suggested segsize and segtotal. segsize should be one unit
   * of 'latency_time' samples, scaling for the fact that latency_time is
   * currently stored in microseconds (FIXME: in 0.11) */
  spec->segsize = gst_util_uint64_scale (spec->rate * spec->bytes_per_sample,
      spec->latency_time, GST_SECOND / GST_USECOND);
  /* Round to an integer number of samples */
  spec->segsize -= spec->segsize % spec->bytes_per_sample;

Wim Taymans's avatar
Wim Taymans committed
353
354
  spec->segtotal = spec->buffer_time / spec->latency_time;

355
356
  gst_ring_buffer_debug_spec_caps (spec);
  gst_ring_buffer_debug_spec_buff (spec);
Wim Taymans's avatar
Wim Taymans committed
357
358
359
360
361
362
363
364
365
366
367

  return TRUE;

  /* ERRORS */
parse_error:
  {
    GST_DEBUG ("could not parse caps");
    return FALSE;
  }
}

368
/**
369
 * gst_ring_buffer_set_callback:
370
371
 * @buf: the #GstRingBuffer to set the callback on
 * @cb: the callback to set
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
372
 * @user_data: user data passed to the callback
373
374
375
376
377
378
379
 *
 * Sets the given callback function on the buffer. This function
 * will be called every time a segment has been written to a device.
 *
 * MT safe.
 */
void
380
gst_ring_buffer_set_callback (GstRingBuffer * buf, GstRingBufferCallback cb,
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
381
    gpointer user_data)
382
{
383
  g_return_if_fail (GST_IS_RING_BUFFER (buf));
384

385
  GST_OBJECT_LOCK (buf);
386
  buf->callback = cb;
387
  buf->cb_data = user_data;
388
  GST_OBJECT_UNLOCK (buf);
389
390
}

391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411

/**
 * gst_ring_buffer_open_device:
 * @buf: the #GstRingBuffer
 *
 * Open the audio device associated with the ring buffer. Does not perform any
 * setup on the device. You must open the device before acquiring the ring
 * buffer.
 *
 * Returns: TRUE if the device could be opened, FALSE on error.
 *
 * MT safe.
 */
gboolean
gst_ring_buffer_open_device (GstRingBuffer * buf)
{
  gboolean res = TRUE;
  GstRingBufferClass *rclass;

  g_return_val_if_fail (GST_IS_RING_BUFFER (buf), FALSE);

412
413
  GST_DEBUG_OBJECT (buf, "opening device");

414
  GST_OBJECT_LOCK (buf);
415
  if (G_UNLIKELY (buf->open))
416
417
    goto was_opened;

418
419
420
421
422
423
  buf->open = TRUE;

  /* if this fails, something is wrong in this file */
  g_assert (!buf->acquired);

  rclass = GST_RING_BUFFER_GET_CLASS (buf);
424
  if (G_LIKELY (rclass->open_device))
425
426
    res = rclass->open_device (buf);

427
  if (G_UNLIKELY (!res))
428
429
430
    goto open_failed;

  GST_DEBUG_OBJECT (buf, "opened device");
431
432

done:
433
  GST_OBJECT_UNLOCK (buf);
434
435

  return res;
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450

  /* ERRORS */
was_opened:
  {
    GST_DEBUG_OBJECT (buf, "Device for ring buffer already open");
    g_warning ("Device for ring buffer %p already open, fix your code", buf);
    res = TRUE;
    goto done;
  }
open_failed:
  {
    buf->open = FALSE;
    GST_DEBUG_OBJECT (buf, "failed opening device");
    goto done;
  }
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
}

/**
 * gst_ring_buffer_close_device:
 * @buf: the #GstRingBuffer
 *
 * Close the audio device associated with the ring buffer. The ring buffer
 * should already have been released via gst_ring_buffer_release().
 *
 * Returns: TRUE if the device could be closed, FALSE on error.
 *
 * MT safe.
 */
gboolean
gst_ring_buffer_close_device (GstRingBuffer * buf)
{
  gboolean res = TRUE;
  GstRingBufferClass *rclass;

  g_return_val_if_fail (GST_IS_RING_BUFFER (buf), FALSE);

472
473
  GST_DEBUG_OBJECT (buf, "closing device");

474
  GST_OBJECT_LOCK (buf);
475
  if (G_UNLIKELY (!buf->open))
476
    goto was_closed;
477

478
  if (G_UNLIKELY (buf->acquired))
479
    goto was_acquired;
480
481
482
483

  buf->open = FALSE;

  rclass = GST_RING_BUFFER_GET_CLASS (buf);
484
  if (G_LIKELY (rclass->close_device))
485
486
    res = rclass->close_device (buf);

487
  if (G_UNLIKELY (!res))
488
489
490
    goto close_error;

  GST_DEBUG_OBJECT (buf, "closed device");
491
492

done:
493
  GST_OBJECT_UNLOCK (buf);
494
495

  return res;
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517

  /* ERRORS */
was_closed:
  {
    GST_DEBUG_OBJECT (buf, "Device for ring buffer already closed");
    g_warning ("Device for ring buffer %p already closed, fix your code", buf);
    res = TRUE;
    goto done;
  }
was_acquired:
  {
    GST_DEBUG_OBJECT (buf, "Resources for ring buffer still acquired");
    g_critical ("Resources for ring buffer %p still acquired", buf);
    res = FALSE;
    goto done;
  }
close_error:
  {
    buf->open = TRUE;
    GST_DEBUG_OBJECT (buf, "error closing device");
    goto done;
  }
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
}

/**
 * gst_ring_buffer_device_is_open:
 * @buf: the #GstRingBuffer
 *
 * Checks the status of the device associated with the ring buffer.
 *
 * Returns: TRUE if the device was open, FALSE if it was closed.
 *
 * MT safe.
 */
gboolean
gst_ring_buffer_device_is_open (GstRingBuffer * buf)
{
  gboolean res = TRUE;

  g_return_val_if_fail (GST_IS_RING_BUFFER (buf), FALSE);

537
  GST_OBJECT_LOCK (buf);
538
  res = buf->open;
539
  GST_OBJECT_UNLOCK (buf);
540
541
542
543
544

  return res;
}


545
/**
546
 * gst_ring_buffer_acquire:
547
548
549
550
551
552
553
554
555
556
557
558
 * @buf: the #GstRingBuffer to acquire
 * @spec: the specs of the buffer
 *
 * Allocate the resources for the ringbuffer. This function fills
 * in the data pointer of the ring buffer with a valid #GstBuffer
 * to which samples can be written.
 *
 * Returns: TRUE if the device could be acquired, FALSE on error.
 *
 * MT safe.
 */
gboolean
559
gst_ring_buffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
560
561
562
{
  gboolean res = FALSE;
  GstRingBufferClass *rclass;
563
564
  gint i, j;
  gint segsize, bps;
565

566
  g_return_val_if_fail (GST_IS_RING_BUFFER (buf), FALSE);
567

568
569
  GST_DEBUG_OBJECT (buf, "acquiring device");

570
  GST_OBJECT_LOCK (buf);
571
  if (G_UNLIKELY (!buf->open))
572
573
    goto not_opened;

574
  if (G_UNLIKELY (buf->acquired))
575
576
    goto was_acquired;

577
578
  buf->acquired = TRUE;

579
  rclass = GST_RING_BUFFER_GET_CLASS (buf);
580
  if (G_LIKELY (rclass->acquire))
581
582
    res = rclass->acquire (buf, spec);

583
  if (G_UNLIKELY (!res))
584
    goto acquire_failed;
585

586
  if (G_UNLIKELY ((bps = buf->spec.bytes_per_sample) == 0))
587
    goto invalid_bps;
588

589
590
591
592
593
594
595
596
597
598
  segsize = buf->spec.segsize;

  buf->samples_per_seg = segsize / bps;

  /* create an empty segment */
  g_free (buf->empty_seg);
  buf->empty_seg = g_malloc (segsize);
  for (i = 0, j = 0; i < segsize; i++) {
    buf->empty_seg[i] = buf->spec.silence_sample[j];
    j = (j + 1) % bps;
599
  }
600
601
  GST_DEBUG_OBJECT (buf, "acquired device");

602
done:
603
  GST_OBJECT_UNLOCK (buf);
604
605

  return res;
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634

  /* ERRORS */
not_opened:
  {
    GST_DEBUG_OBJECT (buf, "device not opened");
    g_critical ("Device for %p not opened", buf);
    res = FALSE;
    goto done;
  }
was_acquired:
  {
    res = TRUE;
    GST_DEBUG_OBJECT (buf, "device was acquired");
    goto done;
  }
acquire_failed:
  {
    buf->acquired = FALSE;
    GST_DEBUG_OBJECT (buf, "failed to acquire device");
    goto done;
  }
invalid_bps:
  {
    g_warning
        ("invalid bytes_per_sample from acquire ringbuffer, fix the element");
    buf->acquired = FALSE;
    res = FALSE;
    goto done;
  }
635
636
637
}

/**
638
 * gst_ring_buffer_release:
639
640
641
642
643
644
645
646
647
 * @buf: the #GstRingBuffer to release
 *
 * Free the resources of the ringbuffer.
 *
 * Returns: TRUE if the device could be released, FALSE on error.
 *
 * MT safe.
 */
gboolean
648
gst_ring_buffer_release (GstRingBuffer * buf)
649
650
651
652
{
  gboolean res = FALSE;
  GstRingBufferClass *rclass;

653
  g_return_val_if_fail (GST_IS_RING_BUFFER (buf), FALSE);
654

655
656
  GST_DEBUG_OBJECT (buf, "releasing device");

657
  gst_ring_buffer_stop (buf);
658

659
  GST_OBJECT_LOCK (buf);
660
  if (G_UNLIKELY (!buf->acquired))
661
662
    goto was_released;

663
664
  buf->acquired = FALSE;

665
666
667
  /* if this fails, something is wrong in this file */
  g_assert (buf->open == TRUE);

668
  rclass = GST_RING_BUFFER_GET_CLASS (buf);
669
  if (G_LIKELY (rclass->release))
670
    res = rclass->release (buf);
671
672

  /* signal any waiters */
673
  GST_DEBUG_OBJECT (buf, "signal waiter");
674
  GST_RING_BUFFER_SIGNAL (buf);
675

676
  if (G_UNLIKELY (!res))
677
678
679
680
681
    goto release_failed;

  g_free (buf->empty_seg);
  buf->empty_seg = NULL;
  GST_DEBUG_OBJECT (buf, "released device");
682
683

done:
684
  GST_OBJECT_UNLOCK (buf);
685
686

  return res;
687
688
689
690
691
692
693
694
695
696
697
698
699
700

  /* ERRORS */
was_released:
  {
    res = TRUE;
    GST_DEBUG_OBJECT (buf, "device was released");
    goto done;
  }
release_failed:
  {
    buf->acquired = TRUE;
    GST_DEBUG_OBJECT (buf, "failed to release device");
    goto done;
  }
701
702
}

703
/**
704
 * gst_ring_buffer_is_acquired:
705
706
707
708
709
710
711
712
713
 * @buf: the #GstRingBuffer to check
 *
 * Check if the ringbuffer is acquired and ready to use.
 *
 * Returns: TRUE if the ringbuffer is acquired, FALSE on error.
 *
 * MT safe.
 */
gboolean
714
gst_ring_buffer_is_acquired (GstRingBuffer * buf)
715
716
717
{
  gboolean res;

718
  g_return_val_if_fail (GST_IS_RING_BUFFER (buf), FALSE);
719

720
  GST_OBJECT_LOCK (buf);
721
  res = buf->acquired;
722
  GST_OBJECT_UNLOCK (buf);
723
724
725
726

  return res;
}

727
728
729
/**
 * gst_ring_buffer_set_flushing:
 * @buf: the #GstRingBuffer to flush
730
 * @flushing: the new mode
731
732
733
734
735
736
737
738
 *
 * Set the ringbuffer to flushing mode or normal mode.
 *
 * MT safe.
 */
void
gst_ring_buffer_set_flushing (GstRingBuffer * buf, gboolean flushing)
{
739
740
  g_return_if_fail (GST_IS_RING_BUFFER (buf));

741
  GST_OBJECT_LOCK (buf);
742
  buf->abidata.ABI.flushing = flushing;
743
744
745
746
747

  gst_ring_buffer_clear_all (buf);
  if (flushing) {
    gst_ring_buffer_pause_unlocked (buf);
  }
748
  GST_OBJECT_UNLOCK (buf);
749
750
}

751
/**
752
 * gst_ring_buffer_start:
Wim Taymans's avatar
Wim Taymans committed
753
 * @buf: the #GstRingBuffer to start
754
 *
Wim Taymans's avatar
Wim Taymans committed
755
 * Start processing samples from the ringbuffer.
756
757
758
759
760
761
 *
 * Returns: TRUE if the device could be started, FALSE on error.
 *
 * MT safe.
 */
gboolean
762
gst_ring_buffer_start (GstRingBuffer * buf)
763
764
765
{
  gboolean res = FALSE;
  GstRingBufferClass *rclass;
766
767
  gboolean resume = FALSE;

768
  g_return_val_if_fail (GST_IS_RING_BUFFER (buf), FALSE);
769

770
771
  GST_DEBUG_OBJECT (buf, "starting ringbuffer");

772
  GST_OBJECT_LOCK (buf);
773
  if (G_UNLIKELY (buf->abidata.ABI.flushing))
774
775
    goto flushing;

Wim Taymans's avatar
Wim Taymans committed
776
  /* if stopped, set to started */
777
  res = g_atomic_int_compare_and_exchange (&buf->state,
778
      GST_RING_BUFFER_STATE_STOPPED, GST_RING_BUFFER_STATE_STARTED);
779
780

  if (!res) {
781
782
    /* was not stopped, try from paused */
    res = g_atomic_int_compare_and_exchange (&buf->state,
783
        GST_RING_BUFFER_STATE_PAUSED, GST_RING_BUFFER_STATE_STARTED);
784
    if (!res) {
Wim Taymans's avatar
Wim Taymans committed
785
      /* was not paused either, must be started then */
786
      res = TRUE;
787
      GST_DEBUG_OBJECT (buf, "was started");
788
789
790
      goto done;
    }
    resume = TRUE;
791
    GST_DEBUG_OBJECT (buf, "resuming");
792
793
  }

794
  rclass = GST_RING_BUFFER_GET_CLASS (buf);
795
  if (resume) {
796
    if (G_LIKELY (rclass->resume))
797
798
      res = rclass->resume (buf);
  } else {
799
    if (G_LIKELY (rclass->start))
Wim Taymans's avatar
Wim Taymans committed
800
      res = rclass->start (buf);
801
  }
802

803
  if (G_UNLIKELY (!res)) {
804
    buf->state = GST_RING_BUFFER_STATE_PAUSED;
805
806
807
    GST_DEBUG_OBJECT (buf, "failed to start");
  } else {
    GST_DEBUG_OBJECT (buf, "started");
808
  }
809

810
done:
811
  GST_OBJECT_UNLOCK (buf);
812
813

  return res;
814
815
816

flushing:
  {
817
    GST_OBJECT_UNLOCK (buf);
818
819
    return FALSE;
  }
820
821
}

822
823
static gboolean
gst_ring_buffer_pause_unlocked (GstRingBuffer * buf)
824
825
826
827
{
  gboolean res = FALSE;
  GstRingBufferClass *rclass;

828
829
  GST_DEBUG_OBJECT (buf, "pausing ringbuffer");

Wim Taymans's avatar
Wim Taymans committed
830
  /* if started, set to paused */
831
  res = g_atomic_int_compare_and_exchange (&buf->state,
832
      GST_RING_BUFFER_STATE_STARTED, GST_RING_BUFFER_STATE_PAUSED);
833

834
835
836
837
838
839
  if (!res)
    goto not_started;

  /* signal any waiters */
  GST_DEBUG_OBJECT (buf, "signal waiter");
  GST_RING_BUFFER_SIGNAL (buf);
840

841
  rclass = GST_RING_BUFFER_GET_CLASS (buf);
842
  if (G_LIKELY (rclass->pause))
843
    res = rclass->pause (buf);
844

845
  if (G_UNLIKELY (!res)) {
846
    buf->state = GST_RING_BUFFER_STATE_STARTED;
847
848
849
    GST_DEBUG_OBJECT (buf, "failed to pause");
  } else {
    GST_DEBUG_OBJECT (buf, "paused");
850
  }
851

852
  return res;
853
854
855
856
857
858
859

not_started:
  {
    /* was not started */
    GST_DEBUG_OBJECT (buf, "was not started");
    return TRUE;
  }
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
}

/**
 * gst_ring_buffer_pause:
 * @buf: the #GstRingBuffer to pause
 *
 * Pause processing samples from the ringbuffer.
 *
 * Returns: TRUE if the device could be paused, FALSE on error.
 *
 * MT safe.
 */
gboolean
gst_ring_buffer_pause (GstRingBuffer * buf)
{
  gboolean res = FALSE;

877
  g_return_val_if_fail (GST_IS_RING_BUFFER (buf), FALSE);
878

879
  GST_OBJECT_LOCK (buf);
880
  if (G_UNLIKELY (buf->abidata.ABI.flushing))
881
882
883
    goto flushing;

  res = gst_ring_buffer_pause_unlocked (buf);
884
  GST_OBJECT_UNLOCK (buf);
885
886

  return res;
887
888
889

flushing:
  {
890
    GST_OBJECT_UNLOCK (buf);
891
892
    return FALSE;
  }
893
894
895
}

/**
896
 * gst_ring_buffer_stop:
897
898
 * @buf: the #GstRingBuffer to stop
 *
Wim Taymans's avatar
Wim Taymans committed
899
 * Stop processing samples from the ringbuffer.
900
901
902
903
904
905
 *
 * Returns: TRUE if the device could be stopped, FALSE on error.
 *
 * MT safe.
 */
gboolean
906
gst_ring_buffer_stop (GstRingBuffer * buf)
907
908
909
910
{
  gboolean res = FALSE;
  GstRingBufferClass *rclass;

911
  g_return_val_if_fail (GST_IS_RING_BUFFER (buf), FALSE);
912

913
914
  GST_DEBUG_OBJECT (buf, "stopping");

915
  GST_OBJECT_LOCK (buf);
916

Wim Taymans's avatar
Wim Taymans committed
917
  /* if started, set to stopped */
918
  res = g_atomic_int_compare_and_exchange (&buf->state,
919
      GST_RING_BUFFER_STATE_STARTED, GST_RING_BUFFER_STATE_STOPPED);
920
921

  if (!res) {
Wim Taymans's avatar
Wim Taymans committed
922
    /* was not started, must be stopped then */
923
    GST_DEBUG_OBJECT (buf, "was not started");
924
925
926
927
928
    res = TRUE;
    goto done;
  }

  /* signal any waiters */
929
  GST_DEBUG_OBJECT (buf, "signal waiter");
930
  GST_RING_BUFFER_SIGNAL (buf);
931

932
  rclass = GST_RING_BUFFER_GET_CLASS (buf);
933
  if (G_LIKELY (rclass->stop))
934
935
    res = rclass->stop (buf);

936
  if (G_UNLIKELY (!res)) {
937
    buf->state = GST_RING_BUFFER_STATE_STARTED;
938
939
940
    GST_DEBUG_OBJECT (buf, "failed to stop");
  } else {
    GST_DEBUG_OBJECT (buf, "stopped");
941
942
  }
done:
943
  GST_OBJECT_UNLOCK (buf);
944
945
946
947
948

  return res;
}

/**
949
 * gst_ring_buffer_delay:
950
951
952
953
954
955
956
957
958
959
960
961
 * @buf: the #GstRingBuffer to query
 *
 * Get the number of samples queued in the audio device. This is
 * usually less than the segment size but can be bigger when the
 * implementation uses another internal buffer between the audio
 * device.
 *
 * Returns: The number of samples queued in the audio device.
 *
 * MT safe.
 */
guint
962
gst_ring_buffer_delay (GstRingBuffer * buf)
963
964
{
  GstRingBufferClass *rclass;
965
  guint res;
966

967
  g_return_val_if_fail (GST_IS_RING_BUFFER (buf), 0);
968

969
970
971
  res = 0;

  /* buffer must be acquired */
972
  if (G_UNLIKELY (!gst_ring_buffer_is_acquired (buf)))
973
    goto done;
974

975
  rclass = GST_RING_BUFFER_GET_CLASS (buf);
976
  if (G_LIKELY (rclass->delay))
977
978
    res = rclass->delay (buf);

979
done:
980
981
982
983
  return res;
}

/**
984
 * gst_ring_buffer_samples_done:
985
986
 * @buf: the #GstRingBuffer to query
 *
Wim Taymans's avatar
Wim Taymans committed
987
 * Get the number of samples that were processed by the ringbuffer
988
989
 * since it was last started.
 *
Wim Taymans's avatar
Wim Taymans committed
990
 * Returns: The number of samples processed by the ringbuffer.
991
992
993
994
 *
 * MT safe.
 */
guint64
995
gst_ring_buffer_samples_done (GstRingBuffer * buf)
996
{
Wim Taymans's avatar
Wim Taymans committed
997
  gint segdone;
998
  guint64 raw, samples;
999
1000
  guint delay;

1001
  g_return_val_if_fail (GST_IS_RING_BUFFER (buf), 0);
1002

Wim Taymans's avatar
Wim Taymans committed
1003
1004
  /* get the amount of segments we processed */
  segdone = g_atomic_int_get (&buf->segdone);
1005

Wim Taymans's avatar
Wim Taymans committed
1006
  /* and the number of samples not yet processed */
1007
  delay = gst_ring_buffer_delay (buf);
1008

1009
  raw = samples = ((guint64) segdone) * buf->samples_per_seg;
1010

1011
  if (G_LIKELY (samples >= delay))
1012
    samples -= delay;
1013
1014
  else
    samples = 0;
1015

1016
1017
  GST_DEBUG_OBJECT (buf, "processed samples: raw %llu, delay %u, real %llu",
      raw, delay, samples);
1018
1019
1020
1021

  return samples;
}

1022
/**
1023
 * gst_ring_buffer_set_sample:
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
 * @buf: the #GstRingBuffer to use
 * @sample: the sample number to set
 *
 * Make sure that the next sample written to the device is
 * accounted for as being the @sample sample written to the
 * device. This value will be used in reporting the current
 * sample position of the ringbuffer.
 *
 * This function will also clear the buffer with silence.
 *
 * MT safe.
 */
Andy Wingo's avatar
Andy Wingo committed
1036
1037
void
gst_ring_buffer_set_sample (GstRingBuffer * buf, guint64 sample)
1038
{
1039
  g_return_if_fail (GST_IS_RING_BUFFER (buf));
1040
1041
1042
1043

  if (sample == -1)
    sample = 0;

1044
  if (G_UNLIKELY (buf->samples_per_seg == 0))
Wim Taymans's avatar
Wim Taymans committed
1045
1046
    return;

1047
1048
  /* FIXME, we assume the ringbuffer can restart at a random 
   * position, round down to the beginning and keep track of
Wim Taymans's avatar
Wim Taymans committed
1049
   * offset when calculating the processed samples. */
Wim Taymans's avatar
Wim Taymans committed
1050
  buf->segbase = buf->segdone - sample / buf->samples_per_seg;
1051

1052
1053
  gst_ring_buffer_clear_all (buf);

1054
1055
  GST_DEBUG_OBJECT (buf, "set sample to %llu, segbase %d", sample,
      buf->segbase);
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
}

/**
 * gst_ring_buffer_clear_all:
 * @buf: the #GstRingBuffer to clear
 *
 * Fill the ringbuffer with silence.
 *
 * MT safe.
 */
Andy Wingo's avatar
Andy Wingo committed
1066
1067
void
gst_ring_buffer_clear_all (GstRingBuffer * buf)
1068
1069
1070
{
  gint i;

1071
  g_return_if_fail (GST_IS_RING_BUFFER (buf));
1072
1073

  /* not fatal, we just are not negotiated yet */
1074
  if (G_UNLIKELY (buf->spec.segtotal <= 0))
1075
    return;
1076

1077
  GST_DEBUG_OBJECT (buf, "clear all segments");
1078

1079
  for (i = 0; i < buf->spec.segtotal; i++) {
1080
    gst_ring_buffer_clear (buf, i);
1081
1082
1083
  }
}

1084

Andy Wingo's avatar
Andy Wingo committed
1085
1086
static gboolean
wait_segment (GstRingBuffer * buf)
1087
{
Wim Taymans's avatar
Wim Taymans committed
1088
  /* buffer must be started now or we deadlock since nobody is reading */
1089
1090
  if (G_UNLIKELY (g_atomic_int_get (&buf->state) !=
          GST_RING_BUFFER_STATE_STARTED)) {
1091
1092
1093
1094
    /* see if we are allowed to start it */
    if (G_UNLIKELY (g_atomic_int_get (&buf->abidata.ABI.may_start) == FALSE))
      goto no_start;

1095
    GST_DEBUG_OBJECT (buf, "start!");
1096
    gst_ring_buffer_start (buf);
1097
1098
1099
  }

  /* take lock first, then update our waiting flag */
1100
  GST_OBJECT_LOCK (buf);
1101
  if (G_UNLIKELY (buf->abidata.ABI.flushing))
1102
1103
    goto flushing;

1104
1105
1106
1107
  if (G_UNLIKELY (g_atomic_int_get (&buf->state) !=
          GST_RING_BUFFER_STATE_STARTED))
    goto not_started;

1108
  if (g_atomic_int_compare_and_exchange (&buf->waiting, 0, 1)) {
1109
    GST_DEBUG_OBJECT (buf, "waiting..");
1110
    GST_RING_BUFFER_WAIT (buf);
1111
1112

    if (G_UNLIKELY (buf->abidata.ABI.flushing))