mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
Added audiosource base classes.
Original commit message from CVS: Added audiosource base classes. Ported alsasrc, still very basic.
This commit is contained in:
parent
a46a991d26
commit
ceb88a7777
14 changed files with 2041 additions and 742 deletions
51
ChangeLog
51
ChangeLog
|
@ -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),
|
||||
|
|
|
@ -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) \
|
||||
|
|
|
@ -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, "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
|
@ -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
|
||||
|
@ -11,45 +10,62 @@
|
|||
*
|
||||
* 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
|
||||
* 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., 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__ */
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
418
gst-libs/gst/audio/gstaudiosrc.c
Normal file
418
gst-libs/gst/audio/gstaudiosrc.c
Normal 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;
|
||||
}
|
84
gst-libs/gst/audio/gstaudiosrc.h
Normal file
84
gst-libs/gst/audio/gstaudiosrc.h
Normal 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__ */
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
403
gst-libs/gst/audio/gstbaseaudiosrc.c
Normal file
403
gst-libs/gst/audio/gstbaseaudiosrc.c
Normal 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;
|
||||
}
|
77
gst-libs/gst/audio/gstbaseaudiosrc.h
Normal file
77
gst-libs/gst/audio/gstbaseaudiosrc.h
Normal 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__ */
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue