gstaudioringbuffer.c 51.1 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
 * SECTION:gstaudioringbuffer
22
 * @short_description: Base class for audio ringbuffer implementations
23
 * @see_also: #GstAudioBaseSink, #GstAudioSink
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

#include <string.h>

44
#include "gstaudioringbuffer.h"
45

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

49 50
static void gst_audio_ring_buffer_dispose (GObject * object);
static void gst_audio_ring_buffer_finalize (GObject * object);
51

52 53 54
static gboolean gst_audio_ring_buffer_pause_unlocked (GstAudioRingBuffer * buf);
static void default_clear_all (GstAudioRingBuffer * buf);
static guint default_commit (GstAudioRingBuffer * buf, guint64 * sample,
55
    guint8 * data, gint in_samples, gint out_samples, gint * accum);
56

57
/* ringbuffer abstract base class */
58 59
G_DEFINE_ABSTRACT_TYPE (GstAudioRingBuffer, gst_audio_ring_buffer,
    GST_TYPE_OBJECT);
60 61

static void
62
gst_audio_ring_buffer_class_init (GstAudioRingBufferClass * klass)
63 64
{
  GObjectClass *gobject_class;
65
  GstAudioRingBufferClass *gstaudioringbuffer_class;
66 67

  gobject_class = (GObjectClass *) klass;
68
  gstaudioringbuffer_class = (GstAudioRingBufferClass *) klass;
69

70
  GST_DEBUG_CATEGORY_INIT (gst_audio_ring_buffer_debug, "ringbuffer", 0,
71
      "ringbuffer class");
72

73 74
  gobject_class->dispose = gst_audio_ring_buffer_dispose;
  gobject_class->finalize = gst_audio_ring_buffer_finalize;
75

76 77
  gstaudioringbuffer_class->clear_all = GST_DEBUG_FUNCPTR (default_clear_all);
  gstaudioringbuffer_class->commit = GST_DEBUG_FUNCPTR (default_commit);
78 79 80
}

static void
81
gst_audio_ring_buffer_init (GstAudioRingBuffer * ringbuffer)
82
{
83
  ringbuffer->open = FALSE;
84
  ringbuffer->acquired = FALSE;
85
  ringbuffer->state = GST_AUDIO_RING_BUFFER_STATE_STOPPED;
86
  g_cond_init (&ringbuffer->cond);
87 88
  ringbuffer->waiting = 0;
  ringbuffer->empty_seg = NULL;
89
  ringbuffer->flushing = TRUE;
90 91 92
}

static void
93
gst_audio_ring_buffer_dispose (GObject * object)
94
{
95
  GstAudioRingBuffer *ringbuffer = GST_AUDIO_RING_BUFFER (object);
96

97 98
  gst_caps_replace (&ringbuffer->spec.caps, NULL);

99
  G_OBJECT_CLASS (gst_audio_ring_buffer_parent_class)->dispose (G_OBJECT
100
      (ringbuffer));
101 102 103
}

static void
104
gst_audio_ring_buffer_finalize (GObject * object)
105
{
106
  GstAudioRingBuffer *ringbuffer = GST_AUDIO_RING_BUFFER (object);
107

108
  g_cond_clear (&ringbuffer->cond);
109
  g_free (ringbuffer->empty_seg);
110

111
  G_OBJECT_CLASS (gst_audio_ring_buffer_parent_class)->finalize (G_OBJECT
112
      (ringbuffer));
113 114
}

115
#ifndef GST_DISABLE_GST_DEBUG
116
static const gchar *format_type_names[] = {
Wim Taymans's avatar
Wim Taymans committed
117
  "raw",
118 119 120 121 122 123 124 125 126 127 128 129
  "mu law",
  "a law",
  "ima adpcm",
  "mpeg",
  "gsm",
  "iec958",
  "ac3",
  "eac3",
  "dts"
};
#endif

130
/**
131
 * gst_audio_ring_buffer_debug_spec_caps:
132 133 134 135
 * @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
136
void
137
gst_audio_ring_buffer_debug_spec_caps (GstAudioRingBufferSpec * spec)
Wim Taymans's avatar
Wim Taymans committed
138
{
Wim Taymans's avatar
Wim Taymans committed
139
#if 0
140
  gint i, bytes;
Wim Taymans's avatar
Wim Taymans committed
141
#endif
142

Wim Taymans's avatar
Wim Taymans committed
143
  GST_DEBUG ("spec caps: %p %" GST_PTR_FORMAT, spec->caps, spec->caps);
144 145
  GST_DEBUG ("parsed caps: type:         %d, '%s'", spec->type,
      format_type_names[spec->type]);
Wim Taymans's avatar
Wim Taymans committed
146
#if 0
Wim Taymans's avatar
Wim Taymans committed
147 148 149 150 151 152
  GST_DEBUG ("parsed caps: width:        %d", spec->width);
  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);
153 154 155 156
  bytes = (spec->width >> 3) * spec->channels;
  for (i = 0; i < bytes; i++) {
    GST_DEBUG ("silence byte %d: %02x", i, spec->silence_sample[i]);
  }
Wim Taymans's avatar
Wim Taymans committed
157
#endif
Wim Taymans's avatar
Wim Taymans committed
158 159
}

160
/**
161
 * gst_audio_ring_buffer_debug_spec_buff:
162 163 164 165
 * @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
166
void
167
gst_audio_ring_buffer_debug_spec_buff (GstAudioRingBufferSpec * spec)
Wim Taymans's avatar
Wim Taymans committed
168
{
Wim Taymans's avatar
Wim Taymans committed
169 170
  gint bpf = GST_AUDIO_INFO_BPF (&spec->info);

Wim Taymans's avatar
Wim Taymans committed
171 172 173 174 175
  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);
176
  GST_DEBUG ("acquire ringbuffer: latency segments: %d", spec->seglatency);
Wim Taymans's avatar
Wim Taymans committed
177
  GST_DEBUG ("acquire ringbuffer: segment size: %d bytes = %d samples",
Wim Taymans's avatar
Wim Taymans committed
178
      spec->segsize, spec->segsize / bpf);
Wim Taymans's avatar
Wim Taymans committed
179
  GST_DEBUG ("acquire ringbuffer: buffer size: %d bytes = %d samples",
Wim Taymans's avatar
Wim Taymans committed
180
      spec->segsize * spec->segtotal, spec->segsize * spec->segtotal / bpf);
Wim Taymans's avatar
Wim Taymans committed
181 182
}

183
/**
184
 * gst_audio_ring_buffer_parse_caps:
185 186 187 188 189 190 191
 * @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
192
gboolean
193
gst_audio_ring_buffer_parse_caps (GstAudioRingBufferSpec * spec, GstCaps * caps)
Wim Taymans's avatar
Wim Taymans committed
194 195 196
{
  const gchar *mimetype;
  GstStructure *structure;
197
  gint i;
Wim Taymans's avatar
Wim Taymans committed
198
  GstAudioInfo info;
Wim Taymans's avatar
Wim Taymans committed
199 200

  structure = gst_caps_get_structure (caps, 0);
Wim Taymans's avatar
Wim Taymans committed
201
  gst_audio_info_init (&info);
Wim Taymans's avatar
Wim Taymans committed
202 203 204 205

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

Wim Taymans's avatar
Wim Taymans committed
206 207
  if (g_str_equal (mimetype, "audio/x-raw")) {
    if (!gst_audio_info_from_caps (&info, caps))
Wim Taymans's avatar
Wim Taymans committed
208 209
      goto parse_error;

210
    spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW;
211
  } else if (g_str_equal (mimetype, "audio/x-alaw")) {
212
    /* extract the needed information from the cap */
Wim Taymans's avatar
Wim Taymans committed
213 214
    if (!(gst_structure_get_int (structure, "rate", &info.rate) &&
            gst_structure_get_int (structure, "channels", &info.channels)))
215 216
      goto parse_error;

217
    spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_A_LAW;
218
    info.bpf = info.channels;
219
  } else if (g_str_equal (mimetype, "audio/x-mulaw")) {
220
    /* extract the needed information from the cap */
Wim Taymans's avatar
Wim Taymans committed
221 222
    if (!(gst_structure_get_int (structure, "rate", &info.rate) &&
            gst_structure_get_int (structure, "channels", &info.channels)))
223 224
      goto parse_error;

225
    spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MU_LAW;
226
    info.bpf = info.channels;
227
  } else if (g_str_equal (mimetype, "audio/x-iec958")) {
228
    /* extract the needed information from the cap */
Wim Taymans's avatar
Wim Taymans committed
229
    if (!(gst_structure_get_int (structure, "rate", &info.rate)))
230 231
      goto parse_error;

232
    spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IEC958;
233
    info.bpf = 4;
234
  } else if (g_str_equal (mimetype, "audio/x-ac3")) {
235
    /* extract the needed information from the cap */
Wim Taymans's avatar
Wim Taymans committed
236
    if (!(gst_structure_get_int (structure, "rate", &info.rate)))
237 238
      goto parse_error;

239
    spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3;
240
    info.bpf = 4;
241
  } else if (g_str_equal (mimetype, "audio/x-eac3")) {
242
    /* extract the needed information from the cap */
Wim Taymans's avatar
Wim Taymans committed
243
    if (!(gst_structure_get_int (structure, "rate", &info.rate)))
244 245
      goto parse_error;

246
    spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_EAC3;
247
    info.bpf = 16;
248
  } else if (g_str_equal (mimetype, "audio/x-dts")) {
249
    /* extract the needed information from the cap */
Wim Taymans's avatar
Wim Taymans committed
250
    if (!(gst_structure_get_int (structure, "rate", &info.rate)))
251 252
      goto parse_error;

253
    spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS;
254
    info.bpf = 4;
255
  } else if (g_str_equal (mimetype, "audio/mpeg") &&
256 257 258 259
      gst_structure_get_int (structure, "mpegaudioversion", &i) &&
      (i == 1 || i == 2)) {
    /* Now we know this is MPEG-1 or MPEG-2 (non AAC) */
    /* extract the needed information from the cap */
Wim Taymans's avatar
Wim Taymans committed
260
    if (!(gst_structure_get_int (structure, "rate", &info.rate)))
261 262
      goto parse_error;

263
    spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG;
264
    info.bpf = 4;
Wim Taymans's avatar
Wim Taymans committed
265 266 267 268 269 270 271 272
  } else {
    goto parse_error;
  }

  gst_caps_replace (&spec->caps, caps);

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

273 274 275
  /* 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) */
Wim Taymans's avatar
Wim Taymans committed
276
  spec->segsize = gst_util_uint64_scale (info.rate * info.bpf,
277 278
      spec->latency_time, GST_SECOND / GST_USECOND);
  /* Round to an integer number of samples */
Wim Taymans's avatar
Wim Taymans committed
279
  spec->segsize -= spec->segsize % info.bpf;
280

Wim Taymans's avatar
Wim Taymans committed
281
  spec->segtotal = spec->buffer_time / spec->latency_time;
282 283 284
  /* leave the latency undefined now, implementations can change it but if it's
   * not changed, we assume the same value as segtotal */
  spec->seglatency = -1;
Wim Taymans's avatar
Wim Taymans committed
285

286 287
  spec->info = info;

288 289
  gst_audio_ring_buffer_debug_spec_caps (spec);
  gst_audio_ring_buffer_debug_spec_buff (spec);
Wim Taymans's avatar
Wim Taymans committed
290 291 292 293 294 295 296 297 298 299 300

  return TRUE;

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

301
/**
302 303
 * gst_audio_ring_buffer_convert:
 * @buf: the #GstAudioRingBuffer
304 305 306 307 308 309 310 311 312 313 314
 * @src_fmt: the source format
 * @src_val: the source value
 * @dest_fmt: the destination format
 * @dest_val: a location to store the converted value
 *
 * Convert @src_val in @src_fmt to the equivalent value in @dest_fmt. The result
 * will be put in @dest_val.
 *
 * Returns: TRUE if the conversion succeeded.
 */
gboolean
315
gst_audio_ring_buffer_convert (GstAudioRingBuffer * buf,
316 317
    GstFormat src_fmt, gint64 src_val, GstFormat dest_fmt, gint64 * dest_val)
{
Wim Taymans's avatar
Wim Taymans committed
318
  gboolean res;
319 320

  GST_OBJECT_LOCK (buf);
Wim Taymans's avatar
Wim Taymans committed
321 322 323
  res =
      gst_audio_info_convert (&buf->spec.info, src_fmt, src_val, dest_fmt,
      dest_val);
324 325 326 327 328
  GST_OBJECT_UNLOCK (buf);

  return res;
}

329
/**
330 331
 * gst_audio_ring_buffer_set_callback:
 * @buf: the #GstAudioRingBuffer to set the callback on
332
 * @cb: the callback to set
Thomas Vander Stichele's avatar
Thomas Vander Stichele committed
333
 * @user_data: user data passed to the callback
334 335 336 337 338 339 340
 *
 * 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
341 342
gst_audio_ring_buffer_set_callback (GstAudioRingBuffer * buf,
    GstAudioRingBufferCallback cb, gpointer user_data)
343
{
344
  g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
345

346
  GST_OBJECT_LOCK (buf);
347
  buf->callback = cb;
348
  buf->cb_data = user_data;
349
  GST_OBJECT_UNLOCK (buf);
350 351
}

352 353

/**
354 355
 * gst_audio_ring_buffer_open_device:
 * @buf: the #GstAudioRingBuffer
356 357 358 359 360 361 362 363 364 365
 *
 * 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
366
gst_audio_ring_buffer_open_device (GstAudioRingBuffer * buf)
367 368
{
  gboolean res = TRUE;
369
  GstAudioRingBufferClass *rclass;
370

371
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
372

373 374
  GST_DEBUG_OBJECT (buf, "opening device");

375
  GST_OBJECT_LOCK (buf);
376
  if (G_UNLIKELY (buf->open))
377 378
    goto was_opened;

379 380 381 382 383
  buf->open = TRUE;

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

384
  rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
385
  if (G_LIKELY (rclass->open_device))
386 387
    res = rclass->open_device (buf);

388
  if (G_UNLIKELY (!res))
389 390 391
    goto open_failed;

  GST_DEBUG_OBJECT (buf, "opened device");
392 393

done:
394
  GST_OBJECT_UNLOCK (buf);
395 396

  return res;
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411

  /* 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;
  }
412 413 414
}

/**
415 416
 * gst_audio_ring_buffer_close_device:
 * @buf: the #GstAudioRingBuffer
417 418
 *
 * Close the audio device associated with the ring buffer. The ring buffer
419
 * should already have been released via gst_audio_ring_buffer_release().
420 421 422 423 424 425
 *
 * Returns: TRUE if the device could be closed, FALSE on error.
 *
 * MT safe.
 */
gboolean
426
gst_audio_ring_buffer_close_device (GstAudioRingBuffer * buf)
427 428
{
  gboolean res = TRUE;
429
  GstAudioRingBufferClass *rclass;
430

431
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
432

433 434
  GST_DEBUG_OBJECT (buf, "closing device");

435
  GST_OBJECT_LOCK (buf);
436
  if (G_UNLIKELY (!buf->open))
437
    goto was_closed;
438

439
  if (G_UNLIKELY (buf->acquired))
440
    goto was_acquired;
441 442 443

  buf->open = FALSE;

444
  rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
445
  if (G_LIKELY (rclass->close_device))
446 447
    res = rclass->close_device (buf);

448
  if (G_UNLIKELY (!res))
449 450 451
    goto close_error;

  GST_DEBUG_OBJECT (buf, "closed device");
452 453

done:
454
  GST_OBJECT_UNLOCK (buf);
455 456

  return res;
457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478

  /* 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;
  }
479 480 481
}

/**
482 483
 * gst_audio_ring_buffer_device_is_open:
 * @buf: the #GstAudioRingBuffer
484 485 486 487 488 489 490 491
 *
 * 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
492
gst_audio_ring_buffer_device_is_open (GstAudioRingBuffer * buf)
493 494 495
{
  gboolean res = TRUE;

496
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
497

498
  GST_OBJECT_LOCK (buf);
499
  res = buf->open;
500
  GST_OBJECT_UNLOCK (buf);
501 502 503 504

  return res;
}

505
/**
506 507
 * gst_audio_ring_buffer_acquire:
 * @buf: the #GstAudioRingBuffer to acquire
508 509 510 511 512 513 514 515 516 517 518
 * @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
519 520
gst_audio_ring_buffer_acquire (GstAudioRingBuffer * buf,
    GstAudioRingBufferSpec * spec)
521 522
{
  gboolean res = FALSE;
523
  GstAudioRingBufferClass *rclass;
524
  gint segsize, bpf, i;
525

526
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
527

Wim Taymans's avatar
Wim Taymans committed
528
  GST_DEBUG_OBJECT (buf, "acquiring device %p", buf);
529

530
  GST_OBJECT_LOCK (buf);
531
  if (G_UNLIKELY (!buf->open))
532 533
    goto not_opened;

534
  if (G_UNLIKELY (buf->acquired))
535 536
    goto was_acquired;

537
  buf->acquired = TRUE;
538
  buf->need_reorder = FALSE;
539

540
  rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
541
  if (G_LIKELY (rclass->acquire))
542 543
    res = rclass->acquire (buf, spec);

544 545 546 547
  /* Only reorder for raw audio */
  buf->need_reorder = (buf->need_reorder
      && buf->spec.type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW);

548
  if (G_UNLIKELY (!res))
549
    goto acquire_failed;
550

551 552 553 554 555 556 557 558
  GST_INFO_OBJECT (buf, "Allocating an array for %d timestamps",
      spec->segtotal);
  buf->timestamps = g_slice_alloc0 (sizeof (GstClockTime) * spec->segtotal);
  /* initialize array with invalid timestamps */
  for (i = 0; i < spec->segtotal; i++) {
    buf->timestamps[i] = GST_CLOCK_TIME_NONE;
  }

Wim Taymans's avatar
Wim Taymans committed
559 560
  if (G_UNLIKELY ((bpf = buf->spec.info.bpf) == 0))
    goto invalid_bpf;
561

562 563 564 565 566
  /* if the seglatency was overwritten with something else than -1, use it, else
   * assume segtotal as the latency */
  if (buf->spec.seglatency == -1)
    buf->spec.seglatency = buf->spec.segtotal;

567 568
  segsize = buf->spec.segsize;

Wim Taymans's avatar
Wim Taymans committed
569
  buf->samples_per_seg = segsize / bpf;
570 571 572 573

  /* create an empty segment */
  g_free (buf->empty_seg);
  buf->empty_seg = g_malloc (segsize);
574

575
  if (buf->spec.type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW) {
Wim Taymans's avatar
Wim Taymans committed
576 577 578 579 580
    gst_audio_format_fill_silence (buf->spec.info.finfo, buf->empty_seg,
        segsize);
  } else {
    /* FIXME, non-raw formats get 0 as the empty sample */
    memset (buf->empty_seg, 0, segsize);
581
  }
582 583
  GST_DEBUG_OBJECT (buf, "acquired device");

584
done:
585
  GST_OBJECT_UNLOCK (buf);
586 587

  return res;
588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608

  /* 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;
  }
Wim Taymans's avatar
Wim Taymans committed
609
invalid_bpf:
610 611
  {
    g_warning
Wim Taymans's avatar
Wim Taymans committed
612
        ("invalid bytes_per_frame from acquire ringbuffer %p, fix the element",
Wim Taymans's avatar
Wim Taymans committed
613
        buf);
614 615 616 617
    buf->acquired = FALSE;
    res = FALSE;
    goto done;
  }
618 619 620
}

/**
621 622
 * gst_audio_ring_buffer_release:
 * @buf: the #GstAudioRingBuffer to release
623 624 625 626 627 628 629 630
 *
 * Free the resources of the ringbuffer.
 *
 * Returns: TRUE if the device could be released, FALSE on error.
 *
 * MT safe.
 */
gboolean
631
gst_audio_ring_buffer_release (GstAudioRingBuffer * buf)
632 633
{
  gboolean res = FALSE;
634
  GstAudioRingBufferClass *rclass;
635

636
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
637

638 639
  GST_DEBUG_OBJECT (buf, "releasing device");

640
  gst_audio_ring_buffer_stop (buf);
641

642
  GST_OBJECT_LOCK (buf);
643 644 645 646 647 648 649 650

  if (G_LIKELY (buf->timestamps)) {
    GST_INFO_OBJECT (buf, "Freeing timestamp buffer, %d entries",
        buf->spec.segtotal);
    g_slice_free1 (sizeof (GstClockTime) * buf->spec.segtotal, buf->timestamps);
    buf->timestamps = NULL;
  }

651
  if (G_UNLIKELY (!buf->acquired))
652 653
    goto was_released;

654 655
  buf->acquired = FALSE;

656 657 658
  /* if this fails, something is wrong in this file */
  g_assert (buf->open == TRUE);

659
  rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
660
  if (G_LIKELY (rclass->release))
661
    res = rclass->release (buf);
662 663

  /* signal any waiters */
664
  GST_DEBUG_OBJECT (buf, "signal waiter");
665
  GST_AUDIO_RING_BUFFER_SIGNAL (buf);
666

667
  if (G_UNLIKELY (!res))
668 669 670 671 672
    goto release_failed;

  g_free (buf->empty_seg);
  buf->empty_seg = NULL;
  GST_DEBUG_OBJECT (buf, "released device");
673 674

done:
675
  GST_OBJECT_UNLOCK (buf);
676 677

  return res;
678 679 680 681 682 683 684 685 686 687 688 689 690 691

  /* 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;
  }
692 693
}

694
/**
695 696
 * gst_audio_ring_buffer_is_acquired:
 * @buf: the #GstAudioRingBuffer to check
697 698 699 700 701 702 703 704
 *
 * Check if the ringbuffer is acquired and ready to use.
 *
 * Returns: TRUE if the ringbuffer is acquired, FALSE on error.
 *
 * MT safe.
 */
gboolean
705
gst_audio_ring_buffer_is_acquired (GstAudioRingBuffer * buf)
706 707 708
{
  gboolean res;

709
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
710

711
  GST_OBJECT_LOCK (buf);
712
  res = buf->acquired;
713
  GST_OBJECT_UNLOCK (buf);
714 715 716 717

  return res;
}

718
/**
719 720
 * gst_audio_ring_buffer_activate:
 * @buf: the #GstAudioRingBuffer to activate
721 722 723 724
 * @active: the new mode
 *
 * Activate @buf to start or stop pulling data.
 *
725 726
 * MT safe.
 *
727 728 729 730
 * Returns: TRUE if the device could be activated in the requested mode,
 * FALSE on error.
 */
gboolean
731
gst_audio_ring_buffer_activate (GstAudioRingBuffer * buf, gboolean active)
732 733
{
  gboolean res = FALSE;
734
  GstAudioRingBufferClass *rclass;
735

736
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
737 738 739 740 741 742 743

  GST_DEBUG_OBJECT (buf, "activate device");

  GST_OBJECT_LOCK (buf);
  if (G_UNLIKELY (active && !buf->acquired))
    goto not_acquired;

744
  if (G_UNLIKELY (buf->active == active))
745 746
    goto was_active;

747
  rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
748 749 750 751 752 753 754 755 756 757
  /* if there is no activate function we assume it was started/released
   * in the acquire method */
  if (G_LIKELY (rclass->activate))
    res = rclass->activate (buf, active);
  else
    res = TRUE;

  if (G_UNLIKELY (!res))
    goto activate_failed;

758
  buf->active = active;
759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786

done:
  GST_OBJECT_UNLOCK (buf);

  return res;

  /* ERRORS */
not_acquired:
  {
    GST_DEBUG_OBJECT (buf, "device not acquired");
    g_critical ("Device for %p not acquired", buf);
    res = FALSE;
    goto done;
  }
was_active:
  {
    res = TRUE;
    GST_DEBUG_OBJECT (buf, "device was active in mode %d", active);
    goto done;
  }
activate_failed:
  {
    GST_DEBUG_OBJECT (buf, "failed to activate device");
    goto done;
  }
}

/**
787 788
 * gst_audio_ring_buffer_is_active:
 * @buf: the #GstAudioRingBuffer
789 790 791
 *
 * Check if @buf is activated.
 *
792 793
 * MT safe.
 *
794 795 796
 * Returns: TRUE if the device is active.
 */
gboolean
797
gst_audio_ring_buffer_is_active (GstAudioRingBuffer * buf)
798 799 800
{
  gboolean res;

801
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
802 803

  GST_OBJECT_LOCK (buf);
804
  res = buf->active;
805 806 807 808 809 810
  GST_OBJECT_UNLOCK (buf);

  return res;
}


811
/**
812 813
 * gst_audio_ring_buffer_set_flushing:
 * @buf: the #GstAudioRingBuffer to flush
814
 * @flushing: the new mode
815 816 817 818 819 820
 *
 * Set the ringbuffer to flushing mode or normal mode.
 *
 * MT safe.
 */
void
821
gst_audio_ring_buffer_set_flushing (GstAudioRingBuffer * buf, gboolean flushing)
822
{
823
  g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
824

825
  GST_OBJECT_LOCK (buf);
826
  buf->flushing = flushing;
827 828

  if (flushing) {
829
    gst_audio_ring_buffer_pause_unlocked (buf);
830
  } else {
831
    gst_audio_ring_buffer_clear_all (buf);
832
  }
833
  GST_OBJECT_UNLOCK (buf);
834 835
}

836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859
/**
 * gst_audio_ring_buffer_is_flushing:
 * @buf: the #GstAudioRingBuffer
 *
 * Check if @buf is flushing.
 *
 * MT safe.
 *
 * Returns: TRUE if the device is flushing.
 */
gboolean
gst_audio_ring_buffer_is_flushing (GstAudioRingBuffer * buf)
{
  gboolean res;

  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), TRUE);

  GST_OBJECT_LOCK (buf);
  res = buf->flushing;
  GST_OBJECT_UNLOCK (buf);

  return res;
}

860
/**
861 862
 * gst_audio_ring_buffer_start:
 * @buf: the #GstAudioRingBuffer to start
863
 *
Wim Taymans's avatar
Wim Taymans committed
864
 * Start processing samples from the ringbuffer.
865 866 867 868 869 870
 *
 * Returns: TRUE if the device could be started, FALSE on error.
 *
 * MT safe.
 */
gboolean
871
gst_audio_ring_buffer_start (GstAudioRingBuffer * buf)
872 873
{
  gboolean res = FALSE;
874
  GstAudioRingBufferClass *rclass;
875 876
  gboolean resume = FALSE;

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

879 880
  GST_DEBUG_OBJECT (buf, "starting ringbuffer");

881
  GST_OBJECT_LOCK (buf);
882
  if (G_UNLIKELY (buf->flushing))
883 884
    goto flushing;

885 886 887
  if (G_UNLIKELY (!buf->acquired))
    goto not_acquired;

888
  if (G_UNLIKELY (g_atomic_int_get (&buf->may_start) == FALSE))
889 890
    goto may_not_start;

Wim Taymans's avatar
Wim Taymans committed
891
  /* if stopped, set to started */
892
  res = g_atomic_int_compare_and_exchange (&buf->state,
893
      GST_AUDIO_RING_BUFFER_STATE_STOPPED, GST_AUDIO_RING_BUFFER_STATE_STARTED);
894 895

  if (!res) {
896
    GST_DEBUG_OBJECT (buf, "was not stopped, try paused");
897 898
    /* was not stopped, try from paused */
    res = g_atomic_int_compare_and_exchange (&buf->state,
899 900
        GST_AUDIO_RING_BUFFER_STATE_PAUSED,
        GST_AUDIO_RING_BUFFER_STATE_STARTED);
901
    if (!res) {
Wim Taymans's avatar
Wim Taymans committed
902
      /* was not paused either, must be started then */
903
      res = TRUE;
904
      GST_DEBUG_OBJECT (buf, "was not paused, must have been started");
905 906 907
      goto done;
    }
    resume = TRUE;
908
    GST_DEBUG_OBJECT (buf, "resuming");
909 910
  }

911
  rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
912
  if (resume) {
913
    if (G_LIKELY (rclass->resume))
914 915
      res = rclass->resume</