mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-20 04:56:24 +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>
|
2005-07-06 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
* ext/theora/theoradec.c: (theora_dec_src_getcaps),
|
* ext/theora/theoradec.c: (theora_dec_src_getcaps),
|
||||||
|
|
|
@ -3,7 +3,8 @@ plugin_LTLIBRARIES = libgstalsa.la
|
||||||
|
|
||||||
libgstalsa_la_SOURCES = \
|
libgstalsa_la_SOURCES = \
|
||||||
gstalsaplugin.c \
|
gstalsaplugin.c \
|
||||||
gstalsasink.c
|
gstalsasink.c \
|
||||||
|
gstalsasrc.c
|
||||||
|
|
||||||
# port alsa stuff then add the _SOURCES above
|
# port alsa stuff then add the _SOURCES above
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
|
@ -11,8 +12,7 @@ EXTRA_DIST = \
|
||||||
gstalsamixertrack.c \
|
gstalsamixertrack.c \
|
||||||
gstalsamixeroptions.c \
|
gstalsamixeroptions.c \
|
||||||
gstalsa.c \
|
gstalsa.c \
|
||||||
gstalsaclock.c \
|
gstalsaclock.c
|
||||||
gstalsasrc.c
|
|
||||||
|
|
||||||
libgstalsa_la_CFLAGS = $(GST_CFLAGS) $(ALSA_CFLAGS)
|
libgstalsa_la_CFLAGS = $(GST_CFLAGS) $(ALSA_CFLAGS)
|
||||||
libgstalsa_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) \
|
libgstalsa_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) \
|
||||||
|
|
|
@ -60,10 +60,10 @@ plugin_init (GstPlugin * plugin)
|
||||||
if (!gst_element_register (plugin, "alsamixer", GST_RANK_NONE,
|
if (!gst_element_register (plugin, "alsamixer", GST_RANK_NONE,
|
||||||
GST_TYPE_ALSA_MIXER))
|
GST_TYPE_ALSA_MIXER))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
*/
|
||||||
if (!gst_element_register (plugin, "alsasrc", GST_RANK_NONE,
|
if (!gst_element_register (plugin, "alsasrc", GST_RANK_NONE,
|
||||||
GST_TYPE_ALSA_SRC))
|
GST_TYPE_ALSA_SRC))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
*/
|
|
||||||
if (!gst_element_register (plugin, "alsasink", GST_RANK_NONE,
|
if (!gst_element_register (plugin, "alsasink", GST_RANK_NONE,
|
||||||
GST_TYPE_ALSA_SINK))
|
GST_TYPE_ALSA_SINK))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,8 +1,7 @@
|
||||||
/*
|
/* GStreamer
|
||||||
* Copyright (C) 2001 CodeFactory AB
|
* Copyright (C) 2005 Wim Taymans <wim@fluendo.com>
|
||||||
* Copyright (C) 2001 Thomas Nyberg <thomas@codefactory.se>
|
*
|
||||||
* Copyright (C) 2001-2002 Andy Wingo <apwingo@eos.ncsu.edu>
|
* gstalsasrc.h:
|
||||||
* Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
|
|
||||||
*
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Library General Public
|
* modify it under the terms of the GNU Library General Public
|
||||||
|
@ -15,41 +14,58 @@
|
||||||
* Library General Public License for more details.
|
* Library General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Library General Public
|
* You should have received a copy of the GNU Library General Public
|
||||||
* License along with this library; if not, write to the Free
|
* License along with this library; if not, write to the
|
||||||
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
* 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
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
#define GST_ALSA_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST(obj, GST_TYPE_ALSA_SRC, GstAlsaSrc))
|
#define GST_TYPE_ALSA_SRC (gst_alsasrc_get_type())
|
||||||
#define GST_ALSA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST(klass, GST_TYPE_ALSA_SRC, GstAlsaSrcClass))
|
#define GST_ALSA_SRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_ALSA_SRC,GstAlsaSrc))
|
||||||
#define GST_IS_ALSA_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE(obj, GST_TYPE_ALSA_SRC))
|
#define GST_ALSA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_ALSA_SRC,GstAlsaSrcClass))
|
||||||
#define GST_IS_ALSA_SRC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE(klass, GST_TYPE_ALSA_SRC))
|
#define GST_IS_ALSA_SRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_ALSA_SRC))
|
||||||
#define GST_TYPE_ALSA_SRC (gst_alsa_src_get_type())
|
#define GST_IS_ALSA_SRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_ALSA_SRC))
|
||||||
|
|
||||||
typedef struct _GstAlsaSrc GstAlsaSrc;
|
typedef struct _GstAlsaSrc GstAlsaSrc;
|
||||||
typedef struct _GstAlsaSrcClass GstAlsaSrcClass;
|
typedef struct _GstAlsaSrcClass GstAlsaSrcClass;
|
||||||
|
|
||||||
struct _GstAlsaSrc {
|
struct _GstAlsaSrc {
|
||||||
GstAlsaMixer parent;
|
GstAudioSrc src;
|
||||||
GstBuffer *buf[GST_ALSA_MAX_TRACKS];
|
|
||||||
snd_pcm_status_t *status;
|
gchar *device;
|
||||||
GstClockTime base_time; /* FIXME: move this up ? already present in element ? */
|
|
||||||
|
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 {
|
struct _GstAlsaSrcClass {
|
||||||
GstAlsaMixerClass parent_class;
|
GstAudioSrcClass parent_class;
|
||||||
};
|
};
|
||||||
|
|
||||||
GType gst_alsa_src_get_type (void);
|
GType gst_alsasrc_get_type(void);
|
||||||
|
|
||||||
gboolean gst_alsa_src_factory_init (GstPlugin *plugin);
|
|
||||||
|
|
||||||
G_END_DECLS
|
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 \
|
libgstaudio_@GST_MAJORMINOR@_la_SOURCES = audio.c gstaudioclock.c \
|
||||||
multichannel.c \
|
multichannel.c \
|
||||||
gstaudiosink.c \
|
gstaudiosink.c \
|
||||||
|
gstaudiosrc.c \
|
||||||
gstbaseaudiosink.c \
|
gstbaseaudiosink.c \
|
||||||
|
gstbaseaudiosrc.c \
|
||||||
gstringbuffer.c
|
gstringbuffer.c
|
||||||
nodist_libgstaudio_@GST_MAJORMINOR@_la_SOURCES = $(built_sources) $(built_headers)
|
nodist_libgstaudio_@GST_MAJORMINOR@_la_SOURCES = $(built_sources) $(built_headers)
|
||||||
|
|
||||||
|
@ -27,7 +29,9 @@ libgstaudio_@GST_MAJORMINOR@include_HEADERS = \
|
||||||
gstaudioclock.h \
|
gstaudioclock.h \
|
||||||
gstaudiofilter.h \
|
gstaudiofilter.h \
|
||||||
gstaudiosink.h \
|
gstaudiosink.h \
|
||||||
|
gstaudiosrc.h \
|
||||||
gstbaseaudiosink.h \
|
gstbaseaudiosink.h \
|
||||||
|
gstbaseaudiosrc.h \
|
||||||
gstringbuffer.h \
|
gstringbuffer.h \
|
||||||
multichannel.h
|
multichannel.h
|
||||||
|
|
||||||
|
|
|
@ -73,12 +73,12 @@ static GstRingBufferClass *ring_parent_class = NULL;
|
||||||
static gboolean gst_audioringbuffer_acquire (GstRingBuffer * buf,
|
static gboolean gst_audioringbuffer_acquire (GstRingBuffer * buf,
|
||||||
GstRingBufferSpec * spec);
|
GstRingBufferSpec * spec);
|
||||||
static gboolean gst_audioringbuffer_release (GstRingBuffer * buf);
|
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 gboolean gst_audioringbuffer_stop (GstRingBuffer * buf);
|
||||||
static guint gst_audioringbuffer_delay (GstRingBuffer * buf);
|
static guint gst_audioringbuffer_delay (GstRingBuffer * buf);
|
||||||
|
|
||||||
/* ringbuffer abstract base class */
|
/* ringbuffer abstract base class */
|
||||||
GType
|
static GType
|
||||||
gst_audioringbuffer_get_type (void)
|
gst_audioringbuffer_get_type (void)
|
||||||
{
|
{
|
||||||
static GType ringbuffer_type = 0;
|
static GType ringbuffer_type = 0;
|
||||||
|
@ -98,7 +98,7 @@ gst_audioringbuffer_get_type (void)
|
||||||
};
|
};
|
||||||
|
|
||||||
ringbuffer_type =
|
ringbuffer_type =
|
||||||
g_type_register_static (GST_TYPE_RINGBUFFER, "GstAudioRingBuffer",
|
g_type_register_static (GST_TYPE_RINGBUFFER, "GstAudioSinkRingBuffer",
|
||||||
&ringbuffer_info, 0);
|
&ringbuffer_info, 0);
|
||||||
}
|
}
|
||||||
return ringbuffer_type;
|
return ringbuffer_type;
|
||||||
|
@ -124,8 +124,8 @@ gst_audioringbuffer_class_init (GstAudioRingBufferClass * klass)
|
||||||
GST_DEBUG_FUNCPTR (gst_audioringbuffer_acquire);
|
GST_DEBUG_FUNCPTR (gst_audioringbuffer_acquire);
|
||||||
gstringbuffer_class->release =
|
gstringbuffer_class->release =
|
||||||
GST_DEBUG_FUNCPTR (gst_audioringbuffer_release);
|
GST_DEBUG_FUNCPTR (gst_audioringbuffer_release);
|
||||||
gstringbuffer_class->play = GST_DEBUG_FUNCPTR (gst_audioringbuffer_play);
|
gstringbuffer_class->start = GST_DEBUG_FUNCPTR (gst_audioringbuffer_start);
|
||||||
gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_audioringbuffer_play);
|
gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_audioringbuffer_start);
|
||||||
gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_audioringbuffer_stop);
|
gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_audioringbuffer_stop);
|
||||||
|
|
||||||
gstringbuffer_class->delay = GST_DEBUG_FUNCPTR (gst_audioringbuffer_delay);
|
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.
|
/* 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
|
* It will write each segment in the ringbuffer and will update the play
|
||||||
* pointer.
|
* pointer.
|
||||||
* The play/stop methods control the thread.
|
* The start/stop methods control the thread.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
audioringbuffer_thread_func (GstRingBuffer * buf)
|
audioringbuffer_thread_func (GstRingBuffer * buf)
|
||||||
|
@ -307,13 +307,13 @@ gst_audioringbuffer_release (GstRingBuffer * buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_audioringbuffer_play (GstRingBuffer * buf)
|
gst_audioringbuffer_start (GstRingBuffer * buf)
|
||||||
{
|
{
|
||||||
GstAudioSink *sink;
|
GstAudioSink *sink;
|
||||||
|
|
||||||
sink = GST_AUDIOSINK (GST_OBJECT_PARENT (buf));
|
sink = GST_AUDIOSINK (GST_OBJECT_PARENT (buf));
|
||||||
|
|
||||||
GST_DEBUG ("play, sending signal");
|
GST_DEBUG ("start, sending signal");
|
||||||
GST_AUDIORINGBUFFER_SIGNAL (buf);
|
GST_AUDIORINGBUFFER_SIGNAL (buf);
|
||||||
|
|
||||||
return TRUE;
|
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)
|
if (sink->ringbuffer == NULL || sink->ringbuffer->spec.rate == 0)
|
||||||
return 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 = samples * GST_SECOND / sink->ringbuffer->spec.rate;
|
||||||
result += GST_ELEMENT (sink)->base_time;
|
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
|
static gboolean
|
||||||
gst_baseaudiosink_setcaps (GstBaseSink * bsink, GstCaps * caps)
|
gst_baseaudiosink_setcaps (GstBaseSink * bsink, GstCaps * caps)
|
||||||
{
|
{
|
||||||
GstBaseAudioSink *sink = GST_BASEAUDIOSINK (bsink);
|
GstBaseAudioSink *sink = GST_BASEAUDIOSINK (bsink);
|
||||||
GstRingBufferSpec *spec;
|
GstRingBufferSpec *spec;
|
||||||
const gchar *mimetype;
|
|
||||||
GstStructure *structure;
|
|
||||||
|
|
||||||
spec = &sink->ringbuffer->spec;
|
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 */
|
/* release old ringbuffer */
|
||||||
mimetype = gst_structure_get_name (structure);
|
gst_ringbuffer_release (sink->ringbuffer);
|
||||||
|
|
||||||
if (!strncmp (mimetype, "audio/x-raw-int", 15)) {
|
GST_DEBUG ("parse caps");
|
||||||
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);
|
|
||||||
|
|
||||||
spec->buffer_time = sink->buffer_time;
|
spec->buffer_time = sink->buffer_time;
|
||||||
spec->latency_time = sink->latency_time;
|
spec->latency_time = sink->latency_time;
|
||||||
|
|
||||||
/* calculate suggested segsize and segtotal */
|
/* parse new caps */
|
||||||
spec->segsize =
|
if (!gst_ringbuffer_parse_caps (spec, caps))
|
||||||
spec->rate * spec->bytes_per_sample * spec->latency_time / GST_MSECOND;
|
goto parse_error;
|
||||||
spec->segtotal = spec->buffer_time / spec->latency_time;
|
|
||||||
|
|
||||||
GST_DEBUG ("release old ringbuffer");
|
gst_ringbuffer_debug_spec_buff (spec);
|
||||||
|
|
||||||
gst_ringbuffer_release (sink->ringbuffer);
|
GST_DEBUG ("acquire new ringbuffer");
|
||||||
|
|
||||||
debug_spec_buffer (sink, spec);
|
|
||||||
|
|
||||||
if (!gst_ringbuffer_acquire (sink->ringbuffer, spec))
|
if (!gst_ringbuffer_acquire (sink->ringbuffer, spec))
|
||||||
goto acquire_error;
|
goto acquire_error;
|
||||||
|
@ -419,7 +246,7 @@ gst_baseaudiosink_setcaps (GstBaseSink * bsink, GstCaps * caps)
|
||||||
spec->segtotal * spec->segsize * GST_MSECOND / (spec->rate *
|
spec->segtotal * spec->segsize * GST_MSECOND / (spec->rate *
|
||||||
spec->bytes_per_sample);
|
spec->bytes_per_sample);
|
||||||
|
|
||||||
debug_spec_buffer (sink, spec);
|
gst_ringbuffer_debug_spec_buff (spec);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
@ -487,10 +314,23 @@ gst_baseaudiosink_event (GstBaseSink * bsink, GstEvent * event)
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_baseaudiosink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
|
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
|
/* we don't really do anything when prerolling. We could make a
|
||||||
* property to play this buffer to have some sort of scrubbing
|
* property to play this buffer to have some sort of scrubbing
|
||||||
* support. */
|
* support. */
|
||||||
return GST_FLOW_OK;
|
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
|
static GstFlowReturn
|
||||||
|
@ -514,6 +354,8 @@ gst_baseaudiosink_render (GstBaseSink * bsink, GstBuffer * buf)
|
||||||
wrong_state:
|
wrong_state:
|
||||||
{
|
{
|
||||||
GST_DEBUG ("ringbuffer in wrong state");
|
GST_DEBUG ("ringbuffer in wrong state");
|
||||||
|
GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
|
||||||
|
("sink not negotiated."), (NULL));
|
||||||
return GST_FLOW_ERROR;
|
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));
|
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:
|
* gst_ringbuffer_set_callback:
|
||||||
* @buf: the #GstRingBuffer to set the callback on
|
* @buf: the #GstRingBuffer to set the callback on
|
||||||
|
@ -264,17 +462,17 @@ gst_ringbuffer_is_acquired (GstRingBuffer * buf)
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_ringbuffer_play:
|
* gst_ringbuffer_start:
|
||||||
* @buf: the #GstRingBuffer to play
|
* @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.
|
* Returns: TRUE if the device could be started, FALSE on error.
|
||||||
*
|
*
|
||||||
* MT safe.
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
gboolean
|
gboolean
|
||||||
gst_ringbuffer_play (GstRingBuffer * buf)
|
gst_ringbuffer_start (GstRingBuffer * buf)
|
||||||
{
|
{
|
||||||
gboolean res = FALSE;
|
gboolean res = FALSE;
|
||||||
GstRingBufferClass *rclass;
|
GstRingBufferClass *rclass;
|
||||||
|
@ -283,16 +481,16 @@ gst_ringbuffer_play (GstRingBuffer * buf)
|
||||||
g_return_val_if_fail (buf != NULL, FALSE);
|
g_return_val_if_fail (buf != NULL, FALSE);
|
||||||
|
|
||||||
GST_LOCK (buf);
|
GST_LOCK (buf);
|
||||||
/* if paused, set to playing */
|
/* if stopped, set to started */
|
||||||
res = g_atomic_int_compare_and_exchange (&buf->state,
|
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) {
|
if (!res) {
|
||||||
/* was not stopped, try from paused */
|
/* was not stopped, try from paused */
|
||||||
res = g_atomic_int_compare_and_exchange (&buf->state,
|
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) {
|
if (!res) {
|
||||||
/* was not paused either, must be playing then */
|
/* was not paused either, must be started then */
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -304,8 +502,8 @@ gst_ringbuffer_play (GstRingBuffer * buf)
|
||||||
if (rclass->resume)
|
if (rclass->resume)
|
||||||
res = rclass->resume (buf);
|
res = rclass->resume (buf);
|
||||||
} else {
|
} else {
|
||||||
if (rclass->play)
|
if (rclass->start)
|
||||||
res = rclass->play (buf);
|
res = rclass->start (buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
|
@ -322,7 +520,7 @@ done:
|
||||||
* gst_ringbuffer_pause:
|
* gst_ringbuffer_pause:
|
||||||
* @buf: the #GstRingBuffer to 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.
|
* 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);
|
g_return_val_if_fail (buf != NULL, FALSE);
|
||||||
|
|
||||||
GST_LOCK (buf);
|
GST_LOCK (buf);
|
||||||
/* if playing, set to paused */
|
/* if started, set to paused */
|
||||||
res = g_atomic_int_compare_and_exchange (&buf->state,
|
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) {
|
if (!res) {
|
||||||
/* was not playing */
|
/* was not started */
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -355,7 +553,7 @@ gst_ringbuffer_pause (GstRingBuffer * buf)
|
||||||
res = rclass->pause (buf);
|
res = rclass->pause (buf);
|
||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
buf->state = GST_RINGBUFFER_STATE_PLAYING;
|
buf->state = GST_RINGBUFFER_STATE_STARTED;
|
||||||
}
|
}
|
||||||
done:
|
done:
|
||||||
GST_UNLOCK (buf);
|
GST_UNLOCK (buf);
|
||||||
|
@ -367,7 +565,7 @@ done:
|
||||||
* gst_ringbuffer_stop:
|
* gst_ringbuffer_stop:
|
||||||
* @buf: the #GstRingBuffer to 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.
|
* 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);
|
g_return_val_if_fail (buf != NULL, FALSE);
|
||||||
|
|
||||||
GST_LOCK (buf);
|
GST_LOCK (buf);
|
||||||
/* if playing, set to stopped */
|
/* if started, set to stopped */
|
||||||
res = g_atomic_int_compare_and_exchange (&buf->state,
|
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) {
|
if (!res) {
|
||||||
/* was not playing, must be stopped then */
|
/* was not started, must be stopped then */
|
||||||
res = TRUE;
|
res = TRUE;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -400,7 +598,7 @@ gst_ringbuffer_stop (GstRingBuffer * buf)
|
||||||
res = rclass->stop (buf);
|
res = rclass->stop (buf);
|
||||||
|
|
||||||
if (!res) {
|
if (!res) {
|
||||||
buf->state = GST_RINGBUFFER_STATE_PLAYING;
|
buf->state = GST_RINGBUFFER_STATE_STARTED;
|
||||||
} else {
|
} else {
|
||||||
gst_ringbuffer_set_sample (buf, 0);
|
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
|
* @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.
|
* 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.
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
guint64
|
guint64
|
||||||
gst_ringbuffer_played_samples (GstRingBuffer * buf)
|
gst_ringbuffer_samples_done (GstRingBuffer * buf)
|
||||||
{
|
{
|
||||||
gint segplayed;
|
gint segdone;
|
||||||
guint64 raw, samples;
|
guint64 raw, samples;
|
||||||
guint delay;
|
guint delay;
|
||||||
|
|
||||||
g_return_val_if_fail (buf != NULL, 0);
|
g_return_val_if_fail (buf != NULL, 0);
|
||||||
|
|
||||||
/* get the amount of segments we played */
|
/* get the amount of segments we processed */
|
||||||
segplayed = g_atomic_int_get (&buf->segplayed);
|
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);
|
delay = gst_ringbuffer_delay (buf);
|
||||||
|
|
||||||
samples = (segplayed * buf->samples_per_seg);
|
samples = (segdone * buf->samples_per_seg);
|
||||||
raw = samples;
|
raw = samples;
|
||||||
|
|
||||||
if (samples >= delay)
|
if (samples >= delay)
|
||||||
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);
|
samples);
|
||||||
|
|
||||||
return 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
|
/* FIXME, we assume the ringbuffer can restart at a random
|
||||||
* position, round down to the beginning and keep track of
|
* position, round down to the beginning and keep track of
|
||||||
* offset when calculating the played samples. */
|
* offset when calculating the processed samples. */
|
||||||
buf->segplayed = sample / buf->samples_per_seg;
|
buf->segdone = sample / buf->samples_per_seg;
|
||||||
buf->next_sample = sample;
|
buf->next_sample = sample;
|
||||||
|
|
||||||
for (i = 0; i < buf->spec.segtotal; i++) {
|
for (i = 0; i < buf->spec.segtotal; i++) {
|
||||||
gst_ringbuffer_clear (buf, 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
|
static gboolean
|
||||||
wait_segment (GstRingBuffer * buf)
|
wait_segment (GstRingBuffer * buf)
|
||||||
{
|
{
|
||||||
/* buffer must be playing now or we deadlock since nobody is reading */
|
/* buffer must be started now or we deadlock since nobody is reading */
|
||||||
if (g_atomic_int_get (&buf->state) != GST_RINGBUFFER_STATE_PLAYING) {
|
if (g_atomic_int_get (&buf->state) != GST_RINGBUFFER_STATE_STARTED) {
|
||||||
GST_DEBUG ("play!");
|
GST_DEBUG ("start!");
|
||||||
gst_ringbuffer_play (buf);
|
gst_ringbuffer_start (buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* take lock first, then update our waiting flag */
|
/* take lock first, then update our waiting flag */
|
||||||
GST_LOCK (buf);
|
GST_LOCK (buf);
|
||||||
if (g_atomic_int_compare_and_exchange (&buf->waiting, 0, 1)) {
|
if (g_atomic_int_compare_and_exchange (&buf->waiting, 0, 1)) {
|
||||||
GST_DEBUG ("waiting..");
|
GST_DEBUG ("waiting..");
|
||||||
if (g_atomic_int_get (&buf->state) != GST_RINGBUFFER_STATE_PLAYING)
|
if (g_atomic_int_get (&buf->state) != GST_RINGBUFFER_STATE_STARTED)
|
||||||
goto not_playing;
|
goto not_started;
|
||||||
|
|
||||||
GST_RINGBUFFER_WAIT (buf);
|
GST_RINGBUFFER_WAIT (buf);
|
||||||
|
|
||||||
if (g_atomic_int_get (&buf->state) != GST_RINGBUFFER_STATE_PLAYING)
|
if (g_atomic_int_get (&buf->state) != GST_RINGBUFFER_STATE_STARTED)
|
||||||
goto not_playing;
|
goto not_started;
|
||||||
}
|
}
|
||||||
GST_UNLOCK (buf);
|
GST_UNLOCK (buf);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* ERROR */
|
/* ERROR */
|
||||||
not_playing:
|
not_started:
|
||||||
{
|
{
|
||||||
GST_UNLOCK (buf);
|
GST_UNLOCK (buf);
|
||||||
GST_DEBUG ("stopped playing");
|
GST_DEBUG ("stopped processing");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -573,7 +771,7 @@ guint
|
||||||
gst_ringbuffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
|
gst_ringbuffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
|
||||||
guint len)
|
guint len)
|
||||||
{
|
{
|
||||||
gint segplayed;
|
gint segdone;
|
||||||
gint segsize, segtotal, bps, sps;
|
gint segsize, segtotal, bps, sps;
|
||||||
guint8 *dest;
|
guint8 *dest;
|
||||||
|
|
||||||
|
@ -582,7 +780,7 @@ gst_ringbuffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
|
||||||
g_return_val_if_fail (data != NULL, -1);
|
g_return_val_if_fail (data != NULL, -1);
|
||||||
|
|
||||||
if (sample == -1) {
|
if (sample == -1) {
|
||||||
/* play aligned with last sample */
|
/* process aligned with last sample */
|
||||||
sample = buf->next_sample;
|
sample = buf->next_sample;
|
||||||
} else {
|
} else {
|
||||||
if (sample != buf->next_sample) {
|
if (sample != buf->next_sample) {
|
||||||
|
@ -614,17 +812,17 @@ gst_ringbuffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
gint diff;
|
gint diff;
|
||||||
|
|
||||||
/* get the currently playing segment */
|
/* get the currently processed segment */
|
||||||
segplayed = g_atomic_int_get (&buf->segplayed);
|
segdone = g_atomic_int_get (&buf->segdone);
|
||||||
|
|
||||||
/* see how far away it is from the write segment */
|
/* see how far away it is from the write segment */
|
||||||
diff = writeseg - segplayed;
|
diff = writeseg - segdone;
|
||||||
|
|
||||||
GST_DEBUG
|
GST_DEBUG
|
||||||
("pointer at %d, sample %llu, write to %d-%d, len %d, diff %d, segtotal %d, segsize %d",
|
("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) {
|
if (diff < 0) {
|
||||||
/* we need to drop one segment at a time, pretend we wrote a
|
/* we need to drop one segment at a time, pretend we wrote a
|
||||||
* segment. */
|
* 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. */
|
/* else we need to wait for the segment to become writable. */
|
||||||
if (!wait_segment (buf))
|
if (!wait_segment (buf))
|
||||||
goto not_playing;
|
goto not_started;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* we can write now */
|
/* we can write now */
|
||||||
|
@ -660,9 +858,127 @@ gst_ringbuffer_commit (GstRingBuffer * buf, guint64 sample, guchar * data,
|
||||||
return len;
|
return len;
|
||||||
|
|
||||||
/* ERRORS */
|
/* 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;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -677,7 +993,7 @@ not_playing:
|
||||||
* Returns a pointer to memory where the data from segment @segment
|
* Returns a pointer to memory where the data from segment @segment
|
||||||
* can be found. This function is used by subclasses.
|
* 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.
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
|
@ -686,23 +1002,24 @@ gst_ringbuffer_prepare_read (GstRingBuffer * buf, gint * segment,
|
||||||
guint8 ** readptr, gint * len)
|
guint8 ** readptr, gint * len)
|
||||||
{
|
{
|
||||||
guint8 *data;
|
guint8 *data;
|
||||||
gint segplayed;
|
gint segdone;
|
||||||
|
|
||||||
/* buffer must be playing */
|
/* buffer must be started */
|
||||||
if (g_atomic_int_get (&buf->state) != GST_RINGBUFFER_STATE_PLAYING)
|
if (g_atomic_int_get (&buf->state) != GST_RINGBUFFER_STATE_STARTED)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
g_return_val_if_fail (buf != NULL, FALSE);
|
g_return_val_if_fail (buf != NULL, FALSE);
|
||||||
g_return_val_if_fail (buf->data != 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 (readptr != NULL, FALSE);
|
||||||
g_return_val_if_fail (len != NULL, FALSE);
|
g_return_val_if_fail (len != NULL, FALSE);
|
||||||
|
|
||||||
data = GST_BUFFER_DATA (buf->data);
|
data = GST_BUFFER_DATA (buf->data);
|
||||||
|
|
||||||
/* get the position of the play pointer */
|
/* get the position of the pointer */
|
||||||
segplayed = g_atomic_int_get (&buf->segplayed);
|
segdone = g_atomic_int_get (&buf->segdone);
|
||||||
|
|
||||||
*segment = segplayed % buf->spec.segtotal;
|
*segment = segdone % buf->spec.segtotal;
|
||||||
*len = buf->spec.segsize;
|
*len = buf->spec.segsize;
|
||||||
*readptr = data + *segment * *len;
|
*readptr = data + *segment * *len;
|
||||||
|
|
||||||
|
@ -711,7 +1028,7 @@ gst_ringbuffer_prepare_read (GstRingBuffer * buf, gint * segment,
|
||||||
buf->callback (buf, *readptr, *len, buf->cb_data);
|
buf->callback (buf, *readptr, *len, buf->cb_data);
|
||||||
|
|
||||||
GST_DEBUG ("prepare read from segment %d (real %d) @%p",
|
GST_DEBUG ("prepare read from segment %d (real %d) @%p",
|
||||||
*segment, segplayed, *readptr);
|
*segment, segdone, *readptr);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@ -722,7 +1039,7 @@ gst_ringbuffer_prepare_read (GstRingBuffer * buf, gint * segment,
|
||||||
* @advance: the number of segments written
|
* @advance: the number of segments written
|
||||||
*
|
*
|
||||||
* Subclasses should call this function to notify the fact that
|
* 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.
|
* MT safe.
|
||||||
*/
|
*/
|
||||||
|
@ -732,7 +1049,7 @@ gst_ringbuffer_advance (GstRingBuffer * buf, guint advance)
|
||||||
g_return_if_fail (buf != NULL);
|
g_return_if_fail (buf != NULL);
|
||||||
|
|
||||||
/* update counter */
|
/* 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,
|
/* the lock is already taken when the waiting flag is set,
|
||||||
* we grab the lock as well to make sure the waiter is actually
|
* 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 {
|
typedef enum {
|
||||||
GST_RINGBUFFER_STATE_STOPPED,
|
GST_RINGBUFFER_STATE_STOPPED,
|
||||||
GST_RINGBUFFER_STATE_PAUSED,
|
GST_RINGBUFFER_STATE_PAUSED,
|
||||||
GST_RINGBUFFER_STATE_PLAYING,
|
GST_RINGBUFFER_STATE_STARTED,
|
||||||
} GstRingBufferState;
|
} GstRingBufferState;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -160,11 +160,11 @@ struct _GstRingBuffer {
|
||||||
|
|
||||||
/*< public >*/ /* ATOMIC */
|
/*< public >*/ /* ATOMIC */
|
||||||
gint state; /* state of the buffer */
|
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 */
|
gint waiting; /* when waiting for a segment to be freed */
|
||||||
|
|
||||||
/*< private >*/
|
/*< private >*/
|
||||||
guint64 next_sample; /* the next sample we need to write */
|
guint64 next_sample; /* the next sample we need to process */
|
||||||
GstRingBufferCallback callback;
|
GstRingBufferCallback callback;
|
||||||
gpointer cb_data;
|
gpointer cb_data;
|
||||||
};
|
};
|
||||||
|
@ -179,7 +179,7 @@ struct _GstRingBufferClass {
|
||||||
gboolean (*release) (GstRingBuffer *buf);
|
gboolean (*release) (GstRingBuffer *buf);
|
||||||
|
|
||||||
/* playback control */
|
/* playback control */
|
||||||
gboolean (*play) (GstRingBuffer *buf);
|
gboolean (*start) (GstRingBuffer *buf);
|
||||||
gboolean (*pause) (GstRingBuffer *buf);
|
gboolean (*pause) (GstRingBuffer *buf);
|
||||||
gboolean (*resume) (GstRingBuffer *buf);
|
gboolean (*resume) (GstRingBuffer *buf);
|
||||||
gboolean (*stop) (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,
|
void gst_ringbuffer_set_callback (GstRingBuffer *buf, GstRingBufferCallback cb,
|
||||||
gpointer user_data);
|
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 */
|
/* allocate resources */
|
||||||
gboolean gst_ringbuffer_acquire (GstRingBuffer *buf, GstRingBufferSpec *spec);
|
gboolean gst_ringbuffer_acquire (GstRingBuffer *buf, GstRingBufferSpec *spec);
|
||||||
gboolean gst_ringbuffer_release (GstRingBuffer *buf);
|
gboolean gst_ringbuffer_release (GstRingBuffer *buf);
|
||||||
|
@ -201,21 +205,25 @@ gboolean gst_ringbuffer_release (GstRingBuffer *buf);
|
||||||
gboolean gst_ringbuffer_is_acquired (GstRingBuffer *buf);
|
gboolean gst_ringbuffer_is_acquired (GstRingBuffer *buf);
|
||||||
|
|
||||||
/* playback/pause */
|
/* playback/pause */
|
||||||
gboolean gst_ringbuffer_play (GstRingBuffer *buf);
|
gboolean gst_ringbuffer_start (GstRingBuffer *buf);
|
||||||
gboolean gst_ringbuffer_pause (GstRingBuffer *buf);
|
gboolean gst_ringbuffer_pause (GstRingBuffer *buf);
|
||||||
gboolean gst_ringbuffer_stop (GstRingBuffer *buf);
|
gboolean gst_ringbuffer_stop (GstRingBuffer *buf);
|
||||||
|
|
||||||
/* get status */
|
/* get status */
|
||||||
guint gst_ringbuffer_delay (GstRingBuffer *buf);
|
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);
|
void gst_ringbuffer_set_sample (GstRingBuffer *buf, guint64 sample);
|
||||||
|
|
||||||
/* commit samples */
|
/* commit samples */
|
||||||
guint gst_ringbuffer_commit (GstRingBuffer *buf, guint64 sample,
|
guint gst_ringbuffer_commit (GstRingBuffer *buf, guint64 sample,
|
||||||
guchar *data, guint len);
|
guchar *data, guint len);
|
||||||
|
/* read samples */
|
||||||
|
guint gst_ringbuffer_read (GstRingBuffer *buf, guint64 sample,
|
||||||
|
guchar *data, guint len);
|
||||||
|
|
||||||
/* mostly protected */
|
/* 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);
|
gboolean gst_ringbuffer_prepare_read (GstRingBuffer *buf, gint *segment, guint8 **readptr, gint *len);
|
||||||
void gst_ringbuffer_clear (GstRingBuffer *buf, gint segment);
|
void gst_ringbuffer_clear (GstRingBuffer *buf, gint segment);
|
||||||
void gst_ringbuffer_advance (GstRingBuffer *buf, guint advance);
|
void gst_ringbuffer_advance (GstRingBuffer *buf, guint advance);
|
||||||
|
|
Loading…
Reference in a new issue