Added audiosource base classes.

Original commit message from CVS:
Added audiosource base classes.
Ported alsasrc, still very basic.
This commit is contained in:
Wim Taymans 2005-07-06 15:27:17 +00:00
parent a46a991d26
commit ceb88a7777
14 changed files with 2041 additions and 742 deletions

View file

@ -1,3 +1,54 @@
2005-07-06 Wim Taymans <wim@fluendo.com>
* ext/alsa/Makefile.am:
* ext/alsa/gstalsaplugin.c: (plugin_init):
* ext/alsa/gstalsasink.c: (gst_alsasink_open):
* ext/alsa/gstalsasrc.c: (gst_alsasrc_get_type),
(gst_alsasrc_dispose), (gst_alsasrc_base_init),
(gst_alsasrc_class_init), (gst_alsasrc_init),
(gst_alsasrc_getcaps), (set_hwparams), (set_swparams),
(alsasrc_parse_spec), (gst_alsasrc_open), (gst_alsasrc_close),
(xrun_recovery), (gst_alsasrc_read), (gst_alsasrc_delay),
(gst_alsasrc_reset):
* ext/alsa/gstalsasrc.h:
* gst-libs/gst/audio/Makefile.am:
* gst-libs/gst/audio/gstaudiosink.c:
(gst_audioringbuffer_get_type), (gst_audioringbuffer_class_init),
(gst_audioringbuffer_start):
* gst-libs/gst/audio/gstaudiosrc.c: (gst_audioringbuffer_get_type),
(gst_audioringbuffer_class_init), (audioringbuffer_thread_func),
(gst_audioringbuffer_init), (gst_audioringbuffer_dispose),
(gst_audioringbuffer_finalize), (gst_audioringbuffer_acquire),
(gst_audioringbuffer_release), (gst_audioringbuffer_start),
(gst_audioringbuffer_stop), (gst_audioringbuffer_delay),
(gst_audiosrc_base_init), (gst_audiosrc_class_init),
(gst_audiosrc_init), (gst_audiosrc_create_ringbuffer):
* gst-libs/gst/audio/gstaudiosrc.h:
* gst-libs/gst/audio/gstbaseaudiosink.c:
(gst_baseaudiosink_class_init), (gst_baseaudiosink_dispose),
(gst_baseaudiosink_get_time), (gst_baseaudiosink_setcaps),
(gst_baseaudiosink_preroll), (gst_baseaudiosink_render):
* gst-libs/gst/audio/gstbaseaudiosrc.c:
(gst_baseaudiosrc_base_init), (gst_baseaudiosrc_class_init),
(gst_baseaudiosrc_init), (gst_baseaudiosrc_get_clock),
(gst_baseaudiosrc_get_time), (gst_baseaudiosrc_set_property),
(gst_baseaudiosrc_get_property), (gst_baseaudiosrc_fixate),
(gst_baseaudiosrc_setcaps), (gst_baseaudiosrc_get_times),
(gst_baseaudiosrc_event), (gst_baseaudiosrc_create),
(gst_baseaudiosrc_create_ringbuffer), (gst_baseaudiosrc_callback),
(gst_baseaudiosrc_change_state):
* gst-libs/gst/audio/gstbaseaudiosrc.h:
* gst-libs/gst/audio/gstringbuffer.c: (build_linear_format),
(gst_ringbuffer_debug_spec_caps), (gst_ringbuffer_debug_spec_buff),
(gst_ringbuffer_parse_caps), (gst_ringbuffer_start),
(gst_ringbuffer_pause), (gst_ringbuffer_stop),
(gst_ringbuffer_samples_done), (gst_ringbuffer_set_sample),
(wait_segment), (gst_ringbuffer_commit), (gst_ringbuffer_read),
(gst_ringbuffer_prepare_read), (gst_ringbuffer_advance):
* gst-libs/gst/audio/gstringbuffer.h:
Added audiosource base classes.
Ported alsasrc, still very basic.
2005-07-06 Wim Taymans <wim@fluendo.com>
* ext/theora/theoradec.c: (theora_dec_src_getcaps),

View file

@ -3,7 +3,8 @@ plugin_LTLIBRARIES = libgstalsa.la
libgstalsa_la_SOURCES = \
gstalsaplugin.c \
gstalsasink.c
gstalsasink.c \
gstalsasrc.c
# port alsa stuff then add the _SOURCES above
EXTRA_DIST = \
@ -11,8 +12,7 @@ EXTRA_DIST = \
gstalsamixertrack.c \
gstalsamixeroptions.c \
gstalsa.c \
gstalsaclock.c \
gstalsasrc.c
gstalsaclock.c
libgstalsa_la_CFLAGS = $(GST_CFLAGS) $(ALSA_CFLAGS)
libgstalsa_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) \

View file

@ -60,10 +60,10 @@ plugin_init (GstPlugin * plugin)
if (!gst_element_register (plugin, "alsamixer", GST_RANK_NONE,
GST_TYPE_ALSA_MIXER))
return FALSE;
*/
if (!gst_element_register (plugin, "alsasrc", GST_RANK_NONE,
GST_TYPE_ALSA_SRC))
return FALSE;
*/
if (!gst_element_register (plugin, "alsasink", GST_RANK_NONE,
GST_TYPE_ALSA_SINK))
return FALSE;

File diff suppressed because it is too large Load diff

View file

@ -1,8 +1,7 @@
/*
* Copyright (C) 2001 CodeFactory AB
* Copyright (C) 2001 Thomas Nyberg <thomas@codefactory.se>
* Copyright (C) 2001-2002 Andy Wingo <apwingo@eos.ncsu.edu>
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
/* GStreamer
* Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
*
* gstalsasrc.h:
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -15,41 +14,58 @@
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#ifndef __GST_ALSA_SRC_H__
#define __GST_ALSA_SRC_H__
#include "gstalsamixer.h"
#ifndef __GST_ALSASRC_H__
#define __GST_ALSASRC_H__
#include <gst/gst.h>
#include <gst/audio/gstaudiosrc.h>
#include <alsa/asoundlib.h>
G_BEGIN_DECLS
#define GST_ALSA_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, GST_TYPE_ALSA_SRC, GstAlsaSrc))
#define GST_ALSA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, GST_TYPE_ALSA_SRC, GstAlsaSrcClass))
#define GST_IS_ALSA_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, GST_TYPE_ALSA_SRC))
#define GST_IS_ALSA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, GST_TYPE_ALSA_SRC))
#define GST_TYPE_ALSA_SRC (gst_alsa_src_get_type())
#define GST_TYPE_ALSA_SRC (gst_alsasrc_get_type())
#define GST_ALSA_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSA_SRC,GstAlsaSrc))
#define GST_ALSA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSA_SRC,GstAlsaSrcClass))
#define GST_IS_ALSA_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSA_SRC))
#define GST_IS_ALSA_SRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSA_SRC))
typedef struct _GstAlsaSrc GstAlsaSrc;
typedef struct _GstAlsaSrcClass GstAlsaSrcClass;
struct _GstAlsaSrc {
GstAlsaMixer parent;
GstBuffer *buf[GST_ALSA_MAX_TRACKS];
snd_pcm_status_t *status;
GstClockTime base_time; /* FIXME: move this up ? already present in element ? */
GstAudioSrc src;
gchar *device;
snd_pcm_t *handle;
snd_pcm_hw_params_t *hwparams;
snd_pcm_sw_params_t *swparams;
snd_pcm_access_t access;
snd_pcm_format_t format;
guint rate;
guint channels;
gint bytes_per_sample;
guint buffer_time;
guint period_time;
snd_pcm_uframes_t buffer_size;
snd_pcm_uframes_t period_size;
};
struct _GstAlsaSrcClass {
GstAlsaMixerClass parent_class;
GstAudioSrcClass parent_class;
};
GType gst_alsa_src_get_type (void);
gboolean gst_alsa_src_factory_init (GstPlugin *plugin);
GType gst_alsasrc_get_type(void);
G_END_DECLS
#endif /* __GST_ALSA_SRC_H__ */
#endif /* __GST_ALSASRC_H__ */

View file

@ -17,7 +17,9 @@ CLEANFILES = gstaudiofilterexample.c \
libgstaudio_@GST_MAJORMINOR@_la_SOURCES = audio.c gstaudioclock.c \
multichannel.c \
gstaudiosink.c \
gstaudiosrc.c \
gstbaseaudiosink.c \
gstbaseaudiosrc.c \
gstringbuffer.c
nodist_libgstaudio_@GST_MAJORMINOR@_la_SOURCES = $(built_sources) $(built_headers)
@ -27,7 +29,9 @@ libgstaudio_@GST_MAJORMINOR@include_HEADERS = \
gstaudioclock.h \
gstaudiofilter.h \
gstaudiosink.h \
gstaudiosrc.h \
gstbaseaudiosink.h \
gstbaseaudiosrc.h \
gstringbuffer.h \
multichannel.h

View file

@ -73,12 +73,12 @@ static GstRingBufferClass *ring_parent_class = NULL;
static gboolean gst_audioringbuffer_acquire (GstRingBuffer * buf,
GstRingBufferSpec * spec);
static gboolean gst_audioringbuffer_release (GstRingBuffer * buf);
static gboolean gst_audioringbuffer_play (GstRingBuffer * buf);
static gboolean gst_audioringbuffer_start (GstRingBuffer * buf);
static gboolean gst_audioringbuffer_stop (GstRingBuffer * buf);
static guint gst_audioringbuffer_delay (GstRingBuffer * buf);
/* ringbuffer abstract base class */
GType
static GType
gst_audioringbuffer_get_type (void)
{
static GType ringbuffer_type = 0;
@ -98,7 +98,7 @@ gst_audioringbuffer_get_type (void)
};
ringbuffer_type =
g_type_register_static (GST_TYPE_RINGBUFFER, "GstAudioRingBuffer",
g_type_register_static (GST_TYPE_RINGBUFFER, "GstAudioSinkRingBuffer",
&ringbuffer_info, 0);
}
return ringbuffer_type;
@ -124,8 +124,8 @@ gst_audioringbuffer_class_init (GstAudioRingBufferClass * klass)
GST_DEBUG_FUNCPTR (gst_audioringbuffer_acquire);
gstringbuffer_class->release =
GST_DEBUG_FUNCPTR (gst_audioringbuffer_release);
gstringbuffer_class->play = GST_DEBUG_FUNCPTR (gst_audioringbuffer_play);
gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_audioringbuffer_play);
gstringbuffer_class->start = GST_DEBUG_FUNCPTR (gst_audioringbuffer_start);
gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_audioringbuffer_start);
gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_audioringbuffer_stop);
gstringbuffer_class->delay = GST_DEBUG_FUNCPTR (gst_audioringbuffer_delay);
@ -136,7 +136,7 @@ typedef guint (*WriteFunc) (GstAudioSink * sink, gpointer data, guint length);
/* this internal thread does nothing else but write samples to the audio device.
* It will write each segment in the ringbuffer and will update the play
* pointer.
* The play/stop methods control the thread.
* The start/stop methods control the thread.
*/
static void
audioringbuffer_thread_func (GstRingBuffer * buf)
@ -307,13 +307,13 @@ gst_audioringbuffer_release (GstRingBuffer * buf)
}
static gboolean
gst_audioringbuffer_play (GstRingBuffer * buf)
gst_audioringbuffer_start (GstRingBuffer * buf)
{
GstAudioSink *sink;
sink = GST_AUDIOSINK (GST_OBJECT_PARENT (buf));
GST_DEBUG ("play, sending signal");
GST_DEBUG ("start, sending signal");
GST_AUDIORINGBUFFER_SIGNAL (buf);
return TRUE;

View file

@ -0,0 +1,418 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2005 Wim Taymans <wim@fluendo.com>
*
* gstaudiosrc.c: simple audio src base class
*
* 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 "gstaudiosrc.h"
GST_DEBUG_CATEGORY_STATIC (gst_audiosrc_debug);
#define GST_CAT_DEFAULT gst_audiosrc_debug
#define GST_TYPE_AUDIORINGBUFFER \
(gst_audioringbuffer_get_type())
#define GST_AUDIORINGBUFFER(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIORINGBUFFER,GstAudioRingBuffer))
#define GST_AUDIORINGBUFFER_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIORINGBUFFER,GstAudioRingBufferClass))
#define GST_AUDIORINGBUFFER_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_AUDIORINGBUFFER, GstAudioRingBufferClass))
#define GST_IS_AUDIORINGBUFFER(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIORINGBUFFER))
#define GST_IS_AUDIORINGBUFFER_CLASS(obj)\
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIORINGBUFFER))
typedef struct _GstAudioRingBuffer GstAudioRingBuffer;
typedef struct _GstAudioRingBufferClass GstAudioRingBufferClass;
#define GST_AUDIORINGBUFFER_GET_COND(buf) (((GstAudioRingBuffer *)buf)->cond)
#define GST_AUDIORINGBUFFER_WAIT(buf) (g_cond_wait (GST_AUDIORINGBUFFER_GET_COND (buf), GST_GET_LOCK (buf)))
#define GST_AUDIORINGBUFFER_SIGNAL(buf) (g_cond_signal (GST_AUDIORINGBUFFER_GET_COND (buf)))
#define GST_AUDIORINGBUFFER_BROADCAST(buf)(g_cond_broadcast (GST_AUDIORINGBUFFER_GET_COND (buf)))
struct _GstAudioRingBuffer
{
GstRingBuffer object;
gboolean running;
gint queuedseg;
GCond *cond;
};
struct _GstAudioRingBufferClass
{
GstRingBufferClass parent_class;
};
static void gst_audioringbuffer_class_init (GstAudioRingBufferClass * klass);
static void gst_audioringbuffer_init (GstAudioRingBuffer * ringbuffer);
static void gst_audioringbuffer_dispose (GObject * object);
static void gst_audioringbuffer_finalize (GObject * object);
static GstRingBufferClass *ring_parent_class = NULL;
static gboolean gst_audioringbuffer_acquire (GstRingBuffer * buf,
GstRingBufferSpec * spec);
static gboolean gst_audioringbuffer_release (GstRingBuffer * buf);
static gboolean gst_audioringbuffer_start (GstRingBuffer * buf);
static gboolean gst_audioringbuffer_stop (GstRingBuffer * buf);
static guint gst_audioringbuffer_delay (GstRingBuffer * buf);
/* ringbuffer abstract base class */
static GType
gst_audioringbuffer_get_type (void)
{
static GType ringbuffer_type = 0;
if (!ringbuffer_type) {
static const GTypeInfo ringbuffer_info = {
sizeof (GstAudioRingBufferClass),
NULL,
NULL,
(GClassInitFunc) gst_audioringbuffer_class_init,
NULL,
NULL,
sizeof (GstAudioRingBuffer),
0,
(GInstanceInitFunc) gst_audioringbuffer_init,
NULL
};
ringbuffer_type =
g_type_register_static (GST_TYPE_RINGBUFFER, "GstAudioSrcRingBuffer",
&ringbuffer_info, 0);
}
return ringbuffer_type;
}
static void
gst_audioringbuffer_class_init (GstAudioRingBufferClass * klass)
{
GObjectClass *gobject_class;
GstObjectClass *gstobject_class;
GstRingBufferClass *gstringbuffer_class;
gobject_class = (GObjectClass *) klass;
gstobject_class = (GstObjectClass *) klass;
gstringbuffer_class = (GstRingBufferClass *) klass;
ring_parent_class = g_type_class_ref (GST_TYPE_RINGBUFFER);
gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_audioringbuffer_dispose);
gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_audioringbuffer_finalize);
gstringbuffer_class->acquire =
GST_DEBUG_FUNCPTR (gst_audioringbuffer_acquire);
gstringbuffer_class->release =
GST_DEBUG_FUNCPTR (gst_audioringbuffer_release);
gstringbuffer_class->start = GST_DEBUG_FUNCPTR (gst_audioringbuffer_start);
gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_audioringbuffer_start);
gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_audioringbuffer_stop);
gstringbuffer_class->delay = GST_DEBUG_FUNCPTR (gst_audioringbuffer_delay);
}
typedef guint (*ReadFunc) (GstAudioSrc * src, gpointer data, guint length);
/* this internal thread does nothing else but read samples from the audio device.
* It will read each segment in the ringbuffer and will update the play
* pointer.
* The start/stop methods control the thread.
*/
static void
audioringbuffer_thread_func (GstRingBuffer * buf)
{
GstAudioSrc *src;
GstAudioSrcClass *csrc;
GstAudioRingBuffer *abuf = GST_AUDIORINGBUFFER (buf);
ReadFunc readfunc;
src = GST_AUDIOSRC (GST_OBJECT_PARENT (buf));
csrc = GST_AUDIOSRC_GET_CLASS (src);
GST_DEBUG ("enter thread");
readfunc = csrc->read;
if (readfunc == NULL)
goto no_function;
while (TRUE) {
gint left, len;
guint8 *readptr;
gint readseg;
if (gst_ringbuffer_prepare_read (buf, &readseg, &readptr, &len)) {
gint read = 0;
left = len;
do {
GST_DEBUG ("transfer %d bytes to segment %d", left, readseg);
read = readfunc (src, readptr + read, left);
GST_DEBUG ("transfered %d bytes", read);
if (read < 0 || read > left) {
GST_WARNING ("error reading data (reason: %s), skipping segment\n",
strerror (errno));
break;
}
left -= read;
} while (left > 0);
/* we read one segment */
gst_ringbuffer_advance (buf, 1);
} else {
GST_LOCK (abuf);
if (!abuf->running)
goto stop_running;
GST_DEBUG ("signal wait");
GST_AUDIORINGBUFFER_SIGNAL (buf);
GST_DEBUG ("wait for action");
GST_AUDIORINGBUFFER_WAIT (buf);
GST_DEBUG ("got signal");
if (!abuf->running)
goto stop_running;
GST_DEBUG ("continue running");
GST_UNLOCK (abuf);
}
}
GST_DEBUG ("exit thread");
return;
/* ERROR */
no_function:
{
GST_DEBUG ("no write function, exit thread");
return;
}
stop_running:
{
GST_UNLOCK (abuf);
GST_DEBUG ("stop running, exit thread");
return;
}
}
static void
gst_audioringbuffer_init (GstAudioRingBuffer * ringbuffer)
{
ringbuffer->running = FALSE;
ringbuffer->queuedseg = 0;
ringbuffer->cond = g_cond_new ();
}
static void
gst_audioringbuffer_dispose (GObject * object)
{
G_OBJECT_CLASS (ring_parent_class)->dispose (object);
}
static void
gst_audioringbuffer_finalize (GObject * object)
{
G_OBJECT_CLASS (ring_parent_class)->finalize (object);
}
static gboolean
gst_audioringbuffer_acquire (GstRingBuffer * buf, GstRingBufferSpec * spec)
{
GstAudioSrc *src;
GstAudioSrcClass *csrc;
GstAudioRingBuffer *abuf;
gboolean result = FALSE;
src = GST_AUDIOSRC (GST_OBJECT_PARENT (buf));
csrc = GST_AUDIOSRC_GET_CLASS (src);
if (csrc->open)
result = csrc->open (src, spec);
if (!result)
goto could_not_open;
/* allocate one more segment as we need some headroom */
spec->segtotal++;
buf->data = gst_buffer_new_and_alloc (spec->segtotal * spec->segsize);
memset (GST_BUFFER_DATA (buf->data), 0, GST_BUFFER_SIZE (buf->data));
abuf = GST_AUDIORINGBUFFER (buf);
abuf->running = TRUE;
src->thread =
g_thread_create ((GThreadFunc) audioringbuffer_thread_func, buf, TRUE,
NULL);
GST_AUDIORINGBUFFER_WAIT (buf);
return result;
could_not_open:
{
return FALSE;
}
}
/* function is called with LOCK */
static gboolean
gst_audioringbuffer_release (GstRingBuffer * buf)
{
GstAudioSrc *src;
GstAudioSrcClass *csrc;
GstAudioRingBuffer *abuf;
gboolean result = FALSE;
src = GST_AUDIOSRC (GST_OBJECT_PARENT (buf));
csrc = GST_AUDIOSRC_GET_CLASS (src);
abuf = GST_AUDIORINGBUFFER (buf);
abuf->running = FALSE;
GST_AUDIORINGBUFFER_SIGNAL (buf);
GST_UNLOCK (buf);
/* join the thread */
g_thread_join (src->thread);
GST_LOCK (buf);
/* free the buffer */
gst_buffer_unref (buf->data);
buf->data = NULL;
if (csrc->close)
result = csrc->close (src);
return result;
}
static gboolean
gst_audioringbuffer_start (GstRingBuffer * buf)
{
GstAudioSrc *src;
src = GST_AUDIOSRC (GST_OBJECT_PARENT (buf));
GST_DEBUG ("start, sending signal");
GST_AUDIORINGBUFFER_SIGNAL (buf);
return TRUE;
}
static gboolean
gst_audioringbuffer_stop (GstRingBuffer * buf)
{
GstAudioSrc *src;
GstAudioSrcClass *csrc;
src = GST_AUDIOSRC (GST_OBJECT_PARENT (buf));
csrc = GST_AUDIOSRC_GET_CLASS (src);
/* unblock any pending writes to the audio device */
if (csrc->reset) {
GST_DEBUG ("reset...");
csrc->reset (src);
GST_DEBUG ("reset done");
}
GST_DEBUG ("stop, waiting...");
GST_AUDIORINGBUFFER_WAIT (buf);
GST_DEBUG ("stoped");
return TRUE;
}
static guint
gst_audioringbuffer_delay (GstRingBuffer * buf)
{
GstAudioSrc *src;
GstAudioSrcClass *csrc;
guint res = 0;
src = GST_AUDIOSRC (GST_OBJECT_PARENT (buf));
csrc = GST_AUDIOSRC_GET_CLASS (src);
if (csrc->delay)
res = csrc->delay (src);
return res;
}
/* AudioSrc signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
enum
{
ARG_0,
};
#define _do_init(bla) \
GST_DEBUG_CATEGORY_INIT (gst_audiosrc_debug, "audiosrc", 0, "audiosrc element");
GST_BOILERPLATE_FULL (GstAudioSrc, gst_audiosrc, GstBaseAudioSrc,
GST_TYPE_BASEAUDIOSRC, _do_init);
static GstRingBuffer *gst_audiosrc_create_ringbuffer (GstBaseAudioSrc * src);
static void
gst_audiosrc_base_init (gpointer g_class)
{
}
static void
gst_audiosrc_class_init (GstAudioSrcClass * klass)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
GstBaseSrcClass *gstbasesrc_class;
GstPushSrcClass *gstpushsrc_class;
GstBaseAudioSrcClass *gstbaseaudiosrc_class;
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
gstbasesrc_class = (GstBaseSrcClass *) klass;
gstpushsrc_class = (GstPushSrcClass *) klass;
gstbaseaudiosrc_class = (GstBaseAudioSrcClass *) klass;
gstbaseaudiosrc_class->create_ringbuffer =
GST_DEBUG_FUNCPTR (gst_audiosrc_create_ringbuffer);
}
static void
gst_audiosrc_init (GstAudioSrc * audiosrc)
{
gst_base_src_set_live (GST_BASE_SRC (audiosrc), TRUE);
}
static GstRingBuffer *
gst_audiosrc_create_ringbuffer (GstBaseAudioSrc * src)
{
GstRingBuffer *buffer;
GST_DEBUG ("creating ringbuffer");
buffer = g_object_new (GST_TYPE_AUDIORINGBUFFER, NULL);
GST_DEBUG ("created ringbuffer @%p", buffer);
return buffer;
}

View file

@ -0,0 +1,84 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2005 Wim Taymans <wim@fluendo.com>
*
* gstaudiosrc.h:
*
* 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.
*/
/* a base class for simple audio srcs.
*
* This base class only requires subclasses to implement a set
* of simple functions.
*
* - open: open the device with the specified caps
* - read: read samples to the audio device
* - close: close the device
* - delay: the number of samples queued in the device
* - reset: unblock a read to the device and reset.
*
* All scheduling of samples and timestamps is done in this
* base class.
*/
#ifndef __GST_AUDIOSRC_H__
#define __GST_AUDIOSRC_H__
#include <gst/gst.h>
#include <gst/audio/gstbaseaudiosrc.h>
G_BEGIN_DECLS
#define GST_TYPE_AUDIOSRC (gst_audiosrc_get_type())
#define GST_AUDIOSRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIOSRC,GstAudioSrc))
#define GST_AUDIOSRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIOSRC,GstAudioSrcClass))
#define GST_AUDIOSRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_AUDIOSRC,GstAudioSrcClass))
#define GST_IS_AUDIOSRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIOSRC))
#define GST_IS_AUDIOSRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIOSRC))
typedef struct _GstAudioSrc GstAudioSrc;
typedef struct _GstAudioSrcClass GstAudioSrcClass;
struct _GstAudioSrc {
GstBaseAudioSrc element;
/*< private >*/ /* with LOCK */
GThread *thread;
};
struct _GstAudioSrcClass {
GstBaseAudioSrcClass parent_class;
/* vtable */
/* open the device with given specs */
gboolean (*open) (GstAudioSrc *src, GstRingBufferSpec *spec);
/* close the device */
gboolean (*close) (GstAudioSrc *src);
/* read samples from the device */
guint (*read) (GstAudioSrc *src, gpointer data, guint length);
/* get number of samples queued in the device */
guint (*delay) (GstAudioSrc *src);
/* reset the audio device, unblock from a write */
void (*reset) (GstAudioSrc *src);
};
GType gst_audiosrc_get_type(void);
G_END_DECLS
#endif /* __GST_AUDIOSRC_H__ */

View file

@ -160,7 +160,7 @@ gst_baseaudiosink_get_time (GstClock * clock, GstBaseAudioSink * sink)
if (sink->ringbuffer == NULL || sink->ringbuffer->spec.rate == 0)
return 0;
samples = gst_ringbuffer_played_samples (sink->ringbuffer);
samples = gst_ringbuffer_samples_done (sink->ringbuffer);
result = samples * GST_SECOND / sink->ringbuffer->spec.rate;
result += GST_ELEMENT (sink)->base_time;
@ -210,204 +210,31 @@ gst_baseaudiosink_get_property (GObject * object, guint prop_id, GValue * value,
}
}
static int linear_formats[4 * 2 * 2] = {
GST_S8,
GST_S8,
GST_U8,
GST_U8,
GST_S16_LE,
GST_S16_BE,
GST_U16_LE,
GST_U16_BE,
GST_S24_LE,
GST_S24_BE,
GST_U24_LE,
GST_U24_BE,
GST_S32_LE,
GST_S32_BE,
GST_U32_LE,
GST_U32_BE
};
static int linear24_formats[3 * 2 * 2] = {
GST_S24_3LE,
GST_S24_3BE,
GST_U24_3LE,
GST_U24_3BE,
GST_S20_3LE,
GST_S20_3BE,
GST_U20_3LE,
GST_U20_3BE,
GST_S18_3LE,
GST_S18_3BE,
GST_U18_3LE,
GST_U18_3BE,
};
static GstBufferFormat
build_linear_format (int depth, int width, int unsignd, int big_endian)
{
if (width == 24) {
switch (depth) {
case 24:
depth = 0;
break;
case 20:
depth = 1;
break;
case 18:
depth = 2;
break;
default:
return GST_UNKNOWN;
}
return ((int (*)[2][2]) linear24_formats)[depth][!!unsignd][!!big_endian];
} else {
switch (depth) {
case 8:
depth = 0;
break;
case 16:
depth = 1;
break;
case 24:
depth = 2;
break;
case 32:
depth = 3;
break;
default:
return GST_UNKNOWN;
}
}
return ((int (*)[2][2]) linear_formats)[depth][!!unsignd][!!big_endian];
}
static void
debug_spec_caps (GstBaseAudioSink * sink, GstRingBufferSpec * spec)
{
GST_DEBUG ("spec caps: %p %" GST_PTR_FORMAT, spec->caps, spec->caps);
GST_DEBUG ("parsed caps: type: %d", spec->type);
GST_DEBUG ("parsed caps: format: %d", spec->format);
GST_DEBUG ("parsed caps: width: %d", spec->width);
GST_DEBUG ("parsed caps: depth: %d", spec->depth);
GST_DEBUG ("parsed caps: sign: %d", spec->sign);
GST_DEBUG ("parsed caps: bigend: %d", spec->bigend);
GST_DEBUG ("parsed caps: rate: %d", spec->rate);
GST_DEBUG ("parsed caps: channels: %d", spec->channels);
GST_DEBUG ("parsed caps: sample bytes: %d", spec->bytes_per_sample);
}
static void
debug_spec_buffer (GstBaseAudioSink * sink, GstRingBufferSpec * spec)
{
GST_DEBUG ("acquire ringbuffer: buffer time: %" G_GINT64_FORMAT " usec",
spec->buffer_time);
GST_DEBUG ("acquire ringbuffer: latency time: %" G_GINT64_FORMAT " usec",
spec->latency_time);
GST_DEBUG ("acquire ringbuffer: total segments: %d", spec->segtotal);
GST_DEBUG ("acquire ringbuffer: segment size: %d bytes = %d samples",
spec->segsize, spec->segsize / spec->bytes_per_sample);
GST_DEBUG ("acquire ringbuffer: buffer size: %d bytes = %d samples",
spec->segsize * spec->segtotal,
spec->segsize * spec->segtotal / spec->bytes_per_sample);
}
static gboolean
gst_baseaudiosink_setcaps (GstBaseSink * bsink, GstCaps * caps)
{
GstBaseAudioSink *sink = GST_BASEAUDIOSINK (bsink);
GstRingBufferSpec *spec;
const gchar *mimetype;
GstStructure *structure;
spec = &sink->ringbuffer->spec;
structure = gst_caps_get_structure (caps, 0);
GST_DEBUG ("release old ringbuffer");
/* we have to differentiate between int and float formats */
mimetype = gst_structure_get_name (structure);
/* release old ringbuffer */
gst_ringbuffer_release (sink->ringbuffer);
if (!strncmp (mimetype, "audio/x-raw-int", 15)) {
gint endianness;
spec->type = GST_BUFTYPE_LINEAR;
/* extract the needed information from the cap */
if (!(gst_structure_get_int (structure, "width", &spec->width) &&
gst_structure_get_int (structure, "depth", &spec->depth) &&
gst_structure_get_boolean (structure, "signed", &spec->sign)))
goto parse_error;
/* extract endianness if needed */
if (spec->width > 8) {
if (!gst_structure_get_int (structure, "endianness", &endianness))
goto parse_error;
} else {
endianness = G_BYTE_ORDER;
}
spec->bigend = endianness == G_LITTLE_ENDIAN ? FALSE : TRUE;
spec->format =
build_linear_format (spec->depth, spec->width, spec->sign ? 0 : 1,
spec->bigend ? 1 : 0);
} else if (!strncmp (mimetype, "audio/x-raw-float", 17)) {
spec->type = GST_BUFTYPE_FLOAT;
/* get layout */
if (!gst_structure_get_int (structure, "width", &spec->width))
goto parse_error;
/* match layout to format wrt to endianness */
switch (spec->width) {
case 32:
spec->format =
G_BYTE_ORDER == G_LITTLE_ENDIAN ? GST_FLOAT32_LE : GST_FLOAT32_BE;
break;
case 64:
spec->format =
G_BYTE_ORDER == G_LITTLE_ENDIAN ? GST_FLOAT64_LE : GST_FLOAT64_BE;
break;
default:
goto parse_error;
}
} else if (!strncmp (mimetype, "audio/x-alaw", 12)) {
spec->type = GST_BUFTYPE_A_LAW;
spec->format = GST_A_LAW;
} else if (!strncmp (mimetype, "audio/x-mulaw", 13)) {
spec->type = GST_BUFTYPE_MU_LAW;
spec->format = GST_MU_LAW;
} else {
goto parse_error;
}
/* get rate and channels */
if (!(gst_structure_get_int (structure, "rate", &spec->rate) &&
gst_structure_get_int (structure, "channels", &spec->channels)))
goto parse_error;
spec->bytes_per_sample = (spec->width >> 3) * spec->channels;
gst_caps_replace (&spec->caps, caps);
debug_spec_caps (sink, spec);
GST_DEBUG ("parse caps");
spec->buffer_time = sink->buffer_time;
spec->latency_time = sink->latency_time;
/* 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;
/* parse new caps */
if (!gst_ringbuffer_parse_caps (spec, caps))
goto parse_error;
GST_DEBUG ("release old ringbuffer");
gst_ringbuffer_debug_spec_buff (spec);
gst_ringbuffer_release (sink->ringbuffer);
debug_spec_buffer (sink, spec);
GST_DEBUG ("acquire new ringbuffer");
if (!gst_ringbuffer_acquire (sink->ringbuffer, spec))
goto acquire_error;
@ -419,7 +246,7 @@ gst_baseaudiosink_setcaps (GstBaseSink * bsink, GstCaps * caps)
spec->segtotal * spec->segsize * GST_MSECOND / (spec->rate *
spec->bytes_per_sample);
debug_spec_buffer (sink, spec);
gst_ringbuffer_debug_spec_buff (spec);
return TRUE;
@ -487,10 +314,23 @@ gst_baseaudiosink_event (GstBaseSink * bsink, GstEvent * event)
static GstFlowReturn
gst_baseaudiosink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
{
GstBaseAudioSink *sink = GST_BASEAUDIOSINK (bsink);
if (!gst_ringbuffer_is_acquired (sink->ringbuffer))
goto wrong_state;
/* we don't really do anything when prerolling. We could make a
* property to play this buffer to have some sort of scrubbing
* support. */
return GST_FLOW_OK;
wrong_state:
{
GST_DEBUG ("ringbuffer in wrong state");
GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
("sink not negotiated."), (NULL));
return GST_FLOW_ERROR;
}
}
static GstFlowReturn
@ -514,6 +354,8 @@ gst_baseaudiosink_render (GstBaseSink * bsink, GstBuffer * buf)
wrong_state:
{
GST_DEBUG ("ringbuffer in wrong state");
GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
("sink not negotiated."), (NULL));
return GST_FLOW_ERROR;
}
}

View file

@ -0,0 +1,403 @@
/* 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"
GST_DEBUG_CATEGORY_STATIC (gst_baseaudiosrc_debug);
#define GST_CAT_DEFAULT gst_baseaudiosrc_debug
/* BaseAudioSrc signals and args */
enum
{
/* FILL ME */
LAST_SIGNAL
};
#define DEFAULT_BUFFER_TIME 500 * GST_USECOND
#define DEFAULT_LATENCY_TIME 10 * GST_USECOND
enum
{
PROP_0,
PROP_BUFFER_TIME,
PROP_LATENCY_TIME,
};
#define _do_init(bla) \
GST_DEBUG_CATEGORY_INIT (gst_baseaudiosrc_debug, "baseaudiosrc", 0, "baseaudiosrc element");
GST_BOILERPLATE_FULL (GstBaseAudioSrc, gst_baseaudiosrc, GstPushSrc,
GST_TYPE_PUSHSRC, _do_init);
static void gst_baseaudiosrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_baseaudiosrc_get_property (GObject * object, guint prop_id,
GValue * value, GParamSpec * pspec);
static void gst_baseaudiosrc_fixate (GstPad * pad, GstCaps * caps);
static GstElementStateReturn gst_baseaudiosrc_change_state (GstElement *
element);
static GstClock *gst_baseaudiosrc_get_clock (GstElement * elem);
static GstClockTime gst_baseaudiosrc_get_time (GstClock * clock,
GstBaseAudioSrc * src);
static GstFlowReturn gst_baseaudiosrc_create (GstPushSrc * psrc,
GstBuffer ** buf);
static gboolean gst_baseaudiosrc_event (GstBaseSrc * bsrc, GstEvent * event);
static void gst_baseaudiosrc_get_times (GstBaseSrc * bsrc,
GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
static gboolean gst_baseaudiosrc_setcaps (GstBaseSrc * bsrc, GstCaps * caps);
//static guint gst_baseaudiosrc_signals[LAST_SIGNAL] = { 0 };
static void
gst_baseaudiosrc_base_init (gpointer g_class)
{
}
static void
gst_baseaudiosrc_class_init (GstBaseAudioSrcClass * klass)
{
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 =
GST_DEBUG_FUNCPTR (gst_baseaudiosrc_set_property);
gobject_class->get_property =
GST_DEBUG_FUNCPTR (gst_baseaudiosrc_get_property);
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BUFFER_TIME,
g_param_spec_int64 ("buffer-time", "Buffer Time",
"Size of audio buffer in milliseconds (-1 = default)",
-1, G_MAXINT64, DEFAULT_BUFFER_TIME, G_PARAM_READWRITE));
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LATENCY_TIME,
g_param_spec_int64 ("latency-time", "Latency Time",
"Audio latency in milliseconds (-1 = default)",
-1, G_MAXINT64, DEFAULT_LATENCY_TIME, G_PARAM_READWRITE));
gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_baseaudiosrc_change_state);
gstelement_class->get_clock = GST_DEBUG_FUNCPTR (gst_baseaudiosrc_get_clock);
gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_baseaudiosrc_setcaps);
gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_baseaudiosrc_event);
gstbasesrc_class->get_times = GST_DEBUG_FUNCPTR (gst_baseaudiosrc_get_times);
gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_baseaudiosrc_create);
}
static void
gst_baseaudiosrc_init (GstBaseAudioSrc * baseaudiosrc)
{
baseaudiosrc->buffer_time = DEFAULT_BUFFER_TIME;
baseaudiosrc->latency_time = DEFAULT_LATENCY_TIME;
baseaudiosrc->clock = gst_audio_clock_new ("clock",
(GstAudioClockGetTimeFunc) gst_baseaudiosrc_get_time, baseaudiosrc);
gst_pad_set_fixatecaps_function (GST_BASE_SRC_PAD (baseaudiosrc),
gst_baseaudiosrc_fixate);
}
static GstClock *
gst_baseaudiosrc_get_clock (GstElement * elem)
{
GstBaseAudioSrc *src;
src = GST_BASEAUDIOSRC (elem);
return GST_CLOCK (gst_object_ref (GST_OBJECT (src->clock)));
}
static GstClockTime
gst_baseaudiosrc_get_time (GstClock * clock, GstBaseAudioSrc * src)
{
guint64 samples;
GstClockTime result;
if (src->ringbuffer == NULL || src->ringbuffer->spec.rate == 0)
return 0;
samples = gst_ringbuffer_samples_done (src->ringbuffer);
result = samples * GST_SECOND / src->ringbuffer->spec.rate;
result += GST_ELEMENT (src)->base_time;
return result;
}
static void
gst_baseaudiosrc_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstBaseAudioSrc *src;
src = GST_BASEAUDIOSRC (object);
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
gst_baseaudiosrc_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstBaseAudioSrc *src;
src = GST_BASEAUDIOSRC (object);
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
gst_baseaudiosrc_fixate (GstPad * pad, GstCaps * caps)
{
GstStructure *s;
s = gst_caps_get_structure (caps, 0);
gst_caps_structure_fixate_field_nearest_int (s, "rate", 44100);
gst_caps_structure_fixate_field_nearest_int (s, "channels", 2);
gst_caps_structure_fixate_field_nearest_int (s, "depth", 16);
gst_caps_structure_fixate_field_nearest_int (s, "width", 16);
gst_structure_set (s, "signed", G_TYPE_BOOLEAN, TRUE, NULL);
gst_caps_structure_fixate_field_nearest_int (s, "endianness", G_BYTE_ORDER);
}
static gboolean
gst_baseaudiosrc_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
{
GstBaseAudioSrc *src = GST_BASEAUDIOSRC (bsrc);
GstRingBufferSpec *spec;
spec = &src->ringbuffer->spec;
spec->buffer_time = src->buffer_time;
spec->latency_time = src->latency_time;
if (!gst_ringbuffer_parse_caps (spec, caps))
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");
gst_ringbuffer_release (src->ringbuffer);
gst_ringbuffer_debug_spec_buff (spec);
GST_DEBUG ("acquire new ringbuffer");
if (!gst_ringbuffer_acquire (src->ringbuffer, spec))
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);
gst_ringbuffer_debug_spec_buff (spec);
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
gst_baseaudiosrc_get_times (GstBaseSrc * bsrc, GstBuffer * buffer,
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
gst_baseaudiosrc_event (GstBaseSrc * bsrc, GstEvent * event)
{
GstBaseAudioSrc *src = GST_BASEAUDIOSRC (bsrc);
switch (GST_EVENT_TYPE (event)) {
case GST_EVENT_FLUSH:
if (GST_EVENT_FLUSH_DONE (event)) {
} else {
gst_ringbuffer_pause (src->ringbuffer);
}
break;
default:
break;
}
return TRUE;
}
static GstFlowReturn
gst_baseaudiosrc_create (GstPushSrc * psrc, GstBuffer ** outbuf)
{
GstBaseAudioSrc *src = GST_BASEAUDIOSRC (psrc);
GstBuffer *buf;
guchar *data;
guint len;
guint res;
if (!gst_ringbuffer_is_acquired (src->ringbuffer))
goto wrong_state;
buf = gst_buffer_new_and_alloc (src->ringbuffer->spec.segsize);
data = GST_BUFFER_DATA (buf);
len = GST_BUFFER_SIZE (buf);
res = gst_ringbuffer_read (src->ringbuffer, -1, data, len);
if (res == -1)
goto stopped;
gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (psrc)));
*outbuf = buf;
return GST_FLOW_OK;
wrong_state:
{
GST_DEBUG ("ringbuffer in wrong state");
return GST_FLOW_WRONG_STATE;
}
stopped:
{
gst_buffer_unref (buf);
GST_DEBUG ("ringbuffer stopped");
return GST_FLOW_WRONG_STATE;
}
}
GstRingBuffer *
gst_baseaudiosrc_create_ringbuffer (GstBaseAudioSrc * src)
{
GstBaseAudioSrcClass *bclass;
GstRingBuffer *buffer = NULL;
bclass = GST_BASEAUDIOSRC_GET_CLASS (src);
if (bclass->create_ringbuffer)
buffer = bclass->create_ringbuffer (src);
if (buffer) {
gst_object_set_parent (GST_OBJECT (buffer), GST_OBJECT (src));
}
return buffer;
}
void
gst_baseaudiosrc_callback (GstRingBuffer * rbuf, guint8 * data, guint len,
gpointer user_data)
{
//GstBaseAudioSrc *src = GST_BASEAUDIOSRC (data);
}
static GstElementStateReturn
gst_baseaudiosrc_change_state (GstElement * element)
{
GstElementStateReturn ret = GST_STATE_SUCCESS;
GstBaseAudioSrc *src = GST_BASEAUDIOSRC (element);
GstElementState transition = GST_STATE_TRANSITION (element);
switch (transition) {
case GST_STATE_NULL_TO_READY:
break;
case GST_STATE_READY_TO_PAUSED:
src->ringbuffer = gst_baseaudiosrc_create_ringbuffer (src);
gst_ringbuffer_set_callback (src->ringbuffer, gst_baseaudiosrc_callback,
src);
break;
case GST_STATE_PAUSED_TO_PLAYING:
break;
default:
break;
}
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
switch (transition) {
case GST_STATE_PLAYING_TO_PAUSED:
gst_ringbuffer_pause (src->ringbuffer);
break;
case GST_STATE_PAUSED_TO_READY:
gst_ringbuffer_stop (src->ringbuffer);
gst_ringbuffer_release (src->ringbuffer);
gst_object_unref (GST_OBJECT (src->ringbuffer));
src->ringbuffer = NULL;
break;
case GST_STATE_READY_TO_NULL:
break;
default:
break;
}
return ret;
}

View file

@ -0,0 +1,77 @@
/* GStreamer
* Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
* 2005 Wim Taymans <wim@fluendo.com>
*
* gstbaseaudiosrc.h:
*
* 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.
*/
/* a base class for audio sources.
*/
#ifndef __GST_BASEAUDIOSRC_H__
#define __GST_BASEAUDIOSRC_H__
#include <gst/gst.h>
#include <gst/base/gstpushsrc.h>
#include "gstringbuffer.h"
#include "gstaudioclock.h"
G_BEGIN_DECLS
#define GST_TYPE_BASEAUDIOSRC (gst_baseaudiosrc_get_type())
#define GST_BASEAUDIOSRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_BASEAUDIOSRC,GstBaseAudioSrc))
#define GST_BASEAUDIOSRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_BASEAUDIOSRC,GstBaseAudioSrcClass))
#define GST_BASEAUDIOSRC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_BASEAUDIOSRC, GstBaseAudioSrcClass))
#define GST_IS_BASEAUDIOSRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_BASEAUDIOSRC))
#define GST_IS_BASEAUDIOSRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_BASEAUDIOSRC))
#define GST_BASEAUDIOSRC_CLOCK(obj) (GST_BASEAUDIOSRC (obj)->clock)
#define GST_BASEAUDIOSRC_PAD(obj) (GST_BASESRC (obj)->srcpad)
typedef struct _GstBaseAudioSrc GstBaseAudioSrc;
typedef struct _GstBaseAudioSrcClass GstBaseAudioSrcClass;
struct _GstBaseAudioSrc {
GstPushSrc element;
/*< protected >*/ /* with LOCK */
/* our ringbuffer */
GstRingBuffer *ringbuffer;
/* required buffer and latency */
GstClockTime buffer_time;
GstClockTime latency_time;
/* clock */
GstClock *clock;
};
struct _GstBaseAudioSrcClass {
GstPushSrcClass parent_class;
/* subclass ringbuffer allocation */
GstRingBuffer* (*create_ringbuffer) (GstBaseAudioSrc *src);
};
GType gst_baseaudiosrc_get_type(void);
GstRingBuffer *gst_baseaudiosrc_create_ringbuffer (GstBaseAudioSrc *src);
G_END_DECLS
#endif /* __GST_BASEAUDIOSRC_H__ */

View file

@ -106,6 +106,204 @@ gst_ringbuffer_finalize (GObject * object)
G_OBJECT_CLASS (parent_class)->finalize (G_OBJECT (ringbuffer));
}
static int linear_formats[4 * 2 * 2] = {
GST_S8,
GST_S8,
GST_U8,
GST_U8,
GST_S16_LE,
GST_S16_BE,
GST_U16_LE,
GST_U16_BE,
GST_S24_LE,
GST_S24_BE,
GST_U24_LE,
GST_U24_BE,
GST_S32_LE,
GST_S32_BE,
GST_U32_LE,
GST_U32_BE
};
static int linear24_formats[3 * 2 * 2] = {
GST_S24_3LE,
GST_S24_3BE,
GST_U24_3LE,
GST_U24_3BE,
GST_S20_3LE,
GST_S20_3BE,
GST_U20_3LE,
GST_U20_3BE,
GST_S18_3LE,
GST_S18_3BE,
GST_U18_3LE,
GST_U18_3BE,
};
static GstBufferFormat
build_linear_format (int depth, int width, int unsignd, int big_endian)
{
if (width == 24) {
switch (depth) {
case 24:
depth = 0;
break;
case 20:
depth = 1;
break;
case 18:
depth = 2;
break;
default:
return GST_UNKNOWN;
}
return ((int (*)[2][2]) linear24_formats)[depth][!!unsignd][!!big_endian];
} else {
switch (depth) {
case 8:
depth = 0;
break;
case 16:
depth = 1;
break;
case 24:
depth = 2;
break;
case 32:
depth = 3;
break;
default:
return GST_UNKNOWN;
}
}
return ((int (*)[2][2]) linear_formats)[depth][!!unsignd][!!big_endian];
}
void
gst_ringbuffer_debug_spec_caps (GstRingBufferSpec * spec)
{
GST_DEBUG ("spec caps: %p %" GST_PTR_FORMAT, spec->caps, spec->caps);
GST_DEBUG ("parsed caps: type: %d", spec->type);
GST_DEBUG ("parsed caps: format: %d", spec->format);
GST_DEBUG ("parsed caps: width: %d", spec->width);
GST_DEBUG ("parsed caps: depth: %d", spec->depth);
GST_DEBUG ("parsed caps: sign: %d", spec->sign);
GST_DEBUG ("parsed caps: bigend: %d", spec->bigend);
GST_DEBUG ("parsed caps: rate: %d", spec->rate);
GST_DEBUG ("parsed caps: channels: %d", spec->channels);
GST_DEBUG ("parsed caps: sample bytes: %d", spec->bytes_per_sample);
}
void
gst_ringbuffer_debug_spec_buff (GstRingBufferSpec * spec)
{
GST_DEBUG ("acquire ringbuffer: buffer time: %" G_GINT64_FORMAT " usec",
spec->buffer_time);
GST_DEBUG ("acquire ringbuffer: latency time: %" G_GINT64_FORMAT " usec",
spec->latency_time);
GST_DEBUG ("acquire ringbuffer: total segments: %d", spec->segtotal);
GST_DEBUG ("acquire ringbuffer: segment size: %d bytes = %d samples",
spec->segsize, spec->segsize / spec->bytes_per_sample);
GST_DEBUG ("acquire ringbuffer: buffer size: %d bytes = %d samples",
spec->segsize * spec->segtotal,
spec->segsize * spec->segtotal / spec->bytes_per_sample);
}
gboolean
gst_ringbuffer_parse_caps (GstRingBufferSpec * spec, GstCaps * caps)
{
const gchar *mimetype;
GstStructure *structure;
structure = gst_caps_get_structure (caps, 0);
/* we have to differentiate between int and float formats */
mimetype = gst_structure_get_name (structure);
if (!strncmp (mimetype, "audio/x-raw-int", 15)) {
gint endianness;
spec->type = GST_BUFTYPE_LINEAR;
/* extract the needed information from the cap */
if (!(gst_structure_get_int (structure, "width", &spec->width) &&
gst_structure_get_int (structure, "depth", &spec->depth) &&
gst_structure_get_boolean (structure, "signed", &spec->sign)))
goto parse_error;
/* extract endianness if needed */
if (spec->width > 8) {
if (!gst_structure_get_int (structure, "endianness", &endianness))
goto parse_error;
} else {
endianness = G_BYTE_ORDER;
}
spec->bigend = endianness == G_LITTLE_ENDIAN ? FALSE : TRUE;
spec->format =
build_linear_format (spec->depth, spec->width, spec->sign ? 0 : 1,
spec->bigend ? 1 : 0);
} else if (!strncmp (mimetype, "audio/x-raw-float", 17)) {
spec->type = GST_BUFTYPE_FLOAT;
/* get layout */
if (!gst_structure_get_int (structure, "width", &spec->width))
goto parse_error;
/* match layout to format wrt to endianness */
switch (spec->width) {
case 32:
spec->format =
G_BYTE_ORDER == G_LITTLE_ENDIAN ? GST_FLOAT32_LE : GST_FLOAT32_BE;
break;
case 64:
spec->format =
G_BYTE_ORDER == G_LITTLE_ENDIAN ? GST_FLOAT64_LE : GST_FLOAT64_BE;
break;
default:
goto parse_error;
}
} else if (!strncmp (mimetype, "audio/x-alaw", 12)) {
spec->type = GST_BUFTYPE_A_LAW;
spec->format = GST_A_LAW;
} else if (!strncmp (mimetype, "audio/x-mulaw", 13)) {
spec->type = GST_BUFTYPE_MU_LAW;
spec->format = GST_MU_LAW;
} else {
goto parse_error;
}
/* get rate and channels */
if (!(gst_structure_get_int (structure, "rate", &spec->rate) &&
gst_structure_get_int (structure, "channels", &spec->channels)))
goto parse_error;
spec->bytes_per_sample = (spec->width >> 3) * spec->channels;
gst_caps_replace (&spec->caps, caps);
g_return_val_if_fail (spec->latency_time != 0, FALSE);
/* 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_ringbuffer_debug_spec_caps (spec);
gst_ringbuffer_debug_spec_buff (spec);
return TRUE;
/* ERRORS */
parse_error:
{
GST_DEBUG ("could not parse caps");
return FALSE;
}
}
/**
* gst_ringbuffer_set_callback:
* @buf: the #GstRingBuffer to set the callback on
@ -264,17 +462,17 @@ gst_ringbuffer_is_acquired (GstRingBuffer * buf)
/**
* gst_ringbuffer_play:
* @buf: the #GstRingBuffer to play
* gst_ringbuffer_start:
* @buf: the #GstRingBuffer to start
*
* Start playing samples from the ringbuffer.
* Start processing samples from the ringbuffer.
*
* Returns: TRUE if the device could be started, FALSE on error.
*
* MT safe.
*/
gboolean
gst_ringbuffer_play (GstRingBuffer * buf)
gst_ringbuffer_start (GstRingBuffer * buf)
{
gboolean res = FALSE;
GstRingBufferClass *rclass;
@ -283,16 +481,16 @@ gst_ringbuffer_play (GstRingBuffer * buf)
g_return_val_if_fail (buf != NULL, FALSE);
GST_LOCK (buf);
/* if paused, set to playing */
/* if stopped, set to started */
res = g_atomic_int_compare_and_exchange (&buf->state,
GST_RINGBUFFER_STATE_STOPPED, GST_RINGBUFFER_STATE_PLAYING);
GST_RINGBUFFER_STATE_STOPPED, GST_RINGBUFFER_STATE_STARTED);
if (!res) {
/* was not stopped, try from paused */
res = g_atomic_int_compare_and_exchange (&buf->state,
GST_RINGBUFFER_STATE_PAUSED, GST_RINGBUFFER_STATE_PLAYING);
GST_RINGBUFFER_STATE_PAUSED, GST_RINGBUFFER_STATE_STARTED);
if (!res) {
/* was not paused either, must be playing then */
/* was not paused either, must be started then */
res = TRUE;
goto done;
}
@ -304,8 +502,8 @@ gst_ringbuffer_play (GstRingBuffer * buf)
if (rclass->resume)
res = rclass->resume (buf);
} else {
if (rclass->play)
res = rclass->play (buf);
if (rclass->start)
res = rclass->start (buf);
}
if (!res) {
@ -322,7 +520,7 @@ done:
* gst_ringbuffer_pause:
* @buf: the #GstRingBuffer to pause
*
* Pause playing samples from the ringbuffer.
* Pause processing samples from the ringbuffer.
*
* Returns: TRUE if the device could be paused, FALSE on error.
*
@ -337,12 +535,12 @@ gst_ringbuffer_pause (GstRingBuffer * buf)
g_return_val_if_fail (buf != NULL, FALSE);
GST_LOCK (buf);
/* if playing, set to paused */
/* if started, set to paused */
res = g_atomic_int_compare_and_exchange (&buf->state,
GST_RINGBUFFER_STATE_PLAYING, GST_RINGBUFFER_STATE_PAUSED);
GST_RINGBUFFER_STATE_STARTED, GST_RINGBUFFER_STATE_PAUSED);
if (!res) {
/* was not playing */
/* was not started */
res = TRUE;
goto done;
}
@ -355,7 +553,7 @@ gst_ringbuffer_pause (GstRingBuffer * buf)
res = rclass->pause (buf);
if (!res) {
buf->state = GST_RINGBUFFER_STATE_PLAYING;
buf->state = GST_RINGBUFFER_STATE_STARTED;
}
done:
GST_UNLOCK (buf);
@ -367,7 +565,7 @@ done:
* gst_ringbuffer_stop:
* @buf: the #GstRingBuffer to stop
*
* Stop playing samples from the ringbuffer.
* Stop processing samples from the ringbuffer.
*
* Returns: TRUE if the device could be stopped, FALSE on error.
*
@ -382,12 +580,12 @@ gst_ringbuffer_stop (GstRingBuffer * buf)
g_return_val_if_fail (buf != NULL, FALSE);
GST_LOCK (buf);
/* if playing, set to stopped */
/* if started, set to stopped */
res = g_atomic_int_compare_and_exchange (&buf->state,
GST_RINGBUFFER_STATE_PLAYING, GST_RINGBUFFER_STATE_STOPPED);
GST_RINGBUFFER_STATE_STARTED, GST_RINGBUFFER_STATE_STOPPED);
if (!res) {
/* was not playing, must be stopped then */
/* was not started, must be stopped then */
res = TRUE;
goto done;
}
@ -400,7 +598,7 @@ gst_ringbuffer_stop (GstRingBuffer * buf)
res = rclass->stop (buf);
if (!res) {
buf->state = GST_RINGBUFFER_STATE_PLAYING;
buf->state = GST_RINGBUFFER_STATE_STARTED;
} else {
gst_ringbuffer_set_sample (buf, 0);
}
@ -442,38 +640,38 @@ gst_ringbuffer_delay (GstRingBuffer * buf)
}
/**
* gst_ringbuffer_played_samples:
* gst_ringbuffer_samples_done:
* @buf: the #GstRingBuffer to query
*
* Get the number of samples that were played by the ringbuffer
* Get the number of samples that were processed by the ringbuffer
* since it was last started.
*
* Returns: The number of samples played by the ringbuffer.
* Returns: The number of samples processed by the ringbuffer.
*
* MT safe.
*/
guint64
gst_ringbuffer_played_samples (GstRingBuffer * buf)
gst_ringbuffer_samples_done (GstRingBuffer * buf)
{
gint segplayed;
gint segdone;
guint64 raw, samples;
guint delay;
g_return_val_if_fail (buf != NULL, 0);
/* get the amount of segments we played */
segplayed = g_atomic_int_get (&buf->segplayed);
/* get the amount of segments we processed */
segdone = g_atomic_int_get (&buf->segdone);
/* and the number of samples not yet played */
/* and the number of samples not yet processed */
delay = gst_ringbuffer_delay (buf);
samples = (segplayed * buf->samples_per_seg);
samples = (segdone * buf->samples_per_seg);
raw = samples;
if (samples >= delay)
samples -= delay;
GST_DEBUG ("played samples: raw %llu, delay %u, real %llu", raw, delay,
GST_DEBUG ("processed samples: raw %llu, delay %u, real %llu", raw, delay,
samples);
return samples;
@ -505,47 +703,47 @@ gst_ringbuffer_set_sample (GstRingBuffer * buf, guint64 sample)
/* FIXME, we assume the ringbuffer can restart at a random
* position, round down to the beginning and keep track of
* offset when calculating the played samples. */
buf->segplayed = sample / buf->samples_per_seg;
* offset when calculating the processed samples. */
buf->segdone = sample / buf->samples_per_seg;
buf->next_sample = sample;
for (i = 0; i < buf->spec.segtotal; i++) {
gst_ringbuffer_clear (buf, i);
}
GST_DEBUG ("setting sample to %llu, segplayed %d", sample, buf->segplayed);
GST_DEBUG ("setting sample to %llu, segdone %d", sample, buf->segdone);
}
static gboolean
wait_segment (GstRingBuffer * buf)
{
/* buffer must be playing now or we deadlock since nobody is reading */
if (g_atomic_int_get (&buf->state) != GST_RINGBUFFER_STATE_PLAYING) {
GST_DEBUG ("play!");
gst_ringbuffer_play (buf);
/* buffer must be started now or we deadlock since nobody is reading */
if (g_atomic_int_get (&buf->state) != GST_RINGBUFFER_STATE_STARTED) {
GST_DEBUG ("start!");
gst_ringbuffer_start (buf);
}
/* take lock first, then update our waiting flag */
GST_LOCK (buf);
if (g_atomic_int_compare_and_exchange (&buf->waiting, 0, 1)) {
GST_DEBUG ("waiting..");
if (g_atomic_int_get (&buf->state) != GST_RINGBUFFER_STATE_PLAYING)
goto not_playing;
if (g_atomic_int_get (&buf->state) != GST_RINGBUFFER_STATE_STARTED)
goto not_started;
GST_RINGBUFFER_WAIT (buf);
if (g_atomic_int_get (&buf->state) != GST_RINGBUFFER_STATE_PLAYING)
goto not_playing;
if (g_atomic_int_get (&buf->state) != GST_RINGBUFFER_STATE_STARTED)
goto not_started;
}
GST_UNLOCK (buf);
return TRUE;
/* ERROR */
not_playing:
not_started:
{
GST_UNLOCK (buf);
GST_DEBUG ("stopped playing");
GST_DEBUG ("stopped processing");
return FALSE;
}
}
@ -573,7 +771,7 @@ guint
gst_ringbuffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
guint len)
{
gint segplayed;
gint segdone;
gint segsize, segtotal, bps, sps;
guint8 *dest;
@ -582,7 +780,7 @@ gst_ringbuffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
g_return_val_if_fail (data != NULL, -1);
if (sample == -1) {
/* play aligned with last sample */
/* process aligned with last sample */
sample = buf->next_sample;
} else {
if (sample != buf->next_sample) {
@ -614,17 +812,17 @@ gst_ringbuffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
while (TRUE) {
gint diff;
/* get the currently playing segment */
segplayed = g_atomic_int_get (&buf->segplayed);
/* get the currently processed segment */
segdone = g_atomic_int_get (&buf->segdone);
/* see how far away it is from the write segment */
diff = writeseg - segplayed;
diff = writeseg - segdone;
GST_DEBUG
("pointer at %d, sample %llu, write to %d-%d, len %d, diff %d, segtotal %d, segsize %d",
segplayed, sample, writeseg, writeoff, len, diff, segtotal, segsize);
segdone, sample, writeseg, writeoff, len, diff, segtotal, segsize);
/* play segment too far ahead, we need to drop */
/* segment too far ahead, we need to drop */
if (diff < 0) {
/* we need to drop one segment at a time, pretend we wrote a
* segment. */
@ -639,7 +837,7 @@ gst_ringbuffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
/* else we need to wait for the segment to become writable. */
if (!wait_segment (buf))
goto not_playing;
goto not_started;
}
/* we can write now */
@ -660,9 +858,127 @@ gst_ringbuffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
return len;
/* ERRORS */
not_playing:
not_started:
{
GST_DEBUG ("stopped playing");
GST_DEBUG ("stopped processing");
return -1;
}
}
/**
* gst_ringbuffer_read:
* @buf: the #GstRingBuffer to read from
* @sample: the sample position of the data
* @data: where the data should be read
* @len: the length of the data to read
*
* Read @length samples from the ringbuffer into the memory pointed
* to by @data.
* The first sample should be read from position @sample in
* the ringbuffer.
*
* @len should not be a multiple of the segment size of the ringbuffer
* although it is recommended.
*
* Returns: The number of samples read from the ringbuffer or -1 on
* error.
*
* MT safe.
*/
guint
gst_ringbuffer_read (GstRingBuffer * buf, guint64 sample, guchar * data,
guint len)
{
gint segdone;
gint segsize, segtotal, bps, sps;
guint8 *dest;
g_return_val_if_fail (buf != NULL, -1);
g_return_val_if_fail (buf->data != NULL, -1);
g_return_val_if_fail (data != NULL, -1);
if (sample == -1) {
/* process aligned with last sample */
sample = buf->next_sample;
} else {
if (sample != buf->next_sample) {
GST_WARNING ("discontinuity found got %" G_GUINT64_FORMAT
", expected %" G_GUINT64_FORMAT, sample, buf->next_sample);
}
}
dest = GST_BUFFER_DATA (buf->data);
segsize = buf->spec.segsize;
segtotal = buf->spec.segtotal;
bps = buf->spec.bytes_per_sample;
sps = buf->samples_per_seg;
/* we assume the complete buffer will be consumed and the next sample
* should be written after this */
buf->next_sample = sample + len / bps;
/* read enough bytes */
while (len > 0) {
gint readlen;
gint readseg, readoff;
/* figure out the segment and the offset inside the segment where
* the sample should be written. */
readseg = sample / sps;
readoff = (sample % sps) * bps;
while (TRUE) {
gint diff;
/* get the currently processed segment */
segdone = g_atomic_int_get (&buf->segdone);
/* see how far away it is from the read segment */
diff = segdone - readseg;
GST_DEBUG
("pointer at %d, sample %llu, read from %d-%d, len %d, diff %d, segtotal %d, segsize %d",
segdone, sample, readseg, readoff, len, diff, segtotal, segsize);
/* segment too far ahead, we need to drop */
if (diff < 0) {
/* we need to drop one segment at a time, pretend we wrote a
* segment. */
readlen = MIN (segsize, len);
goto next;
}
/* read segment is within readable range, we can break the loop and
* start reading the data. */
if (diff > 0 && diff < segtotal)
break;
/* else we need to wait for the segment to become readable. */
if (!wait_segment (buf))
goto not_started;
}
/* we can read now */
readseg = readseg % segtotal;
readlen = MIN (segsize - readoff, len);
GST_DEBUG ("read @%p seg %d, off %d, len %d",
dest + readseg * segsize, readseg, readoff, readlen);
memcpy (data, dest + readseg * segsize + readoff, readlen);
next:
len -= readlen;
data += readlen;
sample += readlen / bps;
}
return len;
/* ERRORS */
not_started:
{
GST_DEBUG ("stopped processing");
return -1;
}
}
@ -677,7 +993,7 @@ not_playing:
* Returns a pointer to memory where the data from segment @segment
* can be found. This function is used by subclasses.
*
* Returns: FALSE if the buffer is not playing.
* Returns: FALSE if the buffer is not started.
*
* MT safe.
*/
@ -686,23 +1002,24 @@ gst_ringbuffer_prepare_read (GstRingBuffer * buf, gint * segment,
guint8 ** readptr, gint * len)
{
guint8 *data;
gint segplayed;
gint segdone;
/* buffer must be playing */
if (g_atomic_int_get (&buf->state) != GST_RINGBUFFER_STATE_PLAYING)
/* buffer must be started */
if (g_atomic_int_get (&buf->state) != GST_RINGBUFFER_STATE_STARTED)
return FALSE;
g_return_val_if_fail (buf != NULL, FALSE);
g_return_val_if_fail (buf->data != NULL, FALSE);
g_return_val_if_fail (segment != NULL, FALSE);
g_return_val_if_fail (readptr != NULL, FALSE);
g_return_val_if_fail (len != NULL, FALSE);
data = GST_BUFFER_DATA (buf->data);
/* get the position of the play pointer */
segplayed = g_atomic_int_get (&buf->segplayed);
/* get the position of the pointer */
segdone = g_atomic_int_get (&buf->segdone);
*segment = segplayed % buf->spec.segtotal;
*segment = segdone % buf->spec.segtotal;
*len = buf->spec.segsize;
*readptr = data + *segment * *len;
@ -711,7 +1028,7 @@ gst_ringbuffer_prepare_read (GstRingBuffer * buf, gint * segment,
buf->callback (buf, *readptr, *len, buf->cb_data);
GST_DEBUG ("prepare read from segment %d (real %d) @%p",
*segment, segplayed, *readptr);
*segment, segdone, *readptr);
return TRUE;
}
@ -722,7 +1039,7 @@ gst_ringbuffer_prepare_read (GstRingBuffer * buf, gint * segment,
* @advance: the number of segments written
*
* Subclasses should call this function to notify the fact that
* @advance segments are now played by the device.
* @advance segments are now processed by the device.
*
* MT safe.
*/
@ -732,7 +1049,7 @@ gst_ringbuffer_advance (GstRingBuffer * buf, guint advance)
g_return_if_fail (buf != NULL);
/* update counter */
g_atomic_int_add (&buf->segplayed, advance);
g_atomic_int_add (&buf->segdone, advance);
/* the lock is already taken when the waiting flag is set,
* we grab the lock as well to make sure the waiter is actually

View file

@ -44,7 +44,7 @@ typedef void (*GstRingBufferCallback) (GstRingBuffer *rbuf, guint8* data, guint
typedef enum {
GST_RINGBUFFER_STATE_STOPPED,
GST_RINGBUFFER_STATE_PAUSED,
GST_RINGBUFFER_STATE_PLAYING,
GST_RINGBUFFER_STATE_STARTED,
} GstRingBufferState;
typedef enum {
@ -160,11 +160,11 @@ struct _GstRingBuffer {
/*< public >*/ /* ATOMIC */
gint state; /* state of the buffer */
gint segplayed; /* number of segments played since last start */
gint segdone; /* number of segments processed since last start */
gint waiting; /* when waiting for a segment to be freed */
/*< private >*/
guint64 next_sample; /* the next sample we need to write */
guint64 next_sample; /* the next sample we need to process */
GstRingBufferCallback callback;
gpointer cb_data;
};
@ -179,7 +179,7 @@ struct _GstRingBufferClass {
gboolean (*release) (GstRingBuffer *buf);
/* playback control */
gboolean (*play) (GstRingBuffer *buf);
gboolean (*start) (GstRingBuffer *buf);
gboolean (*pause) (GstRingBuffer *buf);
gboolean (*resume) (GstRingBuffer *buf);
gboolean (*stop) (GstRingBuffer *buf);
@ -194,6 +194,10 @@ GType gst_ringbuffer_get_type(void);
void gst_ringbuffer_set_callback (GstRingBuffer *buf, GstRingBufferCallback cb,
gpointer user_data);
gboolean gst_ringbuffer_parse_caps (GstRingBufferSpec *spec, GstCaps *caps);
void gst_ringbuffer_debug_spec_caps (GstRingBufferSpec *spec);
void gst_ringbuffer_debug_spec_buff (GstRingBufferSpec *spec);
/* allocate resources */
gboolean gst_ringbuffer_acquire (GstRingBuffer *buf, GstRingBufferSpec *spec);
gboolean gst_ringbuffer_release (GstRingBuffer *buf);
@ -201,21 +205,25 @@ gboolean gst_ringbuffer_release (GstRingBuffer *buf);
gboolean gst_ringbuffer_is_acquired (GstRingBuffer *buf);
/* playback/pause */
gboolean gst_ringbuffer_play (GstRingBuffer *buf);
gboolean gst_ringbuffer_start (GstRingBuffer *buf);
gboolean gst_ringbuffer_pause (GstRingBuffer *buf);
gboolean gst_ringbuffer_stop (GstRingBuffer *buf);
/* get status */
guint gst_ringbuffer_delay (GstRingBuffer *buf);
guint64 gst_ringbuffer_played_samples (GstRingBuffer *buf);
guint64 gst_ringbuffer_samples_done (GstRingBuffer *buf);
void gst_ringbuffer_set_sample (GstRingBuffer *buf, guint64 sample);
/* commit samples */
guint gst_ringbuffer_commit (GstRingBuffer *buf, guint64 sample,
guchar *data, guint len);
/* read samples */
guint gst_ringbuffer_read (GstRingBuffer *buf, guint64 sample,
guchar *data, guint len);
/* mostly protected */
gboolean gst_ringbuffer_prepare_write (GstRingBuffer *buf, gint *segment, guint8 **writeptr, gint *len);
gboolean gst_ringbuffer_prepare_read (GstRingBuffer *buf, gint *segment, guint8 **readptr, gint *len);
void gst_ringbuffer_clear (GstRingBuffer *buf, gint segment);
void gst_ringbuffer_advance (GstRingBuffer *buf, guint advance);