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

#include <string.h>

#include "gstbaseaudiosrc.h"

27
28
GST_DEBUG_CATEGORY_STATIC (gst_base_audio_src_debug);
#define GST_CAT_DEFAULT gst_base_audio_src_debug
Wim Taymans's avatar
Wim Taymans committed
29
30
31
32
33
34
35
36

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

37
38
39
#define DEFAULT_BUFFER_TIME     ((200 * GST_MSECOND) / GST_USECOND)
#define DEFAULT_LATENCY_TIME    ((10 * GST_MSECOND) / GST_USECOND)

Wim Taymans's avatar
Wim Taymans committed
40
41
42
43
44
45
46
47
enum
{
  PROP_0,
  PROP_BUFFER_TIME,
  PROP_LATENCY_TIME,
};

#define _do_init(bla) \
48
    GST_DEBUG_CATEGORY_INIT (gst_base_audio_src_debug, "baseaudiosrc", 0, "baseaudiosrc element");
Wim Taymans's avatar
Wim Taymans committed
49

50
GST_BOILERPLATE_FULL (GstBaseAudioSrc, gst_base_audio_src, GstPushSrc,
51
    GST_TYPE_PUSH_SRC, _do_init);
Wim Taymans's avatar
Wim Taymans committed
52

53
static void gst_base_audio_src_set_property (GObject * object, guint prop_id,
Wim Taymans's avatar
Wim Taymans committed
54
    const GValue * value, GParamSpec * pspec);
55
static void gst_base_audio_src_get_property (GObject * object, guint prop_id,
Wim Taymans's avatar
Wim Taymans committed
56
57
    GValue * value, GParamSpec * pspec);

58
static void gst_base_audio_src_fixate (GstPad * pad, GstCaps * caps);
Wim Taymans's avatar
Wim Taymans committed
59

60
61
static GstStateChangeReturn gst_base_audio_src_change_state (GstElement *
    element, GstStateChange transition);
Wim Taymans's avatar
Wim Taymans committed
62

63
static GstClock *gst_base_audio_src_provide_clock (GstElement * elem);
64
65
static gboolean gst_base_audio_src_set_clock (GstElement * elem,
    GstClock * clock);
66
static GstClockTime gst_base_audio_src_get_time (GstClock * clock,
Wim Taymans's avatar
Wim Taymans committed
67
68
    GstBaseAudioSrc * src);

69
70
71
static GstFlowReturn gst_base_audio_src_create (GstBaseSrc * bsrc,
    guint64 offset, guint length, GstBuffer ** buf);
static gboolean gst_base_audio_src_check_get_range (GstBaseSrc * bsrc);
Wim Taymans's avatar
Wim Taymans committed
72

73
74
static gboolean gst_base_audio_src_event (GstBaseSrc * bsrc, GstEvent * event);
static void gst_base_audio_src_get_times (GstBaseSrc * bsrc,
Wim Taymans's avatar
Wim Taymans committed
75
    GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
76
static gboolean gst_base_audio_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps);
Wim Taymans's avatar
Wim Taymans committed
77

78
//static guint gst_base_audio_src_signals[LAST_SIGNAL] = { 0 };
Wim Taymans's avatar
Wim Taymans committed
79
80

static void
81
gst_base_audio_src_base_init (gpointer g_class)
Wim Taymans's avatar
Wim Taymans committed
82
83
84
85
{
}

static void
86
gst_base_audio_src_class_init (GstBaseAudioSrcClass * klass)
Wim Taymans's avatar
Wim Taymans committed
87
88
89
90
91
92
93
94
95
96
97
98
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;
  GstBaseSrcClass *gstbasesrc_class;
  GstPushSrcClass *gstpushsrc_class;

  gobject_class = (GObjectClass *) klass;
  gstelement_class = (GstElementClass *) klass;
  gstbasesrc_class = (GstBaseSrcClass *) klass;
  gstpushsrc_class = (GstPushSrcClass *) klass;

  gobject_class->set_property =
99
      GST_DEBUG_FUNCPTR (gst_base_audio_src_set_property);
Wim Taymans's avatar
Wim Taymans committed
100
  gobject_class->get_property =
101
      GST_DEBUG_FUNCPTR (gst_base_audio_src_get_property);
Wim Taymans's avatar
Wim Taymans committed
102

103
104
105
  g_object_class_install_property (gobject_class, PROP_BUFFER_TIME,
      g_param_spec_int64 ("buffer-time", "Buffer Time",
          "Size of audio buffer in microseconds", 1,
106
          G_MAXINT64, DEFAULT_BUFFER_TIME, G_PARAM_READWRITE));
107
108
109
110

  g_object_class_install_property (gobject_class, PROP_LATENCY_TIME,
      g_param_spec_int64 ("latency-time", "Latency Time",
          "Audio latency in microseconds", 1,
111
          G_MAXINT64, DEFAULT_LATENCY_TIME, G_PARAM_READWRITE));
Wim Taymans's avatar
Wim Taymans committed
112
113

  gstelement_class->change_state =
114
      GST_DEBUG_FUNCPTR (gst_base_audio_src_change_state);
115
116
  gstelement_class->provide_clock =
      GST_DEBUG_FUNCPTR (gst_base_audio_src_provide_clock);
117
118
  gstelement_class->set_clock =
      GST_DEBUG_FUNCPTR (gst_base_audio_src_set_clock);
Wim Taymans's avatar
Wim Taymans committed
119

120
121
122
123
  gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_base_audio_src_setcaps);
  gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_base_audio_src_event);
  gstbasesrc_class->get_times =
      GST_DEBUG_FUNCPTR (gst_base_audio_src_get_times);
124
125
126
  gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_base_audio_src_create);
  gstbasesrc_class->check_get_range =
      GST_DEBUG_FUNCPTR (gst_base_audio_src_check_get_range);
Wim Taymans's avatar
Wim Taymans committed
127
128
129
}

static void
130
131
gst_base_audio_src_init (GstBaseAudioSrc * baseaudiosrc,
    GstBaseAudioSrcClass * g_class)
Wim Taymans's avatar
Wim Taymans committed
132
133
134
{
  baseaudiosrc->buffer_time = DEFAULT_BUFFER_TIME;
  baseaudiosrc->latency_time = DEFAULT_LATENCY_TIME;
135
136
137
  /* reset blocksize we use latency time to calculate a more useful 
   * value based on negotiated format. */
  GST_BASE_SRC (baseaudiosrc)->blocksize = 0;
Wim Taymans's avatar
Wim Taymans committed
138
139

  baseaudiosrc->clock = gst_audio_clock_new ("clock",
140
      (GstAudioClockGetTimeFunc) gst_base_audio_src_get_time, baseaudiosrc);
Wim Taymans's avatar
Wim Taymans committed
141
142

  gst_pad_set_fixatecaps_function (GST_BASE_SRC_PAD (baseaudiosrc),
143
      gst_base_audio_src_fixate);
144

145
  /* we are always a live source */
146
  gst_base_src_set_live (GST_BASE_SRC (baseaudiosrc), TRUE);
147
  gst_base_src_set_format (GST_BASE_SRC (baseaudiosrc), GST_FORMAT_TIME);
Wim Taymans's avatar
Wim Taymans committed
148
149
}

150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
static gboolean
gst_base_audio_src_set_clock (GstElement * elem, GstClock * clock)
{
  GstBaseAudioSrc *src;

  src = GST_BASE_AUDIO_SRC (elem);

  /* FIXME, we cannot slave to another clock yet, better fail 
   * than to give a bad user experience (tm). */
  if (clock && clock != src->clock)
    goto wrong_clock;

  return TRUE;

  /* ERRORS */
wrong_clock:
  {
    GST_ELEMENT_ERROR (src, CORE, CLOCK,
        (NULL), ("Cannot operate with this clock."));
    return FALSE;
  }
}

Wim Taymans's avatar
Wim Taymans committed
173
static GstClock *
174
gst_base_audio_src_provide_clock (GstElement * elem)
Wim Taymans's avatar
Wim Taymans committed
175
176
{
  GstBaseAudioSrc *src;
177
  GstClock *clock;
Wim Taymans's avatar
Wim Taymans committed
178

179
  src = GST_BASE_AUDIO_SRC (elem);
Wim Taymans's avatar
Wim Taymans committed
180

181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
  /* we have no ringbuffer (must be NULL state) */
  if (src->ringbuffer == NULL)
    goto wrong_state;

  if (!gst_ring_buffer_is_acquired (src->ringbuffer))
    goto wrong_state;

  clock = GST_CLOCK_CAST (gst_object_ref (src->clock));

  return clock;

  /* ERRORS */
wrong_state:
  {
    GST_DEBUG_OBJECT (src, "ringbuffer not acquired");
    return NULL;
  }
Wim Taymans's avatar
Wim Taymans committed
198
199
200
}

static GstClockTime
201
gst_base_audio_src_get_time (GstClock * clock, GstBaseAudioSrc * src)
Wim Taymans's avatar
Wim Taymans committed
202
203
204
205
{
  guint64 samples;
  GstClockTime result;

206
207
  if (G_UNLIKELY (src->ringbuffer == NULL || src->ringbuffer->spec.rate == 0))
    return GST_CLOCK_TIME_NONE;
Wim Taymans's avatar
Wim Taymans committed
208

209
  samples = gst_ring_buffer_samples_done (src->ringbuffer);
Wim Taymans's avatar
Wim Taymans committed
210

211
212
  result = gst_util_uint64_scale_int (samples, GST_SECOND,
      src->ringbuffer->spec.rate);
Wim Taymans's avatar
Wim Taymans committed
213
214
215
216

  return result;
}

217
218
219
220
221
222
223
224
225
226
static gboolean
gst_base_audio_src_check_get_range (GstBaseSrc * bsrc)
{
  /* we allow limited pull base operation of which the details
   * will eventually exposed in an as of yet non-existing query.
   * Basically pulling can be done on any number of bytes as long
   * as the offset is -1 or sequentially increasing. */
  return TRUE;
}

Wim Taymans's avatar
Wim Taymans committed
227
static void
228
gst_base_audio_src_set_property (GObject * object, guint prop_id,
Wim Taymans's avatar
Wim Taymans committed
229
230
231
232
    const GValue * value, GParamSpec * pspec)
{
  GstBaseAudioSrc *src;

233
  src = GST_BASE_AUDIO_SRC (object);
Wim Taymans's avatar
Wim Taymans committed
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248

  switch (prop_id) {
    case PROP_BUFFER_TIME:
      src->buffer_time = g_value_get_int64 (value);
      break;
    case PROP_LATENCY_TIME:
      src->latency_time = g_value_get_int64 (value);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
249
250
gst_base_audio_src_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
Wim Taymans's avatar
Wim Taymans committed
251
252
253
{
  GstBaseAudioSrc *src;

254
  src = GST_BASE_AUDIO_SRC (object);
Wim Taymans's avatar
Wim Taymans committed
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269

  switch (prop_id) {
    case PROP_BUFFER_TIME:
      g_value_set_int64 (value, src->buffer_time);
      break;
    case PROP_LATENCY_TIME:
      g_value_set_int64 (value, src->latency_time);
      break;
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
270
gst_base_audio_src_fixate (GstPad * pad, GstCaps * caps)
Wim Taymans's avatar
Wim Taymans committed
271
272
273
274
275
{
  GstStructure *s;

  s = gst_caps_get_structure (caps, 0);

276
277
278
279
  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, "depth", 16);
  gst_structure_fixate_field_nearest_int (s, "width", 16);
Wim Taymans's avatar
Wim Taymans committed
280
  gst_structure_set (s, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
281
  if (gst_structure_has_field (s, "endianness"))
282
    gst_structure_fixate_field_nearest_int (s, "endianness", G_BYTE_ORDER);
Wim Taymans's avatar
Wim Taymans committed
283
284
285
}

static gboolean
286
gst_base_audio_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
Wim Taymans's avatar
Wim Taymans committed
287
{
288
  GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc);
Wim Taymans's avatar
Wim Taymans committed
289
290
291
292
293
294
295
  GstRingBufferSpec *spec;

  spec = &src->ringbuffer->spec;

  spec->buffer_time = src->buffer_time;
  spec->latency_time = src->latency_time;

296
  if (!gst_ring_buffer_parse_caps (spec, caps))
Wim Taymans's avatar
Wim Taymans committed
297
298
299
300
301
302
303
304
305
    goto parse_error;

  /* calculate suggested segsize and segtotal */
  spec->segsize =
      spec->rate * spec->bytes_per_sample * spec->latency_time / GST_MSECOND;
  spec->segtotal = spec->buffer_time / spec->latency_time;

  GST_DEBUG ("release old ringbuffer");

306
  gst_ring_buffer_release (src->ringbuffer);
Wim Taymans's avatar
Wim Taymans committed
307

308
  gst_ring_buffer_debug_spec_buff (spec);
Wim Taymans's avatar
Wim Taymans committed
309
310
311

  GST_DEBUG ("acquire new ringbuffer");

312
  if (!gst_ring_buffer_acquire (src->ringbuffer, spec))
Wim Taymans's avatar
Wim Taymans committed
313
314
315
316
317
318
319
320
321
    goto acquire_error;

  /* calculate actual latency and buffer times */
  spec->latency_time =
      spec->segsize * GST_MSECOND / (spec->rate * spec->bytes_per_sample);
  spec->buffer_time =
      spec->segtotal * spec->segsize * GST_MSECOND / (spec->rate *
      spec->bytes_per_sample);

322
  gst_ring_buffer_debug_spec_buff (spec);
Wim Taymans's avatar
Wim Taymans committed
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339

  return TRUE;

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

static void
340
gst_base_audio_src_get_times (GstBaseSrc * bsrc, GstBuffer * buffer,
Wim Taymans's avatar
Wim Taymans committed
341
342
343
344
345
346
347
348
349
350
    GstClockTime * start, GstClockTime * end)
{
  /* ne need to sync to a clock here, we schedule the samples based
   * on our own clock for the moment. FIXME, implement this when
   * we are not using our own clock */
  *start = GST_CLOCK_TIME_NONE;
  *end = GST_CLOCK_TIME_NONE;
}

static gboolean
351
gst_base_audio_src_event (GstBaseSrc * bsrc, GstEvent * event)
Wim Taymans's avatar
Wim Taymans committed
352
{
353
  GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc);
Wim Taymans's avatar
Wim Taymans committed
354
355

  switch (GST_EVENT_TYPE (event)) {
356
357
    case GST_EVENT_FLUSH_START:
      gst_ring_buffer_pause (src->ringbuffer);
358
      gst_ring_buffer_clear_all (src->ringbuffer);
359
360
      break;
    case GST_EVENT_FLUSH_STOP:
361
362
363
      /* always resync on sample after a flush */
      src->next_sample = -1;
      gst_ring_buffer_clear_all (src->ringbuffer);
Wim Taymans's avatar
Wim Taymans committed
364
365
366
367
368
369
370
371
      break;
    default:
      break;
  }
  return TRUE;
}

static GstFlowReturn
372
373
gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
    GstBuffer ** outbuf)
Wim Taymans's avatar
Wim Taymans committed
374
{
375
  GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc);
Wim Taymans's avatar
Wim Taymans committed
376
377
  GstBuffer *buf;
  guchar *data;
378
  guint samples;
Wim Taymans's avatar
Wim Taymans committed
379
  guint res;
380
  guint64 sample;
381
  gint bps;
382
383
384
  GstRingBuffer *ringbuffer;

  ringbuffer = src->ringbuffer;
Wim Taymans's avatar
Wim Taymans committed
385

386
  if (G_UNLIKELY (!gst_ring_buffer_is_acquired (ringbuffer)))
Wim Taymans's avatar
Wim Taymans committed
387
388
    goto wrong_state;

389
  bps = ringbuffer->spec.bytes_per_sample;
Wim Taymans's avatar
Wim Taymans committed
390

391
392
393
394
395
396
  if ((length == 0 && bsrc->blocksize == 0) || length == -1)
    /* no length given, use the default segment size */
    length = ringbuffer->spec.segsize;
  else
    /* make sure we round down to an integral number of samples */
    length -= length % bps;
Wim Taymans's avatar
Wim Taymans committed
397

398
399
400
401
402
403
404
405
  /* calculate the sequentially next sample we need to read */
  sample = (src->next_sample != -1 ? src->next_sample : 0);

  if (G_UNLIKELY (offset != -1)) {
    /* if a specific offset was given it must be the next
     * sequential offset we expect or we fail. */
    if (offset / bps != sample)
      goto wrong_offset;
406
407
  }

408
409
410
411
412
413
  /* get the number of samples to read */
  samples = length / bps;

  /* FIXME, using a bufferpool would be nice here */
  buf = gst_buffer_new_and_alloc (length);
  data = GST_BUFFER_DATA (buf);
Wim Taymans's avatar
Wim Taymans committed
414

415
  res = gst_ring_buffer_read (ringbuffer, sample, data, samples);
416
  if (G_UNLIKELY (res == -1))
Wim Taymans's avatar
Wim Taymans committed
417
418
    goto stopped;

419
420
421
422
  /* FIXME, we timestamp against our own clock, also handle the case
   * where we are slaved to another clock. We currently refuse to accept
   * any other clock than the one we provide, so this code is fine for
   * now. */
423
424
  GST_BUFFER_TIMESTAMP (buf) = gst_util_uint64_scale_int (sample,
      GST_SECOND, ringbuffer->spec.rate);
Wim Taymans's avatar
Wim Taymans committed
425
  src->next_sample = sample + samples;
426
427
  GST_BUFFER_DURATION (buf) = gst_util_uint64_scale_int (src->next_sample,
      GST_SECOND, ringbuffer->spec.rate) - GST_BUFFER_TIMESTAMP (buf);
428

429
  gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (bsrc)));
Wim Taymans's avatar
Wim Taymans committed
430
431
432
433
434

  *outbuf = buf;

  return GST_FLOW_OK;

435
  /* ERRORS */
Wim Taymans's avatar
Wim Taymans committed
436
437
wrong_state:
  {
438
    GST_DEBUG_OBJECT (src, "ringbuffer in wrong state");
Wim Taymans's avatar
Wim Taymans committed
439
440
    return GST_FLOW_WRONG_STATE;
  }
441
442
443
444
445
446
447
wrong_offset:
  {
    GST_ELEMENT_ERROR (src, RESOURCE, SEEK,
        (NULL), ("resource can only be operated on sequentially but offset %"
            G_GUINT64_FORMAT " was given", offset));
    return GST_FLOW_ERROR;
  }
Wim Taymans's avatar
Wim Taymans committed
448
449
450
stopped:
  {
    gst_buffer_unref (buf);
451
    GST_DEBUG_OBJECT (src, "ringbuffer stopped");
Wim Taymans's avatar
Wim Taymans committed
452
453
454
455
456
    return GST_FLOW_WRONG_STATE;
  }
}

GstRingBuffer *
457
gst_base_audio_src_create_ringbuffer (GstBaseAudioSrc * src)
Wim Taymans's avatar
Wim Taymans committed
458
459
460
461
{
  GstBaseAudioSrcClass *bclass;
  GstRingBuffer *buffer = NULL;

462
  bclass = GST_BASE_AUDIO_SRC_GET_CLASS (src);
Wim Taymans's avatar
Wim Taymans committed
463
464
465
  if (bclass->create_ringbuffer)
    buffer = bclass->create_ringbuffer (src);

466
467
  if (G_LIKELY (buffer))
    gst_object_set_parent (GST_OBJECT_CAST (buffer), GST_OBJECT_CAST (src));
Wim Taymans's avatar
Wim Taymans committed
468
469
470
471
472

  return buffer;
}

void
473
gst_base_audio_src_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
Wim Taymans's avatar
Wim Taymans committed
474
475
    gpointer user_data)
{
476
  //GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (data);
Wim Taymans's avatar
Wim Taymans committed
477
478
}

479
480
481
static GstStateChangeReturn
gst_base_audio_src_change_state (GstElement * element,
    GstStateChange transition)
Wim Taymans's avatar
Wim Taymans committed
482
{
483
  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
484
  GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (element);
Wim Taymans's avatar
Wim Taymans committed
485
486

  switch (transition) {
487
    case GST_STATE_CHANGE_NULL_TO_READY:
488
489
490
491
492
493
      if (src->ringbuffer == NULL) {
        src->ringbuffer = gst_base_audio_src_create_ringbuffer (src);
        gst_ring_buffer_set_callback (src->ringbuffer,
            gst_base_audio_src_callback, src);
      }
      if (!gst_ring_buffer_open_device (src->ringbuffer))
494
        return GST_STATE_CHANGE_FAILURE;
495
      src->next_sample = 0;
Wim Taymans's avatar
Wim Taymans committed
496
      break;
497
    case GST_STATE_CHANGE_READY_TO_PAUSED:
498
      gst_ring_buffer_set_flushing (src->ringbuffer, FALSE);
Wim Taymans's avatar
Wim Taymans committed
499
      break;
500
    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
501
      gst_ring_buffer_may_start (src->ringbuffer, TRUE);
Wim Taymans's avatar
Wim Taymans committed
502
503
504
505
506
      break;
    default:
      break;
  }

507
  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
Wim Taymans's avatar
Wim Taymans committed
508
509

  switch (transition) {
510
    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
511
      gst_ring_buffer_may_start (src->ringbuffer, FALSE);
512
      gst_ring_buffer_pause (src->ringbuffer);
Wim Taymans's avatar
Wim Taymans committed
513
      break;
514
    case GST_STATE_CHANGE_PAUSED_TO_READY:
515
      gst_ring_buffer_set_flushing (src->ringbuffer, TRUE);
516
      gst_ring_buffer_release (src->ringbuffer);
517
      src->next_sample = 0;
Wim Taymans's avatar
Wim Taymans committed
518
      break;
519
    case GST_STATE_CHANGE_READY_TO_NULL:
520
      gst_ring_buffer_close_device (src->ringbuffer);
521
      gst_object_unparent (GST_OBJECT_CAST (src->ringbuffer));
522
      src->ringbuffer = NULL;
Wim Taymans's avatar
Wim Taymans committed
523
524
525
526
527
528
529
      break;
    default:
      break;
  }

  return ret;
}