Blame gst-libs/gst/audio/gstaudioringbuffer.c

Packit 0652a1
/* GStreamer
Packit 0652a1
 * Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
Packit 0652a1
 *
Packit 0652a1
 * This library is free software; you can redistribute it and/or
Packit 0652a1
 * modify it under the terms of the GNU Library General Public
Packit 0652a1
 * License as published by the Free Software Foundation; either
Packit 0652a1
 * version 2 of the License, or (at your option) any later version.
Packit 0652a1
 *
Packit 0652a1
 * This library is distributed in the hope that it will be useful,
Packit 0652a1
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 0652a1
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 0652a1
 * Library General Public License for more details.
Packit 0652a1
 *
Packit 0652a1
 * You should have received a copy of the GNU Library General Public
Packit 0652a1
 * License along with this library; if not, write to the
Packit 0652a1
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
Packit 0652a1
 * Boston, MA 02110-1301, USA.
Packit 0652a1
 */
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * SECTION:gstaudioringbuffer
Packit 0652a1
 * @title: GstAudioRingBuffer
Packit 0652a1
 * @short_description: Base class for audio ringbuffer implementations
Packit 0652a1
 * @see_also: #GstAudioBaseSink, #GstAudioSink
Packit 0652a1
 *
Packit 0652a1
 * This object is the base class for audio ringbuffers used by the base
Packit 0652a1
 * audio source and sink classes.
Packit 0652a1
 *
Packit 0652a1
 * The ringbuffer abstracts a circular buffer of data. One reader and
Packit 0652a1
 * one writer can operate on the data from different threads in a lockfree
Packit 0652a1
 * manner. The base class is sufficiently flexible to be used as an
Packit 0652a1
 * abstraction for DMA based ringbuffers as well as a pure software
Packit 0652a1
 * implementations.
Packit 0652a1
 *
Packit 0652a1
 */
Packit 0652a1
#ifdef HAVE_CONFIG_H
Packit 0652a1
#include "config.h"
Packit 0652a1
#endif
Packit 0652a1
Packit 0652a1
#include <string.h>
Packit 0652a1
Packit 0652a1
#include <gst/audio/audio.h>
Packit 0652a1
#include "gstaudioringbuffer.h"
Packit 0652a1
Packit 0652a1
GST_DEBUG_CATEGORY_STATIC (gst_audio_ring_buffer_debug);
Packit 0652a1
#define GST_CAT_DEFAULT gst_audio_ring_buffer_debug
Packit 0652a1
Packit 0652a1
static void gst_audio_ring_buffer_dispose (GObject * object);
Packit 0652a1
static void gst_audio_ring_buffer_finalize (GObject * object);
Packit 0652a1
Packit 0652a1
static gboolean gst_audio_ring_buffer_pause_unlocked (GstAudioRingBuffer * buf);
Packit 0652a1
static void default_clear_all (GstAudioRingBuffer * buf);
Packit 0652a1
static guint default_commit (GstAudioRingBuffer * buf, guint64 * sample,
Packit 0652a1
    guint8 * data, gint in_samples, gint out_samples, gint * accum);
Packit 0652a1
Packit 0652a1
/* ringbuffer abstract base class */
Packit 0652a1
G_DEFINE_ABSTRACT_TYPE (GstAudioRingBuffer, gst_audio_ring_buffer,
Packit 0652a1
    GST_TYPE_OBJECT);
Packit 0652a1
Packit 0652a1
static void
Packit 0652a1
gst_audio_ring_buffer_class_init (GstAudioRingBufferClass * klass)
Packit 0652a1
{
Packit 0652a1
  GObjectClass *gobject_class;
Packit 0652a1
  GstAudioRingBufferClass *gstaudioringbuffer_class;
Packit 0652a1
Packit 0652a1
  gobject_class = (GObjectClass *) klass;
Packit 0652a1
  gstaudioringbuffer_class = (GstAudioRingBufferClass *) klass;
Packit 0652a1
Packit 0652a1
  GST_DEBUG_CATEGORY_INIT (gst_audio_ring_buffer_debug, "ringbuffer", 0,
Packit 0652a1
      "ringbuffer class");
Packit 0652a1
Packit 0652a1
  gobject_class->dispose = gst_audio_ring_buffer_dispose;
Packit 0652a1
  gobject_class->finalize = gst_audio_ring_buffer_finalize;
Packit 0652a1
Packit 0652a1
  gstaudioringbuffer_class->clear_all = GST_DEBUG_FUNCPTR (default_clear_all);
Packit 0652a1
  gstaudioringbuffer_class->commit = GST_DEBUG_FUNCPTR (default_commit);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static void
Packit 0652a1
gst_audio_ring_buffer_init (GstAudioRingBuffer * ringbuffer)
Packit 0652a1
{
Packit 0652a1
  ringbuffer->open = FALSE;
Packit 0652a1
  ringbuffer->acquired = FALSE;
Packit 0652a1
  ringbuffer->state = GST_AUDIO_RING_BUFFER_STATE_STOPPED;
Packit 0652a1
  g_cond_init (&ringbuffer->cond);
Packit 0652a1
  ringbuffer->waiting = 0;
Packit 0652a1
  ringbuffer->empty_seg = NULL;
Packit 0652a1
  ringbuffer->flushing = TRUE;
Packit 0652a1
  ringbuffer->segbase = 0;
Packit 0652a1
  ringbuffer->segdone = 0;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static void
Packit 0652a1
gst_audio_ring_buffer_dispose (GObject * object)
Packit 0652a1
{
Packit 0652a1
  GstAudioRingBuffer *ringbuffer = GST_AUDIO_RING_BUFFER (object);
Packit 0652a1
Packit 0652a1
  gst_caps_replace (&ringbuffer->spec.caps, NULL);
Packit 0652a1
Packit 0652a1
  G_OBJECT_CLASS (gst_audio_ring_buffer_parent_class)->dispose (G_OBJECT
Packit 0652a1
      (ringbuffer));
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static void
Packit 0652a1
gst_audio_ring_buffer_finalize (GObject * object)
Packit 0652a1
{
Packit 0652a1
  GstAudioRingBuffer *ringbuffer = GST_AUDIO_RING_BUFFER (object);
Packit 0652a1
Packit 0652a1
  g_cond_clear (&ringbuffer->cond);
Packit 0652a1
  g_free (ringbuffer->empty_seg);
Packit 0652a1
Packit 0652a1
  if (ringbuffer->cb_data_notify != NULL)
Packit 0652a1
    ringbuffer->cb_data_notify (ringbuffer->cb_data);
Packit 0652a1
Packit 0652a1
  G_OBJECT_CLASS (gst_audio_ring_buffer_parent_class)->finalize (G_OBJECT
Packit 0652a1
      (ringbuffer));
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
#ifndef GST_DISABLE_GST_DEBUG
Packit 0652a1
static const gchar *format_type_names[] = {
Packit 0652a1
  "raw",
Packit 0652a1
  "mu law",
Packit 0652a1
  "a law",
Packit 0652a1
  "ima adpcm",
Packit 0652a1
  "mpeg",
Packit 0652a1
  "gsm",
Packit 0652a1
  "iec958",
Packit 0652a1
  "ac3",
Packit 0652a1
  "eac3",
Packit 0652a1
  "dts",
Packit 0652a1
  "aac mpeg2",
Packit 0652a1
  "aac mpeg4",
Packit 0652a1
  "aac mpeg2 raw",
Packit 0652a1
  "aac mpeg4 raw",
Packit 0652a1
  "flac"
Packit 0652a1
};
Packit 0652a1
#endif
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_debug_spec_caps:
Packit 0652a1
 * @spec: the spec to debug
Packit 0652a1
 *
Packit 0652a1
 * Print debug info about the parsed caps in @spec to the debug log.
Packit 0652a1
 */
Packit 0652a1
void
Packit 0652a1
gst_audio_ring_buffer_debug_spec_caps (GstAudioRingBufferSpec * spec)
Packit 0652a1
{
Packit 0652a1
#if 0
Packit 0652a1
  gint i, bytes;
Packit 0652a1
#endif
Packit 0652a1
Packit 0652a1
  GST_DEBUG ("spec caps: %p %" GST_PTR_FORMAT, spec->caps, spec->caps);
Packit 0652a1
  GST_DEBUG ("parsed caps: type:         %d, '%s'", spec->type,
Packit 0652a1
      format_type_names[spec->type]);
Packit 0652a1
#if 0
Packit 0652a1
  GST_DEBUG ("parsed caps: width:        %d", spec->width);
Packit 0652a1
  GST_DEBUG ("parsed caps: sign:         %d", spec->sign);
Packit 0652a1
  GST_DEBUG ("parsed caps: bigend:       %d", spec->bigend);
Packit 0652a1
  GST_DEBUG ("parsed caps: rate:         %d", spec->rate);
Packit 0652a1
  GST_DEBUG ("parsed caps: channels:     %d", spec->channels);
Packit 0652a1
  GST_DEBUG ("parsed caps: sample bytes: %d", spec->bytes_per_sample);
Packit 0652a1
  bytes = (spec->width >> 3) * spec->channels;
Packit 0652a1
  for (i = 0; i < bytes; i++) {
Packit 0652a1
    GST_DEBUG ("silence byte %d: %02x", i, spec->silence_sample[i]);
Packit 0652a1
  }
Packit 0652a1
#endif
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_debug_spec_buff:
Packit 0652a1
 * @spec: the spec to debug
Packit 0652a1
 *
Packit 0652a1
 * Print debug info about the buffer sized in @spec to the debug log.
Packit 0652a1
 */
Packit 0652a1
void
Packit 0652a1
gst_audio_ring_buffer_debug_spec_buff (GstAudioRingBufferSpec * spec)
Packit 0652a1
{
Packit 0652a1
  gint bpf = GST_AUDIO_INFO_BPF (&spec->info);
Packit 0652a1
Packit 0652a1
  GST_DEBUG ("acquire ringbuffer: buffer time: %" G_GINT64_FORMAT " usec",
Packit 0652a1
      spec->buffer_time);
Packit 0652a1
  GST_DEBUG ("acquire ringbuffer: latency time: %" G_GINT64_FORMAT " usec",
Packit 0652a1
      spec->latency_time);
Packit 0652a1
  GST_DEBUG ("acquire ringbuffer: total segments: %d", spec->segtotal);
Packit 0652a1
  GST_DEBUG ("acquire ringbuffer: latency segments: %d", spec->seglatency);
Packit 0652a1
  GST_DEBUG ("acquire ringbuffer: segment size: %d bytes = %d samples",
Packit 0652a1
      spec->segsize, (bpf != 0) ? (spec->segsize / bpf) : -1);
Packit 0652a1
  GST_DEBUG ("acquire ringbuffer: buffer size: %d bytes = %d samples",
Packit 0652a1
      spec->segsize * spec->segtotal,
Packit 0652a1
      (bpf != 0) ? (spec->segsize * spec->segtotal / bpf) : -1);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_parse_caps:
Packit 0652a1
 * @spec: a spec
Packit 0652a1
 * @caps: a #GstCaps
Packit 0652a1
 *
Packit 0652a1
 * Parse @caps into @spec.
Packit 0652a1
 *
Packit 0652a1
 * Returns: TRUE if the caps could be parsed.
Packit 0652a1
 */
Packit 0652a1
gboolean
Packit 0652a1
gst_audio_ring_buffer_parse_caps (GstAudioRingBufferSpec * spec, GstCaps * caps)
Packit 0652a1
{
Packit 0652a1
  const gchar *mimetype;
Packit 0652a1
  GstStructure *structure;
Packit 0652a1
  gint i;
Packit 0652a1
  GstAudioInfo info;
Packit 0652a1
Packit 0652a1
  structure = gst_caps_get_structure (caps, 0);
Packit 0652a1
  gst_audio_info_init (&info;;
Packit 0652a1
Packit 0652a1
  /* we have to differentiate between int and float formats */
Packit 0652a1
  mimetype = gst_structure_get_name (structure);
Packit 0652a1
Packit 0652a1
  if (g_str_equal (mimetype, "audio/x-raw")) {
Packit 0652a1
    if (!gst_audio_info_from_caps (&info, caps))
Packit 0652a1
      goto parse_error;
Packit 0652a1
Packit 0652a1
    spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW;
Packit 0652a1
  } else if (g_str_equal (mimetype, "audio/x-alaw")) {
Packit 0652a1
    /* extract the needed information from the cap */
Packit 0652a1
    if (!(gst_structure_get_int (structure, "rate", &info.rate) &&
Packit 0652a1
            gst_structure_get_int (structure, "channels", &info.channels)))
Packit 0652a1
      goto parse_error;
Packit 0652a1
Packit 0652a1
    if (!(gst_audio_channel_positions_from_mask (info.channels, 0,
Packit 0652a1
                info.position)))
Packit 0652a1
      goto parse_error;
Packit 0652a1
Packit 0652a1
    spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_A_LAW;
Packit 0652a1
    info.bpf = info.channels;
Packit 0652a1
  } else if (g_str_equal (mimetype, "audio/x-mulaw")) {
Packit 0652a1
    /* extract the needed information from the cap */
Packit 0652a1
    if (!(gst_structure_get_int (structure, "rate", &info.rate) &&
Packit 0652a1
            gst_structure_get_int (structure, "channels", &info.channels)))
Packit 0652a1
      goto parse_error;
Packit 0652a1
Packit 0652a1
    if (!(gst_audio_channel_positions_from_mask (info.channels, 0,
Packit 0652a1
                info.position)))
Packit 0652a1
      goto parse_error;
Packit 0652a1
Packit 0652a1
    spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MU_LAW;
Packit 0652a1
    info.bpf = info.channels;
Packit 0652a1
  } else if (g_str_equal (mimetype, "audio/x-iec958")) {
Packit 0652a1
    /* extract the needed information from the cap */
Packit 0652a1
    if (!(gst_structure_get_int (structure, "rate", &info.rate)))
Packit 0652a1
      goto parse_error;
Packit 0652a1
Packit 0652a1
    spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_IEC958;
Packit 0652a1
    info.bpf = 4;
Packit 0652a1
  } else if (g_str_equal (mimetype, "audio/x-ac3")) {
Packit 0652a1
    /* extract the needed information from the cap */
Packit 0652a1
    if (!(gst_structure_get_int (structure, "rate", &info.rate)))
Packit 0652a1
      goto parse_error;
Packit 0652a1
Packit 0652a1
    gst_structure_get_int (structure, "channels", &info.channels);
Packit 0652a1
    spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_AC3;
Packit 0652a1
    info.bpf = 4;
Packit 0652a1
  } else if (g_str_equal (mimetype, "audio/x-eac3")) {
Packit 0652a1
    /* extract the needed information from the cap */
Packit 0652a1
    if (!(gst_structure_get_int (structure, "rate", &info.rate)))
Packit 0652a1
      goto parse_error;
Packit 0652a1
Packit 0652a1
    gst_structure_get_int (structure, "channels", &info.channels);
Packit 0652a1
    spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_EAC3;
Packit 0652a1
    info.bpf = 16;
Packit 0652a1
  } else if (g_str_equal (mimetype, "audio/x-dts")) {
Packit 0652a1
    /* extract the needed information from the cap */
Packit 0652a1
    if (!(gst_structure_get_int (structure, "rate", &info.rate)))
Packit 0652a1
      goto parse_error;
Packit 0652a1
Packit 0652a1
    gst_structure_get_int (structure, "channels", &info.channels);
Packit 0652a1
    spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_DTS;
Packit 0652a1
    info.bpf = 4;
Packit 0652a1
  } else if (g_str_equal (mimetype, "audio/mpeg") &&
Packit 0652a1
      gst_structure_get_int (structure, "mpegaudioversion", &i) &&
Packit 0652a1
      (i == 1 || i == 2 || i == 3)) {
Packit 0652a1
    /* Now we know this is MPEG-1, MPEG-2 or MPEG-2.5 (non AAC) */
Packit 0652a1
    /* extract the needed information from the cap */
Packit 0652a1
    if (!(gst_structure_get_int (structure, "rate", &info.rate)))
Packit 0652a1
      goto parse_error;
Packit 0652a1
Packit 0652a1
    gst_structure_get_int (structure, "channels", &info.channels);
Packit 0652a1
    spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG;
Packit 0652a1
    info.bpf = 1;
Packit 0652a1
  } else if (g_str_equal (mimetype, "audio/mpeg") &&
Packit 0652a1
      gst_structure_get_int (structure, "mpegversion", &i) &&
Packit 0652a1
      (i == 2 || i == 4) &&
Packit 0652a1
      (!g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
Packit 0652a1
              "adts")
Packit 0652a1
          || !g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
Packit 0652a1
              "raw"))) {
Packit 0652a1
    /* MPEG-2 AAC or MPEG-4 AAC */
Packit 0652a1
    if (!(gst_structure_get_int (structure, "rate", &info.rate)))
Packit 0652a1
      goto parse_error;
Packit 0652a1
Packit 0652a1
    gst_structure_get_int (structure, "channels", &info.channels);
Packit 0652a1
    if (!g_strcmp0 (gst_structure_get_string (structure, "stream-format"),
Packit 0652a1
            "adts"))
Packit 0652a1
      spec->type = (i == 2) ? GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG2_AAC :
Packit 0652a1
          GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG4_AAC;
Packit 0652a1
    else
Packit 0652a1
      spec->type = (i == 2) ?
Packit 0652a1
          GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG2_AAC_RAW :
Packit 0652a1
          GST_AUDIO_RING_BUFFER_FORMAT_TYPE_MPEG4_AAC_RAW;
Packit 0652a1
    info.bpf = 1;
Packit 0652a1
  } else if (g_str_equal (mimetype, "audio/x-flac")) {
Packit 0652a1
    /* extract the needed information from the cap */
Packit 0652a1
    if (!(gst_structure_get_int (structure, "rate", &info.rate)))
Packit 0652a1
      goto parse_error;
Packit 0652a1
Packit 0652a1
    gst_structure_get_int (structure, "channels", &info.channels);
Packit 0652a1
    spec->type = GST_AUDIO_RING_BUFFER_FORMAT_TYPE_FLAC;
Packit 0652a1
    info.bpf = 1;
Packit 0652a1
  } else {
Packit 0652a1
    goto parse_error;
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  gst_caps_replace (&spec->caps, caps);
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (spec->latency_time != 0, FALSE);
Packit 0652a1
Packit 0652a1
  /* calculate suggested segsize and segtotal. segsize should be one unit
Packit 0652a1
   * of 'latency_time' samples, scaling for the fact that latency_time is
Packit 0652a1
   * currently stored in microseconds (FIXME: in 0.11) */
Packit 0652a1
  spec->segsize = gst_util_uint64_scale (info.rate * info.bpf,
Packit 0652a1
      spec->latency_time, GST_SECOND / GST_USECOND);
Packit 0652a1
  /* Round to an integer number of samples */
Packit 0652a1
  spec->segsize -= spec->segsize % info.bpf;
Packit 0652a1
Packit 0652a1
  spec->segtotal = spec->buffer_time / spec->latency_time;
Packit 0652a1
  /* leave the latency undefined now, implementations can change it but if it's
Packit 0652a1
   * not changed, we assume the same value as segtotal */
Packit 0652a1
  spec->seglatency = -1;
Packit 0652a1
Packit 0652a1
  spec->info = info;
Packit 0652a1
Packit 0652a1
  gst_audio_ring_buffer_debug_spec_caps (spec);
Packit 0652a1
  gst_audio_ring_buffer_debug_spec_buff (spec);
Packit 0652a1
Packit 0652a1
  return TRUE;
Packit 0652a1
Packit 0652a1
  /* ERRORS */
Packit 0652a1
parse_error:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG ("could not parse caps");
Packit 0652a1
    return FALSE;
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_convert:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer
Packit 0652a1
 * @src_fmt: the source format
Packit 0652a1
 * @src_val: the source value
Packit 0652a1
 * @dest_fmt: the destination format
Packit 0652a1
 * @dest_val: (out): a location to store the converted value
Packit 0652a1
 *
Packit 0652a1
 * Convert @src_val in @src_fmt to the equivalent value in @dest_fmt. The result
Packit 0652a1
 * will be put in @dest_val.
Packit 0652a1
 *
Packit 0652a1
 * Returns: TRUE if the conversion succeeded.
Packit 0652a1
 */
Packit 0652a1
gboolean
Packit 0652a1
gst_audio_ring_buffer_convert (GstAudioRingBuffer * buf,
Packit 0652a1
    GstFormat src_fmt, gint64 src_val, GstFormat dest_fmt, gint64 * dest_val)
Packit 0652a1
{
Packit 0652a1
  gboolean res;
Packit 0652a1
Packit 0652a1
  GST_OBJECT_LOCK (buf);
Packit 0652a1
  res =
Packit 0652a1
      gst_audio_info_convert (&buf->spec.info, src_fmt, src_val, dest_fmt,
Packit 0652a1
      dest_val);
Packit 0652a1
  GST_OBJECT_UNLOCK (buf);
Packit 0652a1
Packit 0652a1
  return res;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_set_callback: (skip)
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to set the callback on
Packit 0652a1
 * @cb: (allow-none): the callback to set
Packit 0652a1
 * @user_data: user data passed to the callback
Packit 0652a1
 *
Packit 0652a1
 * Sets the given callback function on the buffer. This function
Packit 0652a1
 * will be called every time a segment has been written to a device.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
void
Packit 0652a1
gst_audio_ring_buffer_set_callback (GstAudioRingBuffer * buf,
Packit 0652a1
    GstAudioRingBufferCallback cb, gpointer user_data)
Packit 0652a1
{
Packit 0652a1
  gst_audio_ring_buffer_set_callback_full (buf, cb, user_data, NULL);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_set_callback_full: (rename-to gst_audio_ring_buffer_set_callback)
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to set the callback on
Packit 0652a1
 * @cb: (allow-none): the callback to set
Packit 0652a1
 * @user_data: user data passed to the callback
Packit 0652a1
 * @notify: function to be called when @user_data is no longer needed
Packit 0652a1
 *
Packit 0652a1
 * Sets the given callback function on the buffer. This function
Packit 0652a1
 * will be called every time a segment has been written to a device.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 *
Packit 0652a1
 * Since: 1.12
Packit 0652a1
 */
Packit 0652a1
void
Packit 0652a1
gst_audio_ring_buffer_set_callback_full (GstAudioRingBuffer * buf,
Packit 0652a1
    GstAudioRingBufferCallback cb, gpointer user_data, GDestroyNotify notify)
Packit 0652a1
{
Packit 0652a1
  gpointer old_data = NULL;
Packit 0652a1
  GDestroyNotify old_notify;
Packit 0652a1
Packit 0652a1
  g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
Packit 0652a1
Packit 0652a1
  GST_OBJECT_LOCK (buf);
Packit 0652a1
  old_notify = buf->cb_data_notify;
Packit 0652a1
  old_data = buf->cb_data;
Packit 0652a1
Packit 0652a1
  buf->callback = cb;
Packit 0652a1
  buf->cb_data = user_data;
Packit 0652a1
  buf->cb_data_notify = notify;
Packit 0652a1
  GST_OBJECT_UNLOCK (buf);
Packit 0652a1
Packit 0652a1
  if (old_notify) {
Packit 0652a1
    old_notify (old_data);
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_open_device:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer
Packit 0652a1
 *
Packit 0652a1
 * Open the audio device associated with the ring buffer. Does not perform any
Packit 0652a1
 * setup on the device. You must open the device before acquiring the ring
Packit 0652a1
 * buffer.
Packit 0652a1
 *
Packit 0652a1
 * Returns: TRUE if the device could be opened, FALSE on error.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
gboolean
Packit 0652a1
gst_audio_ring_buffer_open_device (GstAudioRingBuffer * buf)
Packit 0652a1
{
Packit 0652a1
  gboolean res = TRUE;
Packit 0652a1
  GstAudioRingBufferClass *rclass;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
Packit 0652a1
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "opening device");
Packit 0652a1
Packit 0652a1
  GST_OBJECT_LOCK (buf);
Packit 0652a1
  if (G_UNLIKELY (buf->open))
Packit 0652a1
    goto was_opened;
Packit 0652a1
Packit 0652a1
  buf->open = TRUE;
Packit 0652a1
Packit 0652a1
  /* if this fails, something is wrong in this file */
Packit 0652a1
  g_assert (!buf->acquired);
Packit 0652a1
Packit 0652a1
  rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
Packit 0652a1
  if (G_LIKELY (rclass->open_device))
Packit 0652a1
    res = rclass->open_device (buf);
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (!res))
Packit 0652a1
    goto open_failed;
Packit 0652a1
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "opened device");
Packit 0652a1
Packit 0652a1
done:
Packit 0652a1
  GST_OBJECT_UNLOCK (buf);
Packit 0652a1
Packit 0652a1
  return res;
Packit 0652a1
Packit 0652a1
  /* ERRORS */
Packit 0652a1
was_opened:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "Device for ring buffer already open");
Packit 0652a1
    g_warning ("Device for ring buffer %p already open, fix your code", buf);
Packit 0652a1
    res = TRUE;
Packit 0652a1
    goto done;
Packit 0652a1
  }
Packit 0652a1
open_failed:
Packit 0652a1
  {
Packit 0652a1
    buf->open = FALSE;
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "failed opening device");
Packit 0652a1
    goto done;
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_close_device:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer
Packit 0652a1
 *
Packit 0652a1
 * Close the audio device associated with the ring buffer. The ring buffer
Packit 0652a1
 * should already have been released via gst_audio_ring_buffer_release().
Packit 0652a1
 *
Packit 0652a1
 * Returns: TRUE if the device could be closed, FALSE on error.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
gboolean
Packit 0652a1
gst_audio_ring_buffer_close_device (GstAudioRingBuffer * buf)
Packit 0652a1
{
Packit 0652a1
  gboolean res = TRUE;
Packit 0652a1
  GstAudioRingBufferClass *rclass;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
Packit 0652a1
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "closing device");
Packit 0652a1
Packit 0652a1
  GST_OBJECT_LOCK (buf);
Packit 0652a1
  if (G_UNLIKELY (!buf->open))
Packit 0652a1
    goto was_closed;
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (buf->acquired))
Packit 0652a1
    goto was_acquired;
Packit 0652a1
Packit 0652a1
  buf->open = FALSE;
Packit 0652a1
Packit 0652a1
  rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
Packit 0652a1
  if (G_LIKELY (rclass->close_device))
Packit 0652a1
    res = rclass->close_device (buf);
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (!res))
Packit 0652a1
    goto close_error;
Packit 0652a1
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "closed device");
Packit 0652a1
Packit 0652a1
done:
Packit 0652a1
  GST_OBJECT_UNLOCK (buf);
Packit 0652a1
Packit 0652a1
  return res;
Packit 0652a1
Packit 0652a1
  /* ERRORS */
Packit 0652a1
was_closed:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "Device for ring buffer already closed");
Packit 0652a1
    g_warning ("Device for ring buffer %p already closed, fix your code", buf);
Packit 0652a1
    res = TRUE;
Packit 0652a1
    goto done;
Packit 0652a1
  }
Packit 0652a1
was_acquired:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "Resources for ring buffer still acquired");
Packit 0652a1
    g_critical ("Resources for ring buffer %p still acquired", buf);
Packit 0652a1
    res = FALSE;
Packit 0652a1
    goto done;
Packit 0652a1
  }
Packit 0652a1
close_error:
Packit 0652a1
  {
Packit 0652a1
    buf->open = TRUE;
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "error closing device");
Packit 0652a1
    goto done;
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_device_is_open:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer
Packit 0652a1
 *
Packit 0652a1
 * Checks the status of the device associated with the ring buffer.
Packit 0652a1
 *
Packit 0652a1
 * Returns: TRUE if the device was open, FALSE if it was closed.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
gboolean
Packit 0652a1
gst_audio_ring_buffer_device_is_open (GstAudioRingBuffer * buf)
Packit 0652a1
{
Packit 0652a1
  gboolean res = TRUE;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
Packit 0652a1
Packit 0652a1
  GST_OBJECT_LOCK (buf);
Packit 0652a1
  res = buf->open;
Packit 0652a1
  GST_OBJECT_UNLOCK (buf);
Packit 0652a1
Packit 0652a1
  return res;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_acquire:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to acquire
Packit 0652a1
 * @spec: the specs of the buffer
Packit 0652a1
 *
Packit 0652a1
 * Allocate the resources for the ringbuffer. This function fills
Packit 0652a1
 * in the data pointer of the ring buffer with a valid #GstBuffer
Packit 0652a1
 * to which samples can be written.
Packit 0652a1
 *
Packit 0652a1
 * Returns: TRUE if the device could be acquired, FALSE on error.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
gboolean
Packit 0652a1
gst_audio_ring_buffer_acquire (GstAudioRingBuffer * buf,
Packit 0652a1
    GstAudioRingBufferSpec * spec)
Packit 0652a1
{
Packit 0652a1
  gboolean res = FALSE;
Packit 0652a1
  GstAudioRingBufferClass *rclass;
Packit 0652a1
  gint segsize, bpf, i;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
Packit 0652a1
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "acquiring device %p", buf);
Packit 0652a1
Packit 0652a1
  GST_OBJECT_LOCK (buf);
Packit 0652a1
  if (G_UNLIKELY (!buf->open))
Packit 0652a1
    goto not_opened;
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (buf->acquired))
Packit 0652a1
    goto was_acquired;
Packit 0652a1
Packit 0652a1
  buf->acquired = TRUE;
Packit 0652a1
  buf->need_reorder = FALSE;
Packit 0652a1
Packit 0652a1
  rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
Packit 0652a1
  if (G_LIKELY (rclass->acquire))
Packit 0652a1
    res = rclass->acquire (buf, spec);
Packit 0652a1
Packit 0652a1
  /* Only reorder for raw audio */
Packit 0652a1
  buf->need_reorder = (buf->need_reorder
Packit 0652a1
      && buf->spec.type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW);
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (!res))
Packit 0652a1
    goto acquire_failed;
Packit 0652a1
Packit 0652a1
  GST_INFO_OBJECT (buf, "Allocating an array for %d timestamps",
Packit 0652a1
      spec->segtotal);
Packit 0652a1
  buf->timestamps = g_slice_alloc0 (sizeof (GstClockTime) * spec->segtotal);
Packit 0652a1
  /* initialize array with invalid timestamps */
Packit 0652a1
  for (i = 0; i < spec->segtotal; i++) {
Packit 0652a1
    buf->timestamps[i] = GST_CLOCK_TIME_NONE;
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY ((bpf = buf->spec.info.bpf) == 0))
Packit 0652a1
    goto invalid_bpf;
Packit 0652a1
Packit 0652a1
  /* if the seglatency was overwritten with something else than -1, use it, else
Packit 0652a1
   * assume segtotal as the latency */
Packit 0652a1
  if (buf->spec.seglatency == -1)
Packit 0652a1
    buf->spec.seglatency = buf->spec.segtotal;
Packit 0652a1
Packit 0652a1
  segsize = buf->spec.segsize;
Packit 0652a1
Packit 0652a1
  buf->samples_per_seg = segsize / bpf;
Packit 0652a1
Packit 0652a1
  /* create an empty segment */
Packit 0652a1
  g_free (buf->empty_seg);
Packit 0652a1
  buf->empty_seg = g_malloc (segsize);
Packit 0652a1
Packit 0652a1
  if (buf->spec.type == GST_AUDIO_RING_BUFFER_FORMAT_TYPE_RAW) {
Packit 0652a1
    gst_audio_format_fill_silence (buf->spec.info.finfo, buf->empty_seg,
Packit 0652a1
        segsize);
Packit 0652a1
  } else {
Packit 0652a1
    /* FIXME, non-raw formats get 0 as the empty sample */
Packit 0652a1
    memset (buf->empty_seg, 0, segsize);
Packit 0652a1
  }
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "acquired device");
Packit 0652a1
Packit 0652a1
done:
Packit 0652a1
  GST_OBJECT_UNLOCK (buf);
Packit 0652a1
Packit 0652a1
  return res;
Packit 0652a1
Packit 0652a1
  /* ERRORS */
Packit 0652a1
not_opened:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "device not opened");
Packit 0652a1
    g_critical ("Device for %p not opened", buf);
Packit 0652a1
    res = FALSE;
Packit 0652a1
    goto done;
Packit 0652a1
  }
Packit 0652a1
was_acquired:
Packit 0652a1
  {
Packit 0652a1
    res = TRUE;
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "device was acquired");
Packit 0652a1
    goto done;
Packit 0652a1
  }
Packit 0652a1
acquire_failed:
Packit 0652a1
  {
Packit 0652a1
    buf->acquired = FALSE;
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "failed to acquire device");
Packit 0652a1
    goto done;
Packit 0652a1
  }
Packit 0652a1
invalid_bpf:
Packit 0652a1
  {
Packit 0652a1
    g_warning
Packit 0652a1
        ("invalid bytes_per_frame from acquire ringbuffer %p, fix the element",
Packit 0652a1
        buf);
Packit 0652a1
    buf->acquired = FALSE;
Packit 0652a1
    res = FALSE;
Packit 0652a1
    goto done;
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_release:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to release
Packit 0652a1
 *
Packit 0652a1
 * Free the resources of the ringbuffer.
Packit 0652a1
 *
Packit 0652a1
 * Returns: TRUE if the device could be released, FALSE on error.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
gboolean
Packit 0652a1
gst_audio_ring_buffer_release (GstAudioRingBuffer * buf)
Packit 0652a1
{
Packit 0652a1
  gboolean res = FALSE;
Packit 0652a1
  GstAudioRingBufferClass *rclass;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
Packit 0652a1
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "releasing device");
Packit 0652a1
Packit 0652a1
  gst_audio_ring_buffer_stop (buf);
Packit 0652a1
Packit 0652a1
  GST_OBJECT_LOCK (buf);
Packit 0652a1
Packit 0652a1
  if (G_LIKELY (buf->timestamps)) {
Packit 0652a1
    GST_INFO_OBJECT (buf, "Freeing timestamp buffer, %d entries",
Packit 0652a1
        buf->spec.segtotal);
Packit 0652a1
    g_slice_free1 (sizeof (GstClockTime) * buf->spec.segtotal, buf->timestamps);
Packit 0652a1
    buf->timestamps = NULL;
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (!buf->acquired))
Packit 0652a1
    goto was_released;
Packit 0652a1
Packit 0652a1
  buf->acquired = FALSE;
Packit 0652a1
Packit 0652a1
  /* if this fails, something is wrong in this file */
Packit 0652a1
  g_assert (buf->open);
Packit 0652a1
Packit 0652a1
  rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
Packit 0652a1
  if (G_LIKELY (rclass->release))
Packit 0652a1
    res = rclass->release (buf);
Packit 0652a1
Packit 0652a1
  /* signal any waiters */
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "signal waiter");
Packit 0652a1
  GST_AUDIO_RING_BUFFER_SIGNAL (buf);
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (!res))
Packit 0652a1
    goto release_failed;
Packit 0652a1
Packit 0652a1
  g_atomic_int_set (&buf->segdone, 0);
Packit 0652a1
  buf->segbase = 0;
Packit 0652a1
  g_free (buf->empty_seg);
Packit 0652a1
  buf->empty_seg = NULL;
Packit 0652a1
  gst_caps_replace (&buf->spec.caps, NULL);
Packit 0652a1
  gst_audio_info_init (&buf->spec.info);
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "released device");
Packit 0652a1
Packit 0652a1
done:
Packit 0652a1
  GST_OBJECT_UNLOCK (buf);
Packit 0652a1
Packit 0652a1
  return res;
Packit 0652a1
Packit 0652a1
  /* ERRORS */
Packit 0652a1
was_released:
Packit 0652a1
  {
Packit 0652a1
    res = TRUE;
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "device was released");
Packit 0652a1
    goto done;
Packit 0652a1
  }
Packit 0652a1
release_failed:
Packit 0652a1
  {
Packit 0652a1
    buf->acquired = TRUE;
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "failed to release device");
Packit 0652a1
    goto done;
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_is_acquired:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to check
Packit 0652a1
 *
Packit 0652a1
 * Check if the ringbuffer is acquired and ready to use.
Packit 0652a1
 *
Packit 0652a1
 * Returns: TRUE if the ringbuffer is acquired, FALSE on error.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
gboolean
Packit 0652a1
gst_audio_ring_buffer_is_acquired (GstAudioRingBuffer * buf)
Packit 0652a1
{
Packit 0652a1
  gboolean res;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
Packit 0652a1
Packit 0652a1
  GST_OBJECT_LOCK (buf);
Packit 0652a1
  res = buf->acquired;
Packit 0652a1
  GST_OBJECT_UNLOCK (buf);
Packit 0652a1
Packit 0652a1
  return res;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_activate:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to activate
Packit 0652a1
 * @active: the new mode
Packit 0652a1
 *
Packit 0652a1
 * Activate @buf to start or stop pulling data.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 *
Packit 0652a1
 * Returns: TRUE if the device could be activated in the requested mode,
Packit 0652a1
 * FALSE on error.
Packit 0652a1
 */
Packit 0652a1
gboolean
Packit 0652a1
gst_audio_ring_buffer_activate (GstAudioRingBuffer * buf, gboolean active)
Packit 0652a1
{
Packit 0652a1
  gboolean res = FALSE;
Packit 0652a1
  GstAudioRingBufferClass *rclass;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
Packit 0652a1
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "activate device");
Packit 0652a1
Packit 0652a1
  GST_OBJECT_LOCK (buf);
Packit 0652a1
  if (G_UNLIKELY (active && !buf->acquired))
Packit 0652a1
    goto not_acquired;
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (buf->active == active))
Packit 0652a1
    goto was_active;
Packit 0652a1
Packit 0652a1
  rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
Packit 0652a1
  /* if there is no activate function we assume it was started/released
Packit 0652a1
   * in the acquire method */
Packit 0652a1
  if (G_LIKELY (rclass->activate))
Packit 0652a1
    res = rclass->activate (buf, active);
Packit 0652a1
  else
Packit 0652a1
    res = TRUE;
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (!res))
Packit 0652a1
    goto activate_failed;
Packit 0652a1
Packit 0652a1
  buf->active = active;
Packit 0652a1
Packit 0652a1
done:
Packit 0652a1
  GST_OBJECT_UNLOCK (buf);
Packit 0652a1
Packit 0652a1
  return res;
Packit 0652a1
Packit 0652a1
  /* ERRORS */
Packit 0652a1
not_acquired:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "device not acquired");
Packit 0652a1
    g_critical ("Device for %p not acquired", buf);
Packit 0652a1
    res = FALSE;
Packit 0652a1
    goto done;
Packit 0652a1
  }
Packit 0652a1
was_active:
Packit 0652a1
  {
Packit 0652a1
    res = TRUE;
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "device was active in mode %d", active);
Packit 0652a1
    goto done;
Packit 0652a1
  }
Packit 0652a1
activate_failed:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "failed to activate device");
Packit 0652a1
    goto done;
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_is_active:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer
Packit 0652a1
 *
Packit 0652a1
 * Check if @buf is activated.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 *
Packit 0652a1
 * Returns: TRUE if the device is active.
Packit 0652a1
 */
Packit 0652a1
gboolean
Packit 0652a1
gst_audio_ring_buffer_is_active (GstAudioRingBuffer * buf)
Packit 0652a1
{
Packit 0652a1
  gboolean res;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
Packit 0652a1
Packit 0652a1
  GST_OBJECT_LOCK (buf);
Packit 0652a1
  res = buf->active;
Packit 0652a1
  GST_OBJECT_UNLOCK (buf);
Packit 0652a1
Packit 0652a1
  return res;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_set_flushing:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to flush
Packit 0652a1
 * @flushing: the new mode
Packit 0652a1
 *
Packit 0652a1
 * Set the ringbuffer to flushing mode or normal mode.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
void
Packit 0652a1
gst_audio_ring_buffer_set_flushing (GstAudioRingBuffer * buf, gboolean flushing)
Packit 0652a1
{
Packit 0652a1
  g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
Packit 0652a1
Packit 0652a1
  GST_OBJECT_LOCK (buf);
Packit 0652a1
  buf->flushing = flushing;
Packit 0652a1
Packit 0652a1
  if (flushing) {
Packit 0652a1
    gst_audio_ring_buffer_pause_unlocked (buf);
Packit 0652a1
  } else {
Packit 0652a1
    gst_audio_ring_buffer_clear_all (buf);
Packit 0652a1
  }
Packit 0652a1
  GST_OBJECT_UNLOCK (buf);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_is_flushing:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer
Packit 0652a1
 *
Packit 0652a1
 * Check if @buf is flushing.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 *
Packit 0652a1
 * Returns: TRUE if the device is flushing.
Packit 0652a1
 */
Packit 0652a1
gboolean
Packit 0652a1
gst_audio_ring_buffer_is_flushing (GstAudioRingBuffer * buf)
Packit 0652a1
{
Packit 0652a1
  gboolean res;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), TRUE);
Packit 0652a1
Packit 0652a1
  GST_OBJECT_LOCK (buf);
Packit 0652a1
  res = buf->flushing;
Packit 0652a1
  GST_OBJECT_UNLOCK (buf);
Packit 0652a1
Packit 0652a1
  return res;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_start:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to start
Packit 0652a1
 *
Packit 0652a1
 * Start processing samples from the ringbuffer.
Packit 0652a1
 *
Packit 0652a1
 * Returns: TRUE if the device could be started, FALSE on error.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
gboolean
Packit 0652a1
gst_audio_ring_buffer_start (GstAudioRingBuffer * buf)
Packit 0652a1
{
Packit 0652a1
  gboolean res = FALSE;
Packit 0652a1
  GstAudioRingBufferClass *rclass;
Packit 0652a1
  gboolean resume = FALSE;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
Packit 0652a1
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "starting ringbuffer");
Packit 0652a1
Packit 0652a1
  GST_OBJECT_LOCK (buf);
Packit 0652a1
  if (G_UNLIKELY (buf->flushing))
Packit 0652a1
    goto flushing;
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (!buf->acquired))
Packit 0652a1
    goto not_acquired;
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (!g_atomic_int_get (&buf->may_start)))
Packit 0652a1
    goto may_not_start;
Packit 0652a1
Packit 0652a1
  /* if stopped, set to started */
Packit 0652a1
  res = g_atomic_int_compare_and_exchange (&buf->state,
Packit 0652a1
      GST_AUDIO_RING_BUFFER_STATE_STOPPED, GST_AUDIO_RING_BUFFER_STATE_STARTED);
Packit 0652a1
Packit 0652a1
  if (!res) {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "was not stopped, try paused");
Packit 0652a1
    /* was not stopped, try from paused */
Packit 0652a1
    res = g_atomic_int_compare_and_exchange (&buf->state,
Packit 0652a1
        GST_AUDIO_RING_BUFFER_STATE_PAUSED,
Packit 0652a1
        GST_AUDIO_RING_BUFFER_STATE_STARTED);
Packit 0652a1
    if (!res) {
Packit 0652a1
      /* was not paused either, must be started then */
Packit 0652a1
      res = TRUE;
Packit 0652a1
      GST_DEBUG_OBJECT (buf, "was not paused, must have been started");
Packit 0652a1
      goto done;
Packit 0652a1
    }
Packit 0652a1
    resume = TRUE;
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "resuming");
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
Packit 0652a1
  if (resume) {
Packit 0652a1
    if (G_LIKELY (rclass->resume))
Packit 0652a1
      res = rclass->resume (buf);
Packit 0652a1
  } else {
Packit 0652a1
    if (G_LIKELY (rclass->start))
Packit 0652a1
      res = rclass->start (buf);
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (!res)) {
Packit 0652a1
    buf->state = GST_AUDIO_RING_BUFFER_STATE_PAUSED;
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "failed to start");
Packit 0652a1
  } else {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "started");
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
done:
Packit 0652a1
  GST_OBJECT_UNLOCK (buf);
Packit 0652a1
Packit 0652a1
  return res;
Packit 0652a1
Packit 0652a1
flushing:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "we are flushing");
Packit 0652a1
    GST_OBJECT_UNLOCK (buf);
Packit 0652a1
    return FALSE;
Packit 0652a1
  }
Packit 0652a1
not_acquired:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "we are not acquired");
Packit 0652a1
    GST_OBJECT_UNLOCK (buf);
Packit 0652a1
    return FALSE;
Packit 0652a1
  }
Packit 0652a1
may_not_start:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "we may not start");
Packit 0652a1
    GST_OBJECT_UNLOCK (buf);
Packit 0652a1
    return FALSE;
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static gboolean
Packit 0652a1
gst_audio_ring_buffer_pause_unlocked (GstAudioRingBuffer * buf)
Packit 0652a1
{
Packit 0652a1
  gboolean res = FALSE;
Packit 0652a1
  GstAudioRingBufferClass *rclass;
Packit 0652a1
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "pausing ringbuffer");
Packit 0652a1
Packit 0652a1
  /* if started, set to paused */
Packit 0652a1
  res = g_atomic_int_compare_and_exchange (&buf->state,
Packit 0652a1
      GST_AUDIO_RING_BUFFER_STATE_STARTED, GST_AUDIO_RING_BUFFER_STATE_PAUSED);
Packit 0652a1
Packit 0652a1
  if (!res)
Packit 0652a1
    goto not_started;
Packit 0652a1
Packit 0652a1
  /* signal any waiters */
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "signal waiter");
Packit 0652a1
  GST_AUDIO_RING_BUFFER_SIGNAL (buf);
Packit 0652a1
Packit 0652a1
  rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
Packit 0652a1
  if (G_LIKELY (rclass->pause))
Packit 0652a1
    res = rclass->pause (buf);
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (!res)) {
Packit 0652a1
    buf->state = GST_AUDIO_RING_BUFFER_STATE_STARTED;
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "failed to pause");
Packit 0652a1
  } else {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "paused");
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  return res;
Packit 0652a1
Packit 0652a1
not_started:
Packit 0652a1
  {
Packit 0652a1
    /* was not started */
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "was not started");
Packit 0652a1
    return TRUE;
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_pause:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to pause
Packit 0652a1
 *
Packit 0652a1
 * Pause processing samples from the ringbuffer.
Packit 0652a1
 *
Packit 0652a1
 * Returns: TRUE if the device could be paused, FALSE on error.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
gboolean
Packit 0652a1
gst_audio_ring_buffer_pause (GstAudioRingBuffer * buf)
Packit 0652a1
{
Packit 0652a1
  gboolean res = FALSE;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
Packit 0652a1
Packit 0652a1
  GST_OBJECT_LOCK (buf);
Packit 0652a1
  if (G_UNLIKELY (buf->flushing))
Packit 0652a1
    goto flushing;
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (!buf->acquired))
Packit 0652a1
    goto not_acquired;
Packit 0652a1
Packit 0652a1
  res = gst_audio_ring_buffer_pause_unlocked (buf);
Packit 0652a1
  GST_OBJECT_UNLOCK (buf);
Packit 0652a1
Packit 0652a1
  return res;
Packit 0652a1
Packit 0652a1
  /* ERRORS */
Packit 0652a1
flushing:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "we are flushing");
Packit 0652a1
    GST_OBJECT_UNLOCK (buf);
Packit 0652a1
    return FALSE;
Packit 0652a1
  }
Packit 0652a1
not_acquired:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "not acquired");
Packit 0652a1
    GST_OBJECT_UNLOCK (buf);
Packit 0652a1
    return FALSE;
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_stop:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to stop
Packit 0652a1
 *
Packit 0652a1
 * Stop processing samples from the ringbuffer.
Packit 0652a1
 *
Packit 0652a1
 * Returns: TRUE if the device could be stopped, FALSE on error.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
gboolean
Packit 0652a1
gst_audio_ring_buffer_stop (GstAudioRingBuffer * buf)
Packit 0652a1
{
Packit 0652a1
  gboolean res = FALSE;
Packit 0652a1
  GstAudioRingBufferClass *rclass;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
Packit 0652a1
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "stopping");
Packit 0652a1
Packit 0652a1
  GST_OBJECT_LOCK (buf);
Packit 0652a1
Packit 0652a1
  /* if started, set to stopped */
Packit 0652a1
  res = g_atomic_int_compare_and_exchange (&buf->state,
Packit 0652a1
      GST_AUDIO_RING_BUFFER_STATE_STARTED, GST_AUDIO_RING_BUFFER_STATE_STOPPED);
Packit 0652a1
Packit 0652a1
  if (!res) {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "was not started, try paused");
Packit 0652a1
    /* was not started, try from paused */
Packit 0652a1
    res = g_atomic_int_compare_and_exchange (&buf->state,
Packit 0652a1
        GST_AUDIO_RING_BUFFER_STATE_PAUSED,
Packit 0652a1
        GST_AUDIO_RING_BUFFER_STATE_STOPPED);
Packit 0652a1
    if (!res) {
Packit 0652a1
      /* was not paused either, must have been stopped then */
Packit 0652a1
      res = TRUE;
Packit 0652a1
      GST_DEBUG_OBJECT (buf, "was not paused, must have been stopped");
Packit 0652a1
      goto done;
Packit 0652a1
    }
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  /* signal any waiters */
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "signal waiter");
Packit 0652a1
  GST_AUDIO_RING_BUFFER_SIGNAL (buf);
Packit 0652a1
Packit 0652a1
  rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
Packit 0652a1
  if (G_LIKELY (rclass->stop))
Packit 0652a1
    res = rclass->stop (buf);
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (!res)) {
Packit 0652a1
    buf->state = GST_AUDIO_RING_BUFFER_STATE_STARTED;
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "failed to stop");
Packit 0652a1
  } else {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "stopped");
Packit 0652a1
  }
Packit 0652a1
done:
Packit 0652a1
  GST_OBJECT_UNLOCK (buf);
Packit 0652a1
Packit 0652a1
  return res;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_delay:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to query
Packit 0652a1
 *
Packit 0652a1
 * Get the number of samples queued in the audio device. This is
Packit 0652a1
 * usually less than the segment size but can be bigger when the
Packit 0652a1
 * implementation uses another internal buffer between the audio
Packit 0652a1
 * device.
Packit 0652a1
 *
Packit 0652a1
 * For playback ringbuffers this is the amount of samples transfered from the
Packit 0652a1
 * ringbuffer to the device but still not played.
Packit 0652a1
 *
Packit 0652a1
 * For capture ringbuffers this is the amount of samples in the device that are
Packit 0652a1
 * not yet transfered to the ringbuffer.
Packit 0652a1
 *
Packit 0652a1
 * Returns: The number of samples queued in the audio device.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
guint
Packit 0652a1
gst_audio_ring_buffer_delay (GstAudioRingBuffer * buf)
Packit 0652a1
{
Packit 0652a1
  GstAudioRingBufferClass *rclass;
Packit 0652a1
  guint res;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), 0);
Packit 0652a1
Packit 0652a1
  /* buffer must be acquired */
Packit 0652a1
  if (G_UNLIKELY (!gst_audio_ring_buffer_is_acquired (buf)))
Packit 0652a1
    goto not_acquired;
Packit 0652a1
Packit 0652a1
  rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
Packit 0652a1
  if (G_LIKELY (rclass->delay))
Packit 0652a1
    res = rclass->delay (buf);
Packit 0652a1
  else
Packit 0652a1
    res = 0;
Packit 0652a1
Packit 0652a1
  return res;
Packit 0652a1
Packit 0652a1
not_acquired:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "not acquired");
Packit 0652a1
    return 0;
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_samples_done:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to query
Packit 0652a1
 *
Packit 0652a1
 * Get the number of samples that were processed by the ringbuffer
Packit 0652a1
 * since it was last started. This does not include the number of samples not
Packit 0652a1
 * yet processed (see gst_audio_ring_buffer_delay()).
Packit 0652a1
 *
Packit 0652a1
 * Returns: The number of samples processed by the ringbuffer.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
guint64
Packit 0652a1
gst_audio_ring_buffer_samples_done (GstAudioRingBuffer * buf)
Packit 0652a1
{
Packit 0652a1
  gint segdone;
Packit 0652a1
  guint64 samples;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), 0);
Packit 0652a1
Packit 0652a1
  /* get the amount of segments we processed */
Packit 0652a1
  segdone = g_atomic_int_get (&buf->segdone);
Packit 0652a1
Packit 0652a1
  /* convert to samples */
Packit 0652a1
  samples = ((guint64) segdone) * buf->samples_per_seg;
Packit 0652a1
Packit 0652a1
  return samples;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_set_sample:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to use
Packit 0652a1
 * @sample: the sample number to set
Packit 0652a1
 *
Packit 0652a1
 * Make sure that the next sample written to the device is
Packit 0652a1
 * accounted for as being the @sample sample written to the
Packit 0652a1
 * device. This value will be used in reporting the current
Packit 0652a1
 * sample position of the ringbuffer.
Packit 0652a1
 *
Packit 0652a1
 * This function will also clear the buffer with silence.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
void
Packit 0652a1
gst_audio_ring_buffer_set_sample (GstAudioRingBuffer * buf, guint64 sample)
Packit 0652a1
{
Packit 0652a1
  g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
Packit 0652a1
Packit 0652a1
  if (sample == -1)
Packit 0652a1
    sample = 0;
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (buf->samples_per_seg == 0))
Packit 0652a1
    return;
Packit 0652a1
Packit 0652a1
  /* FIXME, we assume the ringbuffer can restart at a random
Packit 0652a1
   * position, round down to the beginning and keep track of
Packit 0652a1
   * offset when calculating the processed samples. */
Packit 0652a1
  buf->segbase = buf->segdone - sample / buf->samples_per_seg;
Packit 0652a1
Packit 0652a1
  gst_audio_ring_buffer_clear_all (buf);
Packit 0652a1
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "set sample to %" G_GUINT64_FORMAT ", segbase %d",
Packit 0652a1
      sample, buf->segbase);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
static void
Packit 0652a1
default_clear_all (GstAudioRingBuffer * buf)
Packit 0652a1
{
Packit 0652a1
  gint i;
Packit 0652a1
Packit 0652a1
  /* not fatal, we just are not negotiated yet */
Packit 0652a1
  if (G_UNLIKELY (buf->spec.segtotal <= 0))
Packit 0652a1
    return;
Packit 0652a1
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "clear all segments");
Packit 0652a1
Packit 0652a1
  for (i = 0; i < buf->spec.segtotal; i++) {
Packit 0652a1
    gst_audio_ring_buffer_clear (buf, i);
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_clear_all:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to clear
Packit 0652a1
 *
Packit 0652a1
 * Fill the ringbuffer with silence.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
void
Packit 0652a1
gst_audio_ring_buffer_clear_all (GstAudioRingBuffer * buf)
Packit 0652a1
{
Packit 0652a1
  GstAudioRingBufferClass *rclass;
Packit 0652a1
Packit 0652a1
  g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
Packit 0652a1
Packit 0652a1
  rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
Packit 0652a1
Packit 0652a1
  if (G_LIKELY (rclass->clear_all))
Packit 0652a1
    rclass->clear_all (buf);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
Packit 0652a1
static gboolean
Packit 0652a1
wait_segment (GstAudioRingBuffer * buf)
Packit 0652a1
{
Packit 0652a1
  gint segments;
Packit 0652a1
  gboolean wait = TRUE;
Packit 0652a1
Packit 0652a1
  /* buffer must be started now or we deadlock since nobody is reading */
Packit 0652a1
  if (G_UNLIKELY (g_atomic_int_get (&buf->state) !=
Packit 0652a1
          GST_AUDIO_RING_BUFFER_STATE_STARTED)) {
Packit 0652a1
    /* see if we are allowed to start it */
Packit 0652a1
    if (G_UNLIKELY (!g_atomic_int_get (&buf->may_start)))
Packit 0652a1
      goto no_start;
Packit 0652a1
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "start!");
Packit 0652a1
    segments = g_atomic_int_get (&buf->segdone);
Packit 0652a1
    gst_audio_ring_buffer_start (buf);
Packit 0652a1
Packit 0652a1
    /* After starting, the writer may have wrote segments already and then we
Packit 0652a1
     * don't need to wait anymore */
Packit 0652a1
    if (G_LIKELY (g_atomic_int_get (&buf->segdone) != segments))
Packit 0652a1
      wait = FALSE;
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  /* take lock first, then update our waiting flag */
Packit 0652a1
  GST_OBJECT_LOCK (buf);
Packit 0652a1
  if (G_UNLIKELY (buf->flushing))
Packit 0652a1
    goto flushing;
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (g_atomic_int_get (&buf->state) !=
Packit 0652a1
          GST_AUDIO_RING_BUFFER_STATE_STARTED))
Packit 0652a1
    goto not_started;
Packit 0652a1
Packit 0652a1
  if (G_LIKELY (wait)) {
Packit 0652a1
    if (g_atomic_int_compare_and_exchange (&buf->waiting, 0, 1)) {
Packit 0652a1
      GST_DEBUG_OBJECT (buf, "waiting..");
Packit 0652a1
      GST_AUDIO_RING_BUFFER_WAIT (buf);
Packit 0652a1
Packit 0652a1
      if (G_UNLIKELY (buf->flushing))
Packit 0652a1
        goto flushing;
Packit 0652a1
Packit 0652a1
      if (G_UNLIKELY (g_atomic_int_get (&buf->state) !=
Packit 0652a1
              GST_AUDIO_RING_BUFFER_STATE_STARTED))
Packit 0652a1
        goto not_started;
Packit 0652a1
    }
Packit 0652a1
  }
Packit 0652a1
  GST_OBJECT_UNLOCK (buf);
Packit 0652a1
Packit 0652a1
  return TRUE;
Packit 0652a1
Packit 0652a1
  /* ERROR */
Packit 0652a1
not_started:
Packit 0652a1
  {
Packit 0652a1
    g_atomic_int_compare_and_exchange (&buf->waiting, 1, 0);
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "stopped processing");
Packit 0652a1
    GST_OBJECT_UNLOCK (buf);
Packit 0652a1
    return FALSE;
Packit 0652a1
  }
Packit 0652a1
flushing:
Packit 0652a1
  {
Packit 0652a1
    g_atomic_int_compare_and_exchange (&buf->waiting, 1, 0);
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "flushing");
Packit 0652a1
    GST_OBJECT_UNLOCK (buf);
Packit 0652a1
    return FALSE;
Packit 0652a1
  }
Packit 0652a1
no_start:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "not allowed to start");
Packit 0652a1
    return FALSE;
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
Packit 0652a1
Packit 0652a1
#define REORDER_SAMPLE(d, s, l)                 \
Packit 0652a1
G_STMT_START {                                  \
Packit 0652a1
  gint i;                                       \
Packit 0652a1
  for (i = 0; i < channels; i++) {              \
Packit 0652a1
    memcpy (d + reorder_map[i] * bps, s + i * bps, bps); \
Packit 0652a1
  }                                             \
Packit 0652a1
} G_STMT_END
Packit 0652a1
Packit 0652a1
#define REORDER_SAMPLES(d, s, len)              \
Packit 0652a1
G_STMT_START {                                  \
Packit 0652a1
  gint i, len_ = len / bpf;                     \
Packit 0652a1
  guint8 *d_ = d, *s_ = s;                      \
Packit 0652a1
  for (i = 0; i < len_; i++) {                  \
Packit 0652a1
    REORDER_SAMPLE(d_, s_, bpf);                \
Packit 0652a1
    d_ += bpf;                                  \
Packit 0652a1
    s_ += bpf;                                  \
Packit 0652a1
  }                                             \
Packit 0652a1
} G_STMT_END
Packit 0652a1
Packit 0652a1
#define FWD_SAMPLES(s,se,d,de,F)         	\
Packit 0652a1
G_STMT_START {					\
Packit 0652a1
  /* no rate conversion */			\
Packit 0652a1
  guint towrite = MIN (se + bpf - s, de - d);	\
Packit 0652a1
  /* simple copy */				\
Packit 0652a1
  if (!skip)					\
Packit 0652a1
    F (d, s, towrite);			        \
Packit 0652a1
  in_samples -= towrite / bpf;			\
Packit 0652a1
  out_samples -= towrite / bpf;			\
Packit 0652a1
  s += towrite;					\
Packit 0652a1
  GST_DEBUG ("copy %u bytes", towrite);		\
Packit 0652a1
} G_STMT_END
Packit 0652a1
Packit 0652a1
/* in_samples >= out_samples, rate > 1.0 */
Packit 0652a1
#define FWD_UP_SAMPLES(s,se,d,de,F) 	 	\
Packit 0652a1
G_STMT_START {					\
Packit 0652a1
  guint8 *sb = s, *db = d;			\
Packit 0652a1
  while (s <= se && d < de) {			\
Packit 0652a1
    if (!skip)					\
Packit 0652a1
      F (d, s, bpf);	       	        	\
Packit 0652a1
    s += bpf;					\
Packit 0652a1
    *accum += outr;				\
Packit 0652a1
    if ((*accum << 1) >= inr) {			\
Packit 0652a1
      *accum -= inr;				\
Packit 0652a1
      d += bpf;					\
Packit 0652a1
    }						\
Packit 0652a1
  }						\
Packit 0652a1
  in_samples -= (s - sb)/bpf;			\
Packit 0652a1
  out_samples -= (d - db)/bpf;			\
Packit 0652a1
  GST_DEBUG ("fwd_up end %d/%d",*accum,*toprocess);	\
Packit 0652a1
} G_STMT_END
Packit 0652a1
Packit 0652a1
/* out_samples > in_samples, for rates smaller than 1.0 */
Packit 0652a1
#define FWD_DOWN_SAMPLES(s,se,d,de,F) 	 	\
Packit 0652a1
G_STMT_START {					\
Packit 0652a1
  guint8 *sb = s, *db = d;			\
Packit 0652a1
  while (s <= se && d < de) {			\
Packit 0652a1
    if (!skip)					\
Packit 0652a1
      F (d, s, bpf);	              		\
Packit 0652a1
    d += bpf;					\
Packit 0652a1
    *accum += inr;				\
Packit 0652a1
    if ((*accum << 1) >= outr) {		\
Packit 0652a1
      *accum -= outr;				\
Packit 0652a1
      s += bpf;					\
Packit 0652a1
    }						\
Packit 0652a1
  }						\
Packit 0652a1
  in_samples -= (s - sb)/bpf;			\
Packit 0652a1
  out_samples -= (d - db)/bpf;			\
Packit 0652a1
  GST_DEBUG ("fwd_down end %d/%d",*accum,*toprocess);	\
Packit 0652a1
} G_STMT_END
Packit 0652a1
Packit 0652a1
#define REV_UP_SAMPLES(s,se,d,de,F) 	 	\
Packit 0652a1
G_STMT_START {					\
Packit 0652a1
  guint8 *sb = se, *db = d;			\
Packit 0652a1
  while (s <= se && d < de) {			\
Packit 0652a1
    if (!skip)					\
Packit 0652a1
      F (d, se, bpf);                  		\
Packit 0652a1
    se -= bpf;					\
Packit 0652a1
    *accum += outr;				\
Packit 0652a1
    while (d < de && (*accum << 1) >= inr) {	\
Packit 0652a1
      *accum -= inr;				\
Packit 0652a1
      d += bpf;					\
Packit 0652a1
    }						\
Packit 0652a1
  }						\
Packit 0652a1
  in_samples -= (sb - se)/bpf;			\
Packit 0652a1
  out_samples -= (d - db)/bpf;			\
Packit 0652a1
  GST_DEBUG ("rev_up end %d/%d",*accum,*toprocess);	\
Packit 0652a1
} G_STMT_END
Packit 0652a1
Packit 0652a1
#define REV_DOWN_SAMPLES(s,se,d,de,F) 	 	\
Packit 0652a1
G_STMT_START {					\
Packit 0652a1
  guint8 *sb = se, *db = d;			\
Packit 0652a1
  while (s <= se && d < de) {			\
Packit 0652a1
    if (!skip)					\
Packit 0652a1
      F (d, se, bpf);        			\
Packit 0652a1
    d += bpf;					\
Packit 0652a1
    *accum += inr;				\
Packit 0652a1
    while (s <= se && (*accum << 1) >= outr) {	\
Packit 0652a1
      *accum -= outr;				\
Packit 0652a1
      se -= bpf;				\
Packit 0652a1
    }						\
Packit 0652a1
  }						\
Packit 0652a1
  in_samples -= (sb - se)/bpf;			\
Packit 0652a1
  out_samples -= (d - db)/bpf;			\
Packit 0652a1
  GST_DEBUG ("rev_down end %d/%d",*accum,*toprocess);	\
Packit 0652a1
} G_STMT_END
Packit 0652a1
Packit 0652a1
static guint
Packit 0652a1
default_commit (GstAudioRingBuffer * buf, guint64 * sample,
Packit 0652a1
    guint8 * data, gint in_samples, gint out_samples, gint * accum)
Packit 0652a1
{
Packit 0652a1
  gint segdone;
Packit 0652a1
  gint segsize, segtotal, channels, bps, bpf, sps;
Packit 0652a1
  guint8 *dest, *data_end;
Packit 0652a1
  gint writeseg, sampleoff;
Packit 0652a1
  gint *toprocess;
Packit 0652a1
  gint inr, outr;
Packit 0652a1
  gboolean reverse;
Packit 0652a1
  gboolean need_reorder;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (buf->memory != NULL, -1);
Packit 0652a1
  g_return_val_if_fail (data != NULL, -1);
Packit 0652a1
Packit 0652a1
  need_reorder = buf->need_reorder;
Packit 0652a1
Packit 0652a1
  channels = buf->spec.info.channels;
Packit 0652a1
  dest = buf->memory;
Packit 0652a1
  segsize = buf->spec.segsize;
Packit 0652a1
  segtotal = buf->spec.segtotal;
Packit 0652a1
  bpf = buf->spec.info.bpf;
Packit 0652a1
  bps = bpf / channels;
Packit 0652a1
  sps = buf->samples_per_seg;
Packit 0652a1
Packit 0652a1
  reverse = out_samples < 0;
Packit 0652a1
  out_samples = ABS (out_samples);
Packit 0652a1
Packit 0652a1
  if (in_samples >= out_samples)
Packit 0652a1
    toprocess = &in_samples;
Packit 0652a1
  else
Packit 0652a1
    toprocess = &out_samples;
Packit 0652a1
Packit 0652a1
  inr = in_samples - 1;
Packit 0652a1
  outr = out_samples - 1;
Packit 0652a1
Packit 0652a1
  /* data_end points to the last sample we have to write, not past it. This is
Packit 0652a1
   * needed to properly handle reverse playback: it points to the last sample. */
Packit 0652a1
  data_end = data + (bpf * inr);
Packit 0652a1
Packit 0652a1
  /* figure out the segment and the offset inside the segment where
Packit 0652a1
   * the first sample should be written. */
Packit 0652a1
  writeseg = *sample / sps;
Packit 0652a1
  sampleoff = (*sample % sps) * bpf;
Packit 0652a1
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "write %d : %d", in_samples, out_samples);
Packit 0652a1
Packit 0652a1
  /* write out all samples */
Packit 0652a1
  while (*toprocess > 0) {
Packit 0652a1
    gint avail;
Packit 0652a1
    guint8 *d, *d_end;
Packit 0652a1
    gint ws;
Packit 0652a1
    gboolean skip;
Packit 0652a1
Packit 0652a1
    while (TRUE) {
Packit 0652a1
      gint diff;
Packit 0652a1
Packit 0652a1
      /* get the currently processed segment */
Packit 0652a1
      segdone = g_atomic_int_get (&buf->segdone) - buf->segbase;
Packit 0652a1
Packit 0652a1
      /* see how far away it is from the write segment */
Packit 0652a1
      diff = writeseg - segdone;
Packit 0652a1
Packit 0652a1
      GST_DEBUG_OBJECT (buf,
Packit 0652a1
          "pointer at %d, write to %d-%d, diff %d, segtotal %d, segsize %d, base %d",
Packit 0652a1
          segdone, writeseg, sampleoff, diff, segtotal, segsize, buf->segbase);
Packit 0652a1
Packit 0652a1
      /* segment too far ahead, writer too slow, we need to drop, hopefully UNLIKELY */
Packit 0652a1
      if (G_UNLIKELY (diff < 0)) {
Packit 0652a1
        /* we need to drop one segment at a time, pretend we wrote a segment. */
Packit 0652a1
        skip = TRUE;
Packit 0652a1
        break;
Packit 0652a1
      }
Packit 0652a1
Packit 0652a1
      /* write segment is within writable range, we can break the loop and
Packit 0652a1
       * start writing the data. */
Packit 0652a1
      if (diff < segtotal) {
Packit 0652a1
        skip = FALSE;
Packit 0652a1
        break;
Packit 0652a1
      }
Packit 0652a1
Packit 0652a1
      /* else we need to wait for the segment to become writable. */
Packit 0652a1
      if (!wait_segment (buf))
Packit 0652a1
        goto not_started;
Packit 0652a1
    }
Packit 0652a1
Packit 0652a1
    /* we can write now */
Packit 0652a1
    ws = writeseg % segtotal;
Packit 0652a1
    avail = MIN (segsize - sampleoff, bpf * out_samples);
Packit 0652a1
Packit 0652a1
    d = dest + (ws * segsize) + sampleoff;
Packit 0652a1
    d_end = d + avail;
Packit 0652a1
    *sample += avail / bpf;
Packit 0652a1
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "write @%p seg %d, sps %d, off %d, avail %d",
Packit 0652a1
        dest + ws * segsize, ws, sps, sampleoff, avail);
Packit 0652a1
Packit 0652a1
    if (need_reorder) {
Packit 0652a1
      gint *reorder_map = buf->channel_reorder_map;
Packit 0652a1
Packit 0652a1
      if (G_LIKELY (inr == outr && !reverse)) {
Packit 0652a1
        /* no rate conversion, simply copy samples */
Packit 0652a1
        FWD_SAMPLES (data, data_end, d, d_end, REORDER_SAMPLES);
Packit 0652a1
      } else if (!reverse) {
Packit 0652a1
        if (inr >= outr)
Packit 0652a1
          /* forward speed up */
Packit 0652a1
          FWD_UP_SAMPLES (data, data_end, d, d_end, REORDER_SAMPLE);
Packit 0652a1
        else
Packit 0652a1
          /* forward slow down */
Packit 0652a1
          FWD_DOWN_SAMPLES (data, data_end, d, d_end, REORDER_SAMPLE);
Packit 0652a1
      } else {
Packit 0652a1
        if (inr >= outr)
Packit 0652a1
          /* reverse speed up */
Packit 0652a1
          REV_UP_SAMPLES (data, data_end, d, d_end, REORDER_SAMPLE);
Packit 0652a1
        else
Packit 0652a1
          /* reverse slow down */
Packit 0652a1
          REV_DOWN_SAMPLES (data, data_end, d, d_end, REORDER_SAMPLE);
Packit 0652a1
      }
Packit 0652a1
    } else {
Packit 0652a1
      if (G_LIKELY (inr == outr && !reverse)) {
Packit 0652a1
        /* no rate conversion, simply copy samples */
Packit 0652a1
        FWD_SAMPLES (data, data_end, d, d_end, memcpy);
Packit 0652a1
      } else if (!reverse) {
Packit 0652a1
        if (inr >= outr)
Packit 0652a1
          /* forward speed up */
Packit 0652a1
          FWD_UP_SAMPLES (data, data_end, d, d_end, memcpy);
Packit 0652a1
        else
Packit 0652a1
          /* forward slow down */
Packit 0652a1
          FWD_DOWN_SAMPLES (data, data_end, d, d_end, memcpy);
Packit 0652a1
      } else {
Packit 0652a1
        if (inr >= outr)
Packit 0652a1
          /* reverse speed up */
Packit 0652a1
          REV_UP_SAMPLES (data, data_end, d, d_end, memcpy);
Packit 0652a1
        else
Packit 0652a1
          /* reverse slow down */
Packit 0652a1
          REV_DOWN_SAMPLES (data, data_end, d, d_end, memcpy);
Packit 0652a1
      }
Packit 0652a1
    }
Packit 0652a1
Packit 0652a1
    /* for the next iteration we write to the next segment at the beginning. */
Packit 0652a1
    writeseg++;
Packit 0652a1
    sampleoff = 0;
Packit 0652a1
  }
Packit 0652a1
  /* we consumed all samples here */
Packit 0652a1
  data = data_end + bpf;
Packit 0652a1
Packit 0652a1
done:
Packit 0652a1
  return inr - ((data_end - data) / bpf);
Packit 0652a1
Packit 0652a1
  /* ERRORS */
Packit 0652a1
not_started:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "stopped processing");
Packit 0652a1
    goto done;
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_commit:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to commit
Packit 0652a1
 * @sample: the sample position of the data
Packit 0652a1
 * @data: (array length=in_samples): the data to commit
Packit 0652a1
 * @in_samples: the number of samples in the data to commit
Packit 0652a1
 * @out_samples: the number of samples to write to the ringbuffer
Packit 0652a1
 * @accum: (inout): accumulator for rate conversion.
Packit 0652a1
 *
Packit 0652a1
 * Commit @in_samples samples pointed to by @data to the ringbuffer @buf.
Packit 0652a1
 *
Packit 0652a1
 * @in_samples and @out_samples define the rate conversion to perform on the
Packit 0652a1
 * samples in @data. For negative rates, @out_samples must be negative and
Packit 0652a1
 * @in_samples positive.
Packit 0652a1
 *
Packit 0652a1
 * When @out_samples is positive, the first sample will be written at position @sample
Packit 0652a1
 * in the ringbuffer. When @out_samples is negative, the last sample will be written to
Packit 0652a1
 * @sample in reverse order.
Packit 0652a1
 *
Packit 0652a1
 * @out_samples does not need to be a multiple of the segment size of the ringbuffer
Packit 0652a1
 * although it is recommended for optimal performance.
Packit 0652a1
 *
Packit 0652a1
 * @accum will hold a temporary accumulator used in rate conversion and should be
Packit 0652a1
 * set to 0 when this function is first called. In case the commit operation is
Packit 0652a1
 * interrupted, one can resume the processing by passing the previously returned
Packit 0652a1
 * @accum value back to this function.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 *
Packit 0652a1
 * Returns: The number of samples written to the ringbuffer or -1 on error. The
Packit 0652a1
 * number of samples written can be less than @out_samples when @buf was interrupted
Packit 0652a1
 * with a flush or stop.
Packit 0652a1
 */
Packit 0652a1
guint
Packit 0652a1
gst_audio_ring_buffer_commit (GstAudioRingBuffer * buf, guint64 * sample,
Packit 0652a1
    guint8 * data, gint in_samples, gint out_samples, gint * accum)
Packit 0652a1
{
Packit 0652a1
  GstAudioRingBufferClass *rclass;
Packit 0652a1
  guint res = -1;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), -1);
Packit 0652a1
Packit 0652a1
  if (G_UNLIKELY (in_samples == 0 || out_samples == 0))
Packit 0652a1
    return in_samples;
Packit 0652a1
Packit 0652a1
  rclass = GST_AUDIO_RING_BUFFER_GET_CLASS (buf);
Packit 0652a1
Packit 0652a1
  if (G_LIKELY (rclass->commit))
Packit 0652a1
    res = rclass->commit (buf, sample, data, in_samples, out_samples, accum);
Packit 0652a1
Packit 0652a1
  return res;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_read:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to read from
Packit 0652a1
 * @sample: the sample position of the data
Packit 0652a1
 * @data: (array length=len): where the data should be read
Packit 0652a1
 * @len: the number of samples in data to read
Packit 0652a1
 * @timestamp: (out): where the timestamp is returned
Packit 0652a1
 *
Packit 0652a1
 * Read @len samples from the ringbuffer into the memory pointed
Packit 0652a1
 * to by @data.
Packit 0652a1
 * The first sample should be read from position @sample in
Packit 0652a1
 * the ringbuffer.
Packit 0652a1
 *
Packit 0652a1
 * @len should not be a multiple of the segment size of the ringbuffer
Packit 0652a1
 * although it is recommended.
Packit 0652a1
 *
Packit 0652a1
 * @timestamp will return the timestamp associated with the data returned.
Packit 0652a1
 *
Packit 0652a1
 * Returns: The number of samples read from the ringbuffer or -1 on
Packit 0652a1
 * error.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
guint
Packit 0652a1
gst_audio_ring_buffer_read (GstAudioRingBuffer * buf, guint64 sample,
Packit 0652a1
    guint8 * data, guint len, GstClockTime * timestamp)
Packit 0652a1
{
Packit 0652a1
  gint segdone;
Packit 0652a1
  gint segsize, segtotal, channels, bps, bpf, sps, readseg = 0;
Packit 0652a1
  guint8 *dest;
Packit 0652a1
  guint to_read;
Packit 0652a1
  gboolean need_reorder;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), -1);
Packit 0652a1
  g_return_val_if_fail (buf->memory != NULL, -1);
Packit 0652a1
  g_return_val_if_fail (data != NULL, -1);
Packit 0652a1
Packit 0652a1
  need_reorder = buf->need_reorder;
Packit 0652a1
  dest = buf->memory;
Packit 0652a1
  segsize = buf->spec.segsize;
Packit 0652a1
  segtotal = buf->spec.segtotal;
Packit 0652a1
  channels = buf->spec.info.channels;
Packit 0652a1
  bpf = buf->spec.info.bpf;
Packit 0652a1
  bps = bpf / channels;
Packit 0652a1
  sps = buf->samples_per_seg;
Packit 0652a1
Packit 0652a1
  to_read = len;
Packit 0652a1
  /* read enough samples */
Packit 0652a1
  while (to_read > 0) {
Packit 0652a1
    gint sampleslen;
Packit 0652a1
    gint sampleoff;
Packit 0652a1
Packit 0652a1
    /* figure out the segment and the offset inside the segment where
Packit 0652a1
     * the sample should be read from. */
Packit 0652a1
    readseg = sample / sps;
Packit 0652a1
    sampleoff = (sample % sps);
Packit 0652a1
Packit 0652a1
    while (TRUE) {
Packit 0652a1
      gint diff;
Packit 0652a1
Packit 0652a1
      /* get the currently processed segment */
Packit 0652a1
      segdone = g_atomic_int_get (&buf->segdone) - buf->segbase;
Packit 0652a1
Packit 0652a1
      /* see how far away it is from the read segment, normally segdone (where
Packit 0652a1
       * the hardware is writing) is bigger than readseg (where software is
Packit 0652a1
       * reading) */
Packit 0652a1
      diff = segdone - readseg;
Packit 0652a1
Packit 0652a1
      GST_DEBUG_OBJECT
Packit 0652a1
          (buf, "pointer at %d, sample %" G_GUINT64_FORMAT
Packit 0652a1
          ", read from %d-%d, to_read %d, diff %d, segtotal %d, segsize %d",
Packit 0652a1
          segdone, sample, readseg, sampleoff, to_read, diff, segtotal,
Packit 0652a1
          segsize);
Packit 0652a1
Packit 0652a1
      /* segment too far ahead, reader too slow */
Packit 0652a1
      if (G_UNLIKELY (diff >= segtotal)) {
Packit 0652a1
        /* pretend we read an empty segment. */
Packit 0652a1
        sampleslen = MIN (sps, to_read);
Packit 0652a1
        memcpy (data, buf->empty_seg, sampleslen * bpf);
Packit 0652a1
        goto next;
Packit 0652a1
      }
Packit 0652a1
Packit 0652a1
      /* read segment is within readable range, we can break the loop and
Packit 0652a1
       * start reading the data. */
Packit 0652a1
      if (diff > 0)
Packit 0652a1
        break;
Packit 0652a1
Packit 0652a1
      /* else we need to wait for the segment to become readable. */
Packit 0652a1
      if (!wait_segment (buf))
Packit 0652a1
        goto not_started;
Packit 0652a1
    }
Packit 0652a1
Packit 0652a1
    /* we can read now */
Packit 0652a1
    readseg = readseg % segtotal;
Packit 0652a1
    sampleslen = MIN (sps - sampleoff, to_read);
Packit 0652a1
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "read @%p seg %d, off %d, sampleslen %d",
Packit 0652a1
        dest + readseg * segsize, readseg, sampleoff, sampleslen);
Packit 0652a1
Packit 0652a1
    if (need_reorder) {
Packit 0652a1
      guint8 *ptr = dest + (readseg * segsize) + (sampleoff * bpf);
Packit 0652a1
      gint i, j;
Packit 0652a1
      gint *reorder_map = buf->channel_reorder_map;
Packit 0652a1
Packit 0652a1
      /* Reorder from device order to GStreamer order */
Packit 0652a1
      for (i = 0; i < sampleslen; i++) {
Packit 0652a1
        for (j = 0; j < channels; j++) {
Packit 0652a1
          memcpy (data + i * bpf + reorder_map[j] * bps, ptr + j * bps, bps);
Packit 0652a1
        }
Packit 0652a1
        ptr += bpf;
Packit 0652a1
      }
Packit 0652a1
    } else {
Packit 0652a1
      memcpy (data, dest + (readseg * segsize) + (sampleoff * bpf),
Packit 0652a1
          (sampleslen * bpf));
Packit 0652a1
    }
Packit 0652a1
Packit 0652a1
  next:
Packit 0652a1
    to_read -= sampleslen;
Packit 0652a1
    sample += sampleslen;
Packit 0652a1
    data += sampleslen * bpf;
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  if (buf->timestamps && timestamp) {
Packit 0652a1
    *timestamp = buf->timestamps[readseg % segtotal];
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "Retrieved timestamp %" GST_TIME_FORMAT
Packit 0652a1
        " @ %d", GST_TIME_ARGS (*timestamp), readseg % segtotal);
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  return len - to_read;
Packit 0652a1
Packit 0652a1
  /* ERRORS */
Packit 0652a1
not_started:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "stopped processing");
Packit 0652a1
    return len - to_read;
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_prepare_read:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to read from
Packit 0652a1
 * @segment: (out): the segment to read
Packit 0652a1
 * @readptr: (out) (array length=len):
Packit 0652a1
 *     the pointer to the memory where samples can be read
Packit 0652a1
 * @len: (out): the number of bytes to read
Packit 0652a1
 *
Packit 0652a1
 * Returns a pointer to memory where the data from segment @segment
Packit 0652a1
 * can be found. This function is mostly used by subclasses.
Packit 0652a1
 *
Packit 0652a1
 * Returns: FALSE if the buffer is not started.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
gboolean
Packit 0652a1
gst_audio_ring_buffer_prepare_read (GstAudioRingBuffer * buf, gint * segment,
Packit 0652a1
    guint8 ** readptr, gint * len)
Packit 0652a1
{
Packit 0652a1
  guint8 *data;
Packit 0652a1
  gint segdone;
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
Packit 0652a1
Packit 0652a1
  if (buf->callback == NULL) {
Packit 0652a1
    /* push mode, fail when nothing is started */
Packit 0652a1
    if (g_atomic_int_get (&buf->state) != GST_AUDIO_RING_BUFFER_STATE_STARTED)
Packit 0652a1
      return FALSE;
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  g_return_val_if_fail (buf->memory != NULL, FALSE);
Packit 0652a1
  g_return_val_if_fail (segment != NULL, FALSE);
Packit 0652a1
  g_return_val_if_fail (readptr != NULL, FALSE);
Packit 0652a1
  g_return_val_if_fail (len != NULL, FALSE);
Packit 0652a1
Packit 0652a1
  data = buf->memory;
Packit 0652a1
Packit 0652a1
  /* get the position of the pointer */
Packit 0652a1
  segdone = g_atomic_int_get (&buf->segdone);
Packit 0652a1
Packit 0652a1
  *segment = segdone % buf->spec.segtotal;
Packit 0652a1
  *len = buf->spec.segsize;
Packit 0652a1
  *readptr = data + *segment * *len;
Packit 0652a1
Packit 0652a1
  GST_LOG_OBJECT (buf, "prepare read from segment %d (real %d) @%p",
Packit 0652a1
      *segment, segdone, *readptr);
Packit 0652a1
Packit 0652a1
  /* callback to fill the memory with data, for pull based
Packit 0652a1
   * scheduling. */
Packit 0652a1
  if (buf->callback)
Packit 0652a1
    buf->callback (buf, *readptr, *len, buf->cb_data);
Packit 0652a1
Packit 0652a1
  return TRUE;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_advance:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to advance
Packit 0652a1
 * @advance: the number of segments written
Packit 0652a1
 *
Packit 0652a1
 * Subclasses should call this function to notify the fact that
Packit 0652a1
 * @advance segments are now processed by the device.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
void
Packit 0652a1
gst_audio_ring_buffer_advance (GstAudioRingBuffer * buf, guint advance)
Packit 0652a1
{
Packit 0652a1
  g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
Packit 0652a1
Packit 0652a1
  /* update counter */
Packit 0652a1
  g_atomic_int_add (&buf->segdone, advance);
Packit 0652a1
Packit 0652a1
  /* the lock is already taken when the waiting flag is set,
Packit 0652a1
   * we grab the lock as well to make sure the waiter is actually
Packit 0652a1
   * waiting for the signal */
Packit 0652a1
  if (g_atomic_int_compare_and_exchange (&buf->waiting, 1, 0)) {
Packit 0652a1
    GST_OBJECT_LOCK (buf);
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "signal waiter");
Packit 0652a1
    GST_AUDIO_RING_BUFFER_SIGNAL (buf);
Packit 0652a1
    GST_OBJECT_UNLOCK (buf);
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_clear:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer to clear
Packit 0652a1
 * @segment: the segment to clear
Packit 0652a1
 *
Packit 0652a1
 * Clear the given segment of the buffer with silence samples.
Packit 0652a1
 * This function is used by subclasses.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
void
Packit 0652a1
gst_audio_ring_buffer_clear (GstAudioRingBuffer * buf, gint segment)
Packit 0652a1
{
Packit 0652a1
  guint8 *data;
Packit 0652a1
Packit 0652a1
  g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
Packit 0652a1
Packit 0652a1
  /* no data means it's already cleared */
Packit 0652a1
  if (G_UNLIKELY (buf->memory == NULL))
Packit 0652a1
    return;
Packit 0652a1
Packit 0652a1
  /* no empty_seg means it's not opened */
Packit 0652a1
  if (G_UNLIKELY (buf->empty_seg == NULL))
Packit 0652a1
    return;
Packit 0652a1
Packit 0652a1
  segment %= buf->spec.segtotal;
Packit 0652a1
Packit 0652a1
  data = buf->memory;
Packit 0652a1
  data += segment * buf->spec.segsize;
Packit 0652a1
Packit 0652a1
  GST_LOG_OBJECT (buf, "clear segment %d @%p", segment, data);
Packit 0652a1
Packit 0652a1
  memcpy (data, buf->empty_seg, buf->spec.segsize);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_may_start:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer
Packit 0652a1
 * @allowed: the new value
Packit 0652a1
 *
Packit 0652a1
 * Tell the ringbuffer that it is allowed to start playback when
Packit 0652a1
 * the ringbuffer is filled with samples.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
void
Packit 0652a1
gst_audio_ring_buffer_may_start (GstAudioRingBuffer * buf, gboolean allowed)
Packit 0652a1
{
Packit 0652a1
  g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
Packit 0652a1
Packit 0652a1
  GST_LOG_OBJECT (buf, "may start: %d", allowed);
Packit 0652a1
  g_atomic_int_set (&buf->may_start, allowed);
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/* GST_AUDIO_CHANNEL_POSITION_NONE is used for position-less
Packit 0652a1
 * mutually exclusive channels. In this case we should not attempt
Packit 0652a1
 * to do any reordering.
Packit 0652a1
 */
Packit 0652a1
static gboolean
Packit 0652a1
position_less_channels (const GstAudioChannelPosition * pos, guint channels)
Packit 0652a1
{
Packit 0652a1
  guint i;
Packit 0652a1
Packit 0652a1
  for (i = 0; i < channels; i++) {
Packit 0652a1
    if (pos[i] != GST_AUDIO_CHANNEL_POSITION_NONE)
Packit 0652a1
      return FALSE;
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  return TRUE;
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_audio_ring_buffer_set_channel_positions:
Packit 0652a1
 * @buf: the #GstAudioRingBuffer
Packit 0652a1
 * @position: (array): the device channel positions
Packit 0652a1
 *
Packit 0652a1
 * Tell the ringbuffer about the device's channel positions. This must
Packit 0652a1
 * be called in when the ringbuffer is acquired.
Packit 0652a1
 */
Packit 0652a1
void
Packit 0652a1
gst_audio_ring_buffer_set_channel_positions (GstAudioRingBuffer * buf,
Packit 0652a1
    const GstAudioChannelPosition * position)
Packit 0652a1
{
Packit 0652a1
  const GstAudioChannelPosition *to;
Packit 0652a1
  gint channels;
Packit 0652a1
  gint i;
Packit 0652a1
Packit 0652a1
  g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
Packit 0652a1
  g_return_if_fail (buf->acquired);
Packit 0652a1
Packit 0652a1
  channels = buf->spec.info.channels;
Packit 0652a1
  to = buf->spec.info.position;
Packit 0652a1
Packit 0652a1
  if (memcmp (position, to, channels * sizeof (to[0])) == 0)
Packit 0652a1
    return;
Packit 0652a1
Packit 0652a1
  if (position_less_channels (position, channels)) {
Packit 0652a1
    GST_LOG_OBJECT (buf, "position-less channels, no need to reorder");
Packit 0652a1
    return;
Packit 0652a1
  }
Packit 0652a1
Packit 0652a1
  buf->need_reorder = FALSE;
Packit 0652a1
  if (!gst_audio_get_channel_reorder_map (channels, position, to,
Packit 0652a1
          buf->channel_reorder_map))
Packit 0652a1
    g_return_if_reached ();
Packit 0652a1
Packit 0652a1
  for (i = 0; i < channels; i++) {
Packit 0652a1
    if (buf->channel_reorder_map[i] != i) {
Packit 0652a1
#ifndef GST_DISABLE_GST_DEBUG
Packit 0652a1
      {
Packit 0652a1
        gchar *tmp1, *tmp2;
Packit 0652a1
Packit 0652a1
        tmp1 = gst_audio_channel_positions_to_string (position, channels);
Packit 0652a1
        tmp2 = gst_audio_channel_positions_to_string (to, channels);
Packit 0652a1
        GST_LOG_OBJECT (buf, "may have to reorder channels: %s -> %s", tmp1,
Packit 0652a1
            tmp2);
Packit 0652a1
        g_free (tmp1);
Packit 0652a1
        g_free (tmp2);
Packit 0652a1
      }
Packit 0652a1
#endif /* GST_DISABLE_GST_DEBUG */
Packit 0652a1
Packit 0652a1
      buf->need_reorder = TRUE;
Packit 0652a1
      break;
Packit 0652a1
    }
Packit 0652a1
  }
Packit 0652a1
}
Packit 0652a1
Packit 0652a1
/**
Packit 0652a1
 * gst_ring_buffer_set_timestamp:
Packit 0652a1
 * @buf: the #GstRingBuffer
Packit 0652a1
 * @readseg: the current data segment
Packit 0652a1
 * @timestamp: The new timestamp of the buffer.
Packit 0652a1
 *
Packit 0652a1
 * Set a new timestamp on the buffer.
Packit 0652a1
 *
Packit 0652a1
 * MT safe.
Packit 0652a1
 */
Packit 0652a1
void
Packit 0652a1
gst_audio_ring_buffer_set_timestamp (GstAudioRingBuffer * buf, gint readseg,
Packit 0652a1
    GstClockTime timestamp)
Packit 0652a1
{
Packit 0652a1
  g_return_if_fail (GST_IS_AUDIO_RING_BUFFER (buf));
Packit 0652a1
Packit 0652a1
  GST_DEBUG_OBJECT (buf, "Storing timestamp %" GST_TIME_FORMAT
Packit 0652a1
      " @ %d", GST_TIME_ARGS (timestamp), readseg);
Packit 0652a1
Packit 0652a1
  GST_OBJECT_LOCK (buf);
Packit 0652a1
  if (G_UNLIKELY (!buf->acquired))
Packit 0652a1
    goto not_acquired;
Packit 0652a1
Packit 0652a1
  buf->timestamps[readseg] = timestamp;
Packit 0652a1
Packit 0652a1
done:
Packit 0652a1
  GST_OBJECT_UNLOCK (buf);
Packit 0652a1
  return;
Packit 0652a1
Packit 0652a1
not_acquired:
Packit 0652a1
  {
Packit 0652a1
    GST_DEBUG_OBJECT (buf, "we are not acquired");
Packit 0652a1
    goto done;
Packit 0652a1
  }
Packit 0652a1
}