+++ /dev/null
-/* GStreamer RTSP extension
- * Copyright (C) 2007 Wim Taymans <wim.taymans@gmail.com>
- *
- * gstrtspextension.c: RTSP extension mechanism
- *
- * 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.
- */
-
-/**
- * SECTION:gstrtspextension
- * @short_description: Interface for extending RTSP protocols
- *
- * <refsect2>
- * <para>
- * This interface is implemented e.g. by the Windows Media Streaming RTSP
- * exentension (rtspwms) and the RealMedia RTSP extension (rtspreal).
- * </para>
- * </refsect2>
- *
- * Last reviewed on 2007-07-25 (0.10.14)
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "gstrtsp-marshal.h"
-#include "gstrtsp-enumtypes.h"
-#include "gstrtspextension.h"
-
-static void gst_rtsp_extension_iface_init (GstRTSPExtension * iface);
-
-enum
-{
- SIGNAL_SEND,
- LAST_SIGNAL
-};
-
-static guint gst_rtsp_extension_signals[LAST_SIGNAL] = { 0 };
-
-GType
-gst_rtsp_extension_get_type (void)
-{
- static GType gst_rtsp_extension_type = 0;
-
- if (!gst_rtsp_extension_type) {
- static const GTypeInfo gst_rtsp_extension_info = {
- sizeof (GstRTSPExtensionInterface),
- (GBaseInitFunc) gst_rtsp_extension_iface_init,
- NULL,
- NULL,
- NULL,
- NULL,
- 0,
- 0,
- NULL,
- };
-
- gst_rtsp_extension_type = g_type_register_static (G_TYPE_INTERFACE,
- "GstRTSPExtension", &gst_rtsp_extension_info, 0);
- }
- return gst_rtsp_extension_type;
-}
-
-static void
-gst_rtsp_extension_iface_init (GstRTSPExtension * iface)
-{
- static gboolean initialized = FALSE;
-
- if (!initialized) {
- gst_rtsp_extension_signals[SIGNAL_SEND] =
- g_signal_new ("send", G_TYPE_FROM_CLASS (iface),
- G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPExtensionInterface,
- send), NULL, NULL, gst_rtsp_marshal_ENUM__POINTER_POINTER,
- GST_TYPE_RTSP_RESULT, 2, G_TYPE_POINTER, G_TYPE_POINTER);
- initialized = TRUE;
- }
-}
-
-gboolean
-gst_rtsp_extension_detect_server (GstRTSPExtension * ext, GstRTSPMessage * resp)
-{
- GstRTSPExtensionInterface *iface;
- gboolean res = TRUE;
-
- iface = GST_RTSP_EXTENSION_GET_INTERFACE (ext);
- if (iface->detect_server)
- res = iface->detect_server (ext, resp);
-
- return res;
-}
-
-GstRTSPResult
-gst_rtsp_extension_before_send (GstRTSPExtension * ext, GstRTSPMessage * req)
-{
- GstRTSPExtensionInterface *iface;
- GstRTSPResult res = GST_RTSP_OK;
-
- iface = GST_RTSP_EXTENSION_GET_INTERFACE (ext);
- if (iface->before_send)
- res = iface->before_send (ext, req);
-
- return res;
-}
-
-GstRTSPResult
-gst_rtsp_extension_after_send (GstRTSPExtension * ext, GstRTSPMessage * req,
- GstRTSPMessage * resp)
-{
- GstRTSPExtensionInterface *iface;
- GstRTSPResult res = GST_RTSP_OK;
-
- iface = GST_RTSP_EXTENSION_GET_INTERFACE (ext);
- if (iface->after_send)
- res = iface->after_send (ext, req, resp);
-
- return res;
-}
-
-GstRTSPResult
-gst_rtsp_extension_parse_sdp (GstRTSPExtension * ext, GstSDPMessage * sdp,
- GstStructure * s)
-{
- GstRTSPExtensionInterface *iface;
- GstRTSPResult res = GST_RTSP_OK;
-
- iface = GST_RTSP_EXTENSION_GET_INTERFACE (ext);
- if (iface->parse_sdp)
- res = iface->parse_sdp (ext, sdp, s);
-
- return res;
-}
-
-GstRTSPResult
-gst_rtsp_extension_setup_media (GstRTSPExtension * ext, GstSDPMedia * media)
-{
- GstRTSPExtensionInterface *iface;
- GstRTSPResult res = GST_RTSP_OK;
-
- iface = GST_RTSP_EXTENSION_GET_INTERFACE (ext);
- if (iface->setup_media)
- res = iface->setup_media (ext, media);
-
- return res;
-}
-
-gboolean
-gst_rtsp_extension_configure_stream (GstRTSPExtension * ext, GstCaps * caps)
-{
- GstRTSPExtensionInterface *iface;
- gboolean res = TRUE;
-
- iface = GST_RTSP_EXTENSION_GET_INTERFACE (ext);
- if (iface->configure_stream)
- res = iface->configure_stream (ext, caps);
-
- return res;
-}
-
-GstRTSPResult
-gst_rtsp_extension_get_transports (GstRTSPExtension * ext,
- GstRTSPLowerTrans protocols, gchar ** transport)
-{
- GstRTSPExtensionInterface *iface;
- GstRTSPResult res = GST_RTSP_OK;
-
- iface = GST_RTSP_EXTENSION_GET_INTERFACE (ext);
- if (iface->get_transports)
- res = iface->get_transports (ext, protocols, transport);
-
- return res;
-}
-
-GstRTSPResult
-gst_rtsp_extension_stream_select (GstRTSPExtension * ext, GstRTSPUrl * url)
-{
- GstRTSPExtensionInterface *iface;
- GstRTSPResult res = GST_RTSP_OK;
-
- iface = GST_RTSP_EXTENSION_GET_INTERFACE (ext);
- if (iface->stream_select)
- res = iface->stream_select (ext, url);
-
- return res;
-}
-
-GstRTSPResult
-gst_rtsp_extension_receive_request (GstRTSPExtension * ext,
- GstRTSPMessage * msg)
-{
- GstRTSPExtensionInterface *iface;
- GstRTSPResult res = GST_RTSP_ENOTIMPL;
-
- iface = GST_RTSP_EXTENSION_GET_INTERFACE (ext);
- if (iface->receive_request)
- res = iface->receive_request (ext, msg);
-
- return res;
-}
-
-GstRTSPResult
-gst_rtsp_extension_send (GstRTSPExtension * ext, GstRTSPMessage * req,
- GstRTSPMessage * resp)
-{
- GstRTSPResult res = GST_RTSP_OK;
-
- g_signal_emit (ext, gst_rtsp_extension_signals[SIGNAL_SEND], 0,
- req, resp, &res);
-
- return res;
-}
+++ /dev/null
-/* GStreamer Audio Process
- * Copyright (C) 2010 Wim Taymans <wim.taymans@gmail.com>
- *
- * gstaudioprocess.h: Audio processing extension
- *
- * 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.
- */
-
-#ifndef __GST_AUDIO_PROCESS_H__
-#define __GST_AUDIO_PROCESS_H__
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_AUDIO_PROCESS \
- (gst_audio_process_get_type ())
-#define GST_AUDIO_PROCESS(obj) \
- (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_AUDIO_PROCESS, GstAudioProcess))
-#define GST_IS_AUDIO_PROCESS(obj) \
- (GST_IMPLEMENTS_INTERFACE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_AUDIO_PROCESS))
-#define GST_AUDIO_PROCESS_GET_INTERFACE(inst) \
- (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_AUDIO_PROCESS, GstAudioProcessInterface))
-
-typedef struct _GstAudioProcess GstAudioProcess;
-typedef struct _GstAudioProcessInterface GstAudioProcessInterface;
-
-struct _GstAudioProcessInterface {
- GTypeInterface parent;
-
- /* vfunctions */
- gint (*activate) (GstAudioProcess *process, gboolean active);
- gint (*process) (GstAudioProcess *process, gpointer src_in, gpointer sink_in,
- gpointer src_out, guint length);
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-GType gst_audio_process_get_type (void);
-
-/* invoke vfunction on interface */
-gint gst_audio_process_process (GstAudioProcess *ext, gpointer src_in, gpointer sink_in,
- gpointer src_out, guint length);
-
-G_END_DECLS
-
-#endif /* __GST_AUDIO_PROCESS_H__ */
+++ /dev/null
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2005 Wim Taymans <wim@fluendo.com>
- *
- * gstaudioringbuffer.c: simple audio ringbuffer 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 "gstaudioringbuffer.h"
-
-GST_DEBUG_CATEGORY_STATIC (gst_audio_ring_buffer_debug);
-#define GST_CAT_DEFAULT gst_audio_ring_buffer_debug
-
-static void gst_audio_ring_buffer_class_init (GstAudioRingBufferClass * klass);
-static void gst_audio_ring_buffer_init (GstAudioRingBuffer * ringbuffer,
- GstAudioRingBufferClass * klass);
-static void gst_audio_ring_buffer_dispose (GObject * object);
-static void gst_audio_ring_buffer_finalize (GObject * object);
-
-static GstRingBufferClass *ring_parent_class = NULL;
-
-static gboolean gst_audio_ring_buffer_start (GstRingBuffer * buf);
-static gboolean gst_audio_ring_buffer_pause (GstRingBuffer * buf);
-static gboolean gst_audio_ring_buffer_stop (GstRingBuffer * buf);
-static gboolean gst_audio_ring_buffer_activate (GstRingBuffer * buf,
- gboolean active);
-
-/* ringbuffer abstract base class */
-GType
-gst_audio_ring_buffer_get_type (void)
-{
- static GType ringbuffer_type = 0;
-
- if (!ringbuffer_type) {
- static const GTypeInfo ringbuffer_info = {
- sizeof (GstAudioRingBufferClass),
- NULL,
- NULL,
- (GClassInitFunc) gst_audio_ring_buffer_class_init,
- NULL,
- NULL,
- sizeof (GstAudioRingBuffer),
- 0,
- (GInstanceInitFunc) gst_audio_ring_buffer_init,
- NULL
- };
-
- ringbuffer_type =
- g_type_register_static (GST_TYPE_RING_BUFFER, "GstAudioSinkRingBuffer",
- &ringbuffer_info, G_TYPE_FLAG_ABSTRACT);
-
- GST_DEBUG_CATEGORY_INIT (gst_audio_ring_buffer_debug, "audioringbuffer", 0,
- "audio ringbuffer");
- }
- return ringbuffer_type;
-}
-
-static void
-gst_audio_ring_buffer_class_init (GstAudioRingBufferClass * klass)
-{
- GObjectClass *gobject_class;
- GstRingBufferClass *gstringbuffer_class;
-
- gobject_class = (GObjectClass *) klass;
- gstringbuffer_class = (GstRingBufferClass *) klass;
-
- ring_parent_class = g_type_class_peek_parent (klass);
-
- gobject_class->dispose = gst_audio_ring_buffer_dispose;
- gobject_class->finalize = gst_audio_ring_buffer_finalize;
-
- gstringbuffer_class->start = GST_DEBUG_FUNCPTR (gst_audio_ring_buffer_start);
- gstringbuffer_class->pause = GST_DEBUG_FUNCPTR (gst_audio_ring_buffer_pause);
- gstringbuffer_class->resume = GST_DEBUG_FUNCPTR (gst_audio_ring_buffer_start);
- gstringbuffer_class->stop = GST_DEBUG_FUNCPTR (gst_audio_ring_buffer_stop);
-
- gstringbuffer_class->activate =
- GST_DEBUG_FUNCPTR (gst_audio_ring_buffer_activate);
-}
-
-static void
-gst_audio_ring_buffer_init (GstAudioRingBuffer * ringbuffer,
- GstAudioRingBufferClass * g_class)
-{
-}
-
-static void
-gst_audio_ring_buffer_dispose (GObject * object)
-{
- G_OBJECT_CLASS (ring_parent_class)->dispose (object);
-}
-
-static void
-gst_audio_ring_buffer_finalize (GObject * object)
-{
- G_OBJECT_CLASS (ring_parent_class)->finalize (object);
-}
-
-static gboolean
-gst_audio_ring_buffer_activate (GstRingBuffer * buf, gboolean active)
-{
- GstAudioRingBuffer *abuf;
- gboolean res;
-
- abuf = GST_AUDIO_RING_BUFFER_CAST (buf);
-
- GST_OBJECT_UNLOCK (buf);
- res = gst_ring_buffer_thread_activate (abuf->thread, active);
- GST_OBJECT_LOCK (buf);
-
- return res;
-}
-
-gboolean
-gst_audio_ring_buffer_set_thread (GstAudioRingBuffer * buf,
- GstRingBufferThread * thread)
-{
- GstRingBufferThread *old;
-
- g_return_val_if_fail (GST_IS_AUDIO_RING_BUFFER (buf), FALSE);
-
- old = buf->thread;
- if (thread)
- gst_object_ref (thread);
- buf->thread = thread;
- if (old)
- gst_object_unref (old);
-
- if (thread)
- gst_ring_buffer_thread_set_ringbuffer (thread, buf);
-
- return TRUE;
-}
-
-gboolean
-gst_audio_ring_buffer_link (GstAudioRingBuffer * buf1,
- GstAudioRingBuffer * buf2)
-{
- buf1->link = buf2;
- buf2->link = buf1;
-
- return TRUE;
-}
-
-static gboolean
-gst_audio_ring_buffer_start (GstRingBuffer * buf)
-{
- GstAudioRingBuffer *abuf;
-
- abuf = GST_AUDIO_RING_BUFFER_CAST (buf);
-
- GST_DEBUG_OBJECT (buf, "start, sending signal");
-
- return gst_ring_buffer_thread_start (abuf->thread);
-}
-
-static gboolean
-gst_audio_ring_buffer_pause (GstRingBuffer * buf)
-{
- GstAudioRingBuffer *abuf;
- GstAudioRingBufferClass *cbuf;
-
- abuf = GST_AUDIO_RING_BUFFER_CAST (buf);
- cbuf = GST_AUDIO_RING_BUFFER_GET_CLASS (abuf);
-
- /* unblock any pending writes to the audio device */
- if (cbuf->reset) {
- GST_DEBUG_OBJECT (abuf, "reset...");
- cbuf->reset (abuf);
- GST_DEBUG_OBJECT (abuf, "reset done");
- }
- return TRUE;
-}
-
-static gboolean
-gst_audio_ring_buffer_stop (GstRingBuffer * buf)
-{
- GstAudioRingBuffer *abuf;
- GstAudioRingBufferClass *cbuf;
-
- abuf = GST_AUDIO_RING_BUFFER_CAST (buf);
- cbuf = GST_AUDIO_RING_BUFFER_GET_CLASS (abuf);
-
- /* unblock any pending writes to the audio device */
- if (cbuf->reset) {
- GST_DEBUG_OBJECT (abuf, "reset...");
- cbuf->reset (abuf);
- GST_DEBUG_OBJECT (abuf, "reset done");
- }
-#if 0
- if (abuf->running) {
- GST_DEBUG_OBJECT (sink, "stop, waiting...");
- GST_AUDIO_RING_BUFFER_WAIT (buf);
- GST_DEBUG_OBJECT (sink, "stopped");
- }
-#endif
-
- return TRUE;
-}
+++ /dev/null
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2005 Wim Taymans <wim@fluendo.com>
- *
- * gstaudioringbuffer.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.
- */
-
-#ifndef __GST_AUDIO_RING_BUFFER_H__
-#define __GST_AUDIO_RING_BUFFER_H__
-
-#include <gst/gst.h>
-#include <gst/audio/gstringbuffer.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_AUDIO_RING_BUFFER (gst_audio_ring_buffer_get_type())
-#define GST_AUDIO_RING_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AUDIO_RING_BUFFER,GstAudioRingBuffer))
-#define GST_AUDIO_RING_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AUDIO_RING_BUFFER,GstAudioRingBufferClass))
-#define GST_AUDIO_RING_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_AUDIO_RING_BUFFER,GstAudioRingBufferClass))
-#define GST_IS_AUDIO_RING_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AUDIO_RING_BUFFER))
-#define GST_IS_AUDIO_RING_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AUDIO_RING_BUFFER))
-#define GST_AUDIO_RING_BUFFER_CAST(obj) ((GstAudioRingBuffer *)obj)
-
-typedef struct _GstAudioRingBuffer GstAudioRingBuffer;
-typedef struct _GstAudioRingBufferClass GstAudioRingBufferClass;
-
-#include <gst/audio/gstringbufferthread.h>
-
-typedef enum {
- GST_AUDIO_RING_BUFFER_MODE_UNKNOWN,
- GST_AUDIO_RING_BUFFER_MODE_PLAYBACK,
- GST_AUDIO_RING_BUFFER_MODE_CAPTURE
-} GstAudioRingBufferMode;
-/**
- * GstAudioRingBuffer:
- *
- * Opaque #GstAudioRingBuffer.
- */
-struct _GstAudioRingBuffer {
- GstRingBuffer element;
-
- /*< protected >*/
- GstAudioRingBufferMode mode;
- GstRingBufferThread *thread;
-
- GstAudioRingBuffer *link;
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-/**
- * GstAudioRingBufferClass:
- * @parent_class: the parent class structure.
- * @process: Write/Read data to/from the device.
- * @reset: Returns as quickly as possible from a write/read and flush any pending
- * samples from the device.
- *
- * #GstAudioRingBuffer class. Override the vmethods to implement functionality.
- */
-struct _GstAudioRingBufferClass {
- GstRingBufferClass parent_class;
-
- /* vtable */
-
- /* write/read samples to the device */
- gint (*process) (GstAudioRingBuffer *buf, gpointer data, guint length);
- /* reset the audio device, unblock from a read/write */
- void (*reset) (GstAudioRingBuffer *buf);
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-GType gst_audio_ring_buffer_get_type(void);
-
-gboolean gst_audio_ring_buffer_link (GstAudioRingBuffer *buf1, GstAudioRingBuffer *buf2);
-
-gboolean gst_audio_ring_buffer_set_thread (GstAudioRingBuffer *buf, GstRingBufferThread *thread);
-
-G_END_DECLS
-
-#endif /* __GST_AUDIO_RING_BUFFER_H__ */
+++ /dev/null
-/* 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.
- */
-
-/**
- * SECTION:gstbaseaudiosrc
- * @short_description: Base class for audio sources
- * @see_also: #GstAudioSrc, #GstRingBuffer.
- *
- * This is the base class for audio sources. Subclasses need to implement the
- * ::create_ringbuffer vmethod. This base class will then take care of
- * reading samples from the ringbuffer, synchronisation and flushing.
- *
- * Last reviewed on 2006-09-27 (0.10.12)
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <string.h>
-
-#include "gstbaseaudiosrc.h"
-
-#include "gst/gst-i18n-plugin.h"
-
-GST_DEBUG_CATEGORY_STATIC (gst_base_audio_src_debug);
-#define GST_CAT_DEFAULT gst_base_audio_src_debug
-
-GType
-gst_base_audio_src_slave_method_get_type (void)
-{
- static GType slave_method_type = 0;
- static const GEnumValue slave_method[] = {
- {GST_BASE_AUDIO_SRC_SLAVE_RESAMPLE, "Resampling slaving", "resample"},
- {GST_BASE_AUDIO_SRC_SLAVE_RETIMESTAMP, "Re-timestamp", "re-timestamp"},
- {GST_BASE_AUDIO_SRC_SLAVE_SKEW, "Skew", "skew"},
- {GST_BASE_AUDIO_SRC_SLAVE_NONE, "No slaving", "none"},
- {0, NULL, NULL},
- };
-
- if (!slave_method_type) {
- slave_method_type =
- g_enum_register_static ("GstBaseAudioSrcSlaveMethod", slave_method);
- }
- return slave_method_type;
-}
-
-#define GST_BASE_AUDIO_SRC_GET_PRIVATE(obj) \
- (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_AUDIO_SRC, GstBaseAudioSrcPrivate))
-
-struct _GstBaseAudioSrcPrivate
-{
- gboolean provide_clock;
-
- /* the clock slaving algorithm in use */
- GstBaseAudioSrcSlaveMethod slave_method;
-};
-
-/* BaseAudioSrc signals and args */
-enum
-{
- /* FILL ME */
- LAST_SIGNAL
-};
-
-#define DEFAULT_BUFFER_TIME ((200 * GST_MSECOND) / GST_USECOND)
-#define DEFAULT_LATENCY_TIME ((10 * GST_MSECOND) / GST_USECOND)
-#define DEFAULT_ACTUAL_BUFFER_TIME -1
-#define DEFAULT_ACTUAL_LATENCY_TIME -1
-#define DEFAULT_PROVIDE_CLOCK TRUE
-#define DEFAULT_SLAVE_METHOD GST_BASE_AUDIO_SRC_SLAVE_SKEW
-
-enum
-{
- PROP_0,
- PROP_BUFFER_TIME,
- PROP_LATENCY_TIME,
- PROP_ACTUAL_BUFFER_TIME,
- PROP_ACTUAL_LATENCY_TIME,
- PROP_PROVIDE_CLOCK,
- PROP_SLAVE_METHOD,
- PROP_LAST
-};
-
-static void
-_do_init (GType type)
-{
- GST_DEBUG_CATEGORY_INIT (gst_base_audio_src_debug, "baseaudiosrc", 0,
- "baseaudiosrc element");
-
-#ifdef ENABLE_NLS
- GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
- LOCALEDIR);
- bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
- bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
-#endif /* ENABLE_NLS */
-}
-
-GST_BOILERPLATE_FULL (GstBaseAudioSrc, gst_base_audio_src, GstPushSrc,
- GST_TYPE_PUSH_SRC, _do_init);
-
-static void gst_base_audio_src_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_base_audio_src_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-static void gst_base_audio_src_dispose (GObject * object);
-
-static GstStateChangeReturn gst_base_audio_src_change_state (GstElement *
- element, GstStateChange transition);
-
-static GstClock *gst_base_audio_src_provide_clock (GstElement * elem);
-static GstClockTime gst_base_audio_src_get_time (GstClock * clock,
- GstBaseAudioSrc * src);
-
-static GstFlowReturn gst_base_audio_src_create (GstBaseSrc * bsrc,
- guint64 offset, guint length, GstBuffer ** buf);
-static gboolean gst_base_audio_src_check_get_range (GstBaseSrc * bsrc);
-
-static gboolean gst_base_audio_src_event (GstBaseSrc * bsrc, GstEvent * event);
-static void gst_base_audio_src_get_times (GstBaseSrc * bsrc,
- GstBuffer * buffer, GstClockTime * start, GstClockTime * end);
-static gboolean gst_base_audio_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps);
-static gboolean gst_base_audio_src_query (GstBaseSrc * bsrc, GstQuery * query);
-static void gst_base_audio_src_fixate (GstBaseSrc * bsrc, GstCaps * caps);
-
-/* static guint gst_base_audio_src_signals[LAST_SIGNAL] = { 0 }; */
-
-static void
-gst_base_audio_src_base_init (gpointer g_class)
-{
-}
-
-static void
-gst_base_audio_src_class_init (GstBaseAudioSrcClass * klass)
-{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
- GstBaseSrcClass *gstbasesrc_class;
-
- gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
- gstbasesrc_class = (GstBaseSrcClass *) klass;
-
- g_type_class_add_private (klass, sizeof (GstBaseAudioSrcPrivate));
-
- gobject_class->set_property =
- GST_DEBUG_FUNCPTR (gst_base_audio_src_set_property);
- gobject_class->get_property =
- GST_DEBUG_FUNCPTR (gst_base_audio_src_get_property);
- gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_base_audio_src_dispose);
-
- g_object_class_install_property (gobject_class, PROP_BUFFER_TIME,
- g_param_spec_int64 ("buffer-time", "Buffer Time",
- "Size of audio buffer in microseconds", 1,
- G_MAXINT64, DEFAULT_BUFFER_TIME,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (gobject_class, PROP_LATENCY_TIME,
- g_param_spec_int64 ("latency-time", "Latency Time",
- "Audio latency in microseconds", 1,
- G_MAXINT64, DEFAULT_LATENCY_TIME,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstBaseAudioSrc:actual-buffer-time:
- *
- * Actual configured size of audio buffer in microseconds.
- *
- * Since: 0.10.20
- **/
- g_object_class_install_property (gobject_class, PROP_ACTUAL_BUFFER_TIME,
- g_param_spec_int64 ("actual-buffer-time", "Actual Buffer Time",
- "Actual configured size of audio buffer in microseconds",
- DEFAULT_ACTUAL_BUFFER_TIME, G_MAXINT64, DEFAULT_ACTUAL_BUFFER_TIME,
- G_PARAM_READABLE));
-
- /**
- * GstBaseAudioSrc:actual-latency-time:
- *
- * Actual configured audio latency in microseconds.
- *
- * Since: 0.10.20
- **/
- g_object_class_install_property (gobject_class, PROP_ACTUAL_LATENCY_TIME,
- g_param_spec_int64 ("actual-latency-time", "Actual Latency Time",
- "Actual configured audio latency in microseconds",
- DEFAULT_ACTUAL_LATENCY_TIME, G_MAXINT64, DEFAULT_ACTUAL_LATENCY_TIME,
- G_PARAM_READABLE));
-
- g_object_class_install_property (gobject_class, PROP_PROVIDE_CLOCK,
- g_param_spec_boolean ("provide-clock", "Provide Clock",
- "Provide a clock to be used as the global pipeline clock",
- DEFAULT_PROVIDE_CLOCK, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (gobject_class, PROP_SLAVE_METHOD,
- g_param_spec_enum ("slave-method", "Slave Method",
- "Algorithm to use to match the rate of the masterclock",
- GST_TYPE_BASE_AUDIO_SRC_SLAVE_METHOD, DEFAULT_SLAVE_METHOD,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- gstelement_class->change_state =
- GST_DEBUG_FUNCPTR (gst_base_audio_src_change_state);
- gstelement_class->provide_clock =
- GST_DEBUG_FUNCPTR (gst_base_audio_src_provide_clock);
-
- gstbasesrc_class->set_caps = GST_DEBUG_FUNCPTR (gst_base_audio_src_setcaps);
- gstbasesrc_class->event = GST_DEBUG_FUNCPTR (gst_base_audio_src_event);
- gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_base_audio_src_query);
- gstbasesrc_class->get_times =
- GST_DEBUG_FUNCPTR (gst_base_audio_src_get_times);
- gstbasesrc_class->create = GST_DEBUG_FUNCPTR (gst_base_audio_src_create);
- gstbasesrc_class->check_get_range =
- GST_DEBUG_FUNCPTR (gst_base_audio_src_check_get_range);
- gstbasesrc_class->fixate = GST_DEBUG_FUNCPTR (gst_base_audio_src_fixate);
-
- /* ref class from a thread-safe context to work around missing bit of
- * thread-safety in GObject */
- g_type_class_ref (GST_TYPE_AUDIO_CLOCK);
- g_type_class_ref (GST_TYPE_RING_BUFFER);
-}
-
-static void
-gst_base_audio_src_init (GstBaseAudioSrc * baseaudiosrc,
- GstBaseAudioSrcClass * g_class)
-{
- baseaudiosrc->priv = GST_BASE_AUDIO_SRC_GET_PRIVATE (baseaudiosrc);
-
- baseaudiosrc->buffer_time = DEFAULT_BUFFER_TIME;
- baseaudiosrc->latency_time = DEFAULT_LATENCY_TIME;
- baseaudiosrc->priv->provide_clock = DEFAULT_PROVIDE_CLOCK;
- baseaudiosrc->priv->slave_method = DEFAULT_SLAVE_METHOD;
- /* reset blocksize we use latency time to calculate a more useful
- * value based on negotiated format. */
- GST_BASE_SRC (baseaudiosrc)->blocksize = 0;
-
- baseaudiosrc->clock = gst_audio_clock_new ("GstAudioSrcClock",
- (GstAudioClockGetTimeFunc) gst_base_audio_src_get_time, baseaudiosrc);
-
- /* we are always a live source */
- gst_base_src_set_live (GST_BASE_SRC (baseaudiosrc), TRUE);
- /* we operate in time */
- gst_base_src_set_format (GST_BASE_SRC (baseaudiosrc), GST_FORMAT_TIME);
-}
-
-static void
-gst_base_audio_src_dispose (GObject * object)
-{
- GstBaseAudioSrc *src;
-
- src = GST_BASE_AUDIO_SRC (object);
-
- GST_OBJECT_LOCK (src);
- if (src->clock)
- gst_object_unref (src->clock);
- src->clock = NULL;
-
- if (src->ringbuffer) {
- gst_object_unparent (GST_OBJECT_CAST (src->ringbuffer));
- src->ringbuffer = NULL;
- }
- GST_OBJECT_UNLOCK (src);
-
- G_OBJECT_CLASS (parent_class)->dispose (object);
-}
-
-static GstClock *
-gst_base_audio_src_provide_clock (GstElement * elem)
-{
- GstBaseAudioSrc *src;
- GstClock *clock;
-
- src = GST_BASE_AUDIO_SRC (elem);
-
- /* we have no ringbuffer (must be NULL state) */
- if (src->ringbuffer == NULL)
- goto wrong_state;
-
- if (!gst_ring_buffer_is_acquired (src->ringbuffer))
- goto wrong_state;
-
- GST_OBJECT_LOCK (src);
- if (!src->priv->provide_clock)
- goto clock_disabled;
-
- clock = GST_CLOCK_CAST (gst_object_ref (src->clock));
- GST_OBJECT_UNLOCK (src);
-
- return clock;
-
- /* ERRORS */
-wrong_state:
- {
- GST_DEBUG_OBJECT (src, "ringbuffer not acquired");
- return NULL;
- }
-clock_disabled:
- {
- GST_DEBUG_OBJECT (src, "clock provide disabled");
- GST_OBJECT_UNLOCK (src);
- return NULL;
- }
-}
-
-static GstClockTime
-gst_base_audio_src_get_time (GstClock * clock, GstBaseAudioSrc * src)
-{
- guint64 raw, samples;
- guint delay;
- GstClockTime result;
-
- if (G_UNLIKELY (src->ringbuffer == NULL || src->ringbuffer->spec.rate == 0))
- return GST_CLOCK_TIME_NONE;
-
- raw = samples = gst_ring_buffer_samples_done (src->ringbuffer);
-
- /* the number of samples not yet processed, this is still queued in the
- * device (not yet read for capture). */
- delay = gst_ring_buffer_delay (src->ringbuffer);
-
- samples += delay;
-
- result = gst_util_uint64_scale_int (samples, GST_SECOND,
- src->ringbuffer->spec.rate);
-
- GST_DEBUG_OBJECT (src,
- "processed samples: raw %llu, delay %u, real %llu, time %"
- GST_TIME_FORMAT, raw, delay, samples, GST_TIME_ARGS (result));
-
- return result;
-}
-
-static gboolean
-gst_base_audio_src_check_get_range (GstBaseSrc * bsrc)
-{
- /* we allow limited pull base operation of which the details
- * will eventually exposed in an as of yet non-existing query.
- * Basically pulling can be done on any number of bytes as long
- * as the offset is -1 or sequentially increasing. */
- return TRUE;
-}
-
-/**
- * gst_base_audio_src_set_provide_clock:
- * @src: a #GstBaseAudioSrc
- * @provide: new state
- *
- * Controls whether @src will provide a clock or not. If @provide is %TRUE,
- * gst_element_provide_clock() will return a clock that reflects the datarate
- * of @src. If @provide is %FALSE, gst_element_provide_clock() will return NULL.
- *
- * Since: 0.10.16
- */
-void
-gst_base_audio_src_set_provide_clock (GstBaseAudioSrc * src, gboolean provide)
-{
- g_return_if_fail (GST_IS_BASE_AUDIO_SRC (src));
-
- GST_OBJECT_LOCK (src);
- src->priv->provide_clock = provide;
- GST_OBJECT_UNLOCK (src);
-}
-
-/**
- * gst_base_audio_src_get_provide_clock:
- * @src: a #GstBaseAudioSrc
- *
- * Queries whether @src will provide a clock or not. See also
- * gst_base_audio_src_set_provide_clock.
- *
- * Returns: %TRUE if @src will provide a clock.
- *
- * Since: 0.10.16
- */
-gboolean
-gst_base_audio_src_get_provide_clock (GstBaseAudioSrc * src)
-{
- gboolean result;
-
- g_return_val_if_fail (GST_IS_BASE_AUDIO_SRC (src), FALSE);
-
- GST_OBJECT_LOCK (src);
- result = src->priv->provide_clock;
- GST_OBJECT_UNLOCK (src);
-
- return result;
-}
-
-/**
- * gst_base_audio_src_set_slave_method:
- * @src: a #GstBaseAudioSrc
- * @method: the new slave method
- *
- * Controls how clock slaving will be performed in @src.
- *
- * Since: 0.10.20
- */
-void
-gst_base_audio_src_set_slave_method (GstBaseAudioSrc * src,
- GstBaseAudioSrcSlaveMethod method)
-{
- g_return_if_fail (GST_IS_BASE_AUDIO_SRC (src));
-
- GST_OBJECT_LOCK (src);
- src->priv->slave_method = method;
- GST_OBJECT_UNLOCK (src);
-}
-
-/**
- * gst_base_audio_src_get_slave_method:
- * @src: a #GstBaseAudioSrc
- *
- * Get the current slave method used by @src.
- *
- * Returns: The current slave method used by @src.
- *
- * Since: 0.10.20
- */
-GstBaseAudioSrcSlaveMethod
-gst_base_audio_src_get_slave_method (GstBaseAudioSrc * src)
-{
- GstBaseAudioSrcSlaveMethod result;
-
- g_return_val_if_fail (GST_IS_BASE_AUDIO_SRC (src), -1);
-
- GST_OBJECT_LOCK (src);
- result = src->priv->slave_method;
- GST_OBJECT_UNLOCK (src);
-
- return result;
-}
-
-static void
-gst_base_audio_src_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstBaseAudioSrc *src;
-
- src = GST_BASE_AUDIO_SRC (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;
- case PROP_PROVIDE_CLOCK:
- gst_base_audio_src_set_provide_clock (src, g_value_get_boolean (value));
- break;
- case PROP_SLAVE_METHOD:
- gst_base_audio_src_set_slave_method (src, g_value_get_enum (value));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_base_audio_src_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstBaseAudioSrc *src;
-
- src = GST_BASE_AUDIO_SRC (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;
- case PROP_ACTUAL_BUFFER_TIME:
- GST_OBJECT_LOCK (src);
- if (src->ringbuffer && src->ringbuffer->acquired)
- g_value_set_int64 (value, src->ringbuffer->spec.buffer_time);
- else
- g_value_set_int64 (value, DEFAULT_ACTUAL_BUFFER_TIME);
- GST_OBJECT_UNLOCK (src);
- break;
- case PROP_ACTUAL_LATENCY_TIME:
- GST_OBJECT_LOCK (src);
- if (src->ringbuffer && src->ringbuffer->acquired)
- g_value_set_int64 (value, src->ringbuffer->spec.latency_time);
- else
- g_value_set_int64 (value, DEFAULT_ACTUAL_LATENCY_TIME);
- GST_OBJECT_UNLOCK (src);
- break;
- case PROP_PROVIDE_CLOCK:
- g_value_set_boolean (value, gst_base_audio_src_get_provide_clock (src));
- break;
- case PROP_SLAVE_METHOD:
- g_value_set_enum (value, gst_base_audio_src_get_slave_method (src));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_base_audio_src_fixate (GstBaseSrc * bsrc, GstCaps * caps)
-{
- GstStructure *s;
- gint width, depth;
-
- s = gst_caps_get_structure (caps, 0);
-
- /* fields for all formats */
- gst_structure_fixate_field_nearest_int (s, "rate", 44100);
- gst_structure_fixate_field_nearest_int (s, "channels", 2);
- gst_structure_fixate_field_nearest_int (s, "width", 16);
-
- /* fields for int */
- if (gst_structure_has_field (s, "depth")) {
- gst_structure_get_int (s, "width", &width);
- /* round width to nearest multiple of 8 for the depth */
- depth = GST_ROUND_UP_8 (width);
- gst_structure_fixate_field_nearest_int (s, "depth", depth);
- }
- if (gst_structure_has_field (s, "signed"))
- gst_structure_fixate_field_boolean (s, "signed", TRUE);
- if (gst_structure_has_field (s, "endianness"))
- gst_structure_fixate_field_nearest_int (s, "endianness", G_BYTE_ORDER);
-}
-
-static gboolean
-gst_base_audio_src_setcaps (GstBaseSrc * bsrc, GstCaps * caps)
-{
- GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc);
- GstRingBufferSpec *spec;
-
- spec = &src->ringbuffer->spec;
-
- spec->buffer_time = src->buffer_time;
- spec->latency_time = src->latency_time;
-
- if (!gst_ring_buffer_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_ring_buffer_release (src->ringbuffer);
-
- gst_ring_buffer_debug_spec_buff (spec);
-
- GST_DEBUG ("acquire new ringbuffer");
-
- if (!gst_ring_buffer_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_ring_buffer_debug_spec_buff (spec);
-
- g_object_notify (G_OBJECT (src), "actual-buffer-time");
- g_object_notify (G_OBJECT (src), "actual-latency-time");
-
- 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_base_audio_src_get_times (GstBaseSrc * bsrc, GstBuffer * buffer,
- GstClockTime * start, GstClockTime * end)
-{
- /* no need to sync to a clock here, we schedule the samples based
- * on our own clock for the moment. */
- *start = GST_CLOCK_TIME_NONE;
- *end = GST_CLOCK_TIME_NONE;
-}
-
-static gboolean
-gst_base_audio_src_query (GstBaseSrc * bsrc, GstQuery * query)
-{
- GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc);
- gboolean res = FALSE;
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_LATENCY:
- {
- GstClockTime min_latency, max_latency;
- GstRingBufferSpec *spec;
-
- if (G_UNLIKELY (src->ringbuffer == NULL
- || src->ringbuffer->spec.rate == 0))
- goto done;
-
- spec = &src->ringbuffer->spec;
-
- /* we have at least 1 segment of latency */
- min_latency =
- gst_util_uint64_scale_int (spec->segsize, GST_SECOND,
- spec->rate * spec->bytes_per_sample);
- /* we cannot delay more than the buffersize else we lose data */
- max_latency =
- gst_util_uint64_scale_int (spec->segtotal * spec->segsize, GST_SECOND,
- spec->rate * spec->bytes_per_sample);
-
- GST_DEBUG_OBJECT (src,
- "report latency min %" GST_TIME_FORMAT " max %" GST_TIME_FORMAT,
- GST_TIME_ARGS (min_latency), GST_TIME_ARGS (max_latency));
-
- /* we are always live, the min latency is 1 segment and the max latency is
- * the complete buffer of segments. */
- gst_query_set_latency (query, TRUE, min_latency, max_latency);
-
- res = TRUE;
- break;
- }
- default:
- res = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
- break;
- }
-done:
- return res;
-}
-
-static gboolean
-gst_base_audio_src_event (GstBaseSrc * bsrc, GstEvent * event)
-{
- GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc);
- gboolean res;
-
- res = TRUE;
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH_START:
- GST_DEBUG_OBJECT (bsrc, "flush-start");
- gst_ring_buffer_pause (src->ringbuffer);
- gst_ring_buffer_clear_all (src->ringbuffer);
- break;
- case GST_EVENT_FLUSH_STOP:
- GST_DEBUG_OBJECT (bsrc, "flush-stop");
- /* always resync on sample after a flush */
- src->next_sample = -1;
- gst_ring_buffer_clear_all (src->ringbuffer);
- break;
- case GST_EVENT_SEEK:
- GST_DEBUG_OBJECT (bsrc, "refuse to seek");
- res = FALSE;
- break;
- default:
- GST_DEBUG_OBJECT (bsrc, "dropping event %p", event);
- break;
- }
- return res;
-}
-
-/* get the next offset in the ringbuffer for reading samples.
- * If the next sample is too far away, this function will position itself to the
- * next most recent sample, creating discontinuity */
-static guint64
-gst_base_audio_src_get_offset (GstBaseAudioSrc * src)
-{
- guint64 sample;
- gint readseg, segdone, segtotal, sps;
- gint diff;
-
- /* assume we can append to the previous sample */
- sample = src->next_sample;
- /* no previous sample, try to read from position 0 */
- if (sample == -1)
- sample = 0;
-
- sps = src->ringbuffer->samples_per_seg;
- segtotal = src->ringbuffer->spec.segtotal;
-
- /* figure out the segment and the offset inside the segment where
- * the sample should be read from. */
- readseg = sample / sps;
-
- /* get the currently processed segment */
- segdone = g_atomic_int_get (&src->ringbuffer->segdone)
- - src->ringbuffer->segbase;
-
- GST_DEBUG_OBJECT (src, "reading from %d, we are at %d", readseg, segdone);
-
- /* see how far away it is from the read segment, normally segdone (where new
- * data is written in the ringbuffer) is bigger than readseg (where we are
- * reading). */
- diff = segdone - readseg;
- if (diff >= segtotal) {
- GST_DEBUG_OBJECT (src, "dropped, align to segment %d", segdone);
- /* sample would be dropped, position to next playable position */
- sample = ((guint64) (segdone)) * sps;
- }
-
- return sample;
-}
-
-static GstFlowReturn
-gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
- GstBuffer ** outbuf)
-{
- GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (bsrc);
- GstBuffer *buf;
- guchar *data;
- guint samples, total_samples;
- guint64 sample;
- gint bps;
- GstRingBuffer *ringbuffer;
- GstRingBufferSpec *spec;
- guint read;
- GstClockTime timestamp, duration;
- GstClock *clock;
-
- ringbuffer = src->ringbuffer;
- spec = &ringbuffer->spec;
-
- if (G_UNLIKELY (!gst_ring_buffer_is_acquired (ringbuffer)))
- goto wrong_state;
-
- bps = spec->bytes_per_sample;
-
- if ((length == 0 && bsrc->blocksize == 0) || length == -1)
- /* no length given, use the default segment size */
- length = spec->segsize;
- else
- /* make sure we round down to an integral number of samples */
- length -= length % bps;
-
- /* figure out the offset in the ringbuffer */
- if (G_UNLIKELY (offset != -1)) {
- sample = offset / bps;
- /* if a specific offset was given it must be the next sequential
- * offset we expect or we fail for now. */
- if (src->next_sample != -1 && sample != src->next_sample)
- goto wrong_offset;
- } else {
- /* calculate the sequentially next sample we need to read. This can jump and
- * create a DISCONT. */
- sample = gst_base_audio_src_get_offset (src);
- }
-
- GST_DEBUG_OBJECT (src, "reading from sample %" G_GUINT64_FORMAT, sample);
-
- /* get the number of samples to read */
- total_samples = samples = length / bps;
-
- /* FIXME, using a bufferpool would be nice here */
- buf = gst_buffer_new_and_alloc (length);
- data = GST_BUFFER_DATA (buf);
-
- do {
- read = gst_ring_buffer_read (ringbuffer, sample, data, samples);
- GST_DEBUG_OBJECT (src, "read %u of %u", read, samples);
- /* if we read all, we're done */
- if (read == samples)
- break;
-
- /* else something interrupted us and we wait for playing again. */
- GST_DEBUG_OBJECT (src, "wait playing");
- if (gst_base_src_wait_playing (bsrc) != GST_FLOW_OK)
- goto stopped;
-
- GST_DEBUG_OBJECT (src, "continue playing");
-
- /* read next samples */
- sample += read;
- samples -= read;
- data += read * bps;
- } while (TRUE);
-
- /* mark discontinuity if needed */
- if (G_UNLIKELY (sample != src->next_sample) && src->next_sample != -1) {
- GST_WARNING_OBJECT (src,
- "create DISCONT of %" G_GUINT64_FORMAT " samples at sample %"
- G_GUINT64_FORMAT, sample - src->next_sample, sample);
- GST_ELEMENT_WARNING (src, CORE, CLOCK,
- (_("Can't record audio fast enough")),
- ("Dropped %" G_GUINT64_FORMAT " samples. This is most likely because "
- "downstream can't keep up and is consuming samples too slowly.",
- sample - src->next_sample));
- GST_BUFFER_FLAG_SET (buf, GST_BUFFER_FLAG_DISCONT);
- }
-
- src->next_sample = sample + samples;
-
- /* get the normal timestamp to get the duration. */
- timestamp = gst_util_uint64_scale_int (sample, GST_SECOND, spec->rate);
- duration = gst_util_uint64_scale_int (src->next_sample, GST_SECOND,
- spec->rate) - timestamp;
-
- GST_OBJECT_LOCK (src);
- if (!(clock = GST_ELEMENT_CLOCK (src)))
- goto no_sync;
-
- if (clock != src->clock) {
- /* we are slaved, check how to handle this */
- switch (src->priv->slave_method) {
- case GST_BASE_AUDIO_SRC_SLAVE_RESAMPLE:
- /* not implemented, use skew algorithm. This algorithm should
- * work on the readout pointer and produces more or less samples based
- * on the clock drift */
- case GST_BASE_AUDIO_SRC_SLAVE_SKEW:
- {
- GstClockTime running_time;
- GstClockTime base_time;
- GstClockTime current_time;
- guint64 running_time_sample;
- gint running_time_segment;
- gint current_segment;
- gint segment_skew;
- gint sps;
-
- /* samples per segment */
- sps = ringbuffer->samples_per_seg;
-
- /* get the current time */
- current_time = gst_clock_get_time (clock);
-
- /* get the basetime */
- base_time = GST_ELEMENT_CAST (src)->base_time;
-
- /* get the running_time */
- running_time = current_time - base_time;
-
- /* the running_time converted to a sample (relative to the ringbuffer) */
- running_time_sample =
- gst_util_uint64_scale_int (running_time, spec->rate, GST_SECOND);
-
- /* the segmentnr corrensponding to running_time, round down */
- running_time_segment = running_time_sample / sps;
-
- /* the segment currently read from the ringbuffer */
- current_segment = sample / sps;
-
- /* the skew we have between running_time and the ringbuffertime */
- segment_skew = running_time_segment - current_segment;
-
- GST_DEBUG_OBJECT (bsrc, "\n running_time = %" GST_TIME_FORMAT
- "\n timestamp = %" GST_TIME_FORMAT
- "\n running_time_segment = %d"
- "\n current_segment = %d"
- "\n segment_skew = %d",
- GST_TIME_ARGS (running_time),
- GST_TIME_ARGS (timestamp),
- running_time_segment, current_segment, segment_skew);
-
- /* Resync the ringbuffer if:
- * 1. We get one segment into the future.
- * This is clearly a lie, because we can't
- * possibly have a buffer with timestamp 1 at
- * time 0. (unless it has time-travelled...)
- *
- * 2. We are more than the length of the ringbuffer behind.
- * The length of the ringbuffer then gets to dictate
- * the threshold for what is concidered "too late"
- *
- * 3. If this is our first buffer.
- * We know that we should catch up to running_time
- * the first time we are ran.
- */
- if ((segment_skew < 0) ||
- (segment_skew >= ringbuffer->spec.segtotal) ||
- (current_segment == 0)) {
- gint segments_written;
- gint first_segment;
- gint last_segment;
- gint new_last_segment;
- gint segment_diff;
- gint new_first_segment;
- guint64 new_sample;
-
- /* we are going to say that the last segment was captured at the current time
- (running_time), minus one segment of creation-latency in the ringbuffer.
- This can be thought of as: The segment arrived in the ringbuffer at time X, and
- that means it was created at time X - (one segment). */
- new_last_segment = running_time_segment - 1;
-
- /* for better readablity */
- first_segment = current_segment;
-
- /* get the amount of segments written from the device by now */
- segments_written = g_atomic_int_get (&ringbuffer->segdone);
-
- /* subtract the base to segments_written to get the number of the
- last written segment in the ringbuffer (one segment written = segment 0) */
- last_segment = segments_written - ringbuffer->segbase - 1;
-
- /* we see how many segments the ringbuffer was timeshifted */
- segment_diff = new_last_segment - last_segment;
-
- /* we move the first segment an equal amount */
- new_first_segment = first_segment + segment_diff;
-
- /* and we also move the segmentbase the same amount */
- ringbuffer->segbase -= segment_diff;
-
- /* we calculate the new sample value */
- new_sample = ((guint64) new_first_segment) * sps;
-
- /* and get the relative time to this -> our new timestamp */
- timestamp =
- gst_util_uint64_scale_int (new_sample, GST_SECOND, spec->rate);
-
- /* we update the next sample accordingly */
- src->next_sample = new_sample + samples;
-
- GST_DEBUG_OBJECT (bsrc,
- "Timeshifted the ringbuffer with %d segments: "
- "Updating the timestamp to %" GST_TIME_FORMAT ", "
- "and src->next_sample to %" G_GUINT64_FORMAT, segment_diff,
- GST_TIME_ARGS (timestamp), src->next_sample);
- }
- break;
- }
- case GST_BASE_AUDIO_SRC_SLAVE_RETIMESTAMP:
- {
- GstClockTime base_time, latency;
-
- /* We are slaved to another clock, take running time of the pipeline clock and
- * timestamp against it. Somebody else in the pipeline should figure out the
- * clock drift. We keep the duration we calculated above. */
- timestamp = gst_clock_get_time (clock);
- base_time = GST_ELEMENT_CAST (src)->base_time;
-
- if (timestamp > base_time)
- timestamp -= base_time;
- else
- timestamp = 0;
-
- /* subtract latency */
- latency =
- gst_util_uint64_scale_int (total_samples, GST_SECOND, spec->rate);
- if (timestamp > latency)
- timestamp -= latency;
- else
- timestamp = 0;
- }
- case GST_BASE_AUDIO_SRC_SLAVE_NONE:
- break;
- }
- } else {
- GstClockTime base_time;
-
- /* to get the timestamp against the clock we also need to add our offset */
- timestamp = gst_audio_clock_adjust (clock, timestamp);
-
- /* we are not slaved, subtract base_time */
- base_time = GST_ELEMENT_CAST (src)->base_time;
-
- if (timestamp > base_time) {
- timestamp -= base_time;
- GST_LOG_OBJECT (src,
- "buffer timestamp %" GST_TIME_FORMAT " (base_time %" GST_TIME_FORMAT
- ")", GST_TIME_ARGS (timestamp), GST_TIME_ARGS (base_time));
- } else {
- GST_LOG_OBJECT (src,
- "buffer timestamp 0, ts %" GST_TIME_FORMAT " <= base_time %"
- GST_TIME_FORMAT, GST_TIME_ARGS (timestamp),
- GST_TIME_ARGS (base_time));
- timestamp = 0;
- }
- }
-
-no_sync:
- GST_OBJECT_UNLOCK (src);
-
- GST_BUFFER_TIMESTAMP (buf) = timestamp;
- GST_BUFFER_DURATION (buf) = duration;
- GST_BUFFER_OFFSET (buf) = sample;
- GST_BUFFER_OFFSET_END (buf) = sample + samples;
-
- *outbuf = buf;
-
- return GST_FLOW_OK;
-
- /* ERRORS */
-wrong_state:
- {
- GST_DEBUG_OBJECT (src, "ringbuffer in wrong state");
- return GST_FLOW_WRONG_STATE;
- }
-wrong_offset:
- {
- GST_ELEMENT_ERROR (src, RESOURCE, SEEK,
- (NULL), ("resource can only be operated on sequentially but offset %"
- G_GUINT64_FORMAT " was given", offset));
- return GST_FLOW_ERROR;
- }
-stopped:
- {
- gst_buffer_unref (buf);
- GST_DEBUG_OBJECT (src, "ringbuffer stopped");
- return GST_FLOW_WRONG_STATE;
- }
-}
-
-/**
- * gst_base_audio_src_create_ringbuffer:
- * @src: a #GstBaseAudioSrc.
- *
- * Create and return the #GstRingBuffer for @src. This function will call the
- * ::create_ringbuffer vmethod and will set @src as the parent of the returned
- * buffer (see gst_object_set_parent()).
- *
- * Returns: The new ringbuffer of @src.
- */
-GstRingBuffer *
-gst_base_audio_src_create_ringbuffer (GstBaseAudioSrc * src)
-{
- GstBaseAudioSrcClass *bclass;
- GstRingBuffer *buffer = NULL;
-
- bclass = GST_BASE_AUDIO_SRC_GET_CLASS (src);
- if (bclass->create_ringbuffer)
- buffer = bclass->create_ringbuffer (src);
-
- if (G_LIKELY (buffer))
- gst_object_set_parent (GST_OBJECT_CAST (buffer), GST_OBJECT_CAST (src));
-
- return buffer;
-}
-
-static GstStateChangeReturn
-gst_base_audio_src_change_state (GstElement * element,
- GstStateChange transition)
-{
- GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
- GstBaseAudioSrc *src = GST_BASE_AUDIO_SRC (element);
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- GST_DEBUG_OBJECT (src, "NULL->READY");
- GST_OBJECT_LOCK (src);
- if (src->ringbuffer == NULL) {
- gst_audio_clock_reset (GST_AUDIO_CLOCK (src->clock), 0);
- src->ringbuffer = gst_base_audio_src_create_ringbuffer (src);
- }
- GST_OBJECT_UNLOCK (src);
- if (!gst_ring_buffer_open_device (src->ringbuffer))
- goto open_failed;
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- GST_DEBUG_OBJECT (src, "READY->PAUSED");
- src->next_sample = -1;
- gst_ring_buffer_set_flushing (src->ringbuffer, FALSE);
- gst_ring_buffer_may_start (src->ringbuffer, FALSE);
- break;
- case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
- GST_DEBUG_OBJECT (src, "PAUSED->PLAYING");
- gst_ring_buffer_may_start (src->ringbuffer, TRUE);
- break;
- case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
- GST_DEBUG_OBJECT (src, "PLAYING->PAUSED");
- gst_ring_buffer_may_start (src->ringbuffer, FALSE);
- gst_ring_buffer_pause (src->ringbuffer);
- break;
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- GST_DEBUG_OBJECT (src, "PAUSED->READY");
- gst_ring_buffer_set_flushing (src->ringbuffer, TRUE);
- break;
- default:
- break;
- }
-
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_PAUSED_TO_READY:
- GST_DEBUG_OBJECT (src, "PAUSED->READY");
- gst_ring_buffer_release (src->ringbuffer);
- break;
- case GST_STATE_CHANGE_READY_TO_NULL:
- GST_DEBUG_OBJECT (src, "READY->NULL");
- gst_ring_buffer_close_device (src->ringbuffer);
- GST_OBJECT_LOCK (src);
- gst_object_unparent (GST_OBJECT_CAST (src->ringbuffer));
- src->ringbuffer = NULL;
- GST_OBJECT_UNLOCK (src);
- break;
- default:
- break;
- }
-
- return ret;
-
- /* ERRORS */
-open_failed:
- {
- /* subclass must post a meaningfull error message */
- GST_DEBUG_OBJECT (src, "open failed");
- return GST_STATE_CHANGE_FAILURE;
- }
-
-}
+++ /dev/null
-*************** gst_base_audio_src_create (GstBaseSrc * bsrc, guint64 offset, guint length,
-*** 865,935 ****
- running_time_segment = running_time_sample / sps;
-
- /* the segment currently read from the ringbuffer */
-- current_segment = sample / sps;
--
-- /* the skew we have between running_time and the ringbuffertime */
-- segment_skew = running_time_segment - current_segment;
--
-- GST_DEBUG_OBJECT (bsrc, "\n running_time = %" GST_TIME_FORMAT
-- "\n timestamp = %" GST_TIME_FORMAT
-- "\n running_time_segment = %d"
-- "\n current_segment = %d"
-- "\n segment_skew = %d",
- GST_TIME_ARGS (running_time),
- GST_TIME_ARGS (timestamp),
-- running_time_segment, current_segment, segment_skew);
-
- /* Resync the ringbuffer if:
-- * 1. We are more than the length of the ringbuffer in front.
-- * The length of the ringbuffer then gets to dictate
-- * the threshold for what is concidered "too far ahead"
-- *
-- * 2. We are more than the length of the ringbuffer behind.
- * The length of the ringbuffer then gets to dictate
- * the threshold for what is concidered "too late"
- *
-- * 3. If this is our first buffer.
- * We know that we should catch up to running_time
- * the first time we are ran.
- */
-- if ((segment_skew <= -ringbuffer->spec.segtotal) ||
-- (segment_skew >= ringbuffer->spec.segtotal) ||
-- (current_segment == 0)) {
-- gint segments_written;
-- gint first_segment;
-- gint last_segment;
-- gint new_last_segment;
- gint segment_diff;
-- gint new_first_segment;
- guint64 new_sample;
-
-- /* we are going to say that the last segment was captured at the current time
-- (running_time), minus one segment of creation-latency in the ringbuffer.
-- This can be thought of as: The segment arrived in the ringbuffer at time X, and
-- that means it was created at time X - (one segment). */
-- new_last_segment = running_time_segment - 1;
--
-- /* for better readablity */
-- first_segment = current_segment;
--
-- /* get the amount of segments written from the device by now */
-- segments_written = g_atomic_int_get (&ringbuffer->segdone);
--
-- /* subtract the base to segments_written to get the number of the
-- last written segment in the ringbuffer (one segment written = segment 0) */
-- last_segment = segments_written - ringbuffer->segbase - 1;
--
-- /* we see how many segments the ringbuffer was timeshifted */
-- segment_diff = new_last_segment - last_segment;
-
-- /* we move the first segment an equal amount */
-- new_first_segment = first_segment + segment_diff;
-
-- /* and we also move the segmentbase the same amount */
-- ringbuffer->segbase -= segment_diff;
-
- /* we calculate the new sample value */
-- new_sample = ((guint64) new_first_segment) * sps;
-
- /* and get the relative time to this -> our new timestamp */
- timestamp =
---- 874,926 ----
- running_time_segment = running_time_sample / sps;
-
- /* the segment currently read from the ringbuffer */
-+ last_read_segment = sample / sps;
-+
-+ /* the skew we have between running_time and the ringbuffertime (last written to) */
-+ segment_skew = running_time_segment - last_written_segment;
-+
-+ GST_DEBUG_OBJECT (bsrc,
-+ "\n running_time = %" GST_TIME_FORMAT
-+ "\n timestamp = %" GST_TIME_FORMAT
-+ "\n running_time_segment = %d"
-+ "\n last_written_segment = %d"
-+ "\n segment_skew (running time segment - last_written_segment) = %d"
-+ "\n last_read_segment = %d",
- GST_TIME_ARGS (running_time),
- GST_TIME_ARGS (timestamp),
-+ running_time_segment,
-+ last_written_segment,
-+ segment_skew,
-+ last_read_segment);
-
- /* Resync the ringbuffer if:
-+
-+ * 1. We are more than the length of the ringbuffer behind.
- * The length of the ringbuffer then gets to dictate
- * the threshold for what is concidered "too late"
- *
-+ * 2. If this is our first buffer.
- * We know that we should catch up to running_time
- * the first time we are ran.
- */
-+ if ((segment_skew >= ringbuffer->spec.segtotal) ||
-+ (last_read_segment == 0))
-+ {
-+ gint new_read_segment;
- gint segment_diff;
- guint64 new_sample;
-
-+ /* the difference between running_time and the last written segment */
-+ segment_diff = running_time_segment - last_written_segment;
-
-+ /* advance the ringbuffer */
-+ gst_ring_buffer_advance(ringbuffer, segment_diff);
-
-+ /* we move the new read segment to the last known written segment */
-+ new_read_segment = g_atomic_int_get (&ringbuffer->segdone) - ringbuffer->segbase;
-
- /* we calculate the new sample value */
-+ new_sample = ((guint64) new_read_segment) * sps;
-
- /* and get the relative time to this -> our new timestamp */
- timestamp =
+++ /dev/null
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2005 Wim Taymans <wim@fluendo.com>
- *
- * gstaudioringbuffer.c: simple audio ringbuffer 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 "gstringbufferthread.h"
-
-GST_DEBUG_CATEGORY_STATIC (gst_ring_buffer_thread_debug);
-#define GST_CAT_DEFAULT gst_ring_buffer_thread_debug
-
-static void gst_ring_buffer_thread_class_init (GstRingBufferThreadClass *
- klass);
-static void gst_ring_buffer_thread_init (GstRingBufferThread * ringbuffer,
- GstRingBufferThreadClass * klass);
-static void gst_ring_buffer_thread_dispose (GObject * object);
-static void gst_ring_buffer_thread_finalize (GObject * object);
-
-static GstRingBufferClass *ring_parent_class = NULL;
-
-GType
-gst_ring_buffer_thread_get_type (void)
-{
- static GType ringbuffer_type = 0;
-
- if (!ringbuffer_type) {
- static const GTypeInfo ringbuffer_info = {
- sizeof (GstRingBufferThreadClass),
- NULL,
- NULL,
- (GClassInitFunc) gst_ring_buffer_thread_class_init,
- NULL,
- NULL,
- sizeof (GstRingBufferThread),
- 0,
- (GInstanceInitFunc) gst_ring_buffer_thread_init,
- NULL
- };
-
- ringbuffer_type =
- g_type_register_static (GST_TYPE_OBJECT, "GstRingBufferThread",
- &ringbuffer_info, 0);
-
- GST_DEBUG_CATEGORY_INIT (gst_ring_buffer_thread_debug, "ringbufferthread",
- 0, "ringbuffer thread");
- }
- return ringbuffer_type;
-}
-
-static void
-gst_ring_buffer_thread_class_init (GstRingBufferThreadClass * klass)
-{
- GObjectClass *gobject_class;
-
- gobject_class = (GObjectClass *) klass;
-
- ring_parent_class = g_type_class_peek_parent (klass);
-
- gobject_class->dispose = gst_ring_buffer_thread_dispose;
- gobject_class->finalize = gst_ring_buffer_thread_finalize;
-}
-
-typedef gint (*ProcessFunc) (GstAudioRingBuffer * buf, gpointer data,
- guint length);
-
-/* this internal thread does nothing else but write samples to the audio device.
- * It will write each segment in the ringbuffer and will update the play
- * pointer.
- * The start/stop methods control the thread.
- */
-static void
-ring_buffer_thread_thread_func (GstRingBufferThread * thread)
-{
- GstElement *parent = NULL;
- GstMessage *message;
- GValue val = { 0 };
- GstAudioRingBuffer *capture, *playback;
- ProcessFunc writefunc = NULL, readfunc = NULL;
- gint preroll = 1;
-
- GST_DEBUG_OBJECT (thread, "enter thread");
-
- GST_OBJECT_LOCK (thread);
- GST_DEBUG_OBJECT (thread, "signal wait");
- GST_RING_BUFFER_THREAD_SIGNAL (thread);
- if ((capture = thread->capture))
- gst_object_ref (capture);
- if ((playback = thread->playback))
- gst_object_ref (playback);
- GST_OBJECT_UNLOCK (thread);
-
- if (capture)
- readfunc = GST_AUDIO_RING_BUFFER_GET_CLASS (capture)->process;
- if (playback)
- writefunc = GST_AUDIO_RING_BUFFER_GET_CLASS (playback)->process;
-
- if (parent) {
- g_value_init (&val, G_TYPE_POINTER);
- g_value_set_pointer (&val, thread->thread);
- message = gst_message_new_stream_status (GST_OBJECT_CAST (thread),
- GST_STREAM_STATUS_TYPE_ENTER, NULL);
- gst_message_set_stream_status_object (message, &val);
- GST_DEBUG_OBJECT (thread, "posting ENTER stream status");
- gst_element_post_message (parent, message);
- }
-
- while (TRUE) {
- gint left, processed;
- guint8 *read_ptr, *write_ptr;
- gint read_seg, write_seg;
- gint read_len, write_len;
- gboolean read_active, write_active;
-
- if (playback)
- write_active =
- gst_ring_buffer_prepare_read (GST_RING_BUFFER_CAST (playback),
- &write_seg, &write_ptr, &write_len);
- else
- write_active = FALSE;
-
- if (playback) {
- if (!write_active) {
- write_ptr = GST_RING_BUFFER_CAST (playback)->empty_seg;
- write_len = GST_RING_BUFFER_CAST (playback)->spec.segsize;
- }
-
- left = write_len;
- do {
- processed = writefunc (playback, write_ptr, left);
- GST_LOG_OBJECT (thread, "written %d bytes of %d from segment %d",
- processed, left, write_seg);
- if (processed < 0 || processed > left) {
- /* might not be critical, it e.g. happens when aborting playback */
- GST_WARNING_OBJECT (thread,
- "error writing data in %s (reason: %s), skipping segment (left: %d, processed: %d)",
- GST_DEBUG_FUNCPTR_NAME (writefunc),
- (errno > 1 ? g_strerror (errno) : "unknown"), left, processed);
- break;
- }
- left -= processed;
- write_ptr += processed;
- } while (left > 0);
-
- /* we wrote one segment */
- gst_ring_buffer_advance (GST_RING_BUFFER_CAST (playback), 1);
-
- if (preroll > 0) {
- /* do not start reading until we have read enough data */
- preroll--;
- GST_DEBUG_OBJECT (thread, "need more preroll");
- continue;
- }
- }
-
-
- if (capture)
- read_active =
- gst_ring_buffer_prepare_read (GST_RING_BUFFER_CAST (capture),
- &read_seg, &read_ptr, &read_len);
- else
- read_active = FALSE;
-
- if (capture) {
- left = read_len;
- do {
- processed = readfunc (capture, read_ptr, left);
- GST_LOG_OBJECT (thread, "read %d bytes of %d from segment %d",
- processed, left, read_seg);
- if (processed < 0 || processed > left) {
- /* might not be critical, it e.g. happens when aborting playback */
- GST_WARNING_OBJECT (thread,
- "error reading data in %s (reason: %s), skipping segment (left: %d, processed: %d)",
- GST_DEBUG_FUNCPTR_NAME (readfunc),
- (errno > 1 ? g_strerror (errno) : "unknown"), left, processed);
- break;
- }
- left -= processed;
- read_ptr += processed;
- } while (left > 0);
-
- if (read_active)
- /* we read one segment */
- gst_ring_buffer_advance (GST_RING_BUFFER_CAST (capture), 1);
- }
-
- if (!read_active && !write_active) {
- GST_OBJECT_LOCK (thread);
- if (!thread->running)
- goto stop_running;
- GST_DEBUG_OBJECT (thread, "signal wait");
- GST_RING_BUFFER_THREAD_SIGNAL (thread);
- GST_DEBUG_OBJECT (thread, "wait for action");
- GST_RING_BUFFER_THREAD_WAIT (thread);
- GST_DEBUG_OBJECT (thread, "got signal");
- if (!thread->running)
- goto stop_running;
- GST_DEBUG_OBJECT (thread, "continue running");
- GST_OBJECT_UNLOCK (thread);
- }
- }
-
- /* Will never be reached */
- g_assert_not_reached ();
- return;
-
- /* ERROR */
-stop_running:
- {
- GST_OBJECT_UNLOCK (thread);
- GST_DEBUG_OBJECT (thread, "stop running, exit thread");
- if (parent) {
- message = gst_message_new_stream_status (GST_OBJECT_CAST (thread),
- GST_STREAM_STATUS_TYPE_LEAVE, GST_ELEMENT_CAST (thread));
- gst_message_set_stream_status_object (message, &val);
- GST_DEBUG_OBJECT (thread, "posting LEAVE stream status");
- gst_element_post_message (parent, message);
- }
- return;
- }
-}
-
-static void
-gst_ring_buffer_thread_init (GstRingBufferThread * thread,
- GstRingBufferThreadClass * g_class)
-{
- thread->running = FALSE;
- thread->cond = g_cond_new ();
-}
-
-static void
-gst_ring_buffer_thread_dispose (GObject * object)
-{
- GstRingBufferThread *thread = GST_RING_BUFFER_THREAD_CAST (object);
-
- GST_OBJECT_LOCK (thread);
- if (thread->playback) {
- gst_object_unref (thread->playback);
- thread->playback = NULL;
- }
- if (thread->capture) {
- gst_object_unref (thread->capture);
- thread->capture = NULL;
- }
- GST_OBJECT_UNLOCK (thread);
-
- G_OBJECT_CLASS (ring_parent_class)->dispose (object);
-}
-
-static void
-gst_ring_buffer_thread_finalize (GObject * object)
-{
- GstRingBufferThread *thread = GST_RING_BUFFER_THREAD_CAST (object);
-
- g_cond_free (thread->cond);
-
- G_OBJECT_CLASS (ring_parent_class)->finalize (object);
-}
-
-gboolean
-gst_ring_buffer_thread_activate (GstRingBufferThread * thread, gboolean active)
-{
- GError *error = NULL;
-
- GST_OBJECT_LOCK (thread);
- if (active) {
- if (thread->active_count == 0) {
- thread->running = TRUE;
- GST_DEBUG_OBJECT (thread, "starting thread");
- thread->thread =
- g_thread_create ((GThreadFunc) ring_buffer_thread_thread_func, thread,
- TRUE, &error);
- if (!thread->thread || error != NULL)
- goto thread_failed;
-
- GST_DEBUG_OBJECT (thread, "waiting for thread");
- /* the object lock is taken */
- GST_RING_BUFFER_THREAD_WAIT (thread);
- GST_DEBUG_OBJECT (thread, "thread is started");
- }
- thread->active_count++;
- } else {
- if (thread->active_count == 1) {
- thread->running = FALSE;
- GST_DEBUG_OBJECT (thread, "signal wait");
- GST_RING_BUFFER_THREAD_SIGNAL (thread);
- GST_OBJECT_UNLOCK (thread);
-
- /* join the thread */
- g_thread_join (thread->thread);
-
- GST_OBJECT_LOCK (thread);
- }
- thread->active_count--;
- }
- GST_OBJECT_UNLOCK (thread);
-
- return TRUE;
-
- /* ERRORS */
-thread_failed:
- {
- if (error)
- GST_ERROR_OBJECT (thread, "could not create thread %s", error->message);
- else
- GST_ERROR_OBJECT (thread, "could not create thread for unknown reason");
- thread->running = FALSE;
- GST_OBJECT_UNLOCK (thread);
- return FALSE;
- }
-}
-
-gboolean
-gst_ring_buffer_thread_set_ringbuffer (GstRingBufferThread * thread,
- GstAudioRingBuffer * buf)
-{
- GstAudioRingBuffer *old, **new;
-
- g_return_val_if_fail (GST_IS_RING_BUFFER_THREAD (thread), FALSE);
-
- if (buf->mode == GST_AUDIO_RING_BUFFER_MODE_PLAYBACK)
- new = &thread->playback;
- else
- new = &thread->capture;
-
- old = *new;
- if (buf)
- gst_object_ref (buf);
- *new = buf;
- if (old)
- gst_object_unref (old);
-
- return TRUE;
-}
-
-gboolean
-gst_ring_buffer_thread_start (GstRingBufferThread * thread)
-{
- g_return_val_if_fail (GST_IS_RING_BUFFER_THREAD (thread), FALSE);
-
- GST_RING_BUFFER_THREAD_SIGNAL (thread);
-
- return TRUE;
-}
+++ /dev/null
-/* GStreamer
- * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
- * 2005 Wim Taymans <wim@fluendo.com>
- *
- * gstaudioringbuffer.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.
- */
-
-#ifndef __GST_RING_BUFFER_THREAD_H__
-#define __GST_RING_BUFFER_THREAD_H__
-
-#include <gst/gst.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_RING_BUFFER_THREAD (gst_ring_buffer_thread_get_type())
-#define GST_RING_BUFFER_THREAD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RING_BUFFER_THREAD,GstRingBufferThread))
-#define GST_RING_BUFFER_THREAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RING_BUFFER_THREAD,GstRingBufferThreadClass))
-#define GST_RING_BUFFER_THREAD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),GST_TYPE_RING_BUFFER_THREAD,GstRingBufferThreadClass))
-#define GST_IS_RING_BUFFER_THREAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RING_BUFFER_THREAD))
-#define GST_IS_RING_BUFFER_THREAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RING_BUFFER_THREAD))
-#define GST_RING_BUFFER_THREAD_CAST(obj) ((GstRingBufferThread *)obj)
-
-typedef struct _GstRingBufferThread GstRingBufferThread;
-typedef struct _GstRingBufferThreadClass GstRingBufferThreadClass;
-
-#include <gst/audio/gstaudioringbuffer.h>
-
-#define GST_RING_BUFFER_THREAD_GET_COND(buf) (((GstRingBufferThread *)buf)->cond)
-#define GST_RING_BUFFER_THREAD_WAIT(buf) (g_cond_wait (GST_RING_BUFFER_THREAD_GET_COND (buf), GST_OBJECT_GET_LOCK (buf)))
-#define GST_RING_BUFFER_THREAD_SIGNAL(buf) (g_cond_signal (GST_RING_BUFFER_THREAD_GET_COND (buf)))
-#define GST_RING_BUFFER_THREAD_BROADCAST(buf)(g_cond_broadcast (GST_RING_BUFFER_THREAD_GET_COND (buf)))
-
-/**
- * GstRingBufferThread:
- *
- * Opaque #GstRingBufferThread.
- */
-struct _GstRingBufferThread {
- GstObject parent;
-
- gint active_count;
-
- /*< private >*/ /* with LOCK */
- GThread *thread;
- gboolean running;
- GCond *cond;
-
- GstAudioRingBuffer *playback;
- GstAudioRingBuffer *capture;
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-/**
- * GstRingBufferThreadClass:
- * @parent_class: the parent class structure.
- *
- * #GstRingBufferThread class. Override the vmethods to implement functionality.
- */
-struct _GstRingBufferThreadClass {
- GstObjectClass parent_class;
-
- /*< private >*/
- gpointer _gst_reserved[GST_PADDING];
-};
-
-GType gst_ring_buffer_thread_get_type(void);
-
-gboolean gst_ring_buffer_thread_set_ringbuffer (GstRingBufferThread *thread, GstAudioRingBuffer *buf);
-
-gboolean gst_ring_buffer_thread_activate (GstRingBufferThread *thread, gboolean active);
-
-gboolean gst_ring_buffer_thread_start (GstRingBufferThread *thread);
-
-G_END_DECLS
-
-#endif /* __GST_RING_BUFFER_THREAD_H__ */
+++ /dev/null
-? foo
-Index: Makefile.am
-===================================================================
-RCS file: /cvs/gstreamer/gst-plugins-base/gst-libs/gst/cdda/Makefile.am,v
-retrieving revision 1.4
-diff -u -p -u -p -r1.4 Makefile.am
---- Makefile.am 3 Apr 2008 06:39:27 -0000 1.4
-+++ Makefile.am 21 Aug 2008 14:17:21 -0000
-@@ -1,9 +1,7 @@
- lib_LTLIBRARIES = libgstcdda-@GST_MAJORMINOR@.la
-
- libgstcdda_@GST_MAJORMINOR@_la_SOURCES = \
-- gstcddabasesrc.c \
-- sha1.c \
-- sha1.h
-+ gstcddabasesrc.c
-
- libgstcdda_@GST_MAJORMINOR@includedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/cdda
- libgstcdda_@GST_MAJORMINOR@include_HEADERS = \
-Index: gstcddabasesrc.c
-===================================================================
-RCS file: /cvs/gstreamer/gst-plugins-base/gst-libs/gst/cdda/gstcddabasesrc.c,v
-retrieving revision 1.19
-diff -u -p -u -p -r1.19 gstcddabasesrc.c
---- gstcddabasesrc.c 28 May 2008 15:48:33 -0000 1.19
-+++ gstcddabasesrc.c 21 Aug 2008 14:17:21 -0000
-@@ -1084,36 +1084,35 @@ cddb_sum (gint n)
- return ret;
- }
-
--#include "sha1.h"
--
- static void
- gst_cddabasesrc_calculate_musicbrainz_discid (GstCddaBaseSrc * src)
- {
- GString *s;
-- SHA_INFO sha;
-+ GChecksum *sha;
- guchar digest[20];
- gchar *ptr;
- gchar tmp[9];
- gulong i;
- guint leadout_sector;
-+ gsize digest_len;
-
- s = g_string_new (NULL);
-
- leadout_sector = src->tracks[src->num_tracks - 1].end + 1 + CD_MSF_OFFSET;
-
- /* generate SHA digest */
-- sha_init (&sha);
-+ sha = g_checksum_new (G_CHECKSUM_SHA1);
- g_snprintf (tmp, sizeof (tmp), "%02X", src->tracks[0].num);
- g_string_append_printf (s, "%02X", src->tracks[0].num);
-- sha_update (&sha, (SHA_BYTE *) tmp, 2);
-+ g_checksum_update (sha, (guchar *) tmp, 2);
-
- g_snprintf (tmp, sizeof (tmp), "%02X", src->tracks[src->num_tracks - 1].num);
- g_string_append_printf (s, " %02X", src->tracks[src->num_tracks - 1].num);
-- sha_update (&sha, (SHA_BYTE *) tmp, 2);
-+ g_checksum_update (sha, (guchar *) tmp, 2);
-
- g_snprintf (tmp, sizeof (tmp), "%08X", leadout_sector);
- g_string_append_printf (s, " %08X", leadout_sector);
-- sha_update (&sha, (SHA_BYTE *) tmp, 8);
-+ g_checksum_update (sha, (guchar *) tmp, 8);
-
- for (i = 0; i < 99; i++) {
- if (i < src->num_tracks) {
-@@ -1121,15 +1120,17 @@ gst_cddabasesrc_calculate_musicbrainz_di
-
- g_snprintf (tmp, sizeof (tmp), "%08X", frame_offset);
- g_string_append_printf (s, " %08X", frame_offset);
-- sha_update (&sha, (SHA_BYTE *) tmp, 8);
-+ g_checksum_update (sha, (guchar *) tmp, 8);
- } else {
-- sha_update (&sha, (SHA_BYTE *) "00000000", 8);
-+ g_checksum_update (sha, (guchar *) "00000000", 8);
- }
- }
-- sha_final (digest, &sha);
-+ digest_len = 20;
-+ g_checksum_get_digest (sha, (guint8 *) &digest, &digest_len);
-
- /* re-encode to base64 */
-- ptr = g_base64_encode (digest, 20);
-+ ptr = g_base64_encode (digest, digest_len);
-+ g_checksum_free (sha);
- i = strlen (ptr);
-
- g_assert (i < sizeof (src->mb_discid) + 1);
-Index: sha1.c
-===================================================================
-RCS file: sha1.c
-diff -N sha1.c
---- sha1.c 27 Feb 2008 10:42:08 -0000 1.2
-+++ /dev/null 1 Jan 1970 00:00:00 -0000
-@@ -1,450 +0,0 @@
--/* (PD) 2001 The Bitzi Corporation
-- * Please see file COPYING or http://bitzi.com/publicdomain
-- * for more info.
-- *
-- * NIST Secure Hash Algorithm
-- * heavily modified by Uwe Hollerbach <uh@alumni.caltech edu>
-- * from Peter C. Gutmann's implementation as found in
-- * Applied Cryptography by Bruce Schneier
-- * Further modifications to include the "UNRAVEL" stuff, below
-- *
-- * This code is in the public domain
-- *
-- * $Id: sha1.c,v 1.2 2008-02-27 10:42:08 slomo Exp $
-- */
--
--#ifdef HAVE_CONFIG_H
--#include "config.h"
--#endif
--#include <glib.h>
--#define SHA_BYTE_ORDER G_BYTE_ORDER
--
--#include <string.h>
--#include "sha1.h"
--
--/* UNRAVEL should be fastest & biggest */
--/* UNROLL_LOOPS should be just as big, but slightly slower */
--/* both undefined should be smallest and slowest */
--
--#define UNRAVEL
--/* #define UNROLL_LOOPS */
--
--/* SHA f()-functions */
--
--#define f1(x,y,z) ((x & y) | (~x & z))
--#define f2(x,y,z) (x ^ y ^ z)
--#define f3(x,y,z) ((x & y) | (x & z) | (y & z))
--#define f4(x,y,z) (x ^ y ^ z)
--
--/* SHA constants */
--
--#define CONST1 0x5a827999L
--#define CONST2 0x6ed9eba1L
--#define CONST3 0x8f1bbcdcL
--#define CONST4 0xca62c1d6L
--
--/* truncate to 32 bits -- should be a null op on 32-bit machines */
--
--#define T32(x) ((x) & 0xffffffffL)
--
--/* 32-bit rotate */
--
--#define R32(x,n) T32(((x << n) | (x >> (32 - n))))
--
--/* the generic case, for when the overall rotation is not unraveled */
--
--#define FG(n) \
-- T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); \
-- E = D; D = C; C = R32(B,30); B = A; A = T
--
--/* specific cases, for when the overall rotation is unraveled */
--
--#define FA(n) \
-- T = T32(R32(A,5) + f##n(B,C,D) + E + *WP++ + CONST##n); B = R32(B,30)
--
--#define FB(n) \
-- E = T32(R32(T,5) + f##n(A,B,C) + D + *WP++ + CONST##n); A = R32(A,30)
--
--#define FC(n) \
-- D = T32(R32(E,5) + f##n(T,A,B) + C + *WP++ + CONST##n); T = R32(T,30)
--
--#define FD(n) \
-- C = T32(R32(D,5) + f##n(E,T,A) + B + *WP++ + CONST##n); E = R32(E,30)
--
--#define FE(n) \
-- B = T32(R32(C,5) + f##n(D,E,T) + A + *WP++ + CONST##n); D = R32(D,30)
--
--#define FT(n) \
-- A = T32(R32(B,5) + f##n(C,D,E) + T + *WP++ + CONST##n); C = R32(C,30)
--
--/* do SHA transformation */
--
--static void
--sha_transform (SHA_INFO * sha_info)
--{
-- int i;
-- SHA_BYTE *dp;
-- SHA_LONG T, A, B, C, D, E, W[80], *WP;
--
-- dp = sha_info->data;
--
--/*
--the following makes sure that at least one code block below is
--traversed or an error is reported, without the necessity for nested
--preprocessor if/else/endif blocks, which are a great pain in the
--nether regions of the anatomy...
--*/
--#undef SWAP_DONE
--
--#if (SHA_BYTE_ORDER == 1234)
--#define SWAP_DONE
-- for (i = 0; i < 16; ++i) {
-- memcpy (&T, dp, sizeof (SHA_LONG));
-- dp += 4;
-- W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
-- ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
-- }
--#endif /* SHA_BYTE_ORDER == 1234 */
--
--#if (SHA_BYTE_ORDER == 4321)
--#define SWAP_DONE
-- for (i = 0; i < 16; ++i) {
-- memcpy (&T, dp, sizeof (SHA_LONG));
-- dp += 4;
-- W[i] = T32 (T);
-- }
--#endif /* SHA_BYTE_ORDER == 4321 */
--
--#if (SHA_BYTE_ORDER == 12345678)
--#define SWAP_DONE
-- for (i = 0; i < 16; i += 2) {
-- memcpy (&T, dp, sizeof (SHA_LONG));
-- dp += 8;
-- W[i] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
-- ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
-- T >>= 32;
-- W[i + 1] = ((T << 24) & 0xff000000) | ((T << 8) & 0x00ff0000) |
-- ((T >> 8) & 0x0000ff00) | ((T >> 24) & 0x000000ff);
-- }
--#endif /* SHA_BYTE_ORDER == 12345678 */
--
--#if (SHA_BYTE_ORDER == 87654321)
--#define SWAP_DONE
-- for (i = 0; i < 16; i += 2) {
-- memcpy (&T, dp, sizeof (SHA_LONG));
-- dp += 8;
-- W[i] = T32 (T >> 32);
-- W[i + 1] = T32 (T);
-- }
--#endif /* SHA_BYTE_ORDER == 87654321 */
--
--#ifndef SWAP_DONE
--#error Unknown byte order -- you need to add code here
--#endif /* SWAP_DONE */
--
-- for (i = 16; i < 80; ++i) {
-- W[i] = W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16];
--#if (SHA_VERSION == 1)
-- W[i] = R32 (W[i], 1);
--#endif /* SHA_VERSION */
-- }
-- A = sha_info->digest[0];
-- B = sha_info->digest[1];
-- C = sha_info->digest[2];
-- D = sha_info->digest[3];
-- E = sha_info->digest[4];
-- WP = W;
--#ifdef UNRAVEL
-- FA (1);
-- FB (1);
-- FC (1);
-- FD (1);
-- FE (1);
-- FT (1);
-- FA (1);
-- FB (1);
-- FC (1);
-- FD (1);
-- FE (1);
-- FT (1);
-- FA (1);
-- FB (1);
-- FC (1);
-- FD (1);
-- FE (1);
-- FT (1);
-- FA (1);
-- FB (1);
-- FC (2);
-- FD (2);
-- FE (2);
-- FT (2);
-- FA (2);
-- FB (2);
-- FC (2);
-- FD (2);
-- FE (2);
-- FT (2);
-- FA (2);
-- FB (2);
-- FC (2);
-- FD (2);
-- FE (2);
-- FT (2);
-- FA (2);
-- FB (2);
-- FC (2);
-- FD (2);
-- FE (3);
-- FT (3);
-- FA (3);
-- FB (3);
-- FC (3);
-- FD (3);
-- FE (3);
-- FT (3);
-- FA (3);
-- FB (3);
-- FC (3);
-- FD (3);
-- FE (3);
-- FT (3);
-- FA (3);
-- FB (3);
-- FC (3);
-- FD (3);
-- FE (3);
-- FT (3);
-- FA (4);
-- FB (4);
-- FC (4);
-- FD (4);
-- FE (4);
-- FT (4);
-- FA (4);
-- FB (4);
-- FC (4);
-- FD (4);
-- FE (4);
-- FT (4);
-- FA (4);
-- FB (4);
-- FC (4);
-- FD (4);
-- FE (4);
-- FT (4);
-- FA (4);
-- FB (4);
-- sha_info->digest[0] = T32 (sha_info->digest[0] + E);
-- sha_info->digest[1] = T32 (sha_info->digest[1] + T);
-- sha_info->digest[2] = T32 (sha_info->digest[2] + A);
-- sha_info->digest[3] = T32 (sha_info->digest[3] + B);
-- sha_info->digest[4] = T32 (sha_info->digest[4] + C);
--#else /* !UNRAVEL */
--#ifdef UNROLL_LOOPS
-- FG (1);
-- FG (1);
-- FG (1);
-- FG (1);
-- FG (1);
-- FG (1);
-- FG (1);
-- FG (1);
-- FG (1);
-- FG (1);
-- FG (1);
-- FG (1);
-- FG (1);
-- FG (1);
-- FG (1);
-- FG (1);
-- FG (1);
-- FG (1);
-- FG (1);
-- FG (1);
-- FG (2);
-- FG (2);
-- FG (2);
-- FG (2);
-- FG (2);
-- FG (2);
-- FG (2);
-- FG (2);
-- FG (2);
-- FG (2);
-- FG (2);
-- FG (2);
-- FG (2);
-- FG (2);
-- FG (2);
-- FG (2);
-- FG (2);
-- FG (2);
-- FG (2);
-- FG (2);
-- FG (3);
-- FG (3);
-- FG (3);
-- FG (3);
-- FG (3);
-- FG (3);
-- FG (3);
-- FG (3);
-- FG (3);
-- FG (3);
-- FG (3);
-- FG (3);
-- FG (3);
-- FG (3);
-- FG (3);
-- FG (3);
-- FG (3);
-- FG (3);
-- FG (3);
-- FG (3);
-- FG (4);
-- FG (4);
-- FG (4);
-- FG (4);
-- FG (4);
-- FG (4);
-- FG (4);
-- FG (4);
-- FG (4);
-- FG (4);
-- FG (4);
-- FG (4);
-- FG (4);
-- FG (4);
-- FG (4);
-- FG (4);
-- FG (4);
-- FG (4);
-- FG (4);
-- FG (4);
--#else /* !UNROLL_LOOPS */
-- for (i = 0; i < 20; ++i) {
-- FG (1);
-- }
-- for (i = 20; i < 40; ++i) {
-- FG (2);
-- }
-- for (i = 40; i < 60; ++i) {
-- FG (3);
-- }
-- for (i = 60; i < 80; ++i) {
-- FG (4);
-- }
--#endif /* !UNROLL_LOOPS */
-- sha_info->digest[0] = T32 (sha_info->digest[0] + A);
-- sha_info->digest[1] = T32 (sha_info->digest[1] + B);
-- sha_info->digest[2] = T32 (sha_info->digest[2] + C);
-- sha_info->digest[3] = T32 (sha_info->digest[3] + D);
-- sha_info->digest[4] = T32 (sha_info->digest[4] + E);
--#endif /* !UNRAVEL */
--}
--
--/* initialize the SHA digest */
--
--void
--sha_init (SHA_INFO * sha_info)
--{
-- sha_info->digest[0] = 0x67452301L;
-- sha_info->digest[1] = 0xefcdab89L;
-- sha_info->digest[2] = 0x98badcfeL;
-- sha_info->digest[3] = 0x10325476L;
-- sha_info->digest[4] = 0xc3d2e1f0L;
-- sha_info->count_lo = 0L;
-- sha_info->count_hi = 0L;
-- sha_info->local = 0;
--}
--
--/* update the SHA digest */
--
--void
--sha_update (SHA_INFO * sha_info, SHA_BYTE * buffer, int count)
--{
-- int i;
-- SHA_LONG clo;
--
-- clo = T32 (sha_info->count_lo + ((SHA_LONG) count << 3));
-- if (clo < sha_info->count_lo) {
-- ++sha_info->count_hi;
-- }
-- sha_info->count_lo = clo;
-- sha_info->count_hi += (SHA_LONG) count >> 29;
-- if (sha_info->local) {
-- i = SHA_BLOCKSIZE - sha_info->local;
-- if (i > count) {
-- i = count;
-- }
-- memcpy (((SHA_BYTE *) sha_info->data) + sha_info->local, buffer, i);
-- count -= i;
-- buffer += i;
-- sha_info->local += i;
-- if (sha_info->local == SHA_BLOCKSIZE) {
-- sha_transform (sha_info);
-- } else {
-- return;
-- }
-- }
-- while (count >= SHA_BLOCKSIZE) {
-- memcpy (sha_info->data, buffer, SHA_BLOCKSIZE);
-- buffer += SHA_BLOCKSIZE;
-- count -= SHA_BLOCKSIZE;
-- sha_transform (sha_info);
-- }
-- memcpy (sha_info->data, buffer, count);
-- sha_info->local = count;
--}
--
--/* finish computing the SHA digest */
--
--void
--sha_final (unsigned char digest[20], SHA_INFO * sha_info)
--{
-- int count;
-- SHA_LONG lo_bit_count, hi_bit_count;
--
-- lo_bit_count = sha_info->count_lo;
-- hi_bit_count = sha_info->count_hi;
-- count = (int) ((lo_bit_count >> 3) & 0x3f);
-- ((SHA_BYTE *) sha_info->data)[count++] = 0x80;
-- if (count > SHA_BLOCKSIZE - 8) {
-- memset (((SHA_BYTE *) sha_info->data) + count, 0, SHA_BLOCKSIZE - count);
-- sha_transform (sha_info);
-- memset ((SHA_BYTE *) sha_info->data, 0, SHA_BLOCKSIZE - 8);
-- } else {
-- memset (((SHA_BYTE *) sha_info->data) + count, 0,
-- SHA_BLOCKSIZE - 8 - count);
-- }
-- sha_info->data[56] = (unsigned char) ((hi_bit_count >> 24) & 0xff);
-- sha_info->data[57] = (unsigned char) ((hi_bit_count >> 16) & 0xff);
-- sha_info->data[58] = (unsigned char) ((hi_bit_count >> 8) & 0xff);
-- sha_info->data[59] = (unsigned char) ((hi_bit_count >> 0) & 0xff);
-- sha_info->data[60] = (unsigned char) ((lo_bit_count >> 24) & 0xff);
-- sha_info->data[61] = (unsigned char) ((lo_bit_count >> 16) & 0xff);
-- sha_info->data[62] = (unsigned char) ((lo_bit_count >> 8) & 0xff);
-- sha_info->data[63] = (unsigned char) ((lo_bit_count >> 0) & 0xff);
-- sha_transform (sha_info);
-- digest[0] = (unsigned char) ((sha_info->digest[0] >> 24) & 0xff);
-- digest[1] = (unsigned char) ((sha_info->digest[0] >> 16) & 0xff);
-- digest[2] = (unsigned char) ((sha_info->digest[0] >> 8) & 0xff);
-- digest[3] = (unsigned char) ((sha_info->digest[0]) & 0xff);
-- digest[4] = (unsigned char) ((sha_info->digest[1] >> 24) & 0xff);
-- digest[5] = (unsigned char) ((sha_info->digest[1] >> 16) & 0xff);
-- digest[6] = (unsigned char) ((sha_info->digest[1] >> 8) & 0xff);
-- digest[7] = (unsigned char) ((sha_info->digest[1]) & 0xff);
-- digest[8] = (unsigned char) ((sha_info->digest[2] >> 24) & 0xff);
-- digest[9] = (unsigned char) ((sha_info->digest[2] >> 16) & 0xff);
-- digest[10] = (unsigned char) ((sha_info->digest[2] >> 8) & 0xff);
-- digest[11] = (unsigned char) ((sha_info->digest[2]) & 0xff);
-- digest[12] = (unsigned char) ((sha_info->digest[3] >> 24) & 0xff);
-- digest[13] = (unsigned char) ((sha_info->digest[3] >> 16) & 0xff);
-- digest[14] = (unsigned char) ((sha_info->digest[3] >> 8) & 0xff);
-- digest[15] = (unsigned char) ((sha_info->digest[3]) & 0xff);
-- digest[16] = (unsigned char) ((sha_info->digest[4] >> 24) & 0xff);
-- digest[17] = (unsigned char) ((sha_info->digest[4] >> 16) & 0xff);
-- digest[18] = (unsigned char) ((sha_info->digest[4] >> 8) & 0xff);
-- digest[19] = (unsigned char) ((sha_info->digest[4]) & 0xff);
--}
-Index: sha1.h
-===================================================================
-RCS file: sha1.h
-diff -N sha1.h
---- sha1.h 13 Dec 2007 10:10:35 -0000 1.2
-+++ /dev/null 1 Jan 1970 00:00:00 -0000
-@@ -1,62 +0,0 @@
--/* NIST Secure Hash Algorithm */
--/* heavily modified by Uwe Hollerbach <uh@alumni.caltech edu> */
--/* from Peter C. Gutmann's implementation as found in */
--/* Applied Cryptography by Bruce Schneier */
--/* This code is in the public domain */
--/* $Id: sha1.h,v 1.2 2007-12-13 10:10:35 tpm Exp $ */
--
--#ifndef __GST_CDDA_SHA_H__
--#define __GST_CDDA_SHA_H__
--
--#include <stdlib.h>
--#include <stdio.h>
--
--/* Useful defines & typedefs */
--typedef unsigned char SHA_BYTE; /* 8-bit quantity */
--typedef unsigned long SHA_LONG; /* 32-or-more-bit quantity */
--
--#define SHA_BLOCKSIZE 64
--#define SHA_DIGESTSIZE 20
--
--typedef struct {
-- SHA_LONG digest[5]; /* message digest */
-- SHA_LONG count_lo, count_hi; /* 64-bit bit count */
-- SHA_BYTE data[SHA_BLOCKSIZE]; /* SHA data buffer */
-- int local; /* unprocessed amount in data */
--} SHA_INFO;
--
--#define sha_init __gst_cdda_sha_init
--#define sha_update __gst_cdda_sha_update
--#define sha_final __gst_cdda_sha_final
--
--void sha_init(SHA_INFO *);
--void sha_update(SHA_INFO *, SHA_BYTE *, int);
--void sha_final(unsigned char [20], SHA_INFO *);
--
--#define SHA_VERSION 1
--
--#ifdef HAVE_CONFIG_H
--#include "config.h"
--
--
--#ifdef WORDS_BIGENDIAN
--# if SIZEOF_LONG == 4
--# define SHA_BYTE_ORDER 4321
--# elif SIZEOF_LONG == 8
--# define SHA_BYTE_ORDER 87654321
--# endif
--#else
--# if SIZEOF_LONG == 4
--# define SHA_BYTE_ORDER 1234
--# elif SIZEOF_LONG == 8
--# define SHA_BYTE_ORDER 12345678
--# endif
--#endif
--
--#else
--
--#define SHA_BYTE_ORDER 1234
--
--#endif
--
--#endif /* __GST_CDDA_SHA_H__ */
+++ /dev/null
-/* GStreamer
- * Copyright (C) 1999 Erik Walthinsen <omega@cse.ogi.edu>
- * Copyright (C) 2005 Tim-Philipp Müller <tim centricular net>
- *
- * 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.
- */
-
-/* TODO:
- *
- * - in ::start(), we want to post a tags message with an array or a list
- * of tagslists of all tracks, so that applications know at least the
- * number of tracks and all track durations immediately without having
- * to do any querying. We have to decide what type and name to use for
- * this array of track taglists.
- *
- * - FIX cddb discid calculation algorithm for mixed mode CDs - do we use
- * offsets and duration of ALL tracks (data + audio) for the CDDB ID
- * calculation, or only audio tracks?
- *
- * - Do we really need properties for the TOC bias/offset stuff? Wouldn't
- * environment variables make much more sense? Do we need this at all
- * (does it only affect ancient hardware?)
- */
-
-/**
- * SECTION:gstcddabasesrc
- * @short_description: Base class for CD digital audio (CDDA) sources
- *
- * <refsect2>
- * <para>
- * Provides a base class for CDDA sources, which handles things like seeking,
- * querying, discid calculation, tags, and buffer timestamping.
- * </para>
- * <title>Using GstCddaBaseSrc-based elements in applications</title>
- * <para>
- * GstCddaBaseSrc registers two #GstFormat<!-- -->s of its own, namely
- * the "track" format and the "sector" format. Applications will usually
- * only find the "track" format interesting. You can retrieve that #GstFormat
- * for use in seek events or queries with gst_format_get_by_nick("track").
- * </para>
- * <para>
- * In order to query the number of tracks, for example, an application would
- * set the CDDA source element to READY or PAUSED state and then query the
- * the number of tracks via gst_element_query_duration() using the track
- * format acquired above. Applications can query the currently playing track
- * in the same way.
- * </para>
- * <para>
- * Alternatively, applications may retrieve the currently playing track and
- * the total number of tracks from the taglist that will posted on the bus
- * whenever the CD is opened or the currently playing track changes. The
- * taglist will contain GST_TAG_TRACK_NUMBER and GST_TAG_TRACK_COUNT tags.
- * </para>
- * <para>
- * Applications playing back CD audio using playbin and cdda://n URIs should
- * issue a seek command in track format to change between tracks, rather than
- * setting a new cdda://n+1 URI on playbin (as setting a new URI on playbin
- * involves closing and re-opening the CD device, which is much much slower).
- * </para>
- * <title>Tags and meta-information</title>
- * <para>
- * CDDA sources will automatically emit a number of tags, details about which
- * can be found in the libgsttag documentation. Those tags are:
- * #GST_TAG_CDDA_CDDB_DISCID, #GST_TAG_CDDA_CDDB_DISCID_FULL,
- * #GST_TAG_CDDA_MUSICBRAINZ_DISCID, #GST_TAG_CDDA_MUSICBRAINZ_DISCID_FULL,
- * among others.
- * </para>
- * </refsect2>
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <string.h>
-#include <stdlib.h> /* for strtol */
-
-#include "gstcddabasesrc.h"
-#include "gst/gst-i18n-plugin.h"
-
-GST_DEBUG_CATEGORY_STATIC (gst_cdda_base_src_debug);
-#define GST_CAT_DEFAULT gst_cdda_base_src_debug
-
-#define DEFAULT_DEVICE "/dev/cdrom"
-
-#define CD_FRAMESIZE_RAW (2352)
-
-#define SECTORS_PER_SECOND (75)
-#define SECTORS_PER_MINUTE (75*60)
-#define SAMPLES_PER_SECTOR (CD_FRAMESIZE_RAW >> 2)
-#define TIME_INTERVAL_FROM_SECTORS(sectors) ((SAMPLES_PER_SECTOR * sectors * GST_SECOND) / 44100)
-#define SECTORS_FROM_TIME_INTERVAL(dtime) (dtime * 44100 / (SAMPLES_PER_SECTOR * GST_SECOND))
-
-enum
-{
- ARG_0,
- ARG_MODE,
- ARG_DEVICE,
- ARG_TRACK,
- ARG_TOC_OFFSET,
- ARG_TOC_BIAS
-};
-
-static void gst_cdda_base_src_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-static void gst_cdda_base_src_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_cdda_base_src_finalize (GObject * obj);
-static const GstQueryType *gst_cdda_base_src_get_query_types (GstPad * pad);
-static gboolean gst_cdda_base_src_query (GstBaseSrc * src, GstQuery * query);
-static gboolean gst_cdda_base_src_handle_event (GstBaseSrc * basesrc,
- GstEvent * event);
-static gboolean gst_cdda_base_src_do_seek (GstBaseSrc * basesrc,
- GstSegment * segment);
-static void gst_cdda_base_src_setup_interfaces (GType type);
-static gboolean gst_cdda_base_src_start (GstBaseSrc * basesrc);
-static gboolean gst_cdda_base_src_stop (GstBaseSrc * basesrc);
-static GstFlowReturn gst_cdda_base_src_create (GstPushSrc * pushsrc,
- GstBuffer ** buf);
-static gboolean gst_cdda_base_src_is_seekable (GstBaseSrc * basesrc);
-static void gst_cdda_base_src_update_duration (GstCddaBaseSrc * src);
-static void gst_cdda_base_src_set_index (GstElement * src, GstIndex * index);
-static GstIndex *gst_cdda_base_src_get_index (GstElement * src);
-
-GST_BOILERPLATE_FULL (GstCddaBaseSrc, gst_cdda_base_src, GstPushSrc,
- GST_TYPE_PUSH_SRC, gst_cdda_base_src_setup_interfaces);
-
-#define SRC_CAPS \
- "audio/x-raw-int, " \
- "endianness = (int) BYTE_ORDER, " \
- "signed = (boolean) true, " \
- "width = (int) 16, " \
- "depth = (int) 16, " \
- "rate = (int) 44100, " \
- "channels = (int) 2" \
-
-static GstStaticPadTemplate gst_cdda_base_src_src_template =
-GST_STATIC_PAD_TEMPLATE ("src",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
- GST_STATIC_CAPS (SRC_CAPS)
- );
-
-/* our two formats */
-static GstFormat track_format;
-static GstFormat sector_format;
-
-GType
-gst_cdda_base_src_mode_get_type (void)
-{
- static GType mode_type; /* 0 */
- static const GEnumValue modes[] = {
- {GST_CDDA_BASE_SRC_MODE_NORMAL, "Stream consists of a single track",
- "normal"},
- {GST_CDDA_BASE_SRC_MODE_CONTINUOUS, "Stream consists of the whole disc",
- "continuous"},
- {0, NULL, NULL}
- };
-
- if (mode_type == 0)
- mode_type = g_enum_register_static ("GstCddaBaseSrcMode", modes);
-
- return mode_type;
-}
-
-static void
-gst_cdda_base_src_base_init (gpointer g_class)
-{
- GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
-
- gst_element_class_add_pad_template (element_class,
- gst_static_pad_template_get (&gst_cdda_base_src_src_template));
-
- /* our very own formats */
- track_format = gst_format_register ("track", "CD track");
- sector_format = gst_format_register ("sector", "CD sector");
-
- /* register CDDA tags */
- gst_tag_register_musicbrainz_tags ();
-
-#if 0
- ///// FIXME: what type to use here? ///////
- gst_tag_register (GST_TAG_CDDA_TRACK_TAGS, GST_TAG_FLAG_META, GST_TYPE_TAG_LIST, "track-tags", "CDDA taglist for one track", gst_tag_merge_use_first); ///////////// FIXME: right function??? ///////
-#endif
-
- GST_DEBUG_CATEGORY_INIT (gst_cdda_base_src_debug, "cddabasesrc", 0,
- "CDDA Base Source");
-}
-
-static void
-gst_cdda_base_src_class_init (GstCddaBaseSrcClass * klass)
-{
- GstElementClass *element_class;
- GstPushSrcClass *pushsrc_class;
- GstBaseSrcClass *basesrc_class;
- GObjectClass *gobject_class;
-
- gobject_class = (GObjectClass *) klass;
- element_class = (GstElementClass *) klass;
- basesrc_class = (GstBaseSrcClass *) klass;
- pushsrc_class = (GstPushSrcClass *) klass;
-
- gobject_class->set_property = gst_cdda_base_src_set_property;
- gobject_class->get_property = gst_cdda_base_src_get_property;
- gobject_class->finalize = gst_cdda_base_src_finalize;
-
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_DEVICE,
- g_param_spec_string ("device", "Device", "CD device location",
- NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_MODE,
- g_param_spec_enum ("mode", "Mode", "Mode", GST_TYPE_CDDA_BASE_SRC_MODE,
- GST_CDDA_BASE_SRC_MODE_NORMAL,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TRACK,
- g_param_spec_uint ("track", "Track", "Track", 1, 99, 1,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
-#if 0
- /* Do we really need this toc adjustment stuff as properties? does the user
- * have a chance to set it in practice, e.g. when using sound-juicer, rb,
- * totem, whatever? Shouldn't we rather use environment variables
- * for this? (tpm) */
-
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TOC_OFFSET,
- g_param_spec_int ("toc-offset", "Table of contents offset",
- "Add <n> sectors to the values reported", G_MININT, G_MAXINT, 0,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_TOC_BIAS,
- g_param_spec_boolean ("toc-bias", "Table of contents bias",
- "Assume that the beginning offset of track 1 as reported in the TOC "
- "will be addressed as LBA 0. Necessary for some Toshiba drives to "
- "get track boundaries", FALSE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-#endif
-
- element_class->set_index = GST_DEBUG_FUNCPTR (gst_cdda_base_src_set_index);
- element_class->get_index = GST_DEBUG_FUNCPTR (gst_cdda_base_src_get_index);
-
- basesrc_class->start = GST_DEBUG_FUNCPTR (gst_cdda_base_src_start);
- basesrc_class->stop = GST_DEBUG_FUNCPTR (gst_cdda_base_src_stop);
- basesrc_class->query = GST_DEBUG_FUNCPTR (gst_cdda_base_src_query);
- basesrc_class->event = GST_DEBUG_FUNCPTR (gst_cdda_base_src_handle_event);
- basesrc_class->do_seek = GST_DEBUG_FUNCPTR (gst_cdda_base_src_do_seek);
- basesrc_class->is_seekable =
- GST_DEBUG_FUNCPTR (gst_cdda_base_src_is_seekable);
-
- pushsrc_class->create = GST_DEBUG_FUNCPTR (gst_cdda_base_src_create);
-}
-
-static void
-gst_cdda_base_src_init (GstCddaBaseSrc * src, GstCddaBaseSrcClass * klass)
-{
- gst_pad_set_query_type_function (GST_BASE_SRC_PAD (src),
- GST_DEBUG_FUNCPTR (gst_cdda_base_src_get_query_types));
-
- /* we're not live and we operate in time */
- gst_base_src_set_format (GST_BASE_SRC (src), GST_FORMAT_TIME);
- gst_base_src_set_live (GST_BASE_SRC (src), FALSE);
-
- src->device = NULL;
- src->mode = GST_CDDA_BASE_SRC_MODE_NORMAL;
- src->uri_track = -1;
-}
-
-static void
-gst_cdda_base_src_finalize (GObject * obj)
-{
- GstCddaBaseSrc *cddasrc = GST_CDDA_BASE_SRC (obj);
-
- g_free (cddasrc->uri);
- g_free (cddasrc->device);
-
- G_OBJECT_CLASS (parent_class)->finalize (obj);
-}
-
-static void
-gst_cdda_base_src_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (object);
-
- GST_OBJECT_LOCK (src);
-
- switch (prop_id) {
- case ARG_MODE:{
- src->mode = g_value_get_enum (value);
- break;
- }
- case ARG_DEVICE:{
- const gchar *dev = g_value_get_string (value);
-
- g_free (src->device);
- if (dev && *dev) {
- src->device = g_strdup (dev);
- } else {
- src->device = NULL;
- }
- break;
- }
- case ARG_TRACK:{
- guint track = g_value_get_uint (value);
-
- if (src->num_tracks > 0 && track > src->num_tracks) {
- g_warning ("Invalid track %u", track);
- } else if (track > 0 && src->tracks != NULL) {
- src->cur_sector = src->tracks[track - 1].start;
- src->uri_track = track;
- } else {
- src->uri_track = track; /* seek will be done in start() */
- }
- break;
- }
- case ARG_TOC_OFFSET:{
- src->toc_offset = g_value_get_int (value);
- break;
- }
- case ARG_TOC_BIAS:{
- src->toc_bias = g_value_get_boolean (value);
- break;
- }
- default:{
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
- }
-
- GST_OBJECT_UNLOCK (src);
-}
-
-static void
-gst_cdda_base_src_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstCddaBaseSrcClass *klass = GST_CDDA_BASE_SRC_GET_CLASS (object);
- GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (object);
-
- GST_OBJECT_LOCK (src);
-
- switch (prop_id) {
- case ARG_MODE:
- g_value_set_enum (value, src->mode);
- break;
- case ARG_DEVICE:{
- if (src->device == NULL && klass->get_default_device != NULL) {
- gchar *d = klass->get_default_device (src);
-
- if (d != NULL) {
- g_value_set_string (value, DEFAULT_DEVICE);
- g_free (d);
- break;
- }
- }
- if (src->device == NULL)
- g_value_set_string (value, DEFAULT_DEVICE);
- else
- g_value_set_string (value, src->device);
- break;
- }
- case ARG_TRACK:{
- if (src->num_tracks <= 0 && src->uri_track > 0) {
- g_value_set_uint (value, src->uri_track);
- } else {
- g_value_set_uint (value, src->cur_track + 1);
- }
- break;
- }
- case ARG_TOC_OFFSET:
- g_value_set_int (value, src->toc_offset);
- break;
- case ARG_TOC_BIAS:
- g_value_set_boolean (value, src->toc_bias);
- break;
- default:{
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
- }
-
- GST_OBJECT_UNLOCK (src);
-}
-
-static gint
-gst_cdda_base_src_get_track_from_sector (GstCddaBaseSrc * src, gint sector)
-{
- gint i;
-
- for (i = 0; i < src->num_tracks; ++i) {
- if (sector >= src->tracks[i].start && sector <= src->tracks[i].end)
- return i;
- }
- return -1;
-}
-
-static const GstQueryType *
-gst_cdda_base_src_get_query_types (GstPad * pad)
-{
- static const GstQueryType src_query_types[] = {
- GST_QUERY_DURATION,
- GST_QUERY_POSITION,
- GST_QUERY_CONVERT,
- 0
- };
-
- return src_query_types;
-}
-
-static gboolean
-gst_cdda_base_src_convert (GstCddaBaseSrc * src, GstFormat src_format,
- gint64 src_val, GstFormat dest_format, gint64 * dest_val)
-{
- gboolean started;
-
- GST_LOG_OBJECT (src, "converting value %" G_GINT64_FORMAT " from %s into %s",
- src_val, gst_format_get_name (src_format),
- gst_format_get_name (dest_format));
-
- if (src_format == dest_format) {
- *dest_val = src_val;
- return TRUE;
- }
-
- started = GST_OBJECT_FLAG_IS_SET (GST_BASE_SRC (src), GST_BASE_SRC_STARTED);
-
- if (src_format == track_format) {
- if (!started)
- goto not_started;
- if (src_val < 0 || src_val >= src->num_tracks) {
- GST_DEBUG_OBJECT (src, "track number %d out of bounds", (gint) src_val);
- goto wrong_value;
- }
- src_format = GST_FORMAT_DEFAULT;
- src_val = src->tracks[src_val].start * SAMPLES_PER_SECTOR;
- } else if (src_format == sector_format) {
- src_format = GST_FORMAT_DEFAULT;
- src_val = src_val * SAMPLES_PER_SECTOR;
- }
-
- if (src_format == dest_format) {
- *dest_val = src_val;
- goto done;
- }
-
- switch (src_format) {
- case GST_FORMAT_BYTES:
- /* convert to samples (4 bytes per sample) */
- src_val = src_val >> 2;
- /* fallthrough */
- case GST_FORMAT_DEFAULT:{
- switch (dest_format) {
- case GST_FORMAT_BYTES:{
- if (src_val < 0) {
- GST_DEBUG_OBJECT (src, "sample source value negative");
- goto wrong_value;
- }
- *dest_val = src_val << 2; /* 4 bytes per sample */
- break;
- }
- case GST_FORMAT_TIME:{
- *dest_val = gst_util_uint64_scale_int (src_val, GST_SECOND, 44100);
- break;
- }
- default:{
- gint64 sector = src_val / SAMPLES_PER_SECTOR;
-
- if (dest_format == sector_format) {
- *dest_val = sector;
- } else if (dest_format == track_format) {
- if (!started)
- goto not_started;
- *dest_val = gst_cdda_base_src_get_track_from_sector (src, sector);
- } else {
- goto unknown_format;
- }
- break;
- }
- }
- break;
- }
- case GST_FORMAT_TIME:{
- gint64 sample_offset;
-
- if (src_val == GST_CLOCK_TIME_NONE) {
- GST_DEBUG_OBJECT (src, "source time value invalid");
- goto wrong_value;
- }
-
- sample_offset = gst_util_uint64_scale_int (src_val, 44100, GST_SECOND);
- switch (dest_format) {
- case GST_FORMAT_BYTES:{
- *dest_val = sample_offset << 2; /* 4 bytes per sample */
- break;
- }
- case GST_FORMAT_DEFAULT:{
- *dest_val = sample_offset;
- break;
- }
- default:{
- gint64 sector = sample_offset / SAMPLES_PER_SECTOR;
-
- if (dest_format == sector_format) {
- *dest_val = sector;
- } else if (dest_format == track_format) {
- if (!started)
- goto not_started;
- *dest_val = gst_cdda_base_src_get_track_from_sector (src, sector);
- } else {
- goto unknown_format;
- }
- break;
- }
- }
- break;
- }
- default:{
- goto unknown_format;
- }
- }
-
-done:
- {
- GST_LOG_OBJECT (src, "returning %" G_GINT64_FORMAT, *dest_val);
- return TRUE;
- }
-
-unknown_format:
- {
- GST_DEBUG_OBJECT (src, "conversion failed: %s", "unsupported format");
- return FALSE;
- }
-
-wrong_value:
- {
- GST_DEBUG_OBJECT (src, "conversion failed: %s",
- "source value not within allowed range");
- return FALSE;
- }
-
-not_started:
- {
- GST_DEBUG_OBJECT (src, "conversion failed: %s",
- "cannot do this conversion, device not open");
- return FALSE;
- }
-}
-
-static gboolean
-gst_cdda_base_src_query (GstBaseSrc * basesrc, GstQuery * query)
-{
- GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (basesrc);
- gboolean started;
-
- started = GST_OBJECT_FLAG_IS_SET (basesrc, GST_BASE_SRC_STARTED);
-
- GST_LOG_OBJECT (src, "handling %s query",
- gst_query_type_get_name (GST_QUERY_TYPE (query)));
-
- switch (GST_QUERY_TYPE (query)) {
- case GST_QUERY_DURATION:{
- GstFormat dest_format;
- gint64 dest_val;
- guint sectors;
-
- gst_query_parse_duration (query, &dest_format, NULL);
-
- if (!started)
- return FALSE;
-
- g_assert (src->tracks != NULL);
-
- if (dest_format == track_format) {
- GST_LOG_OBJECT (src, "duration: %d tracks", src->num_tracks);
- gst_query_set_duration (query, track_format, src->num_tracks);
- return TRUE;
- }
-
- if (src->cur_track < 0 || src->cur_track >= src->num_tracks)
- return FALSE;
-
- if (src->mode == GST_CDDA_BASE_SRC_MODE_NORMAL) {
- sectors = src->tracks[src->cur_track].end -
- src->tracks[src->cur_track].start + 1;
- } else {
- sectors = src->tracks[src->num_tracks - 1].end -
- src->tracks[0].start + 1;
- }
-
- /* ... and convert into final format */
- if (!gst_cdda_base_src_convert (src, sector_format, sectors,
- dest_format, &dest_val)) {
- return FALSE;
- }
-
- gst_query_set_duration (query, dest_format, dest_val);
-
- GST_LOG ("duration: %u sectors, %" G_GINT64_FORMAT " in format %s",
- sectors, dest_val, gst_format_get_name (dest_format));
- break;
- }
- case GST_QUERY_POSITION:{
- GstFormat dest_format;
- gint64 pos_sector;
- gint64 dest_val;
-
- gst_query_parse_position (query, &dest_format, NULL);
-
- if (!started)
- return FALSE;
-
- g_assert (src->tracks != NULL);
-
- if (dest_format == track_format) {
- GST_LOG_OBJECT (src, "position: track %d", src->cur_track);
- gst_query_set_position (query, track_format, src->cur_track);
- return TRUE;
- }
-
- if (src->cur_track < 0 || src->cur_track >= src->num_tracks)
- return FALSE;
-
- if (src->mode == GST_CDDA_BASE_SRC_MODE_NORMAL) {
- pos_sector = src->cur_sector - src->tracks[src->cur_track].start;
- } else {
- pos_sector = src->cur_sector - src->tracks[0].start;
- }
-
- if (!gst_cdda_base_src_convert (src, sector_format, pos_sector,
- dest_format, &dest_val)) {
- return FALSE;
- }
-
- gst_query_set_position (query, dest_format, dest_val);
-
- GST_LOG ("position: sector %u, %" G_GINT64_FORMAT " in format %s",
- (guint) pos_sector, dest_val, gst_format_get_name (dest_format));
- break;
- }
- case GST_QUERY_CONVERT:{
- GstFormat src_format, dest_format;
- gint64 src_val, dest_val;
-
- gst_query_parse_convert (query, &src_format, &src_val, &dest_format,
- NULL);
-
- if (!gst_cdda_base_src_convert (src, src_format, src_val, dest_format,
- &dest_val)) {
- return FALSE;
- }
-
- gst_query_set_convert (query, src_format, src_val, dest_format, dest_val);
- break;
- }
- default:{
- GST_DEBUG_OBJECT (src, "unhandled query, chaining up to parent class");
- return GST_BASE_SRC_CLASS (parent_class)->query (basesrc, query);
- }
- }
-
- return TRUE;
-}
-
-static gboolean
-gst_cdda_base_src_is_seekable (GstBaseSrc * basesrc)
-{
- return TRUE;
-}
-
-static gboolean
-gst_cdda_base_src_do_seek (GstBaseSrc * basesrc, GstSegment * segment)
-{
- GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (basesrc);
- gint64 seek_sector;
-
- GST_DEBUG_OBJECT (src, "segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
- GST_TIME_ARGS (segment->start), GST_TIME_ARGS (segment->stop));
-
- if (!gst_cdda_base_src_convert (src, GST_FORMAT_TIME, segment->start,
- sector_format, &seek_sector)) {
- GST_WARNING_OBJECT (src, "conversion failed");
- return FALSE;
- }
-
- /* we should only really be called when open */
- g_assert (src->cur_track >= 0 && src->cur_track < src->num_tracks);
-
- switch (src->mode) {
- case GST_CDDA_BASE_SRC_MODE_NORMAL:
- seek_sector += src->tracks[src->cur_track].start;
- break;
- case GST_CDDA_BASE_SRC_MODE_CONTINUOUS:
- seek_sector += src->tracks[0].start;
- break;
- default:
- g_return_val_if_reached (FALSE);
- }
-
- src->cur_sector = (gint) seek_sector;
-
- GST_DEBUG_OBJECT (src, "seek'd to sector %d", src->cur_sector);
-
- return TRUE;
-}
-
-static gboolean
-gst_cdda_base_src_handle_track_seek (GstCddaBaseSrc * src, gdouble rate,
- GstSeekFlags flags, GstSeekType start_type, gint64 start,
- GstSeekType stop_type, gint64 stop)
-{
- GstBaseSrc *basesrc = GST_BASE_SRC (src);
- GstEvent *event;
-
- if ((flags & GST_SEEK_FLAG_SEGMENT) == GST_SEEK_FLAG_SEGMENT) {
- gint64 start_time = -1;
- gint64 stop_time = -1;
-
- if (src->mode != GST_CDDA_BASE_SRC_MODE_CONTINUOUS) {
- GST_DEBUG_OBJECT (src, "segment seek in track format is only "
- "supported in CONTINUOUS mode, not in mode %d", src->mode);
- return FALSE;
- }
-
- switch (start_type) {
- case GST_SEEK_TYPE_SET:
- if (!gst_cdda_base_src_convert (src, track_format, start,
- GST_FORMAT_TIME, &start_time)) {
- GST_DEBUG_OBJECT (src, "cannot convert track %d to time",
- (gint) start);
- return FALSE;
- }
- break;
- case GST_SEEK_TYPE_END:
- if (!gst_cdda_base_src_convert (src, track_format,
- src->num_tracks - start - 1, GST_FORMAT_TIME, &start_time)) {
- GST_DEBUG_OBJECT (src, "cannot convert track %d to time",
- (gint) start);
- return FALSE;
- }
- start_type = GST_SEEK_TYPE_SET;
- break;
- case GST_SEEK_TYPE_NONE:
- start_time = -1;
- break;
- default:
- g_return_val_if_reached (FALSE);
- }
-
- switch (stop_type) {
- case GST_SEEK_TYPE_SET:
- if (!gst_cdda_base_src_convert (src, track_format, stop,
- GST_FORMAT_TIME, &stop_time)) {
- GST_DEBUG_OBJECT (src, "cannot convert track %d to time",
- (gint) stop);
- return FALSE;
- }
- break;
- case GST_SEEK_TYPE_END:
- if (!gst_cdda_base_src_convert (src, track_format,
- src->num_tracks - stop - 1, GST_FORMAT_TIME, &stop_time)) {
- GST_DEBUG_OBJECT (src, "cannot convert track %d to time",
- (gint) stop);
- return FALSE;
- }
- stop_type = GST_SEEK_TYPE_SET;
- break;
- case GST_SEEK_TYPE_NONE:
- stop_time = -1;
- break;
- default:
- g_return_val_if_reached (FALSE);
- }
-
- GST_LOG_OBJECT (src, "seek segment %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
- GST_TIME_ARGS (start_time), GST_TIME_ARGS (stop_time));
-
- /* send fake segment seek event in TIME format to
- * base class, which will hopefully handle the rest */
-
- event = gst_event_new_seek (rate, GST_FORMAT_TIME, flags, start_type,
- start_time, stop_type, stop_time);
-
- return GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event);
- }
-
- /* not a segment seek */
-
- if (start_type == GST_SEEK_TYPE_NONE) {
- GST_LOG_OBJECT (src, "start seek type is NONE, nothing to do");
- return TRUE;
- }
-
- if (stop_type != GST_SEEK_TYPE_NONE) {
- GST_WARNING_OBJECT (src, "ignoring stop seek type (expected NONE)");
- }
-
- if (start < 0 || start >= src->num_tracks) {
- GST_DEBUG_OBJECT (src, "invalid track %" G_GINT64_FORMAT, start);
- return FALSE;
- }
-
- GST_DEBUG_OBJECT (src, "seeking to track %" G_GINT64_FORMAT, start + 1);
-
- src->cur_sector = src->tracks[start].start;
- GST_DEBUG_OBJECT (src, "starting at sector %d", src->cur_sector);
-
- if (src->cur_track != start) {
- src->cur_track = (gint) start;
- src->uri_track = -1;
- src->prev_track = -1;
-
- gst_cdda_base_src_update_duration (src);
- } else {
- GST_DEBUG_OBJECT (src, "is current track, just seeking back to start");
- }
-
- /* send fake segment seek event in TIME format to
- * base class (so we get a newsegment etc.) */
- event = gst_event_new_seek (rate, GST_FORMAT_TIME, flags,
- GST_SEEK_TYPE_SET, 0, GST_SEEK_TYPE_NONE, -1);
-
- return GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event);
-}
-
-static gboolean
-gst_cdda_base_src_handle_event (GstBaseSrc * basesrc, GstEvent * event)
-{
- GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (basesrc);
- gboolean ret = FALSE;
-
- GST_LOG_OBJECT (src, "handling %s event", GST_EVENT_TYPE_NAME (event));
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_SEEK:{
- GstSeekType start_type, stop_type;
- GstSeekFlags flags;
- GstFormat format;
- gdouble rate;
- gint64 start, stop;
-
- if (!GST_OBJECT_FLAG_IS_SET (basesrc, GST_BASE_SRC_STARTED)) {
- GST_DEBUG_OBJECT (src, "seek failed: device not open");
- break;
- }
-
- gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
- &stop_type, &stop);
-
- if (format == sector_format) {
- GST_DEBUG_OBJECT (src, "seek in sector format not supported");
- break;
- }
-
- if (format == track_format) {
- ret = gst_cdda_base_src_handle_track_seek (src, rate, flags,
- start_type, start, stop_type, stop);
- } else {
- GST_LOG_OBJECT (src, "let base class handle seek in %s format",
- gst_format_get_name (format));
- event = gst_event_ref (event);
- ret = GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event);
- }
- break;
- }
- default:{
- GST_LOG_OBJECT (src, "let base class handle event");
- ret = GST_BASE_SRC_CLASS (parent_class)->event (basesrc, event);
- break;
- }
- }
-
- return ret;
-}
-
-static GstURIType
-gst_cdda_base_src_uri_get_type (void)
-{
- return GST_URI_SRC;
-}
-
-static gchar **
-gst_cdda_base_src_uri_get_protocols (void)
-{
- static gchar *protocols[] = { "cdda", NULL };
-
- return protocols;
-}
-
-static const gchar *
-gst_cdda_base_src_uri_get_uri (GstURIHandler * handler)
-{
- GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (handler);
-
- GST_OBJECT_LOCK (src);
-
- g_free (src->uri);
-
- if (GST_OBJECT_FLAG_IS_SET (GST_BASE_SRC (src), GST_BASE_SRC_STARTED)) {
- src->uri = g_strdup_printf ("cdda://%d", src->uri_track);
- } else {
- src->uri = g_strdup ("cdda://1");
- }
-
- GST_OBJECT_UNLOCK (src);
-
- return src->uri;
-}
-
-/* Note: gst_element_make_from_uri() might call us with just 'cdda://' as
- * URI and expects us to return TRUE then (and this might be in any state) */
-
-static gboolean
-gst_cdda_base_src_uri_set_uri (GstURIHandler * handler, const gchar * uri)
-{
- GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (handler);
- gchar *protocol, *location;
-
- GST_OBJECT_LOCK (src);
-
- protocol = gst_uri_get_protocol (uri);
- if (!protocol || strcmp (protocol, "cdda") != 0) {
- g_free (protocol);
- goto failed;
- }
- g_free (protocol);
-
- location = gst_uri_get_location (uri);
- if (location == NULL || *location == '\0') {
- g_free (location);
- location = g_strdup ("1");
- }
-
- src->uri_track = strtol (location, NULL, 10);
- g_free (location);
-
- if (src->uri_track == 0)
- goto failed;
-
- if (src->num_tracks > 0
- && src->tracks != NULL && src->uri_track > src->num_tracks)
- goto failed;
-
- if (src->uri_track > 0 && src->tracks != NULL) {
- GST_OBJECT_UNLOCK (src);
-
- gst_pad_send_event (GST_BASE_SRC_PAD (src),
- gst_event_new_seek (1.0, track_format, GST_SEEK_FLAG_FLUSH,
- GST_SEEK_TYPE_SET, src->uri_track - 1, GST_SEEK_TYPE_NONE, -1));
- } else {
- /* seek will be done in start() */
- GST_OBJECT_UNLOCK (src);
- }
-
- GST_LOG_OBJECT (handler, "successfully handled uri '%s'", uri);
-
- return TRUE;
-
-failed:
- {
- GST_OBJECT_UNLOCK (src);
- GST_DEBUG_OBJECT (src, "cannot handle URI '%s'", uri);
- return FALSE;
- }
-}
-
-static void
-gst_cdda_base_src_uri_handler_init (gpointer g_iface, gpointer iface_data)
-{
- GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
-
- iface->get_type = gst_cdda_base_src_uri_get_type;
- iface->get_uri = gst_cdda_base_src_uri_get_uri;
- iface->set_uri = gst_cdda_base_src_uri_set_uri;
- iface->get_protocols = gst_cdda_base_src_uri_get_protocols;
-}
-
-static void
-gst_cdda_base_src_setup_interfaces (GType type)
-{
- static const GInterfaceInfo urihandler_info = {
- gst_cdda_base_src_uri_handler_init,
- NULL,
- NULL,
- };
-
- g_type_add_interface_static (type, GST_TYPE_URI_HANDLER, &urihandler_info);
-}
-
-/**
- * gst_cdda_base_src_add_track:
- * @src: a #GstCddaBaseSrc
- * @track: address of #GstCddaBaseSrcTrack to add
- *
- * CDDA sources use this function from their start vfunc to announce the
- * available data and audio tracks to the base source class. The caller
- * should allocate @track on the stack, the base source will do a shallow
- * copy of the structure (and take ownership of the taglist if there is one).
- *
- * Returns: FALSE on error, otherwise TRUE.
- */
-
-gboolean
-gst_cdda_base_src_add_track (GstCddaBaseSrc * src, GstCddaBaseSrcTrack * track)
-{
- g_return_val_if_fail (GST_IS_CDDA_BASE_SRC (src), FALSE);
- g_return_val_if_fail (track != NULL, FALSE);
- g_return_val_if_fail (track->num > 0, FALSE);
-
- GST_DEBUG_OBJECT (src, "adding track %2u (%2u) [%6u-%6u] [%5s], tags: %"
- GST_PTR_FORMAT, src->num_tracks + 1, track->num, track->start,
- track->end, (track->is_audio) ? "AUDIO" : "DATA ", track->tags);
-
- if (src->num_tracks > 0) {
- guint end_of_previous_track = src->tracks[src->num_tracks - 1].end;
-
- if (track->start <= end_of_previous_track) {
- GST_WARNING ("track %2u overlaps with previous tracks", track->num);
- return FALSE;
- }
- }
-
- GST_OBJECT_LOCK (src);
-
- ++src->num_tracks;
- src->tracks = g_renew (GstCddaBaseSrcTrack, src->tracks, src->num_tracks);
- src->tracks[src->num_tracks - 1] = *track;
-
- GST_OBJECT_UNLOCK (src);
-
- return TRUE;
-}
-
-static void
-gst_cdda_base_src_update_duration (GstCddaBaseSrc * src)
-{
- GstBaseSrc *basesrc;
- GstFormat format;
- gint64 duration;
-
- basesrc = GST_BASE_SRC (src);
-
- format = GST_FORMAT_TIME;
- if (gst_pad_query_duration (GST_BASE_SRC_PAD (src), &format, &duration)) {
- gst_segment_set_duration (&basesrc->segment, GST_FORMAT_TIME, duration);
- } else {
- gst_segment_set_duration (&basesrc->segment, GST_FORMAT_TIME, -1);
- duration = GST_CLOCK_TIME_NONE;
- }
-
- gst_element_post_message (GST_ELEMENT (src),
- gst_message_new_duration (GST_OBJECT (src), GST_FORMAT_TIME, -1));
-
- GST_LOG_OBJECT (src, "duration updated to %" GST_TIME_FORMAT,
- GST_TIME_ARGS (duration));
-}
-
-#define CD_MSF_OFFSET 150
-
-/* the cddb hash function */
-static guint
-cddb_sum (gint n)
-{
- guint ret;
-
- ret = 0;
- while (n > 0) {
- ret += (n % 10);
- n /= 10;
- }
- return ret;
-}
-
-#include "sha1.h"
-
-static void
-gst_cddabasesrc_calculate_musicbrainz_discid (GstCddaBaseSrc * src)
-{
- GString *s;
- SHA_INFO sha;
- guchar digest[20];
- gchar *ptr;
- gchar tmp[9];
- gulong i;
- guint leadout_sector;
-
- s = g_string_new (NULL);
-
- leadout_sector = src->tracks[src->num_tracks - 1].end + 1 + CD_MSF_OFFSET;
-
- /* generate SHA digest */
- sha_init (&sha);
- g_snprintf (tmp, sizeof (tmp), "%02X", src->tracks[0].num);
- g_string_append_printf (s, "%02X", src->tracks[0].num);
- sha_update (&sha, (SHA_BYTE *) tmp, 2);
-
- g_snprintf (tmp, sizeof (tmp), "%02X", src->tracks[src->num_tracks - 1].num);
- g_string_append_printf (s, " %02X", src->tracks[src->num_tracks - 1].num);
- sha_update (&sha, (SHA_BYTE *) tmp, 2);
-
- g_snprintf (tmp, sizeof (tmp), "%08X", leadout_sector);
- g_string_append_printf (s, " %08X", leadout_sector);
- sha_update (&sha, (SHA_BYTE *) tmp, 8);
-
- for (i = 0; i < 99; i++) {
- if (i < src->num_tracks) {
- guint frame_offset = src->tracks[i].start + CD_MSF_OFFSET;
-
- g_snprintf (tmp, sizeof (tmp), "%08X", frame_offset);
- g_string_append_printf (s, " %08X", frame_offset);
- sha_update (&sha, (SHA_BYTE *) tmp, 8);
- } else {
- sha_update (&sha, (SHA_BYTE *) "00000000", 8);
- }
- }
- sha_final (digest, &sha);
-
- /* re-encode to base64 */
- ptr = g_base64_encode (digest, 20);
- i = strlen (ptr);
-
- g_assert (i < sizeof (src->mb_discid) + 1);
- memcpy (src->mb_discid, ptr, i);
- src->mb_discid[i] = '\0';
- free (ptr);
-
- /* Replace '/', '+' and '=' by '_', '.' and '-' as specified on
- * http://musicbrainz.org/doc/DiscIDCalculation
- */
- for (ptr = src->mb_discid; *ptr != '\0'; ptr++) {
- if (*ptr == '/')
- *ptr = '_';
- else if (*ptr == '+')
- *ptr = '.';
- else if (*ptr == '=')
- *ptr = '-';
- }
-
- GST_DEBUG_OBJECT (src, "musicbrainz-discid = %s", src->mb_discid);
- GST_DEBUG_OBJECT (src, "musicbrainz-discid-full = %s", s->str);
-
- gst_tag_list_add (src->tags, GST_TAG_MERGE_REPLACE,
- GST_TAG_CDDA_MUSICBRAINZ_DISCID, src->mb_discid,
- GST_TAG_CDDA_MUSICBRAINZ_DISCID_FULL, s->str, NULL);
-
- g_string_free (s, TRUE);
-}
-
-static void
-lba_to_msf (guint sector, guint * p_m, guint * p_s, guint * p_f, guint * p_secs)
-{
- guint m, s, f;
-
- m = sector / SECTORS_PER_MINUTE;
- sector = sector % SECTORS_PER_MINUTE;
- s = sector / SECTORS_PER_SECOND;
- f = sector % SECTORS_PER_SECOND;
-
- if (p_m)
- *p_m = m;
- if (p_s)
- *p_s = s;
- if (p_f)
- *p_f = f;
- if (p_secs)
- *p_secs = s + (m * 60);
-}
-
-static void
-gst_cdda_base_src_calculate_cddb_id (GstCddaBaseSrc * src)
-{
- GString *s;
- guint first_sector = 0, last_sector = 0;
- guint start_secs, end_secs, secs, len_secs;
- guint total_secs, num_audio_tracks;
- guint id, t, i;
-
- id = 0;
- total_secs = 0;
- num_audio_tracks = 0;
-
- /* FIXME: do we use offsets and duration of ALL tracks (data + audio)
- * for the CDDB ID calculation, or only audio tracks? */
- for (i = 0; i < src->num_tracks; ++i) {
- if (1) { /* src->tracks[i].is_audio) { */
- if (num_audio_tracks == 0) {
- first_sector = src->tracks[i].start + CD_MSF_OFFSET;
- }
- last_sector = src->tracks[i].end + CD_MSF_OFFSET + 1;
- ++num_audio_tracks;
-
- lba_to_msf (src->tracks[i].start + CD_MSF_OFFSET, NULL, NULL, NULL,
- &secs);
-
- len_secs = (src->tracks[i].end - src->tracks[i].start + 1) / 75;
-
- GST_DEBUG_OBJECT (src, "track %02u: lsn %6u (%02u:%02u), "
- "length: %u seconds (%02u:%02u)",
- num_audio_tracks, src->tracks[i].start + CD_MSF_OFFSET,
- secs / 60, secs % 60, len_secs, len_secs / 60, len_secs % 60);
-
- id += cddb_sum (secs);
- total_secs += len_secs;
- }
- }
-
- /* first_sector = src->tracks[0].start + CD_MSF_OFFSET; */
- lba_to_msf (first_sector, NULL, NULL, NULL, &start_secs);
-
- /* last_sector = src->tracks[src->num_tracks-1].end + CD_MSF_OFFSET; */
- lba_to_msf (last_sector, NULL, NULL, NULL, &end_secs);
-
- GST_DEBUG_OBJECT (src, "first_sector = %u = %u secs (%02u:%02u)",
- first_sector, start_secs, start_secs / 60, start_secs % 60);
- GST_DEBUG_OBJECT (src, "last_sector = %u = %u secs (%02u:%02u)",
- last_sector, end_secs, end_secs / 60, end_secs % 60);
-
- t = end_secs - start_secs;
-
- GST_DEBUG_OBJECT (src, "total length = %u secs (%02u:%02u), added title "
- "lengths = %u seconds (%02u:%02u)", t, t / 60, t % 60, total_secs,
- total_secs / 60, total_secs % 60);
-
- src->discid = ((id % 0xff) << 24 | t << 8 | num_audio_tracks);
-
- s = g_string_new (NULL);
- g_string_append_printf (s, "%08x", src->discid);
-
- gst_tag_list_add (src->tags, GST_TAG_MERGE_REPLACE,
- GST_TAG_CDDA_CDDB_DISCID, s->str, NULL);
-
- g_string_append_printf (s, " %u", src->num_tracks);
- for (i = 0; i < src->num_tracks; ++i) {
- g_string_append_printf (s, " %u", src->tracks[i].start + CD_MSF_OFFSET);
- }
- g_string_append_printf (s, " %u", t);
-
- gst_tag_list_add (src->tags, GST_TAG_MERGE_REPLACE,
- GST_TAG_CDDA_CDDB_DISCID_FULL, s->str, NULL);
-
- GST_DEBUG_OBJECT (src, "cddb discid = %s", s->str);
-
- g_string_free (s, TRUE);
-}
-
-static void
-gst_cdda_base_src_add_tags (GstCddaBaseSrc * src)
-{
- gint i;
-
- /* fill in details for each track */
- for (i = 0; i < src->num_tracks; ++i) {
- gint64 duration;
- guint num_sectors;
-
- if (src->tracks[i].tags == NULL)
- src->tracks[i].tags = gst_tag_list_new ();
-
- num_sectors = src->tracks[i].end - src->tracks[i].start + 1;
- gst_cdda_base_src_convert (src, sector_format, num_sectors,
- GST_FORMAT_TIME, &duration);
-
- gst_tag_list_add (src->tracks[i].tags,
- GST_TAG_MERGE_REPLACE,
- GST_TAG_TRACK_NUMBER, i + 1,
- GST_TAG_TRACK_COUNT, src->num_tracks, GST_TAG_DURATION, duration, NULL);
- }
-
- /* now fill in per-album tags and include each track's tags
- * in the album tags, so that interested parties can retrieve
- * the relevant details for each track in one go */
-
- /* /////////////////////////////// FIXME should we rather insert num_tracks
- * tags by the name of 'track-tags' and have the caller use
- * gst_tag_list_get_value_index() rather than use tag names incl.
- * the track number ?? *////////////////////////////////////////
-
- gst_tag_list_add (src->tags, GST_TAG_MERGE_REPLACE,
- GST_TAG_TRACK_COUNT, src->num_tracks, NULL);
-#if 0
- for (i = 0; i < src->num_tracks; ++i) {
- gst_tag_list_add (src->tags, GST_TAG_MERGE_APPEND,
- GST_TAG_CDDA_TRACK_TAGS, src->tracks[i].tags, NULL);
- }
-#endif
-
- GST_DEBUG ("src->tags = %" GST_PTR_FORMAT, src->tags);
-}
-
-static void
-gst_cdda_base_src_add_index_associations (GstCddaBaseSrc * src)
-{
- gint i;
-
- for (i = 0; i < src->num_tracks; i++) {
- gint64 sector;
-
- sector = src->tracks[i].start;
- gst_index_add_association (src->index, src->index_id, GST_ASSOCIATION_FLAG_KEY_UNIT, track_format, i, /* here we count from 0 */
- sector_format, sector,
- GST_FORMAT_TIME,
- (gint64) (((CD_FRAMESIZE_RAW >> 2) * sector * GST_SECOND) / 44100),
- GST_FORMAT_BYTES, (gint64) (sector << 2), GST_FORMAT_DEFAULT,
- (gint64) ((CD_FRAMESIZE_RAW >> 2) * sector), NULL);
- }
-}
-
-static void
-gst_cdda_base_src_set_index (GstElement * element, GstIndex * index)
-{
- GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (element);
-
- src->index = index;
-
- gst_index_get_writer_id (index, GST_OBJECT (src), &src->index_id);
- gst_index_add_format (index, src->index_id, track_format);
- gst_index_add_format (index, src->index_id, sector_format);
-}
-
-
-static GstIndex *
-gst_cdda_base_src_get_index (GstElement * element)
-{
- GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (element);
-
- return src->index;
-}
-
-static gint
-gst_cdda_base_src_track_sort_func (gconstpointer a, gconstpointer b,
- gpointer foo)
-{
- GstCddaBaseSrcTrack *track_a = ((GstCddaBaseSrcTrack *) a);
- GstCddaBaseSrcTrack *track_b = ((GstCddaBaseSrcTrack *) b);
-
- /* sort data tracks to the end, and audio tracks by track number */
- if (track_a->is_audio == track_b->is_audio)
- return (gint) track_a->num - (gint) track_b->num;
-
- if (track_a->is_audio) {
- return -1;
- } else {
- return 1;
- }
-}
-
-static gboolean
-gst_cdda_base_src_start (GstBaseSrc * basesrc)
-{
- GstCddaBaseSrcClass *klass = GST_CDDA_BASE_SRC_GET_CLASS (basesrc);
- GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (basesrc);
- gboolean ret;
- gchar *device = NULL;
-
- src->discid = 0;
- src->mb_discid[0] = '\0';
-
- g_assert (klass->open != NULL);
-
- if (src->device != NULL) {
- device = g_strdup (src->device);
- } else if (klass->get_default_device != NULL) {
- device = klass->get_default_device (src);
- }
-
- if (device == NULL)
- device = g_strdup (DEFAULT_DEVICE);
-
- GST_LOG_OBJECT (basesrc, "opening device %s", device);
-
- src->tags = gst_tag_list_new ();
-
- ret = klass->open (src, device);
- g_free (device);
- device = NULL;
-
- if (!ret) {
- GST_DEBUG_OBJECT (basesrc, "failed to open device");
- /* subclass (should have) posted an error message with the details */
- gst_cdda_base_src_stop (basesrc);
- return FALSE;
- }
-
- if (src->num_tracks == 0 || src->tracks == NULL) {
- GST_DEBUG_OBJECT (src, "no tracks");
- GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
- (_("This CD has no audio tracks")), (NULL));
- gst_cdda_base_src_stop (basesrc);
- return FALSE;
- }
-
- /* need to calculate disc IDs before we ditch the data tracks */
- gst_cdda_base_src_calculate_cddb_id (src);
- gst_cddabasesrc_calculate_musicbrainz_discid (src);
-
-#if 0
- /* adjust sector offsets if necessary */
- if (src->toc_bias) {
- src->toc_offset -= src->tracks[0].start;
- }
- for (i = 0; i < src->num_tracks; ++i) {
- src->tracks[i].start += src->toc_offset;
- src->tracks[i].end += src->toc_offset;
- }
-#endif
-
- /* now that we calculated the various disc IDs,
- * sort the data tracks to end and ignore them */
- src->num_all_tracks = src->num_tracks;
-
- g_qsort_with_data (src->tracks, src->num_tracks,
- sizeof (GstCddaBaseSrcTrack), gst_cdda_base_src_track_sort_func, NULL);
-
- while (src->num_tracks > 0 && !src->tracks[src->num_tracks - 1].is_audio)
- --src->num_tracks;
-
- if (src->num_tracks == 0) {
- GST_DEBUG_OBJECT (src, "no audio tracks");
- GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
- (_("This CD has no audio tracks")), (NULL));
- gst_cdda_base_src_stop (basesrc);
- return FALSE;
- }
-
- gst_cdda_base_src_add_tags (src);
-
- if (src->index && GST_INDEX_IS_WRITABLE (src->index))
- gst_cdda_base_src_add_index_associations (src);
-
- src->cur_track = 0;
- src->prev_track = -1;
-
- if (src->uri_track > 0 && src->uri_track <= src->num_tracks) {
- GST_LOG_OBJECT (src, "seek to track %d", src->uri_track);
- src->cur_track = src->uri_track - 1;
- src->uri_track = -1;
- src->mode = GST_CDDA_BASE_SRC_MODE_NORMAL;
- }
-
- src->cur_sector = src->tracks[src->cur_track].start;
- GST_LOG_OBJECT (src, "starting at sector %d", src->cur_sector);
-
- gst_cdda_base_src_update_duration (src);
-
- return TRUE;
-}
-
-static void
-gst_cdda_base_src_clear_tracks (GstCddaBaseSrc * src)
-{
- if (src->tracks != NULL) {
- gint i;
-
- for (i = 0; i < src->num_all_tracks; ++i) {
- if (src->tracks[i].tags)
- gst_tag_list_free (src->tracks[i].tags);
- }
-
- g_free (src->tracks);
- src->tracks = NULL;
- }
- src->num_tracks = 0;
- src->num_all_tracks = 0;
-}
-
-static gboolean
-gst_cdda_base_src_stop (GstBaseSrc * basesrc)
-{
- GstCddaBaseSrcClass *klass = GST_CDDA_BASE_SRC_GET_CLASS (basesrc);
- GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (basesrc);
-
- g_assert (klass->close != NULL);
-
- klass->close (src);
-
- gst_cdda_base_src_clear_tracks (src);
-
- if (src->tags) {
- gst_tag_list_free (src->tags);
- src->tags = NULL;
- }
-
- src->prev_track = -1;
- src->cur_track = -1;
-
- return TRUE;
-}
-
-
-static GstFlowReturn
-gst_cdda_base_src_create (GstPushSrc * pushsrc, GstBuffer ** buffer)
-{
- GstCddaBaseSrcClass *klass = GST_CDDA_BASE_SRC_GET_CLASS (pushsrc);
- GstCddaBaseSrc *src = GST_CDDA_BASE_SRC (pushsrc);
- GstBuffer *buf;
- GstFormat format;
- gboolean eos;
-
- GstClockTime position = GST_CLOCK_TIME_NONE;
- GstClockTime duration = GST_CLOCK_TIME_NONE;
- gint64 qry_position;
-
- g_assert (klass->read_sector != NULL);
-
- switch (src->mode) {
- case GST_CDDA_BASE_SRC_MODE_NORMAL:
- eos = (src->cur_sector > src->tracks[src->cur_track].end);
- break;
- case GST_CDDA_BASE_SRC_MODE_CONTINUOUS:
- eos = (src->cur_sector > src->tracks[src->num_tracks - 1].end);
- src->cur_track = gst_cdda_base_src_get_track_from_sector (src,
- src->cur_sector);
- break;
- default:
- g_return_val_if_reached (GST_FLOW_ERROR);
- }
-
- if (eos) {
- src->prev_track = -1;
- GST_DEBUG_OBJECT (src, "EOS at sector %d, cur_track=%d, mode=%d",
- src->cur_sector, src->cur_track, src->mode);
- /* base class will send EOS for us */
- return GST_FLOW_UNEXPECTED;
- }
-
- if (src->prev_track != src->cur_track) {
- GstTagList *tags;
-
- tags = gst_tag_list_merge (src->tags, src->tracks[src->cur_track].tags,
- GST_TAG_MERGE_REPLACE);
- GST_LOG_OBJECT (src, "announcing tags: %" GST_PTR_FORMAT, tags);
- gst_element_found_tags_for_pad (GST_ELEMENT (src),
- GST_BASE_SRC_PAD (src), tags);
- src->prev_track = src->cur_track;
-
- gst_cdda_base_src_update_duration (src);
-
- g_object_notify (G_OBJECT (src), "track");
- }
-
- GST_LOG_OBJECT (src, "asking for sector %u", src->cur_sector);
-
- buf = klass->read_sector (src, src->cur_sector);
-
- if (buf == NULL) {
- GST_WARNING_OBJECT (src, "failed to read sector %u", src->cur_sector);
- return GST_FLOW_ERROR;
- }
-
- if (GST_BUFFER_CAPS (buf) == NULL) {
- gst_buffer_set_caps (buf, GST_PAD_CAPS (GST_BASE_SRC_PAD (src)));
- }
-
- format = GST_FORMAT_TIME;
- if (gst_pad_query_position (GST_BASE_SRC_PAD (src), &format, &qry_position)) {
- gint64 next_ts = 0;
-
- position = (GstClockTime) qry_position;
-
- ++src->cur_sector;
- if (gst_pad_query_position (GST_BASE_SRC_PAD (src), &format, &next_ts)) {
- duration = (GstClockTime) (next_ts - qry_position);
- }
- --src->cur_sector;
- }
-
- /* fallback duration: 4 bytes per sample, 44100 samples per second */
- if (duration == GST_CLOCK_TIME_NONE) {
- duration = gst_util_uint64_scale_int (GST_BUFFER_SIZE (buf) >> 2,
- GST_SECOND, 44100);
- }
-
- GST_BUFFER_TIMESTAMP (buf) = position;
- GST_BUFFER_DURATION (buf) = duration;
-
- GST_LOG_OBJECT (src, "pushing sector %d with timestamp %" GST_TIME_FORMAT,
- src->cur_sector, GST_TIME_ARGS (position));
-
- ++src->cur_sector;
-
- *buffer = buf;
-
- return GST_FLOW_OK;
-}
+++ /dev/null
-diff --git a/gst-libs/gst/rtp/gstrtcpbuffer.c b/gst-libs/gst/rtp/gstrtcpbuffer.c
-index ab77c8a..fb35a92 100644
---- a/gst-libs/gst/rtp/gstrtcpbuffer.c
-+++ b/gst-libs/gst/rtp/gstrtcpbuffer.c
-@@ -449,6 +449,11 @@ gst_rtcp_buffer_add_packet (GstBuffer * buffer, GstRTCPType type,
- case GST_RTCP_TYPE_APP:
- len = 12;
- break;
-+ case GST_RTCP_TYPE_RTPFB:
-+ len = 12;
-+ break;
-+ case GST_RTCP_TYPE_PSFB:
-+ len = 12;
- default:
- goto unknown_type;
- }
-@@ -1637,6 +1642,147 @@ no_space:
- }
-
- /**
-+ * gst_rtcp_packet_fb_get_sender_ssrc:
-+ * @packet: a valid RTPFB or PSFB #GstRTCPPacket
-+ *
-+ * Get the sender SSRC field of the RTPFB or PSFB @packet.
-+ *
-+ * Returns: the sender SSRC.
-+ */
-+guint32
-+gst_rtcp_packet_fb_get_sender_ssrc (GstRTCPPacket * packet)
-+{
-+ guint8 *data;
-+ guint32 ssrc;
-+
-+ g_return_val_if_fail (packet != NULL, 0);
-+ g_return_val_if_fail ((packet->type == GST_RTCP_TYPE_RTPFB ||
-+ packet->type == GST_RTCP_TYPE_PSFB), 0);
-+ g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
-+
-+ data = GST_BUFFER_DATA (packet->buffer);
-+
-+ /* skip header */
-+ data += packet->offset + 4;
-+ ssrc = GST_READ_UINT32_BE (data);
-+
-+ return ssrc;
-+}
-+
-+/**
-+ * gst_rtcp_packet_fb_set_sender_ssrc:
-+ * @packet: a valid RTPFB or PSFB #GstRTCPPacket
-+ *
-+ * Set the sender SSRC field of the RTPFB or PSFB @packet.
-+ */
-+void
-+gst_rtcp_packet_fb_set_sender_ssrc (GstRTCPPacket *packet, guint32 ssrc)
-+{
-+ guint8 *data;
-+
-+ g_return_if_fail (packet != NULL);
-+ g_return_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
-+ packet->type == GST_RTCP_TYPE_PSFB);
-+ g_return_if_fail (GST_IS_BUFFER (packet->buffer));
-+
-+ data = GST_BUFFER_DATA (packet->buffer);
-+
-+ /* skip header */
-+ data += packet->offset + 4;
-+ GST_WRITE_UINT32_BE (data, ssrc);
-+}
-+
-+/**
-+ * gst_rtcp_packet_fb_get_media_ssrc:
-+ * @packet: a valid RTPFB or PSFB #GstRTCPPacket
-+ *
-+ * Get the media SSRC field of the RTPFB or PSFB @packet.
-+ *
-+ * Returns: the media SSRC.
-+ */
-+guint32
-+gst_rtcp_packet_fb_get_media_ssrc (GstRTCPPacket * packet)
-+{
-+ guint8 *data;
-+ guint32 ssrc;
-+
-+ g_return_val_if_fail (packet != NULL, 0);
-+ g_return_val_if_fail ((packet->type == GST_RTCP_TYPE_RTPFB ||
-+ packet->type == GST_RTCP_TYPE_PSFB), 0);
-+ g_return_val_if_fail (GST_IS_BUFFER (packet->buffer), 0);
-+
-+ data = GST_BUFFER_DATA (packet->buffer);
-+
-+ /* skip header and sender ssrc */
-+ data += packet->offset + 8;
-+ ssrc = GST_READ_UINT32_BE (data);
-+
-+ return ssrc;
-+}
-+
-+/**
-+ * gst_rtcp_packet_fb_set_media_ssrc:
-+ * @packet: a valid RTPFB or PSFB #GstRTCPPacket
-+ *
-+ * Set the media SSRC field of the RTPFB or PSFB @packet.
-+ */
-+void
-+gst_rtcp_packet_fb_set_media_ssrc (GstRTCPPacket *packet, guint32 ssrc)
-+{
-+ guint8 *data;
-+
-+ g_return_if_fail (packet != NULL);
-+ g_return_if_fail (packet->type == GST_RTCP_TYPE_RTPFB ||
-+ packet->type == GST_RTCP_TYPE_PSFB);
-+ g_return_if_fail (GST_IS_BUFFER (packet->buffer));
-+
-+ data = GST_BUFFER_DATA (packet->buffer);
-+
-+ /* skip header and sender ssrc */
-+ data += packet->offset + 8;
-+ GST_WRITE_UINT32_BE (data, ssrc);
-+}
-+
-+/**
-+ * gst_rtcp_packet_psfb_get_type:
-+ * @packet: a valid PSFB #GstRTCPPacket
-+ *
-+ * Get the feedback message type of the PSFB @packet.
-+ *
-+ * Returns: The feedback message type.
-+ */
-+GstRTCPPSFBType
-+gst_rtcp_packet_psfb_get_type (GstRTCPPacket *packet)
-+{
-+ g_return_val_if_fail (packet != NULL, GST_RTCP_PSFB_TYPE_INVALID);
-+ g_return_val_if_fail (packet->type == GST_RTCP_TYPE_PSFB,
-+ GST_RTCP_PSFB_TYPE_INVALID);
-+
-+ return packet->count;
-+}
-+
-+/**
-+ * gst_rtcp_packet_psfb_set_type:
-+ * @packet: a valid PSFB #GstRTCPPacket
-+ * @type: the #GstRTCPPSFBType to set
-+ *
-+ * Set the feedback message type of the PSFB @packet.
-+ */
-+void
-+gst_rtcp_packet_psfb_set_type (GstRTCPPacket *packet, GstRTCPPSFBType type)
-+{
-+ guint8 *data;
-+
-+ g_return_if_fail (packet != NULL);
-+ g_return_if_fail (packet->type == GST_RTCP_TYPE_PSFB);
-+ g_return_if_fail (GST_IS_BUFFER (packet->buffer));
-+
-+ data = GST_BUFFER_DATA (packet->buffer);
-+
-+ data[packet->offset] = (data[packet->offset] & 0xE0) | type;
-+}
-+
-+/**
- * gst_rtcp_ntp_to_unix:
- * @ntptime: an NTP timestamp
- *
-diff --git a/gst-libs/gst/rtp/gstrtcpbuffer.h b/gst-libs/gst/rtp/gstrtcpbuffer.h
-index 9c908a8..bb247c9 100644
---- a/gst-libs/gst/rtp/gstrtcpbuffer.h
-+++ b/gst-libs/gst/rtp/gstrtcpbuffer.h
-@@ -42,6 +42,8 @@ G_BEGIN_DECLS
- * @GST_RTCP_TYPE_SDES: Source description
- * @GST_RTCP_TYPE_BYE: Goodbye
- * @GST_RTCP_TYPE_APP: Application defined
-+ * @GST_RTCP_TYPE_RTPFB: Transport layer feedback
-+ * @GST_RTCP_TYPE_PSFB: Payload-specific feedback
- *
- * Different RTCP packet types.
- */
-@@ -52,9 +54,28 @@ typedef enum
- GST_RTCP_TYPE_RR = 201,
- GST_RTCP_TYPE_SDES = 202,
- GST_RTCP_TYPE_BYE = 203,
-- GST_RTCP_TYPE_APP = 204
-+ GST_RTCP_TYPE_APP = 204,
-+ GST_RTCP_TYPE_RTPFB = 205,
-+ GST_RTCP_TYPE_PSFB = 206
- } GstRTCPType;
-
-+/**
-+ * GstRTCPPSFBType:
-+ * @GST_RTCP_PSFB_TYPE_INVALID: Invalid type
-+ * @GST_RTCP_PSFB_TYPE_PLI: Picture Loss Indication
-+ * @GST_RTCP_PSFB_TYPE_SLI: Slice Loss Indication
-+ * @GST_RTCP_PSFB_TYPE_RPSI: Reference Picture Selection Indication
-+ * @GST_RTCP_PSFB_TYPE_AFB: Application layer Feedback
-+ */
-+typedef enum
-+{
-+ GST_RTCP_PSFB_TYPE_INVALID = 0,
-+ GST_RTCP_PSFB_TYPE_PLI = 1,
-+ GST_RTCP_PSFB_TYPE_SLI = 2,
-+ GST_RTCP_PSFB_TYPE_RPSI = 3,
-+ GST_RTCP_PSFB_TYPE_AFB = 15
-+} GstRTCPPSFBType;
-+
- /**
- * GstRTCPSDESType:
- * @GST_RTCP_SDES_INVALID: Invalid SDES entry
-@@ -232,6 +253,16 @@ guint8 gst_rtcp_packet_bye_get_reason_len (GstRTCPPacket *packet);
- gchar* gst_rtcp_packet_bye_get_reason (GstRTCPPacket *packet);
- gboolean gst_rtcp_packet_bye_set_reason (GstRTCPPacket *packet, const gchar *reason);
-
-+/* feedback packets */
-+guint32 gst_rtcp_packet_fb_get_sender_ssrc (GstRTCPPacket *packet);
-+void gst_rtcp_packet_fb_set_sender_ssrc (GstRTCPPacket *packet, guint32 ssrc);
-+guint32 gst_rtcp_packet_fb_get_media_ssrc (GstRTCPPacket *packet);
-+void gst_rtcp_packet_fb_set_media_ssrc (GstRTCPPacket *packet, guint32 ssrc);
-+
-+/* psfb packets */
-+GstRTCPPSFBType gst_rtcp_packet_psfb_get_type (GstRTCPPacket *packet);
-+void gst_rtcp_packet_psfb_set_type (GstRTCPPacket *packet, GstRTCPPSFBType type);
-+
- /* helper functions */
- guint64 gst_rtcp_ntp_to_unix (guint64 ntptime);
- guint64 gst_rtcp_unix_to_ntp (guint64 unixtime);
+++ /dev/null
-/* GStreamer
- * Copyright (C) <2005> Wim Taymans <wim@fluendo.com>
- *
- * 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
- */
-
-/**
- * SECTION:gstbasertppayload
- * @short_description: Base class for RTP payloader
- *
- * <refsect2>
- * <para>
- * Provides a base class for RTP payloaders
- * </para>
- * </refsect2>
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include <string.h>
-
-#include <gst/rtp/gstrtpbuffer.h>
-
-#include "gstbasertppayload.h"
-
-GST_DEBUG_CATEGORY_STATIC (basertppayload_debug);
-#define GST_CAT_DEFAULT (basertppayload_debug)
-
-#define GST_BASE_RTP_PAYLOAD_GET_PRIVATE(obj) \
- (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_RTP_PAYLOAD, GstBaseRTPPayloadPrivate))
-
-struct _GstBaseRTPPayloadPrivate
-{
- gboolean ts_offset_random;
- gboolean seqnum_offset_random;
- gboolean ssrc_random;
- guint16 next_seqnum;
- gboolean perfect_rtptime;
-
- gint64 prop_max_ptime;
- gint64 caps_max_ptime;
-};
-
-/* BaseRTPPayload signals and args */
-enum
-{
- /* FILL ME */
- LAST_SIGNAL
-};
-
-/* FIXME 0.11, a better default is the Ethernet MTU of
- * 1500 - sizeof(headers) as pointed out by marcelm in IRC:
- * So an Ethernet MTU of 1500, minus 60 for the max IP, minus 8 for UDP, gives
- * 1432 bytes or so. And that should be adjusted downward further for other
- * encapsulations like PPPoE, so 1400 at most.
- */
-#define DEFAULT_MTU 1400
-#define DEFAULT_PT 96
-#define DEFAULT_SSRC -1
-#define DEFAULT_TIMESTAMP_OFFSET -1
-#define DEFAULT_SEQNUM_OFFSET -1
-#define DEFAULT_MAX_PTIME -1
-#define DEFAULT_MIN_PTIME 0
-#define DEFAULT_PERFECT_RTPTIME TRUE
-#define DEFAULT_PTIME_MULTIPLE 0
-
-enum
-{
- PROP_0,
- PROP_MTU,
- PROP_PT,
- PROP_SSRC,
- PROP_TIMESTAMP_OFFSET,
- PROP_SEQNUM_OFFSET,
- PROP_MAX_PTIME,
- PROP_MIN_PTIME,
- PROP_TIMESTAMP,
- PROP_SEQNUM,
- PROP_PERFECT_RTPTIME,
- PROP_PTIME_MULTIPLE,
- PROP_LAST
-};
-
-static void gst_basertppayload_class_init (GstBaseRTPPayloadClass * klass);
-static void gst_basertppayload_base_init (GstBaseRTPPayloadClass * klass);
-static void gst_basertppayload_init (GstBaseRTPPayload * basertppayload,
- gpointer g_class);
-static void gst_basertppayload_finalize (GObject * object);
-
-static gboolean gst_basertppayload_sink_setcaps (GstPad * pad, GstCaps * caps);
-static GstCaps *gst_basertppayload_sink_getcaps (GstPad * pad);
-static gboolean gst_basertppayload_event (GstPad * pad, GstEvent * event);
-static GstFlowReturn gst_basertppayload_chain (GstPad * pad,
- GstBuffer * buffer);
-
-static void gst_basertppayload_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec);
-static void gst_basertppayload_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec);
-
-static GstStateChangeReturn gst_basertppayload_change_state (GstElement *
- element, GstStateChange transition);
-
-static GstElementClass *parent_class = NULL;
-
-/* FIXME 0.11: API should be changed to gst_base_typ_payload_xyz */
-
-GType
-gst_basertppayload_get_type (void)
-{
- static GType basertppayload_type = 0;
-
- if (!basertppayload_type) {
- static const GTypeInfo basertppayload_info = {
- sizeof (GstBaseRTPPayloadClass),
- (GBaseInitFunc) gst_basertppayload_base_init,
- NULL,
- (GClassInitFunc) gst_basertppayload_class_init,
- NULL,
- NULL,
- sizeof (GstBaseRTPPayload),
- 0,
- (GInstanceInitFunc) gst_basertppayload_init,
- };
-
- basertppayload_type =
- g_type_register_static (GST_TYPE_ELEMENT, "GstBaseRTPPayload",
- &basertppayload_info, G_TYPE_FLAG_ABSTRACT);
- }
- return basertppayload_type;
-}
-
-static void
-gst_basertppayload_base_init (GstBaseRTPPayloadClass * klass)
-{
-}
-
-static void
-gst_basertppayload_class_init (GstBaseRTPPayloadClass * klass)
-{
- GObjectClass *gobject_class;
- GstElementClass *gstelement_class;
-
- gobject_class = (GObjectClass *) klass;
- gstelement_class = (GstElementClass *) klass;
-
- g_type_class_add_private (klass, sizeof (GstBaseRTPPayloadPrivate));
-
- parent_class = g_type_class_peek_parent (klass);
-
- gobject_class->finalize = gst_basertppayload_finalize;
-
- gobject_class->set_property = gst_basertppayload_set_property;
- gobject_class->get_property = gst_basertppayload_get_property;
-
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MTU,
- g_param_spec_uint ("mtu", "MTU",
- "Maximum size of one packet",
- 28, G_MAXUINT, DEFAULT_MTU,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PT,
- g_param_spec_uint ("pt", "payload type",
- "The payload type of the packets", 0, 0x80, DEFAULT_PT,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SSRC,
- g_param_spec_uint ("ssrc", "SSRC",
- "The SSRC of the packets (default == random)", 0, G_MAXUINT32,
- DEFAULT_SSRC, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass),
- PROP_TIMESTAMP_OFFSET, g_param_spec_uint ("timestamp-offset",
- "Timestamp Offset",
- "Offset to add to all outgoing timestamps (default = random)", 0,
- G_MAXUINT32, DEFAULT_TIMESTAMP_OFFSET,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM_OFFSET,
- g_param_spec_int ("seqnum-offset", "Sequence number Offset",
- "Offset to add to all outgoing seqnum (-1 = random)", -1, G_MAXUINT16,
- DEFAULT_SEQNUM_OFFSET, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MAX_PTIME,
- g_param_spec_int64 ("max-ptime", "Max packet time",
- "Maximum duration of the packet data in ns (-1 = unlimited up to MTU)",
- -1, G_MAXINT64, DEFAULT_MAX_PTIME,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- /**
- * GstBaseRTPAudioPayload:min-ptime:
- *
- * Minimum duration of the packet data in ns (can't go above MTU)
- *
- * Since: 0.10.13
- **/
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MIN_PTIME,
- g_param_spec_int64 ("min-ptime", "Min packet time",
- "Minimum duration of the packet data in ns (can't go above MTU)",
- 0, G_MAXINT64, DEFAULT_MIN_PTIME,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_TIMESTAMP,
- g_param_spec_uint ("timestamp", "Timestamp",
- "The RTP timestamp of the last processed packet",
- 0, G_MAXUINT32, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SEQNUM,
- g_param_spec_uint ("seqnum", "Sequence number",
- "The RTP sequence number of the last processed packet",
- 0, G_MAXUINT16, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
-
- /**
- * GstBaseRTPAudioPayload:perfect-rtptime:
- *
- * Try to use the offset fields to generate perfect RTP timestamps. when this
- * option is disabled, RTP timestamps are generated from the GStreamer
- * timestamps, which could result in RTP timestamps that don't increment with
- * the amount of data in the packet.
- *
- * Since: 0.10.25
- */
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PERFECT_RTPTIME,
- g_param_spec_boolean ("perfect-rtptime", "Perfect RTP Time",
- "Generate perfect RTP timestamps when possible",
- DEFAULT_PERFECT_RTPTIME, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- /**
- * GstBaseRTPAudioPayload:ptime-multiple:
- *
- * Force buffers to be multiples of this duration in ns (0 disables)
- *
- * Since: 0.10.29
- **/
- g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PTIME_MULTIPLE,
- g_param_spec_int64 ("ptime-multiple", "Packet time multiple",
- "Force buffers to be multiples of this duration in ns (0 disables)",
- 0, G_MAXINT64, DEFAULT_PTIME_MULTIPLE,
- G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
-
- gstelement_class->change_state = gst_basertppayload_change_state;
-
- GST_DEBUG_CATEGORY_INIT (basertppayload_debug, "basertppayload", 0,
- "Base class for RTP Payloaders");
-}
-
-static void
-gst_basertppayload_init (GstBaseRTPPayload * basertppayload, gpointer g_class)
-{
- GstPadTemplate *templ;
- GstBaseRTPPayloadPrivate *priv;
-
- basertppayload->priv = priv =
- GST_BASE_RTP_PAYLOAD_GET_PRIVATE (basertppayload);
-
- templ =
- gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "src");
- g_return_if_fail (templ != NULL);
-
- basertppayload->srcpad = gst_pad_new_from_template (templ, "src");
- gst_element_add_pad (GST_ELEMENT (basertppayload), basertppayload->srcpad);
-
- templ =
- gst_element_class_get_pad_template (GST_ELEMENT_CLASS (g_class), "sink");
- g_return_if_fail (templ != NULL);
-
- basertppayload->sinkpad = gst_pad_new_from_template (templ, "sink");
- gst_pad_set_setcaps_function (basertppayload->sinkpad,
- gst_basertppayload_sink_setcaps);
- gst_pad_set_getcaps_function (basertppayload->sinkpad,
- gst_basertppayload_sink_getcaps);
- gst_pad_set_event_function (basertppayload->sinkpad,
- gst_basertppayload_event);
- gst_pad_set_chain_function (basertppayload->sinkpad,
- gst_basertppayload_chain);
- gst_element_add_pad (GST_ELEMENT (basertppayload), basertppayload->sinkpad);
-
- basertppayload->seq_rand = g_rand_new_with_seed (g_random_int ());
- basertppayload->ssrc_rand = g_rand_new_with_seed (g_random_int ());
- basertppayload->ts_rand = g_rand_new_with_seed (g_random_int ());
-
- basertppayload->mtu = DEFAULT_MTU;
- basertppayload->pt = DEFAULT_PT;
- basertppayload->seqnum_offset = DEFAULT_SEQNUM_OFFSET;
- basertppayload->ssrc = DEFAULT_SSRC;
- basertppayload->ts_offset = DEFAULT_TIMESTAMP_OFFSET;
- priv->seqnum_offset_random = (basertppayload->seqnum_offset == -1);
- priv->ts_offset_random = (basertppayload->ts_offset == -1);
- priv->ssrc_random = (basertppayload->ssrc == -1);
-
- basertppayload->max_ptime = DEFAULT_MAX_PTIME;
- basertppayload->min_ptime = DEFAULT_MIN_PTIME;
- basertppayload->priv->perfect_rtptime = DEFAULT_PERFECT_RTPTIME;
- basertppayload->abidata.ABI.ptime_multiple = DEFAULT_PTIME_MULTIPLE;
-
- basertppayload->media = NULL;
- basertppayload->encoding_name = NULL;
-
- basertppayload->clock_rate = 0;
-
- basertppayload->priv->caps_max_ptime = DEFAULT_MAX_PTIME;
- basertppayload->priv->prop_max_ptime = DEFAULT_MAX_PTIME;
-}
-
-static void
-gst_basertppayload_finalize (GObject * object)
-{
- GstBaseRTPPayload *basertppayload;
-
- basertppayload = GST_BASE_RTP_PAYLOAD (object);
-
- g_rand_free (basertppayload->seq_rand);
- basertppayload->seq_rand = NULL;
- g_rand_free (basertppayload->ssrc_rand);
- basertppayload->ssrc_rand = NULL;
- g_rand_free (basertppayload->ts_rand);
- basertppayload->ts_rand = NULL;
-
- g_free (basertppayload->media);
- basertppayload->media = NULL;
- g_free (basertppayload->encoding_name);
- basertppayload->encoding_name = NULL;
-
- G_OBJECT_CLASS (parent_class)->finalize (object);
-}
-
-static gboolean
-gst_basertppayload_sink_setcaps (GstPad * pad, GstCaps * caps)
-{
- GstBaseRTPPayload *basertppayload;
- GstBaseRTPPayloadClass *basertppayload_class;
- gboolean ret = TRUE;
-
- GST_DEBUG_OBJECT (pad, "setting caps %" GST_PTR_FORMAT, caps);
- basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad));
- basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload);
-
- if (basertppayload_class->set_caps)
- ret = basertppayload_class->set_caps (basertppayload, caps);
-
- gst_object_unref (basertppayload);
-
- return ret;
-}
-
-static GstCaps *
-gst_basertppayload_sink_getcaps (GstPad * pad)
-{
- GstBaseRTPPayload *basertppayload;
- GstBaseRTPPayloadClass *basertppayload_class;
- GstCaps *caps = NULL;
-
- GST_DEBUG_OBJECT (pad, "getting caps");
-
- basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad));
- basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload);
-
- if (basertppayload_class->get_caps)
- caps = basertppayload_class->get_caps (basertppayload, pad);
-
- if (!caps) {
- caps = GST_PAD_TEMPLATE_CAPS (GST_PAD_PAD_TEMPLATE (pad));
- GST_DEBUG_OBJECT (pad,
- "using pad template %p with caps %p %" GST_PTR_FORMAT,
- GST_PAD_PAD_TEMPLATE (pad), caps, caps);
-
- caps = gst_caps_ref (caps);
- }
-
- gst_object_unref (basertppayload);
-
- return caps;
-}
-
-static gboolean
-gst_basertppayload_event (GstPad * pad, GstEvent * event)
-{
- GstBaseRTPPayload *basertppayload;
- GstBaseRTPPayloadClass *basertppayload_class;
- gboolean res;
-
- basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad));
- basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload);
-
- if (basertppayload_class->handle_event) {
- res = basertppayload_class->handle_event (pad, event);
- if (res)
- goto done;
- }
-
- switch (GST_EVENT_TYPE (event)) {
- case GST_EVENT_FLUSH_START:
- res = gst_pad_event_default (pad, event);
- break;
- case GST_EVENT_FLUSH_STOP:
- res = gst_pad_event_default (pad, event);
- gst_segment_init (&basertppayload->segment, GST_FORMAT_UNDEFINED);
- break;
- case GST_EVENT_NEWSEGMENT:
- {
- gboolean update;
- gdouble rate;
- GstFormat fmt;
- gint64 start, stop, position;
-
- gst_event_parse_new_segment (event, &update, &rate, &fmt, &start, &stop,
- &position);
- gst_segment_set_newsegment (&basertppayload->segment, update, rate, fmt,
- start, stop, position);
-
- /* fallthrough */
- }
- default:
- res = gst_pad_event_default (pad, event);
- break;
- }
-
-done:
- gst_object_unref (basertppayload);
-
- return res;
-}
-
-
-static GstFlowReturn
-gst_basertppayload_chain (GstPad * pad, GstBuffer * buffer)
-{
- GstBaseRTPPayload *basertppayload;
- GstBaseRTPPayloadClass *basertppayload_class;
- GstFlowReturn ret;
-
- basertppayload = GST_BASE_RTP_PAYLOAD (gst_pad_get_parent (pad));
- basertppayload_class = GST_BASE_RTP_PAYLOAD_GET_CLASS (basertppayload);
-
- if (!basertppayload_class->handle_buffer)
- goto no_function;
-
- ret = basertppayload_class->handle_buffer (basertppayload, buffer);
-
- gst_object_unref (basertppayload);
-
- return ret;
-
- /* ERRORS */
-no_function:
- {
- GST_ELEMENT_ERROR (basertppayload, STREAM, NOT_IMPLEMENTED, (NULL),
- ("subclass did not implement handle_buffer function"));
- gst_object_unref (basertppayload);
- gst_buffer_unref (buffer);
- return GST_FLOW_ERROR;
- }
-}
-
-/**
- * gst_basertppayload_set_options:
- * @payload: a #GstBaseRTPPayload
- * @media: the media type (typically "audio" or "video")
- * @dynamic: if the payload type is dynamic
- * @encoding_name: the encoding name
- * @clock_rate: the clock rate of the media
- *
- * Set the rtp options of the payloader. These options will be set in the caps
- * of the payloader. Subclasses must call this method before calling
- * gst_basertppayload_push() or gst_basertppayload_set_outcaps().
- */
-void
-gst_basertppayload_set_options (GstBaseRTPPayload * payload,
- const gchar * media, gboolean dynamic, const gchar * encoding_name,
- guint32 clock_rate)
-{
- g_return_if_fail (payload != NULL);
- g_return_if_fail (clock_rate != 0);
-
- g_free (payload->media);
- payload->media = g_strdup (media);
- payload->dynamic = dynamic;
- g_free (payload->encoding_name);
- payload->encoding_name = g_strdup (encoding_name);
- payload->clock_rate = clock_rate;
-}
-
-static gboolean
-copy_fixed (GQuark field_id, const GValue * value, GstStructure * dest)
-{
- if (gst_value_is_fixed (value)) {
- gst_structure_id_set_value (dest, field_id, value);
- }
- return TRUE;
-}
-
-static void
-update_max_ptime (GstBaseRTPPayload * basertppayload)
-{
- if (basertppayload->priv->caps_max_ptime != -1 &&
- basertppayload->priv->prop_max_ptime != -1)
- basertppayload->max_ptime = MIN (basertppayload->priv->caps_max_ptime,
- basertppayload->priv->prop_max_ptime);
- else if (basertppayload->priv->caps_max_ptime != -1)
- basertppayload->max_ptime = basertppayload->priv->caps_max_ptime;
- else if (basertppayload->priv->prop_max_ptime != -1)
- basertppayload->max_ptime = basertppayload->priv->prop_max_ptime;
- else
- basertppayload->max_ptime = DEFAULT_MAX_PTIME;
-}
-
-/**
- * gst_basertppayload_set_outcaps:
- * @payload: a #GstBaseRTPPayload
- * @fieldname: the first field name or %NULL
- * @...: field values
- *
- * Configure the output caps with the optional parameters.
- *
- * Variable arguments should be in the form field name, field type
- * (as a GType), value(s). The last variable argument should be NULL.
- *
- * Returns: %TRUE if the caps could be set.
- */
-gboolean
-gst_basertppayload_set_outcaps (GstBaseRTPPayload * payload,
- const gchar * fieldname, ...)
-{
- GstCaps *srccaps, *peercaps;
- gboolean res;
-
- /* fill in the defaults, their properties cannot be negotiated. */
- srccaps = gst_caps_new_simple ("application/x-rtp",
- "media", G_TYPE_STRING, payload->media,
- "clock-rate", G_TYPE_INT, payload->clock_rate,
- "encoding-name", G_TYPE_STRING, payload->encoding_name, NULL);
-
- GST_DEBUG_OBJECT (payload, "defaults: %" GST_PTR_FORMAT, srccaps);
-
- if (fieldname) {
- va_list varargs;
-
- /* override with custom properties */
- va_start (varargs, fieldname);
- gst_caps_set_simple_valist (srccaps, fieldname, varargs);
- va_end (varargs);
-
- GST_DEBUG_OBJECT (payload, "custom added: %" GST_PTR_FORMAT, srccaps);
- }
-
- payload->priv->caps_max_ptime = DEFAULT_MAX_PTIME;
- payload->abidata.ABI.ptime = 0;
-
- /* the peer caps can override some of the defaults */
- peercaps = gst_pad_peer_get_caps (payload->srcpad);
- if (peercaps == NULL) {
- /* no peer caps, just add the other properties */
- gst_caps_set_simple (srccaps,
- "payload", G_TYPE_INT, GST_BASE_RTP_PAYLOAD_PT (payload),
- "ssrc", G_TYPE_UINT, payload->current_ssrc,
- "clock-base", G_TYPE_UINT, payload->ts_base,
- "seqnum-base", G_TYPE_UINT, payload->seqnum_base, NULL);
-
- GST_DEBUG_OBJECT (payload, "no peer caps: %" GST_PTR_FORMAT, srccaps);
- } else {
- GstCaps *temp;
- GstStructure *s, *d;
- const GValue *value;
- gint pt;
- guint max_ptime, ptime;
-
- /* peer provides caps we can use to fixate, intersect. This always returns a
- * writable caps. */
- temp = gst_caps_intersect (srccaps, peercaps);
- gst_caps_unref (srccaps);
- gst_caps_unref (peercaps);
-
- if (gst_caps_is_empty (temp)) {
- gst_caps_unref (temp);
- return FALSE;
- }
-
- /* now fixate, start by taking the first caps */
- gst_caps_truncate (temp);
-
- /* get first structure */
- s = gst_caps_get_structure (temp, 0);
-
- if (gst_structure_get_uint (s, "maxptime", &max_ptime))
- payload->priv->caps_max_ptime = max_ptime * GST_MSECOND;
-
- if (gst_structure_get_uint (s, "ptime", &ptime))
- payload->abidata.ABI.ptime = ptime * GST_MSECOND;
-
- if (gst_structure_get_int (s, "payload", &pt)) {
- /* use peer pt */
- GST_BASE_RTP_PAYLOAD_PT (payload) = pt;
- GST_LOG_OBJECT (payload, "using peer pt %d", pt);
- } else {
- if (gst_structure_has_field (s, "payload")) {
- /* can only fixate if there is a field */
- gst_structure_fixate_field_nearest_int (s, "payload",
- GST_BASE_RTP_PAYLOAD_PT (payload));
- gst_structure_get_int (s, "payload", &pt);
- GST_LOG_OBJECT (payload, "using peer pt %d", pt);
- } else {
- /* no pt field, use the internal pt */
- pt = GST_BASE_RTP_PAYLOAD_PT (payload);
- gst_structure_set (s, "payload", G_TYPE_INT, pt, NULL);
- GST_LOG_OBJECT (payload, "using internal pt %d", pt);
- }
- }
-
- if (gst_structure_has_field_typed (s, "ssrc", G_TYPE_UINT)) {
- value = gst_structure_get_value (s, "ssrc");
- payload->current_ssrc = g_value_get_uint (value);
- GST_LOG_OBJECT (payload, "using peer ssrc %08x", payload->current_ssrc);
- } else {
- /* FIXME, fixate_nearest_uint would be even better */
- gst_structure_set (s, "ssrc", G_TYPE_UINT, payload->current_ssrc, NULL);
- GST_LOG_OBJECT (payload, "using internal ssrc %08x",
- payload->current_ssrc);
- }
-
- if (gst_structure_has_field_typed (s, "clock-base", G_TYPE_UINT)) {
- value = gst_structure_get_value (s, "clock-base");
- payload->ts_base = g_value_get_uint (value);
- GST_LOG_OBJECT (payload, "using peer clock-base %u", payload->ts_base);
- } else {
- /* FIXME, fixate_nearest_uint would be even better */
- gst_structure_set (s, "clock-base", G_TYPE_UINT, payload->ts_base, NULL);
- GST_LOG_OBJECT (payload, "using internal clock-base %u",
- payload->ts_base);
- }
- if (gst_structure_has_field_typed (s, "seqnum-base", G_TYPE_UINT)) {
- value = gst_structure_get_value (s, "seqnum-base");
- payload->seqnum_base = g_value_get_uint (value);
- GST_LOG_OBJECT (payload, "using peer seqnum-base %u",
- payload->seqnum_base);
- } else {
- /* FIXME, fixate_nearest_uint would be even better */
- gst_structure_set (s, "seqnum-base", G_TYPE_UINT, payload->seqnum_base,
- NULL);
- GST_LOG_OBJECT (payload, "using internal seqnum-base %u",
- payload->seqnum_base);
- }
-
- /* make the target caps by copying over all the fixed caps, removing the
- * unfixed caps. */
- srccaps = gst_caps_new_simple (gst_structure_get_name (s), NULL);
- d = gst_caps_get_structure (srccaps, 0);
-
- gst_structure_foreach (s, (GstStructureForeachFunc) copy_fixed, d);
-
- gst_caps_unref (temp);
-
- GST_DEBUG_OBJECT (payload, "with peer caps: %" GST_PTR_FORMAT, srccaps);
- }
-
- update_max_ptime (payload);
-
- res = gst_pad_set_caps (GST_BASE_RTP_PAYLOAD_SRCPAD (payload), srccaps);
- gst_caps_unref (srccaps);
-
- return res;
-}
-
-/**
- * gst_basertppayload_is_filled:
- * @payload: a #GstBaseRTPPayload
- * @size: the size of the packet
- * @duration: the duration of the packet
- *
- * Check if the packet with @size and @duration would exceed the configured
- * maximum size.
- *
- * Returns: %TRUE if the packet of @size and @duration would exceed the
- * configured MTU or max_ptime.
- */
-gboolean
-gst_basertppayload_is_filled (GstBaseRTPPayload * payload,
- guint size, GstClockTime duration)
-{
- if (size > payload->mtu)
- return TRUE;
-
- if (payload->max_ptime != -1 && duration >= payload->max_ptime)
- return TRUE;
-
- return FALSE;
-}
-
-typedef struct
-{
- GstBaseRTPPayload *payload;
- guint32 ssrc;
- guint16 seqnum;
- guint8 pt;
- GstCaps *caps;
- GstClockTime timestamp;
- guint64 offset;
- guint32 rtptime;
-} HeaderData;
-
-static GstBufferListItem
-find_timestamp (GstBuffer ** buffer, guint group, guint idx, HeaderData * data)
-{
- data->timestamp = GST_BUFFER_TIMESTAMP (*buffer);
- data->offset = GST_BUFFER_OFFSET (*buffer);
-
- /* stop when we find a timestamp. We take whatever offset is associated with
- * the timestamp (if any) to do perfect timestamps when we need to. */
- if (data->timestamp != -1)
- return GST_BUFFER_LIST_END;
- else
- return GST_BUFFER_LIST_CONTINUE;
-}
-
-static GstBufferListItem
-set_headers (GstBuffer ** buffer, guint group, guint idx, HeaderData * data)
-{
- gst_rtp_buffer_set_ssrc (*buffer, data->ssrc);
- gst_rtp_buffer_set_payload_type (*buffer, data->pt);
- gst_rtp_buffer_set_seq (*buffer, data->seqnum);
- gst_rtp_buffer_set_timestamp (*buffer, data->rtptime);
- gst_buffer_set_caps (*buffer, data->caps);
- /* increment the seqnum for each buffer */
- data->seqnum++;
-
- return GST_BUFFER_LIST_SKIP_GROUP;
-}
-
-/* Updates the SSRC, payload type, seqnum and timestamp of the RTP buffer
- * before the buffer is pushed. */
-static GstFlowReturn
-gst_basertppayload_prepare_push (GstBaseRTPPayload * payload,
- gpointer obj, gboolean is_list)
-{
- GstBaseRTPPayloadPrivate *priv;
- HeaderData data;
-
- if (payload->clock_rate == 0)
- goto no_rate;
-
- priv = payload->priv;
-
- /* update first, so that the property is set to the last
- * seqnum pushed */
- payload->seqnum = priv->next_seqnum;
-
- /* fill in the fields we want to set on all headers */
- data.payload = payload;
- data.seqnum = payload->seqnum;
- data.ssrc = payload->current_ssrc;
- data.pt = payload->pt;
- data.caps = GST_PAD_CAPS (payload->srcpad);
-
- /* find the first buffer with a timestamp */
- if (is_list) {
- data.timestamp = -1;
- data.offset = GST_BUFFER_OFFSET_NONE;
- gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj),
- (GstBufferListFunc) find_timestamp, &data);
- } else {
- data.timestamp = GST_BUFFER_TIMESTAMP (GST_BUFFER_CAST (obj));
- data.offset = GST_BUFFER_OFFSET (GST_BUFFER_CAST (obj));
- }
-
- /* convert to RTP time */
- if (priv->perfect_rtptime && data.offset != GST_BUFFER_OFFSET_NONE) {
- /* if we have an offset, use that for making an RTP timestamp */
- data.rtptime = payload->ts_base + data.offset;
- GST_LOG_OBJECT (payload,
- "Using offset %" G_GUINT64_FORMAT " for RTP timestamp", data.offset);
- } else if (GST_CLOCK_TIME_IS_VALID (data.timestamp)) {
- gint64 rtime;
-
- /* no offset, use the gstreamer timestamp */
- rtime = gst_segment_to_running_time (&payload->segment, GST_FORMAT_TIME,
- data.timestamp);
-
- GST_LOG_OBJECT (payload,
- "Using running_time %" GST_TIME_FORMAT " for RTP timestamp",
- GST_TIME_ARGS (rtime));
-
- rtime = gst_util_uint64_scale_int (rtime, payload->clock_rate, GST_SECOND);
-
- /* add running_time in clock-rate units to the base timestamp */
- data.rtptime = payload->ts_base + rtime;
- } else {
- GST_LOG_OBJECT (payload,
- "Using previous RTP timestamp %" G_GUINT32_FORMAT, payload->timestamp);
- /* no timestamp to convert, take previous timestamp */
- data.rtptime = payload->timestamp;
- }
-
- /* set ssrc, payload type, seq number, caps and rtptime */
- if (is_list) {
- gst_buffer_list_foreach (GST_BUFFER_LIST_CAST (obj),
- (GstBufferListFunc) set_headers, &data);
- } else {
- GstBuffer *buf = GST_BUFFER_CAST (obj);
- set_headers (&buf, 0, 0, &data);
- }
-
- priv->next_seqnum = data.seqnum;
- payload->timestamp = data.rtptime;
-
- GST_LOG_OBJECT (payload,
- "Preparing to push packet with size %d, seq=%d, rtptime=%u, timestamp %"
- GST_TIME_FORMAT, (is_list) ? -1 :
- GST_BUFFER_SIZE (GST_BUFFER (obj)), payload->seqnum, data.rtptime,
- GST_TIME_ARGS (data.timestamp));
-
- return GST_FLOW_OK;
-
- /* ERRORS */
-no_rate:
- {
- GST_ELEMENT_ERROR (payload, STREAM, NOT_IMPLEMENTED, (NULL),
- ("subclass did not specify clock-rate"));
- return GST_FLOW_ERROR;
- }
-}
-
-/**
- * gst_basertppayload_push_list:
- * @payload: a #GstBaseRTPPayload
- * @list: a #GstBufferList
- *
- * Push @list to the peer element of the payloader. The SSRC, payload type,
- * seqnum and timestamp of the RTP buffer will be updated first.
- *
- * This function takes ownership of @list.
- *
- * Returns: a #GstFlowReturn.
- *
- * Since: 0.10.24
- */
-GstFlowReturn
-gst_basertppayload_push_list (GstBaseRTPPayload * payload, GstBufferList * list)
-{
- GstFlowReturn res;
-
- res = gst_basertppayload_prepare_push (payload, list, TRUE);
-
- if (G_LIKELY (res == GST_FLOW_OK))
- res = gst_pad_push_list (payload->srcpad, list);
- else
- gst_buffer_list_unref (list);
-
- return res;
-}
-
-/**
- * gst_basertppayload_push:
- * @payload: a #GstBaseRTPPayload
- * @buffer: a #GstBuffer
- *
- * Push @buffer to the peer element of the payloader. The SSRC, payload type,
- * seqnum and timestamp of the RTP buffer will be updated first.
- *
- * This function takes ownership of @buffer.
- *
- * Returns: a #GstFlowReturn.
- */
-GstFlowReturn
-gst_basertppayload_push (GstBaseRTPPayload * payload, GstBuffer * buffer)
-{
- GstFlowReturn res;
-
- res = gst_basertppayload_prepare_push (payload, buffer, FALSE);
-
- if (G_LIKELY (res == GST_FLOW_OK))
- res = gst_pad_push (payload->srcpad, buffer);
- else
- gst_buffer_unref (buffer);
-
- return res;
-}
-
-static void
-gst_basertppayload_set_property (GObject * object, guint prop_id,
- const GValue * value, GParamSpec * pspec)
-{
- GstBaseRTPPayload *basertppayload;
- GstBaseRTPPayloadPrivate *priv;
- gint64 val;
-
- basertppayload = GST_BASE_RTP_PAYLOAD (object);
- priv = basertppayload->priv;
-
- switch (prop_id) {
- case PROP_MTU:
- basertppayload->mtu = g_value_get_uint (value);
- break;
- case PROP_PT:
- basertppayload->pt = g_value_get_uint (value);
- break;
- case PROP_SSRC:
- val = g_value_get_uint (value);
- basertppayload->ssrc = val;
- priv->ssrc_random = FALSE;
- break;
- case PROP_TIMESTAMP_OFFSET:
- val = g_value_get_uint (value);
- basertppayload->ts_offset = val;
- priv->ts_offset_random = FALSE;
- break;
- case PROP_SEQNUM_OFFSET:
- val = g_value_get_int (value);
- basertppayload->seqnum_offset = val;
- priv->seqnum_offset_random = (val == -1);
- GST_DEBUG_OBJECT (basertppayload, "seqnum offset 0x%04x, random %d",
- basertppayload->seqnum_offset, priv->seqnum_offset_random);
- break;
- case PROP_MAX_PTIME:
- basertppayload->priv->prop_max_ptime = g_value_get_int64 (value);
- update_max_ptime (basertppayload);
- break;
- case PROP_MIN_PTIME:
- basertppayload->min_ptime = g_value_get_int64 (value);
- break;
- case PROP_PERFECT_RTPTIME:
- priv->perfect_rtptime = g_value_get_boolean (value);
- break;
- case PROP_PTIME_MULTIPLE:
- basertppayload->abidata.ABI.ptime_multiple = g_value_get_int64 (value);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_basertppayload_get_property (GObject * object, guint prop_id,
- GValue * value, GParamSpec * pspec)
-{
- GstBaseRTPPayload *basertppayload;
- GstBaseRTPPayloadPrivate *priv;
-
- basertppayload = GST_BASE_RTP_PAYLOAD (object);
- priv = basertppayload->priv;
-
- switch (prop_id) {
- case PROP_MTU:
- g_value_set_uint (value, basertppayload->mtu);
- break;
- case PROP_PT:
- g_value_set_uint (value, basertppayload->pt);
- break;
- case PROP_SSRC:
- if (priv->ssrc_random)
- g_value_set_uint (value, -1);
- else
- g_value_set_uint (value, basertppayload->ssrc);
- break;
- case PROP_TIMESTAMP_OFFSET:
- if (priv->ts_offset_random)
- g_value_set_uint (value, -1);
- else
- g_value_set_uint (value, (guint32) basertppayload->ts_offset);
- break;
- case PROP_SEQNUM_OFFSET:
- if (priv->seqnum_offset_random)
- g_value_set_int (value, -1);
- else
- g_value_set_int (value, (guint16) basertppayload->seqnum_offset);
- break;
- case PROP_MAX_PTIME:
- g_value_set_int64 (value, basertppayload->max_ptime);
- break;
- case PROP_MIN_PTIME:
- g_value_set_int64 (value, basertppayload->min_ptime);
- break;
- case PROP_TIMESTAMP:
- g_value_set_uint (value, basertppayload->timestamp);
- break;
- case PROP_SEQNUM:
- g_value_set_uint (value, basertppayload->seqnum);
- break;
- case PROP_PERFECT_RTPTIME:
- g_value_set_boolean (value, priv->perfect_rtptime);
- break;
- case PROP_PTIME_MULTIPLE:
- g_value_set_int64 (value, basertppayload->abidata.ABI.ptime_multiple);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static GstStateChangeReturn
-gst_basertppayload_change_state (GstElement * element,
- GstStateChange transition)
-{
- GstBaseRTPPayload *basertppayload;
- GstBaseRTPPayloadPrivate *priv;
- GstStateChangeReturn ret;
-
- basertppayload = GST_BASE_RTP_PAYLOAD (element);
- priv = basertppayload->priv;
-
- switch (transition) {
- case GST_STATE_CHANGE_NULL_TO_READY:
- break;
- case GST_STATE_CHANGE_READY_TO_PAUSED:
- gst_segment_init (&basertppayload->segment, GST_FORMAT_UNDEFINED);
-
- if (priv->seqnum_offset_random)
- basertppayload->seqnum_base = g_random_int_range (0, G_MAXUINT16);
- else
- basertppayload->seqnum_base = basertppayload->seqnum_offset;
- priv->next_seqnum = basertppayload->seqnum_base;
- basertppayload->seqnum = basertppayload->seqnum_base;
-
- if (priv->ssrc_random)
- basertppayload->current_ssrc = g_random_int ();
- else
- basertppayload->current_ssrc = basertppayload->ssrc;
-
- if (priv->ts_offset_random)
- basertppayload->ts_base = g_random_int ();
- else
- basertppayload->ts_base = basertppayload->ts_offset;
- basertppayload->timestamp = basertppayload->ts_base;
- break;
- default:
- break;
- }
-
- ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
-
- switch (transition) {
- case GST_STATE_CHANGE_READY_TO_NULL:
- break;
- default:
- break;
- }
- return ret;
-}
+++ /dev/null
-*************** struct _GstBaseRTPPayloadPrivate
-*** 48,53 ****
- guint16 next_seqnum;
- gboolean perfect_rtptime;
- gboolean timestamp_valid;
-
- gint64 prop_max_ptime;
- gint64 caps_max_ptime;
---- 48,54 ----
- guint16 next_seqnum;
- gboolean perfect_rtptime;
- gboolean timestamp_valid;
-+ gboolean notified_first_timestamp;
-
- gint64 prop_max_ptime;
- gint64 caps_max_ptime;
+++ /dev/null
-/* GStreamer
- * Copyright (C) <2005> Philippe Khalaf <burger@speedy.org>
- * Copyright (C) <2006> Wim Taymans <wim@fluendo.com>
- *
- * 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.
- */
-
-/**
- * SECTION:gstrtpbuffer
- * @short_description: Helper methods for dealing with RTP buffers
- * @see_also: #GstBaseRTPPayload, #GstBaseRTPDepayload, gstrtcpbuffer
- *
- * <refsect2>
- * <para>
- * The GstRTPBuffer helper functions makes it easy to parse and create regular
- * #GstBuffer objects that contain RTP payloads. These buffers are typically of
- * 'application/x-rtp' #GstCaps.
- * </para>
- * </refsect2>
- *
- * Last reviewed on 2006-07-17 (0.10.10)
- */
-
-#include "gstrtpbuffer.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#define GST_RTP_HEADER_LEN 12
-
-/* Note: we use bitfields here to make sure the compiler doesn't add padding
- * between fields on certain architectures; can't assume aligned access either
- */
-typedef struct _GstRTPHeader
-{
-#if G_BYTE_ORDER == G_LITTLE_ENDIAN
- unsigned int csrc_count:4; /* CSRC count */
- unsigned int extension:1; /* header extension flag */
- unsigned int padding:1; /* padding flag */
- unsigned int version:2; /* protocol version */
- unsigned int payload_type:7; /* payload type */
- unsigned int marker:1; /* marker bit */
-#elif G_BYTE_ORDER == G_BIG_ENDIAN
- unsigned int version:2; /* protocol version */
- unsigned int padding:1; /* padding flag */
- unsigned int extension:1; /* header extension flag */
- unsigned int csrc_count:4; /* CSRC count */
- unsigned int marker:1; /* marker bit */
- unsigned int payload_type:7; /* payload type */
-#else
-#error "G_BYTE_ORDER should be big or little endian."
-#endif
- unsigned int seq:16; /* sequence number */
- unsigned int timestamp:32; /* timestamp */
- unsigned int ssrc:32; /* synchronization source */
- guint8 csrclist[4]; /* optional CSRC list, 32 bits each */
-} GstRTPHeader;
-
-#define GST_RTP_HEADER_VERSION(data) (((GstRTPHeader *)(data))->version)
-#define GST_RTP_HEADER_PADDING(data) (((GstRTPHeader *)(data))->padding)
-#define GST_RTP_HEADER_EXTENSION(data) (((GstRTPHeader *)(data))->extension)
-#define GST_RTP_HEADER_CSRC_COUNT(data) (((GstRTPHeader *)(data))->csrc_count)
-#define GST_RTP_HEADER_MARKER(data) (((GstRTPHeader *)(data))->marker)
-#define GST_RTP_HEADER_PAYLOAD_TYPE(data) (((GstRTPHeader *)(data))->payload_type)
-#define GST_RTP_HEADER_SEQ(data) (((GstRTPHeader *)(data))->seq)
-#define GST_RTP_HEADER_TIMESTAMP(data) (((GstRTPHeader *)(data))->timestamp)
-#define GST_RTP_HEADER_SSRC(data) (((GstRTPHeader *)(data))->ssrc)
-#define GST_RTP_HEADER_CSRC_LIST_OFFSET(data,i) \
- data + G_STRUCT_OFFSET(GstRTPHeader, csrclist) + \
- ((i) * sizeof(guint32))
-#define GST_RTP_HEADER_CSRC_SIZE(data) (GST_RTP_HEADER_CSRC_COUNT(data) * sizeof (guint32))
-
-typedef enum
-{
- PAYLOAD_TYPE,
- SEQ,
- TIMESTAMP,
- SSRC,
- NO_MORE
-} rtp_header_data_type;
-
-static gboolean validate_data (guint8 * data, guint len, guint8 * payload,
- guint payload_len);
-static guint8 *gst_rtp_buffer_list_get_data (GstBufferList * list);
-static void gst_rtp_buffer_list_set_rtp_headers (GstBufferList * list,
- gpointer data, rtp_header_data_type type);
-static void gst_rtp_buffer_list_set_data (guint8 * rtp_header, gpointer data,
- rtp_header_data_type type);
-
-/**
- * gst_rtp_buffer_allocate_data:
- * @buffer: a #GstBuffer
- * @payload_len: the length of the payload
- * @pad_len: the amount of padding
- * @csrc_count: the number of CSRC entries
- *
- * Allocate enough data in @buffer to hold an RTP packet with @csrc_count CSRCs,
- * a payload length of @payload_len and padding of @pad_len.
- * MALLOCDATA of @buffer will be overwritten and will not be freed.
- * All other RTP header fields will be set to 0/FALSE.
- */
-void
-gst_rtp_buffer_allocate_data (GstBuffer * buffer, guint payload_len,
- guint8 pad_len, guint8 csrc_count)
-{
- guint len;
- guint8 *data;
-
- g_return_if_fail (csrc_count <= 15);
- g_return_if_fail (GST_IS_BUFFER (buffer));
-
- len = GST_RTP_HEADER_LEN + csrc_count * sizeof (guint32)
- + payload_len + pad_len;
-
- data = g_malloc (len);
- GST_BUFFER_MALLOCDATA (buffer) = data;
- GST_BUFFER_DATA (buffer) = data;
- GST_BUFFER_SIZE (buffer) = len;
-
- /* fill in defaults */
- GST_RTP_HEADER_VERSION (data) = GST_RTP_VERSION;
- GST_RTP_HEADER_PADDING (data) = FALSE;
- GST_RTP_HEADER_EXTENSION (data) = FALSE;
- GST_RTP_HEADER_CSRC_COUNT (data) = csrc_count;
- memset (GST_RTP_HEADER_CSRC_LIST_OFFSET (data, 0), 0,
- csrc_count * sizeof (guint32));
- GST_RTP_HEADER_MARKER (data) = FALSE;
- GST_RTP_HEADER_PAYLOAD_TYPE (data) = 0;
- GST_RTP_HEADER_SEQ (data) = 0;
- GST_RTP_HEADER_TIMESTAMP (data) = 0;
- GST_RTP_HEADER_SSRC (data) = 0;
-}
-
-/**
- * gst_rtp_buffer_new_take_data:
- * @data: data for the new buffer
- * @len: the length of data
- *
- * Create a new buffer and set the data and size of the buffer to @data and @len
- * respectively. @data will be freed when the buffer is unreffed, so this
- * function transfers ownership of @data to the new buffer.
- *
- * Returns: A newly allocated buffer with @data and of size @len.
- */
-GstBuffer *
-gst_rtp_buffer_new_take_data (gpointer data, guint len)
-{
- GstBuffer *result;
-
- g_return_val_if_fail (data != NULL, NULL);
- g_return_val_if_fail (len > 0, NULL);
-
- result = gst_buffer_new ();
-
- GST_BUFFER_MALLOCDATA (result) = data;
- GST_BUFFER_DATA (result) = data;
- GST_BUFFER_SIZE (result) = len;
-
- return result;
-}
-
-/**
- * gst_rtp_buffer_new_copy_data:
- * @data: data for the new buffer
- * @len: the length of data
- *
- * Create a new buffer and set the data to a copy of @len
- * bytes of @data and the size to @len. The data will be freed when the buffer
- * is freed.
- *
- * Returns: A newly allocated buffer with a copy of @data and of size @len.
- */
-GstBuffer *
-gst_rtp_buffer_new_copy_data (gpointer data, guint len)
-{
- return gst_rtp_buffer_new_take_data (g_memdup (data, len), len);
-}
-
-/**
- * gst_rtp_buffer_new_allocate:
- * @payload_len: the length of the payload
- * @pad_len: the amount of padding
- * @csrc_count: the number of CSRC entries
- *
- * Allocate a new #Gstbuffer with enough data to hold an RTP packet with @csrc_count CSRCs,
- * a payload length of @payload_len and padding of @pad_len.
- * All other RTP header fields will be set to 0/FALSE.
- *
- * Returns: A newly allocated buffer that can hold an RTP packet with given
- * parameters.
- */
-GstBuffer *
-gst_rtp_buffer_new_allocate (guint payload_len, guint8 pad_len,
- guint8 csrc_count)
-{
- GstBuffer *result;
-
- g_return_val_if_fail (csrc_count <= 15, NULL);
-
- result = gst_buffer_new ();
- gst_rtp_buffer_allocate_data (result, payload_len, pad_len, csrc_count);
-
- return result;
-}
-
-/**
- * gst_rtp_buffer_new_allocate_len:
- * @packet_len: the total length of the packet
- * @pad_len: the amount of padding
- * @csrc_count: the number of CSRC entries
- *
- * Create a new #GstBuffer that can hold an RTP packet that is exactly
- * @packet_len long. The length of the payload depends on @pad_len and
- * @csrc_count and can be calculated with gst_rtp_buffer_calc_payload_len().
- * All RTP header fields will be set to 0/FALSE.
- *
- * Returns: A newly allocated buffer that can hold an RTP packet of @packet_len.
- */
-GstBuffer *
-gst_rtp_buffer_new_allocate_len (guint packet_len, guint8 pad_len,
- guint8 csrc_count)
-{
- guint len;
-
- g_return_val_if_fail (csrc_count <= 15, NULL);
-
- len = gst_rtp_buffer_calc_payload_len (packet_len, pad_len, csrc_count);
-
- return gst_rtp_buffer_new_allocate (len, pad_len, csrc_count);
-}
-
-/**
- * gst_rtp_buffer_calc_header_len:
- * @csrc_count: the number of CSRC entries
- *
- * Calculate the header length of an RTP packet with @csrc_count CSRC entries.
- * An RTP packet can have at most 15 CSRC entries.
- *
- * Returns: The length of an RTP header with @csrc_count CSRC entries.
- */
-guint
-gst_rtp_buffer_calc_header_len (guint8 csrc_count)
-{
- g_return_val_if_fail (csrc_count <= 15, 0);
-
- return GST_RTP_HEADER_LEN + (csrc_count * sizeof (guint32));
-}
-
-/**
- * gst_rtp_buffer_calc_packet_len:
- * @payload_len: the length of the payload
- * @pad_len: the amount of padding
- * @csrc_count: the number of CSRC entries
- *
- * Calculate the total length of an RTP packet with a payload size of @payload_len,
- * a padding of @pad_len and a @csrc_count CSRC entries.
- *
- * Returns: The total length of an RTP header with given parameters.
- */
-guint
-gst_rtp_buffer_calc_packet_len (guint payload_len, guint8 pad_len,
- guint8 csrc_count)
-{
- g_return_val_if_fail (csrc_count <= 15, 0);
-
- return payload_len + GST_RTP_HEADER_LEN + (csrc_count * sizeof (guint32))
- + pad_len;
-}
-
-/**
- * gst_rtp_buffer_calc_payload_len:
- * @packet_len: the length of the total RTP packet
- * @pad_len: the amount of padding
- * @csrc_count: the number of CSRC entries
- *
- * Calculate the length of the payload of an RTP packet with size @packet_len,
- * a padding of @pad_len and a @csrc_count CSRC entries.
- *
- * Returns: The length of the payload of an RTP packet with given parameters.
- */
-guint
-gst_rtp_buffer_calc_payload_len (guint packet_len, guint8 pad_len,
- guint8 csrc_count)
-{
- g_return_val_if_fail (csrc_count <= 15, 0);
-
- return packet_len - GST_RTP_HEADER_LEN - (csrc_count * sizeof (guint32))
- - pad_len;
-}
-
-/**
- * gst_rtp_buffer_validate_data:
- * @data: the data to validate
- * @len: the length of @data to validate
- *
- * Check if the @data and @size point to the data of a valid RTP packet.
- * This function checks the length, version and padding of the packet data.
- * Use this function to validate a packet before using the other functions in
- * this module.
- *
- * Returns: TRUE if the data points to a valid RTP packet.
- */
-gboolean
-gst_rtp_buffer_validate_data (guint8 * data, guint len)
-{
- return validate_data (data, len, NULL, 0);
-}
-
-/**
- * gst_rtp_buffer_validate:
- * @buffer: the buffer to validate
- *
- * Check if the data pointed to by @buffer is a valid RTP packet using
- * validate_data().
- * Use this function to validate a packet before using the other functions in
- * this module.
- *
- * Returns: TRUE if @buffer is a valid RTP packet.
- */
-gboolean
-gst_rtp_buffer_validate (GstBuffer * buffer)
-{
- guint8 *data;
- guint len;
-
- g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
-
- data = GST_BUFFER_DATA (buffer);
- len = GST_BUFFER_SIZE (buffer);
-
- return validate_data (data, len, NULL, 0);
-}
-
-/**
- * gst_rtp_buffer_list_validate:
- * @list: the buffer list to validate
- *
- * Check if all RTP packets in the @list are valid using validate_data().
- * Use this function to validate an list before using the other functions in
- * this module.
- *
- * Returns: TRUE if @list consists only of valid RTP packets.
- */
-gboolean
-gst_rtp_buffer_list_validate (GstBufferList * list)
-{
- guint16 prev_seqnum = 0;
- GstBufferListIterator *it;
- guint i = 0;
-
- g_return_val_if_fail (GST_IS_BUFFER_LIST (list), FALSE);
-
- it = gst_buffer_list_iterate (list);
- g_return_val_if_fail (it != NULL, FALSE);
-
- /* iterate through all the RTP packets in the list */
- while (gst_buffer_list_iterator_next_group (it)) {
- GstBuffer *rtpbuf;
- GstBuffer *paybuf;
- guint8 *packet_header;
- guint8 *packet_payload;
- guint payload_size;
- guint packet_size;
-
- /* each group should consists of 2 buffers: one containing the RTP header
- * and the other one the payload */
- if (gst_buffer_list_iterator_n_buffers (it) != 2)
- goto invalid_list;
-
- /* get the RTP header */
- rtpbuf = gst_buffer_list_iterator_next (it);
- packet_header = GST_BUFFER_DATA (rtpbuf);
- if (packet_header == NULL)
- goto invalid_list;
-
- /* get the payload */
- paybuf = gst_buffer_list_iterator_next (it);
- packet_payload = GST_BUFFER_DATA (paybuf);
- if (packet_payload == NULL) {
- goto invalid_list;
- }
- payload_size = GST_BUFFER_SIZE (paybuf);
- if (payload_size == 0) {
- goto invalid_list;
- }
-
- /* the size of the RTP packet within the current group */
- packet_size = GST_BUFFER_SIZE (rtpbuf) + payload_size;
-
- /* check the sequence number */
- if (G_UNLIKELY (i == 0)) {
- prev_seqnum = g_ntohs (GST_RTP_HEADER_SEQ (packet_header));
- i++;
- } else {
- if (++prev_seqnum != g_ntohs (GST_RTP_HEADER_SEQ (packet_header)))
- goto invalid_list;
- }
-
- /* validate packet */
- if (!validate_data (packet_header, packet_size, packet_payload,
- payload_size)) {
- goto invalid_list;
- }
- }
-
- gst_buffer_list_iterator_free (it);
- return TRUE;
-
-invalid_list:
- gst_buffer_list_iterator_free (it);
- g_return_val_if_reached (FALSE);
-}
-
-/**
- * validate_data:
- * @data: the data to validate
- * @len: the length of @data to validate
- * @payload: the payload if @data represents the header only
- * @payload_len: the len of the payload
- *
- * Checks if @data is a valid RTP packet.
- *
- * Returns: TRUE if @data is a valid RTP packet
- */
-static gboolean
-validate_data (guint8 * data, guint len, guint8 * payload, guint payload_len)
-{
- guint8 padding;
- guint8 csrc_count;
- guint header_len;
- guint8 version;
-
- g_return_val_if_fail (data != NULL, FALSE);
-
- header_len = GST_RTP_HEADER_LEN;
- if (G_UNLIKELY (len < header_len))
- goto wrong_length;
-
- /* check version */
- version = (data[0] & 0xc0);
- if (G_UNLIKELY (version != (GST_RTP_VERSION << 6)))
- goto wrong_version;
-
- /* calc header length with csrc */
- csrc_count = (data[0] & 0x0f);
- header_len += csrc_count * sizeof (guint32);
-
- /* calc extension length when present. */
- if (data[0] & 0x10) {
- guint8 *extpos;
- guint16 extlen;
-
- /* this points to the extenstion bits and header length */
- extpos = &data[header_len];
-
- /* skip the header and check that we have enough space */
- header_len += 4;
- if (G_UNLIKELY (len < header_len))
- goto wrong_length;
-
- /* skip id */
- extpos += 2;
- /* read length as the number of 32 bits words */
- extlen = GST_READ_UINT16_BE (extpos);
-
- header_len += extlen * sizeof (guint32);
- }
-
- /* check for padding */
- if (data[0] & 0x20) {
- if (payload)
- padding = payload[payload_len - 1];
- else
- padding = data[len - 1];
- } else {
- padding = 0;
- }
-
- /* check if padding and header not bigger than packet length */
- if (G_UNLIKELY (len < padding + header_len))
- goto wrong_padding;
-
- return TRUE;
-
- /* ERRORS */
-wrong_length:
- {
- GST_DEBUG ("len < header_len check failed (%d < %d)", len, header_len);
- return FALSE;
- }
-wrong_version:
- {
- GST_DEBUG ("version check failed (%d != %d)", version, GST_RTP_VERSION);
- return FALSE;
- }
-wrong_padding:
- {
- GST_DEBUG ("padding check failed (%d - %d < %d)", len, header_len, padding);
- return FALSE;
- }
-}
-
-/**
- * gst_rtp_buffer_set_packet_len:
- * @buffer: the buffer
- * @len: the new packet length
- *
- * Set the total @buffer size to @len. The data in the buffer will be made
- * larger if needed. Any padding will be removed from the packet.
- */
-void
-gst_rtp_buffer_set_packet_len (GstBuffer * buffer, guint len)
-{
- guint oldlen;
- guint8 *data;
-
- oldlen = GST_BUFFER_SIZE (buffer);
- data = GST_BUFFER_DATA (buffer);
-
- if (oldlen < len) {
- data = g_realloc (GST_BUFFER_MALLOCDATA (buffer), len);
- GST_BUFFER_MALLOCDATA (buffer) = data;
- GST_BUFFER_DATA (buffer) = data;
- }
- GST_BUFFER_SIZE (buffer) = len;
-
- /* remove any padding */
- GST_RTP_HEADER_PADDING (data) = FALSE;
-}
-
-/**
- * gst_rtp_buffer_get_packet_len:
- * @buffer: the buffer
- *
- * Return the total length of the packet in @buffer.
- *
- * Returns: The total length of the packet in @buffer.
- */
-guint
-gst_rtp_buffer_get_packet_len (GstBuffer * buffer)
-{
- return GST_BUFFER_SIZE (buffer);
-}
-
-/**
- * gst_rtp_buffer_get_header_len:
- * @buffer: the buffer
- *
- * Return the total length of the header in @buffer. This include the length of
- * the fixed header, the CSRC list and the extension header.
- *
- * Returns: The total length of the header in @buffer.
- */
-guint
-gst_rtp_buffer_get_header_len (GstBuffer * buffer)
-{
- guint len;
- guint8 *data;
-
- data = GST_BUFFER_DATA (buffer);
-
- len = GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (data);
- if (GST_RTP_HEADER_EXTENSION (data))
- len += GST_READ_UINT16_BE (data + len + 2) * 4 + 4;
-
- return len;
-}
-
-/**
- * gst_rtp_buffer_get_version:
- * @buffer: the buffer
- *
- * Get the version number of the RTP packet in @buffer.
- *
- * Returns: The version of @buffer.
- */
-guint8
-gst_rtp_buffer_get_version (GstBuffer * buffer)
-{
- return GST_RTP_HEADER_VERSION (GST_BUFFER_DATA (buffer));
-}
-
-/**
- * gst_rtp_buffer_set_version:
- * @buffer: the buffer
- * @version: the new version
- *
- * Set the version of the RTP packet in @buffer to @version.
- */
-void
-gst_rtp_buffer_set_version (GstBuffer * buffer, guint8 version)
-{
- g_return_if_fail (version < 0x04);
-
- GST_RTP_HEADER_VERSION (GST_BUFFER_DATA (buffer)) = version;
-}
-
-/**
- * gst_rtp_buffer_get_padding:
- * @buffer: the buffer
- *
- * Check if the padding bit is set on the RTP packet in @buffer.
- *
- * Returns: TRUE if @buffer has the padding bit set.
- */
-gboolean
-gst_rtp_buffer_get_padding (GstBuffer * buffer)
-{
- return GST_RTP_HEADER_PADDING (GST_BUFFER_DATA (buffer));
-}
-
-/**
- * gst_rtp_buffer_set_padding:
- * @buffer: the buffer
- * @padding: the new padding
- *
- * Set the padding bit on the RTP packet in @buffer to @padding.
- */
-void
-gst_rtp_buffer_set_padding (GstBuffer * buffer, gboolean padding)
-{
- GST_RTP_HEADER_PADDING (GST_BUFFER_DATA (buffer)) = padding;
-}
-
-/**
- * gst_rtp_buffer_pad_to:
- * @buffer: the buffer
- * @len: the new amount of padding
- *
- * Set the amount of padding in the RTP packet in @buffer to
- * @len. If @len is 0, the padding is removed.
- *
- * NOTE: This function does not work correctly.
- */
-void
-gst_rtp_buffer_pad_to (GstBuffer * buffer, guint len)
-{
- guint8 *data;
-
- data = GST_BUFFER_DATA (buffer);
-
- if (len > 0)
- GST_RTP_HEADER_PADDING (data) = TRUE;
- else
- GST_RTP_HEADER_PADDING (data) = FALSE;
-
- /* FIXME, set the padding byte at the end of the payload data */
-}
-
-/**
- * gst_rtp_buffer_get_extension:
- * @buffer: the buffer
- *
- * Check if the extension bit is set on the RTP packet in @buffer.
- *
- * Returns: TRUE if @buffer has the extension bit set.
- */
-gboolean
-gst_rtp_buffer_get_extension (GstBuffer * buffer)
-{
- return GST_RTP_HEADER_EXTENSION (GST_BUFFER_DATA (buffer));
-}
-
-/**
- * gst_rtp_buffer_set_extension:
- * @buffer: the buffer
- * @extension: the new extension
- *
- * Set the extension bit on the RTP packet in @buffer to @extension.
- */
-void
-gst_rtp_buffer_set_extension (GstBuffer * buffer, gboolean extension)
-{
- GST_RTP_HEADER_EXTENSION (GST_BUFFER_DATA (buffer)) = extension;
-}
-
-/**
- * gst_rtp_buffer_get_extension_data:
- * @buffer: the buffer
- * @bits: location for result bits
- * @data: location for data
- * @wordlen: location for length of @data in 32 bits words
- *
- * Get the extension data. @bits will contain the extension 16 bits of custom
- * data. @data will point to the data in the extension and @wordlen will contain
- * the length of @data in 32 bits words.
- *
- * If @buffer did not contain an extension, this function will return %FALSE
- * with @bits, @data and @wordlen unchanged.
- *
- * Returns: TRUE if @buffer had the extension bit set.
- *
- * Since: 0.10.15
- */
-gboolean
-gst_rtp_buffer_get_extension_data (GstBuffer * buffer, guint16 * bits,
- gpointer * data, guint * wordlen)
-{
- guint len;
- guint8 *pdata;
-
- pdata = GST_BUFFER_DATA (buffer);
-
- if (!GST_RTP_HEADER_EXTENSION (pdata))
- return FALSE;
-
- /* move to the extension */
- len = GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (pdata);
- pdata += len;
-
- if (bits)
- *bits = GST_READ_UINT16_BE (pdata);
- if (wordlen)
- *wordlen = GST_READ_UINT16_BE (pdata + 2);
- if (data)
- *data = pdata + 4;
-
- return TRUE;
-}
-
-/**
- * gst_rtp_buffer_set_extension_data:
- * @buffer: the buffer
- * @bits: the bits specific for the extension
- * @length: the length that counts the number of 32-bit words in
- * the extension, excluding the extension header ( therefore zero is a valid length)
- *
- * Set the extension bit of the rtp buffer and fill in the @bits and @length of the
- * extension header. It will refuse to set the extension data if the buffer is not
- * large enough.
- *
- * Returns: True if done.
- *
- * Since : 0.10.18
- */
-gboolean
-gst_rtp_buffer_set_extension_data (GstBuffer * buffer, guint16 bits,
- guint16 length)
-{
- guint32 min_size = 0;
- guint8 *data;
-
- data = GST_BUFFER_DATA (buffer);
-
- /* check if the buffer is big enough to hold the extension */
- min_size =
- GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (data) + 4 +
- length * sizeof (guint32);
- if (G_UNLIKELY (min_size > GST_BUFFER_SIZE (buffer)))
- goto too_small;
-
- /* now we can set the extension bit */
- gst_rtp_buffer_set_extension (buffer, TRUE);
-
- data += GST_RTP_HEADER_LEN + GST_RTP_HEADER_CSRC_SIZE (data);
- GST_WRITE_UINT16_BE (data, bits);
- GST_WRITE_UINT16_BE (data + 2, length);
-
- return TRUE;
-
- /* ERRORS */
-too_small:
- {
- g_warning
- ("rtp buffer too small: need more than %d bytes but only have %d bytes",
- min_size, GST_BUFFER_SIZE (buffer));
- return FALSE;
- }
-}
-
-/**
- * gst_rtp_buffer_get_ssrc:
- * @buffer: the buffer
- *
- * Get the SSRC of the RTP packet in @buffer.
- *
- * Returns: the SSRC of @buffer in host order.
- */
-guint32
-gst_rtp_buffer_get_ssrc (GstBuffer * buffer)
-{
- return g_ntohl (GST_RTP_HEADER_SSRC (GST_BUFFER_DATA (buffer)));
-}
-
-/**
- * gst_rtp_buffer_list_get_ssrc:
- * @list: the list
- *
- * Get the SSRC of the first RTP packet in @list.
- * All RTP packets within @list have the same SSRC.
- *
- * Returns: the SSRC of @list in host order.
- */
-guint32
-gst_rtp_buffer_list_get_ssrc (GstBufferList * list)
-{
- guint8 *data;
- data = gst_rtp_buffer_list_get_data (list);
- g_return_val_if_fail (data != NULL, 0);
- return g_ntohl (GST_RTP_HEADER_SSRC (data));
-}
-
-/**
- * gst_rtp_buffer_set_ssrc:
- * @buffer: the buffer
- * @ssrc: the new SSRC
- *
- * Set the SSRC on the RTP packet in @buffer to @ssrc.
- */
-void
-gst_rtp_buffer_set_ssrc (GstBuffer * buffer, guint32 ssrc)
-{
- GST_RTP_HEADER_SSRC (GST_BUFFER_DATA (buffer)) = g_htonl (ssrc);
-}
-
-/**
- * gst_rtp_buffer_list_set_ssrc:
- * @list: the buffer list
- * @ssrc: the new SSRC
- *
- * Set the SSRC on each RTP packet in @list to @ssrc.
- */
-void
-gst_rtp_buffer_list_set_ssrc (GstBufferList * list, guint32 ssrc)
-{
- gst_rtp_buffer_list_set_rtp_headers (list, &ssrc, SSRC);
-}
-
-/**
- * gst_rtp_buffer_get_csrc_count:
- * @buffer: the buffer
- *
- * Get the CSRC count of the RTP packet in @buffer.
- *
- * Returns: the CSRC count of @buffer.
- */
-guint8
-gst_rtp_buffer_get_csrc_count (GstBuffer * buffer)
-{
- return GST_RTP_HEADER_CSRC_COUNT (GST_BUFFER_DATA (buffer));
-}
-
-/**
- * gst_rtp_buffer_get_csrc:
- * @buffer: the buffer
- * @idx: the index of the CSRC to get
- *
- * Get the CSRC at index @idx in @buffer.
- *
- * Returns: the CSRC at index @idx in host order.
- */
-guint32
-gst_rtp_buffer_get_csrc (GstBuffer * buffer, guint8 idx)
-{
- guint8 *data;
-
- data = GST_BUFFER_DATA (buffer);
-
- g_return_val_if_fail (idx < GST_RTP_HEADER_CSRC_COUNT (data), 0);
-
- return GST_READ_UINT32_BE (GST_RTP_HEADER_CSRC_LIST_OFFSET (data, idx));
-}
-
-/**
- * gst_rtp_buffer_set_csrc:
- * @buffer: the buffer
- * @idx: the CSRC index to set
- * @csrc: the CSRC in host order to set at @idx
- *
- * Modify the CSRC at index @idx in @buffer to @csrc.
- */
-void
-gst_rtp_buffer_set_csrc (GstBuffer * buffer, guint8 idx, guint32 csrc)
-{
- guint8 *data;
-
- data = GST_BUFFER_DATA (buffer);
-
- g_return_if_fail (idx < GST_RTP_HEADER_CSRC_COUNT (data));
-
- GST_WRITE_UINT32_BE (GST_RTP_HEADER_CSRC_LIST_OFFSET (data, idx), csrc);
-}
-
-/**
- * gst_rtp_buffer_get_marker:
- * @buffer: the buffer
- *
- * Check if the marker bit is set on the RTP packet in @buffer.
- *
- * Returns: TRUE if @buffer has the marker bit set.
- */
-gboolean
-gst_rtp_buffer_get_marker (GstBuffer * buffer)
-{
- return GST_RTP_HEADER_MARKER (GST_BUFFER_DATA (buffer));
-}
-
-/**
- * gst_rtp_buffer_set_marker:
- * @buffer: the buffer
- * @marker: the new marker
- *
- * Set the marker bit on the RTP packet in @buffer to @marker.
- */
-void
-gst_rtp_buffer_set_marker (GstBuffer * buffer, gboolean marker)
-{
- GST_RTP_HEADER_MARKER (GST_BUFFER_DATA (buffer)) = marker;
-}
-
-/**
- * gst_rtp_buffer_get_payload_type:
- * @buffer: the buffer
- *
- * Get the payload type of the RTP packet in @buffer.
- *
- * Returns: The payload type.
- */
-guint8
-gst_rtp_buffer_get_payload_type (GstBuffer * buffer)
-{
- return GST_RTP_HEADER_PAYLOAD_TYPE (GST_BUFFER_DATA (buffer));
-}
-
-/**
- * gst_rtp_buffer_list_get_payload_type:
- * @list: the list
- *
- * Get the payload type of the first RTP packet in @list.
- * All packets in @list should have the same payload type.
- *
- * Returns: The payload type.
- */
-guint8
-gst_rtp_buffer_list_get_payload_type (GstBufferList * list)
-{
- guint8 *data;
- data = gst_rtp_buffer_list_get_data (list);
- g_return_val_if_fail (data != NULL, 0);
- return GST_RTP_HEADER_PAYLOAD_TYPE (data);
-}
-
-/**
- * gst_rtp_buffer_set_payload_type:
- * @buffer: the buffer
- * @payload_type: the new type
- *
- * Set the payload type of the RTP packet in @buffer to @payload_type.
- */
-void
-gst_rtp_buffer_set_payload_type (GstBuffer * buffer, guint8 payload_type)
-{
- g_return_if_fail (payload_type < 0x80);
-
- GST_RTP_HEADER_PAYLOAD_TYPE (GST_BUFFER_DATA (buffer)) = payload_type;
-}
-
-/**
- * gst_rtp_buffer_list_set_payload_type:
- * @list: the buffer list
- * @payload_type: the new type
- *
- * Set the payload type of each RTP packet in @list to @payload_type.
- */
-void
-gst_rtp_buffer_list_set_payload_type (GstBufferList * list, guint8 payload_type)
-{
- g_return_if_fail (payload_type < 0x80);
-
- gst_rtp_buffer_list_set_rtp_headers (list, &payload_type, PAYLOAD_TYPE);
-}
-
-/**
- * gst_rtp_buffer_get_seq:
- * @buffer: the buffer
- *
- * Get the sequence number of the RTP packet in @buffer.
- *
- * Returns: The sequence number in host order.
- */
-guint16
-gst_rtp_buffer_get_seq (GstBuffer * buffer)
-{
- return g_ntohs (GST_RTP_HEADER_SEQ (GST_BUFFER_DATA (buffer)));
-}
-
-/**
- * gst_rtp_buffer_set_seq:
- * @buffer: the buffer
- * @seq: the new sequence number
- *
- * Set the sequence number of the RTP packet in @buffer to @seq.
- */
-void
-gst_rtp_buffer_set_seq (GstBuffer * buffer, guint16 seq)
-{
- GST_RTP_HEADER_SEQ (GST_BUFFER_DATA (buffer)) = g_htons (seq);
-}
-
-/**
- * gst_rtp_buffer_list_set_seq:
- * @list: the buffer list
- * @seq: the new sequence number
- *
- * Set the sequence number of each RTP packet in @list to @seq.
- *
- * Returns: The seq number of the last packet in the list + 1.
- */
-guint16
-gst_rtp_buffer_list_set_seq (GstBufferList * list, guint16 seq)
-{
- gst_rtp_buffer_list_set_rtp_headers (list, &seq, SEQ);
- return seq;
-}
-
-/**
- * gst_rtp_buffer_get_timestamp:
- * @buffer: the buffer
- *
- * Get the timestamp of the RTP packet in @buffer.
- *
- * Returns: The timestamp in host order.
- */
-guint32
-gst_rtp_buffer_get_timestamp (GstBuffer * buffer)
-{
- return g_ntohl (GST_RTP_HEADER_TIMESTAMP (GST_BUFFER_DATA (buffer)));
-}
-
-/**
- * gst_rtp_buffer_list_get_timestamp:
- * @list: the list
- *
- * Get the timestamp of the first RTP packet in @list.
- * All packets within @list have the same timestamp.
- *
- * Returns: The timestamp in host order.
- */
-guint32
-gst_rtp_buffer_list_get_timestamp (GstBufferList * list)
-{
- guint8 *data;
- data = gst_rtp_buffer_list_get_data (list);
- g_return_val_if_fail (data != NULL, 0);
- return g_ntohl (GST_RTP_HEADER_TIMESTAMP (data));
-}
-
-/**
- * gst_rtp_buffer_set_timestamp:
- * @buffer: the buffer
- * @timestamp: the new timestamp
- *
- * Set the timestamp of the RTP packet in @buffer to @timestamp.
- */
-void
-gst_rtp_buffer_set_timestamp (GstBuffer * buffer, guint32 timestamp)
-{
- GST_RTP_HEADER_TIMESTAMP (GST_BUFFER_DATA (buffer)) = g_htonl (timestamp);
-}
-
-/**
- * gst_rtp_buffer_list_set_timestamp:
- * @list: the buffer list
- * @timestamp: the new timestamp
- *
- * Set the timestamp of each RTP packet in @list to @timestamp.
- */
-void
-gst_rtp_buffer_list_set_timestamp (GstBufferList * list, guint32 timestamp)
-{
- gst_rtp_buffer_list_set_rtp_headers (list, ×tamp, TIMESTAMP);
-}
-
-/**
- * gst_rtp_buffer_get_payload_subbuffer:
- * @buffer: the buffer
- * @offset: the offset in the payload
- * @len: the length in the payload
- *
- * Create a subbuffer of the payload of the RTP packet in @buffer. @offset bytes
- * are skipped in the payload and the subbuffer will be of size @len.
- * If @len is -1 the total payload starting from @offset if subbuffered.
- *
- * Returns: A new buffer with the specified data of the payload.
- *
- * Since: 0.10.10
- */
-GstBuffer *
-gst_rtp_buffer_get_payload_subbuffer (GstBuffer * buffer, guint offset,
- guint len)
-{
- guint poffset, plen;
-
- plen = gst_rtp_buffer_get_payload_len (buffer);
- /* we can't go past the length */
- if (G_UNLIKELY (offset >= plen))
- goto wrong_offset;
-
- /* apply offset */
- poffset = gst_rtp_buffer_get_header_len (buffer) + offset;
- plen -= offset;
-
- /* see if we need to shrink the buffer based on @len */
- if (len != -1 && len < plen)
- plen = len;
-
- return gst_buffer_create_sub (buffer, poffset, plen);
-
- /* ERRORS */
-wrong_offset:
- {
- g_warning ("offset=%u should be less then plen=%u", offset, plen);
- return NULL;
- }
-}
-
-/**
- * gst_rtp_buffer_get_payload_buffer:
- * @buffer: the buffer
- *
- * Create a buffer of the payload of the RTP packet in @buffer. This function
- * will internally create a subbuffer of @buffer so that a memcpy can be
- * avoided.
- *
- * Returns: A new buffer with the data of the payload.
- */
-GstBuffer *
-gst_rtp_buffer_get_payload_buffer (GstBuffer * buffer)
-{
- return gst_rtp_buffer_get_payload_subbuffer (buffer, 0, -1);
-}
-
-/**
- * gst_rtp_buffer_get_payload_len:
- * @buffer: the buffer
- *
- * Get the length of the payload of the RTP packet in @buffer.
- *
- * Returns: The length of the payload in @buffer.
- */
-guint
-gst_rtp_buffer_get_payload_len (GstBuffer * buffer)
-{
- guint len, size;
- guint8 *data;
-
- size = GST_BUFFER_SIZE (buffer);
- data = GST_BUFFER_DATA (buffer);
-
- len = size - gst_rtp_buffer_get_header_len (buffer);
-
- if (GST_RTP_HEADER_PADDING (data))
- len -= data[size - 1];
-
- return len;
-}
-
-/**
- * gst_rtp_buffer_list_get_payload_len:
- * @buffer: the buffer
- *
- * Get the length of the payload of the RTP packet in @list.
- *
- * Returns: The length of the payload in @list.
- */
-guint
-gst_rtp_buffer_list_get_payload_len (GstBufferList * list)
-{
- guint len = 0;
- GstBufferListIterator *it;
- it = gst_buffer_list_iterate (list);
-
- while (gst_buffer_list_iterator_next_group (it)) {
- guint i;
- GstBuffer *buf;
-
- i = 0;
- while ((buf = gst_buffer_list_iterator_next (it))) {
- /* skip the RTP header */
- if (!i++)
- continue;
- /* take the size of the current buffer */
- len += GST_BUFFER_SIZE (buf);
- }
- }
-
- gst_buffer_list_iterator_free (it);
-
- return len;
-}
-
-/**
- * gst_rtp_buffer_get_payload:
- * @buffer: the buffer
- *
- * Get a pointer to the payload data in @buffer. This pointer is valid as long
- * as a reference to @buffer is held.
- *
- * Returns: A pointer to the payload data in @buffer.
- */
-gpointer
-gst_rtp_buffer_get_payload (GstBuffer * buffer)
-{
- return GST_BUFFER_DATA (buffer) + gst_rtp_buffer_get_header_len (buffer);
-}
-
-/**
- * gst_rtp_buffer_default_clock_rate:
- * @payload_type: the static payload type
- *
- * Get the default clock-rate for the static payload type @payload_type.
- *
- * Returns: the default clock rate or -1 if the payload type is not static or
- * the clock-rate is undefined.
- *
- * Since: 0.10.13
- */
-guint32
-gst_rtp_buffer_default_clock_rate (guint8 payload_type)
-{
- const GstRTPPayloadInfo *info;
- guint32 res;
-
- info = gst_rtp_payload_info_for_pt (payload_type);
- if (!info)
- return -1;
-
- res = info->clock_rate;
- /* 0 means unknown so we have to return -1 from this function */
- if (res == 0)
- res = -1;
-
- return res;
-}
-
-/**
- * gst_rtp_buffer_compare_seqnum:
- * @seqnum1: a sequence number
- * @seqnum2: a sequence number
- *
- * Compare two sequence numbers, taking care of wraparounds. This function
- * returns the difference between @seqnum1 and @seqnum2.
- *
- * Returns: a negative value if @seqnum1 is bigger than @seqnum2, 0 if they
- * are equal or a positive value if @seqnum1 is smaller than @segnum2.
- *
- * Since: 0.10.15
- */
-gint
-gst_rtp_buffer_compare_seqnum (guint16 seqnum1, guint16 seqnum2)
-{
- return (gint16) (seqnum2 - seqnum1);
-}
-
-/**
- * gst_rtp_buffer_ext_timestamp:
- * @exttimestamp: a previous extended timestamp
- * @timestamp: a new timestamp
- *
- * Update the @exttimestamp field with @timestamp. For the first call of the
- * method, @exttimestamp should point to a location with a value of -1.
- *
- * This function makes sure that the returned value is a constantly increasing
- * value even in the case where there is a timestamp wraparound.
- *
- * Returns: The extended timestamp of @timestamp.
- *
- * Since: 0.10.15
- */
-guint64
-gst_rtp_buffer_ext_timestamp (guint64 * exttimestamp, guint32 timestamp)
-{
- guint64 result, diff, ext;
-
- g_return_val_if_fail (exttimestamp != NULL, -1);
-
- ext = *exttimestamp;
-
- if (ext == -1) {
- result = timestamp;
- } else {
- /* pick wraparound counter from previous timestamp and add to new timestamp */
- result = timestamp + (ext & ~(G_GINT64_CONSTANT (0xffffffff)));
-
- /* check for timestamp wraparound */
- if (result < ext)
- diff = ext - result;
- else
- diff = result - ext;
-
- if (diff > G_MAXINT32) {
- /* timestamp went backwards more than allowed, we wrap around and get
- * updated extended timestamp. */
- result += (G_GINT64_CONSTANT (1) << 32);
- }
- }
- *exttimestamp = result;
-
- return result;
-}
-
-/**
- * gst_rtp_buffer_list_get_data:
- * @list: a buffer list
- *
- * Returns ponter to the RTP header of the first packet within the list
- *
- * Returns: pointer to the first RTP header
- */
-static guint8 *
-gst_rtp_buffer_list_get_data (GstBufferList * list)
-{
- GstBufferListIterator *it;
- GstBuffer *rtpbuf;
-
- it = gst_buffer_list_iterate (list);
- if (!gst_buffer_list_iterator_next_group (it))
- goto invalid_list;
- rtpbuf = gst_buffer_list_iterator_next (it);
- if (!rtpbuf)
- goto invalid_list;
-
- gst_buffer_list_iterator_free (it);
- return GST_BUFFER_DATA (rtpbuf);
-
-invalid_list:
- gst_buffer_list_iterator_free (it);
- g_return_val_if_reached (FALSE);
-}
-
-/**
- * gst_rtp_buffer_list_set_rtp_headers:
- * @list: a buffer list
- * @data: data to be set
- * @type: which field in the header to be set
- *
- * Sets the field specified by @type to @data.
- * This function updates all RTP headers within @list.
- */
-static void
-gst_rtp_buffer_list_set_rtp_headers (GstBufferList * list,
- gpointer data, rtp_header_data_type type)
-{
- GstBufferListIterator *it;
- it = gst_buffer_list_iterate (list);
-
- while (gst_buffer_list_iterator_next_group (it)) {
- GstBuffer *rtpbuf;
- guint8 *rtp_header;
- rtpbuf = gst_buffer_list_iterator_next (it);
- rtp_header = GST_BUFFER_DATA (rtpbuf);
- gst_rtp_buffer_list_set_data (rtp_header, data, type);
- }
-
- gst_buffer_list_iterator_free (it);
-}
-
-/**
- * gst_rtp_buffer_list_set_data:
- * @rtp_header: rtp header to be updated
- * @data: data to be set
- * @type: which field in the header to be set
- *
- * Sets the field specified by @type to @data.
- * When setting SEQ number, this function will also increase
- * @data by one.
- */
-static void
-gst_rtp_buffer_list_set_data (guint8 * rtp_header,
- gpointer data, rtp_header_data_type type)
-{
- switch (type) {
- case PAYLOAD_TYPE:
- GST_RTP_HEADER_PAYLOAD_TYPE (rtp_header) = *(guint8 *) data;
- break;
- case SEQ:
- GST_RTP_HEADER_SEQ (rtp_header) = g_htons (*(guint16 *) data);
- (*(guint16 *) data)++;
- break;
- case SSRC:
- GST_RTP_HEADER_SSRC (rtp_header) = g_htonl (*(guint32 *) data);
- break;
- case TIMESTAMP:
- GST_RTP_HEADER_TIMESTAMP (rtp_header) = g_htonl (*(guint32 *) data);
- break;
- default:
- g_warning ("Unknown data type");
- break;
- }
-}
+++ /dev/null
-/* GStreamer
- * Copyright (C) <2005-2009> Wim Taymans <wim.taymans@gmail.com>
- *
- * 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.
- */
-/*
- * Unless otherwise indicated, Source Code is licensed under MIT license.
- * See further explanation attached in License Statement (distributed in the file
- * LICENSE).
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/**
- * SECTION:gstrtspconnection
- * @short_description: manage RTSP connections
- * @see_also: gstrtspurl
- *
- * <refsect2>
- * <para>
- * This object manages the RTSP connection to the server. It provides function
- * to receive and send bytes and messages.
- * </para>
- * </refsect2>
- *
- * Last reviewed on 2007-07-24 (0.10.14)
- */
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
-/* we include this here to get the G_OS_* defines */
-#include <glib.h>
-#include <gst/gst.h>
-
-#ifdef G_OS_WIN32
-/* ws2_32.dll has getaddrinfo and freeaddrinfo on Windows XP and later.
- * minwg32 headers check WINVER before allowing the use of these */
-#ifndef WINVER
-#define WINVER 0x0501
-#endif
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#define EINPROGRESS WSAEINPROGRESS
-#else
-#include <sys/ioctl.h>
-#include <netdb.h>
-#include <sys/socket.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-#endif
-
-#ifdef HAVE_FIONREAD_IN_SYS_FILIO
-#include <sys/filio.h>
-#endif
-
-#include "gstrtspconnection.h"
-#include "gstrtspbase64.h"
-
-union gst_sockaddr
-{
- struct sockaddr sa;
- struct sockaddr_in sa_in;
- struct sockaddr_in6 sa_in6;
- struct sockaddr_storage sa_stor;
-};
-
-typedef struct
-{
- gint state;
- guint save;
- guchar out[3]; /* the size must be evenly divisible by 3 */
- guint cout;
- guint coutl;
-} DecodeCtx;
-
-#ifdef G_OS_WIN32
-#define READ_SOCKET(fd, buf, len) recv (fd, (char *)buf, len, 0)
-#define WRITE_SOCKET(fd, buf, len) send (fd, (const char *)buf, len, 0)
-#define SETSOCKOPT(sock, level, name, val, len) setsockopt (sock, level, name, (const char *)val, len)
-#define CLOSE_SOCKET(sock) closesocket (sock)
-#define ERRNO_IS_EAGAIN (WSAGetLastError () == WSAEWOULDBLOCK)
-#define ERRNO_IS_EINTR (WSAGetLastError () == WSAEINTR)
-/* According to Microsoft's connect() documentation this one returns
- * WSAEWOULDBLOCK and not WSAEINPROGRESS. */
-#define ERRNO_IS_EINPROGRESS (WSAGetLastError () == WSAEWOULDBLOCK)
-#else
-#define READ_SOCKET(fd, buf, len) read (fd, buf, len)
-#define WRITE_SOCKET(fd, buf, len) write (fd, buf, len)
-#define SETSOCKOPT(sock, level, name, val, len) setsockopt (sock, level, name, val, len)
-#define CLOSE_SOCKET(sock) close (sock)
-#define ERRNO_IS_EAGAIN (errno == EAGAIN)
-#define ERRNO_IS_EINTR (errno == EINTR)
-#define ERRNO_IS_EINPROGRESS (errno == EINPROGRESS)
-#endif
-
-#define ADD_POLLFD(fdset, pfd, fd) \
-G_STMT_START { \
- (pfd)->fd = fd; \
- gst_poll_add_fd (fdset, pfd); \
-} G_STMT_END
-
-#define REMOVE_POLLFD(fdset, pfd) \
-G_STMT_START { \
- if ((pfd)->fd != -1) { \
- GST_DEBUG ("remove fd %d", (pfd)->fd); \
- gst_poll_remove_fd (fdset, pfd); \
- CLOSE_SOCKET ((pfd)->fd); \
- (pfd)->fd = -1; \
- } \
-} G_STMT_END
-
-typedef enum
-{
- TUNNEL_STATE_NONE,
- TUNNEL_STATE_GET,
- TUNNEL_STATE_POST,
- TUNNEL_STATE_COMPLETE
-} GstRTSPTunnelState;
-
-#define TUNNELID_LEN 24
-
-struct _GstRTSPConnection
-{
- /*< private > */
- /* URL for the connection */
- GstRTSPUrl *url;
-
- /* connection state */
- GstPollFD fd0;
- GstPollFD fd1;
-
- GstPollFD *readfd;
- GstPollFD *writefd;
-
- gboolean manual_http;
-
- gchar tunnelid[TUNNELID_LEN];
- gboolean tunneled;
- GstRTSPTunnelState tstate;
-
- GstPoll *fdset;
- gchar *ip;
-
- gint read_ahead;
-
- gchar *initial_buffer;
- gsize initial_buffer_offset;
-
- /* Session state */
- gint cseq; /* sequence number */
- gchar session_id[512]; /* session id */
- gint timeout; /* session timeout in seconds */
- GTimer *timer; /* timeout timer */
-
- /* Authentication */
- GstRTSPAuthMethod auth_method;
- gchar *username;
- gchar *passwd;
- GHashTable *auth_params;
-
- DecodeCtx ctx;
- DecodeCtx *ctxp;
-
- gchar *proxy_host;
- guint proxy_port;
-};
-
-enum
-{
- STATE_START = 0,
- STATE_DATA_HEADER,
- STATE_DATA_BODY,
- STATE_READ_LINES,
- STATE_END,
- STATE_LAST
-};
-
-enum
-{
- READ_AHEAD_EOH = -1, /* end of headers */
- READ_AHEAD_CRLF = -2,
- READ_AHEAD_CRLFCR = -3
-};
-
-/* a structure for constructing RTSPMessages */
-typedef struct
-{
- gint state;
- GstRTSPResult status;
- guint8 buffer[4096];
- guint offset;
-
- guint line;
- guint8 *body_data;
- glong body_len;
-} GstRTSPBuilder;
-
-static void
-build_reset (GstRTSPBuilder * builder)
-{
- g_free (builder->body_data);
- memset (builder, 0, sizeof (GstRTSPBuilder));
-}
-
-/**
- * gst_rtsp_connection_create:
- * @url: a #GstRTSPUrl
- * @conn: storage for a #GstRTSPConnection
- *
- * Create a newly allocated #GstRTSPConnection from @url and store it in @conn.
- * The connection will not yet attempt to connect to @url, use
- * gst_rtsp_connection_connect().
- *
- * A copy of @url will be made.
- *
- * Returns: #GST_RTSP_OK when @conn contains a valid connection.
- */
-GstRTSPResult
-gst_rtsp_connection_create (const GstRTSPUrl * url, GstRTSPConnection ** conn)
-{
- GstRTSPConnection *newconn;
-#ifdef G_OS_WIN32
- WSADATA w;
- int error;
-#endif
-
- g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
-
-#ifdef G_OS_WIN32
- error = WSAStartup (0x0202, &w);
-
- if (error)
- goto startup_error;
-
- if (w.wVersion != 0x0202)
- goto version_error;
-#endif
-
- newconn = g_new0 (GstRTSPConnection, 1);
-
- if ((newconn->fdset = gst_poll_new (TRUE)) == NULL)
- goto no_fdset;
-
- newconn->url = gst_rtsp_url_copy (url);
- newconn->fd0.fd = -1;
- newconn->fd1.fd = -1;
- newconn->timer = g_timer_new ();
- newconn->timeout = 60;
- newconn->cseq = 1;
-
- newconn->auth_method = GST_RTSP_AUTH_NONE;
- newconn->username = NULL;
- newconn->passwd = NULL;
- newconn->auth_params = NULL;
-
- *conn = newconn;
-
- return GST_RTSP_OK;
-
- /* ERRORS */
-#ifdef G_OS_WIN32
-startup_error:
- {
- g_warning ("Error %d on WSAStartup", error);
- return GST_RTSP_EWSASTART;
- }
-version_error:
- {
- g_warning ("Windows sockets are not version 0x202 (current 0x%x)",
- w.wVersion);
- WSACleanup ();
- return GST_RTSP_EWSAVERSION;
- }
-#endif
-no_fdset:
- {
- g_free (newconn);
-#ifdef G_OS_WIN32
- WSACleanup ();
-#endif
- return GST_RTSP_ESYS;
- }
-}
-
-/**
- * gst_rtsp_connection_create_from_fd:
- * @fd: a file descriptor
- * @ip: the IP address of the other end
- * @port: the port used by the other end
- * @initial_buffer: data already read from @fd
- * @conn: storage for a #GstRTSPConnection
- *
- * Create a new #GstRTSPConnection for handling communication on the existing
- * file descriptor @fd. The @initial_buffer contains any data already read from
- * @fd which should be used before starting to read new data.
- *
- * Returns: #GST_RTSP_OK when @conn contains a valid connection.
- *
- * Since: 0.10.25
- */
-GstRTSPResult
-gst_rtsp_connection_create_from_fd (gint fd, const gchar * ip, guint16 port,
- const gchar * initial_buffer, GstRTSPConnection ** conn)
-{
- GstRTSPConnection *newconn = NULL;
- GstRTSPUrl *url;
-#ifdef G_OS_WIN32
- gulong flags = 1;
-#endif
- GstRTSPResult res;
-
- g_return_val_if_fail (fd >= 0, GST_RTSP_EINVAL);
- g_return_val_if_fail (ip != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
-
- /* set to non-blocking mode so that we can cancel the communication */
-#ifndef G_OS_WIN32
- fcntl (fd, F_SETFL, O_NONBLOCK);
-#else
- ioctlsocket (fd, FIONBIO, &flags);
-#endif /* G_OS_WIN32 */
-
- /* create a url for the client address */
- url = g_new0 (GstRTSPUrl, 1);
- url->host = g_strdup (ip);
- url->port = port;
-
- /* now create the connection object */
- GST_RTSP_CHECK (gst_rtsp_connection_create (url, &newconn), newconn_failed);
- gst_rtsp_url_free (url);
-
- ADD_POLLFD (newconn->fdset, &newconn->fd0, fd);
-
- /* both read and write initially */
- newconn->readfd = &newconn->fd0;
- newconn->writefd = &newconn->fd0;
-
- newconn->ip = g_strdup (ip);
-
- newconn->initial_buffer = g_strdup (initial_buffer);
-
- *conn = newconn;
-
- return GST_RTSP_OK;
-
- /* ERRORS */
-newconn_failed:
- {
- gst_rtsp_url_free (url);
- return res;
- }
-}
-
-/**
- * gst_rtsp_connection_accept:
- * @sock: a socket
- * @conn: storage for a #GstRTSPConnection
- *
- * Accept a new connection on @sock and create a new #GstRTSPConnection for
- * handling communication on new socket.
- *
- * Returns: #GST_RTSP_OK when @conn contains a valid connection.
- *
- * Since: 0.10.23
- */
-GstRTSPResult
-gst_rtsp_connection_accept (gint sock, GstRTSPConnection ** conn)
-{
- int fd;
- union gst_sockaddr sa;
- socklen_t slen = sizeof (sa);
- gchar ip[INET6_ADDRSTRLEN];
- guint16 port;
-
- g_return_val_if_fail (sock >= 0, GST_RTSP_EINVAL);
- g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
-
- memset (&sa, 0, slen);
-
-#ifndef G_OS_WIN32
- fd = accept (sock, &sa.sa, &slen);
-#else
- fd = accept (sock, &sa.sa, (gint *) & slen);
-#endif /* G_OS_WIN32 */
- if (fd == -1)
- goto accept_failed;
-
- if (getnameinfo (&sa.sa, slen, ip, sizeof (ip), NULL, 0, NI_NUMERICHOST) != 0)
- goto getnameinfo_failed;
-
- if (sa.sa.sa_family == AF_INET)
- port = sa.sa_in.sin_port;
- else if (sa.sa.sa_family == AF_INET6)
- port = sa.sa_in6.sin6_port;
- else
- goto wrong_family;
-
- return gst_rtsp_connection_create_from_fd (fd, ip, port, NULL, conn);
-
- /* ERRORS */
-accept_failed:
- {
- return GST_RTSP_ESYS;
- }
-getnameinfo_failed:
-wrong_family:
- {
- CLOSE_SOCKET (fd);
- return GST_RTSP_ERROR;
- }
-}
-
-static gchar *
-do_resolve (const gchar * host)
-{
- static gchar ip[INET6_ADDRSTRLEN];
- struct addrinfo *aires;
- struct addrinfo *ai;
- gint aierr;
-
- aierr = getaddrinfo (host, NULL, NULL, &aires);
- if (aierr != 0)
- goto no_addrinfo;
-
- for (ai = aires; ai; ai = ai->ai_next) {
- if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
- break;
- }
- }
- if (ai == NULL)
- goto no_family;
-
- aierr = getnameinfo (ai->ai_addr, ai->ai_addrlen, ip, sizeof (ip), NULL, 0,
- NI_NUMERICHOST | NI_NUMERICSERV);
- if (aierr != 0)
- goto no_address;
-
- freeaddrinfo (aires);
-
- return g_strdup (ip);
-
- /* ERRORS */
-no_addrinfo:
- {
- GST_ERROR ("no addrinfo found for %s: %s", host, gai_strerror (aierr));
- return NULL;
- }
-no_family:
- {
- GST_ERROR ("no family found for %s", host);
- freeaddrinfo (aires);
- return NULL;
- }
-no_address:
- {
- GST_ERROR ("no address found for %s: %s", host, gai_strerror (aierr));
- freeaddrinfo (aires);
- return NULL;
- }
-}
-
-static GstRTSPResult
-do_connect (const gchar * ip, guint16 port, GstPollFD * fdout,
- GstPoll * fdset, GTimeVal * timeout)
-{
- gint fd;
- struct addrinfo hints;
- struct addrinfo *aires;
- struct addrinfo *ai;
- gint aierr;
- gchar service[NI_MAXSERV];
- gint ret;
-#ifdef G_OS_WIN32
- unsigned long flags = 1;
-#endif /* G_OS_WIN32 */
- GstClockTime to;
- gint retval;
-
- memset (&hints, 0, sizeof hints);
- hints.ai_flags = AI_NUMERICHOST;
- hints.ai_family = AF_UNSPEC;
- hints.ai_socktype = SOCK_STREAM;
- g_snprintf (service, sizeof (service) - 1, "%hu", port);
- service[sizeof (service) - 1] = '\0';
-
- aierr = getaddrinfo (ip, service, &hints, &aires);
- if (aierr != 0)
- goto no_addrinfo;
-
- for (ai = aires; ai; ai = ai->ai_next) {
- if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) {
- break;
- }
- }
- if (ai == NULL)
- goto no_family;
-
- fd = socket (ai->ai_family, SOCK_STREAM, 0);
- if (fd == -1)
- goto no_socket;
-
- /* set to non-blocking mode so that we can cancel the connect */
-#ifndef G_OS_WIN32
- fcntl (fd, F_SETFL, O_NONBLOCK);
-#else
- ioctlsocket (fd, FIONBIO, &flags);
-#endif /* G_OS_WIN32 */
-
- /* add the socket to our fdset */
- ADD_POLLFD (fdset, fdout, fd);
-
- /* we are going to connect ASYNC now */
- ret = connect (fd, ai->ai_addr, ai->ai_addrlen);
- if (ret == 0)
- goto done;
- if (!ERRNO_IS_EINPROGRESS)
- goto sys_error;
-
- /* wait for connect to complete up to the specified timeout or until we got
- * interrupted. */
- gst_poll_fd_ctl_write (fdset, fdout, TRUE);
-
- to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
-
- do {
- retval = gst_poll_wait (fdset, to);
- } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
-
- if (retval == 0)
- goto timeout;
- else if (retval == -1)
- goto sys_error;
-
- /* we can still have an error connecting on windows */
- if (gst_poll_fd_has_error (fdset, fdout)) {
- socklen_t len = sizeof (errno);
-#ifndef G_OS_WIN32
- getsockopt (fd, SOL_SOCKET, SO_ERROR, &errno, &len);
-#else
- getsockopt (fd, SOL_SOCKET, SO_ERROR, (char *) &errno, &len);
-#endif
- goto sys_error;
- }
-
- gst_poll_fd_ignored (fdset, fdout);
-
-done:
- freeaddrinfo (aires);
-
- return GST_RTSP_OK;
-
- /* ERRORS */
-no_addrinfo:
- {
- GST_ERROR ("no addrinfo found for %s: %s", ip, gai_strerror (aierr));
- return GST_RTSP_ERROR;
- }
-no_family:
- {
- GST_ERROR ("no family found for %s", ip);
- freeaddrinfo (aires);
- return GST_RTSP_ERROR;
- }
-no_socket:
- {
- GST_ERROR ("no socket %d (%s)", errno, g_strerror (errno));
- freeaddrinfo (aires);
- return GST_RTSP_ESYS;
- }
-sys_error:
- {
- GST_ERROR ("system error %d (%s)", errno, g_strerror (errno));
- REMOVE_POLLFD (fdset, fdout);
- freeaddrinfo (aires);
- return GST_RTSP_ESYS;
- }
-timeout:
- {
- GST_ERROR ("timeout");
- REMOVE_POLLFD (fdset, fdout);
- freeaddrinfo (aires);
- return GST_RTSP_ETIMEOUT;
- }
-}
-
-static GstRTSPResult
-setup_tunneling (GstRTSPConnection * conn, GTimeVal * timeout)
-{
- gint i;
- GstRTSPResult res;
- gchar *ip;
- gchar *uri;
- gchar *value;
- guint16 port, url_port;
- GstRTSPUrl *url;
- gchar *hostparam;
- GstRTSPMessage *msg;
- GstRTSPMessage response;
- gboolean old_http;
-
- memset (&response, 0, sizeof (response));
- gst_rtsp_message_init (&response);
-
- /* create a random sessionid */
- for (i = 0; i < TUNNELID_LEN; i++)
- conn->tunnelid[i] = g_random_int_range ('a', 'z');
- conn->tunnelid[TUNNELID_LEN - 1] = '\0';
-
- url = conn->url;
- /* get the port from the url */
- gst_rtsp_url_get_port (url, &url_port);
-
- if (conn->proxy_host) {
- uri = g_strdup_printf ("http://%s:%d%s%s%s", url->host, url_port,
- url->abspath, url->query ? "?" : "", url->query ? url->query : "");
- hostparam = g_strdup_printf ("%s:%d", url->host, url_port);
- ip = conn->proxy_host;
- port = conn->proxy_port;
- } else {
- uri = g_strdup_printf ("%s%s%s", url->abspath, url->query ? "?" : "",
- url->query ? url->query : "");
- hostparam = NULL;
- ip = conn->ip;
- port = url_port;
- }
-
- /* create the GET request for the read connection */
- GST_RTSP_CHECK (gst_rtsp_message_new_request (&msg, GST_RTSP_GET, uri),
- no_message);
- msg->type = GST_RTSP_MESSAGE_HTTP_REQUEST;
-
- if (hostparam != NULL)
- gst_rtsp_message_add_header (msg, GST_RTSP_HDR_HOST, hostparam);
- gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SESSIONCOOKIE,
- conn->tunnelid);
- gst_rtsp_message_add_header (msg, GST_RTSP_HDR_ACCEPT,
- "application/x-rtsp-tunnelled");
- gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-cache");
- gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache");
-
- /* we start by writing to this fd */
- conn->writefd = &conn->fd0;
-
- /* we need to temporarily set conn->tunneled to FALSE to prevent the HTTP
- * request from being base64 encoded */
- conn->tunneled = FALSE;
- GST_RTSP_CHECK (gst_rtsp_connection_send (conn, msg, timeout), write_failed);
- gst_rtsp_message_free (msg);
- conn->tunneled = TRUE;
-
- /* receive the response to the GET request */
- /* we need to temporarily set manual_http to TRUE since
- * gst_rtsp_connection_receive() will treat the HTTP response as a parsing
- * failure otherwise */
- old_http = conn->manual_http;
- conn->manual_http = TRUE;
- GST_RTSP_CHECK (gst_rtsp_connection_receive (conn, &response, timeout),
- read_failed);
- conn->manual_http = old_http;
-
- if (response.type != GST_RTSP_MESSAGE_HTTP_RESPONSE ||
- response.type_data.response.code != GST_RTSP_STS_OK)
- goto wrong_result;
-
- if (gst_rtsp_message_get_header (&response, GST_RTSP_HDR_X_SERVER_IP_ADDRESS,
- &value, 0) != GST_RTSP_OK) {
- if (conn->proxy_host) {
- /* if we use a proxy we need to change the destination url */
- g_free (url->host);
- url->host = g_strdup (value);
- g_free (hostparam);
- hostparam = g_strdup_printf ("%s:%d", url->host, url_port);
- } else {
- /* and resolve the new ip address */
- if (!(ip = do_resolve (conn->ip)))
- goto not_resolved;
- g_free (conn->ip);
- conn->ip = ip;
- }
- }
-
- /* connect to the host/port */
- res = do_connect (ip, port, &conn->fd1, conn->fdset, timeout);
- if (res != GST_RTSP_OK)
- goto connect_failed;
-
- /* this is now our writing socket */
- conn->writefd = &conn->fd1;
-
- /* create the POST request for the write connection */
- GST_RTSP_CHECK (gst_rtsp_message_new_request (&msg, GST_RTSP_POST, uri),
- no_message);
- msg->type = GST_RTSP_MESSAGE_HTTP_REQUEST;
-
- if (hostparam != NULL)
- gst_rtsp_message_add_header (msg, GST_RTSP_HDR_HOST, hostparam);
- gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SESSIONCOOKIE,
- conn->tunnelid);
- gst_rtsp_message_add_header (msg, GST_RTSP_HDR_ACCEPT,
- "application/x-rtsp-tunnelled");
- gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-cache");
- gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache");
- gst_rtsp_message_add_header (msg, GST_RTSP_HDR_EXPIRES,
- "Sun, 9 Jan 1972 00:00:00 GMT");
- gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_LENGTH, "32767");
-
- /* we need to temporarily set conn->tunneled to FALSE to prevent the HTTP
- * request from being base64 encoded */
- conn->tunneled = FALSE;
- GST_RTSP_CHECK (gst_rtsp_connection_send (conn, msg, timeout), write_failed);
- gst_rtsp_message_free (msg);
- conn->tunneled = TRUE;
-
-exit:
- gst_rtsp_message_unset (&response);
- g_free (hostparam);
- g_free (uri);
-
- return res;
-
- /* ERRORS */
-no_message:
- {
- GST_ERROR ("failed to create request (%d)", res);
- goto exit;
- }
-write_failed:
- {
- GST_ERROR ("write failed (%d)", res);
- gst_rtsp_message_free (msg);
- conn->tunneled = TRUE;
- goto exit;
- }
-read_failed:
- {
- GST_ERROR ("read failed (%d)", res);
- conn->manual_http = FALSE;
- goto exit;
- }
-wrong_result:
- {
- GST_ERROR ("got failure response %d %s", response.type_data.response.code,
- response.type_data.response.reason);
- res = GST_RTSP_ERROR;
- goto exit;
- }
-not_resolved:
- {
- GST_ERROR ("could not resolve %s", conn->ip);
- res = GST_RTSP_ENET;
- goto exit;
- }
-connect_failed:
- {
- GST_ERROR ("failed to connect");
- goto exit;
- }
-}
-
-/**
- * gst_rtsp_connection_connect:
- * @conn: a #GstRTSPConnection
- * @timeout: a #GTimeVal timeout
- *
- * Attempt to connect to the url of @conn made with
- * gst_rtsp_connection_create(). If @timeout is #NULL this function can block
- * forever. If @timeout contains a valid timeout, this function will return
- * #GST_RTSP_ETIMEOUT after the timeout expired.
- *
- * This function can be cancelled with gst_rtsp_connection_flush().
- *
- * Returns: #GST_RTSP_OK when a connection could be made.
- */
-GstRTSPResult
-gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout)
-{
- GstRTSPResult res;
- gchar *ip;
- guint16 port;
- GstRTSPUrl *url;
-
- g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (conn->url != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (conn->fd0.fd < 0, GST_RTSP_EINVAL);
-
- url = conn->url;
-
- if (conn->proxy_host && conn->tunneled) {
- if (!(ip = do_resolve (conn->proxy_host))) {
- GST_ERROR ("could not resolve %s", conn->proxy_host);
- goto not_resolved;
- }
- port = conn->proxy_port;
- g_free (conn->proxy_host);
- conn->proxy_host = ip;
- } else {
- if (!(ip = do_resolve (url->host))) {
- GST_ERROR ("could not resolve %s", url->host);
- goto not_resolved;
- }
- /* get the port from the url */
- gst_rtsp_url_get_port (url, &port);
-
- g_free (conn->ip);
- conn->ip = ip;
- }
-
- /* connect to the host/port */
- res = do_connect (ip, port, &conn->fd0, conn->fdset, timeout);
- if (res != GST_RTSP_OK)
- goto connect_failed;
-
- /* this is our read URL */
- conn->readfd = &conn->fd0;
-
- if (conn->tunneled) {
- res = setup_tunneling (conn, timeout);
- if (res != GST_RTSP_OK)
- goto tunneling_failed;
- } else {
- conn->writefd = &conn->fd0;
- }
-
- return GST_RTSP_OK;
-
-not_resolved:
- {
- return GST_RTSP_ENET;
- }
-connect_failed:
- {
- GST_ERROR ("failed to connect");
- return res;
- }
-tunneling_failed:
- {
- GST_ERROR ("failed to setup tunneling");
- return res;
- }
-}
-
-static void
-auth_digest_compute_hex_urp (const gchar * username,
- const gchar * realm, const gchar * password, gchar hex_urp[33])
-{
- GChecksum *md5_context = g_checksum_new (G_CHECKSUM_MD5);
- const gchar *digest_string;
-
- g_checksum_update (md5_context, (const guchar *) username, strlen (username));
- g_checksum_update (md5_context, (const guchar *) ":", 1);
- g_checksum_update (md5_context, (const guchar *) realm, strlen (realm));
- g_checksum_update (md5_context, (const guchar *) ":", 1);
- g_checksum_update (md5_context, (const guchar *) password, strlen (password));
- digest_string = g_checksum_get_string (md5_context);
-
- memset (hex_urp, 0, 33);
- memcpy (hex_urp, digest_string, strlen (digest_string));
-
- g_checksum_free (md5_context);
-}
-
-static void
-auth_digest_compute_response (const gchar * method,
- const gchar * uri, const gchar * hex_a1, const gchar * nonce,
- gchar response[33])
-{
- char hex_a2[33] = { 0, };
- GChecksum *md5_context = g_checksum_new (G_CHECKSUM_MD5);
- const gchar *digest_string;
-
- /* compute A2 */
- g_checksum_update (md5_context, (const guchar *) method, strlen (method));
- g_checksum_update (md5_context, (const guchar *) ":", 1);
- g_checksum_update (md5_context, (const guchar *) uri, strlen (uri));
- digest_string = g_checksum_get_string (md5_context);
- memcpy (hex_a2, digest_string, strlen (digest_string));
-
- /* compute KD */
- g_checksum_reset (md5_context);
- g_checksum_update (md5_context, (const guchar *) hex_a1, strlen (hex_a1));
- g_checksum_update (md5_context, (const guchar *) ":", 1);
- g_checksum_update (md5_context, (const guchar *) nonce, strlen (nonce));
- g_checksum_update (md5_context, (const guchar *) ":", 1);
-
- g_checksum_update (md5_context, (const guchar *) hex_a2, 32);
- digest_string = g_checksum_get_string (md5_context);
- memset (response, 0, 33);
- memcpy (response, digest_string, strlen (digest_string));
-
- g_checksum_free (md5_context);
-}
-
-static void
-add_auth_header (GstRTSPConnection * conn, GstRTSPMessage * message)
-{
- switch (conn->auth_method) {
- case GST_RTSP_AUTH_BASIC:{
- gchar *user_pass;
- gchar *user_pass64;
- gchar *auth_string;
-
- user_pass = g_strdup_printf ("%s:%s", conn->username, conn->passwd);
- user_pass64 = g_base64_encode ((guchar *) user_pass, strlen (user_pass));
- auth_string = g_strdup_printf ("Basic %s", user_pass64);
-
- gst_rtsp_message_take_header (message, GST_RTSP_HDR_AUTHORIZATION,
- auth_string);
-
- g_free (user_pass);
- g_free (user_pass64);
- break;
- }
- case GST_RTSP_AUTH_DIGEST:{
- gchar response[33], hex_urp[33];
- gchar *auth_string, *auth_string2;
- gchar *realm;
- gchar *nonce;
- gchar *opaque;
- const gchar *uri;
- const gchar *method;
-
- /* we need to have some params set */
- if (conn->auth_params == NULL)
- break;
-
- /* we need the realm and nonce */
- realm = (gchar *) g_hash_table_lookup (conn->auth_params, "realm");
- nonce = (gchar *) g_hash_table_lookup (conn->auth_params, "nonce");
- if (realm == NULL || nonce == NULL)
- break;
-
- auth_digest_compute_hex_urp (conn->username, realm, conn->passwd,
- hex_urp);
-
- method = gst_rtsp_method_as_text (message->type_data.request.method);
- uri = message->type_data.request.uri;
-
- /* Assume no qop, algorithm=md5, stale=false */
- /* For algorithm MD5, a1 = urp. */
- auth_digest_compute_response (method, uri, hex_urp, nonce, response);
- auth_string = g_strdup_printf ("Digest username=\"%s\", "
- "realm=\"%s\", nonce=\"%s\", uri=\"%s\", response=\"%s\"",
- conn->username, realm, nonce, uri, response);
-
- opaque = (gchar *) g_hash_table_lookup (conn->auth_params, "opaque");
- if (opaque) {
- auth_string2 = g_strdup_printf ("%s, opaque=\"%s\"", auth_string,
- opaque);
- g_free (auth_string);
- auth_string = auth_string2;
- }
- gst_rtsp_message_take_header (message, GST_RTSP_HDR_AUTHORIZATION,
- auth_string);
- break;
- }
- default:
- /* Nothing to do */
- break;
- }
-}
-
-static void
-gen_date_string (gchar * date_string, guint len)
-{
- GTimeVal tv;
- time_t t;
-#ifdef HAVE_GMTIME_R
- struct tm tm_;
-#endif
-
- g_get_current_time (&tv);
- t = (time_t) tv.tv_sec;
-
-#ifdef HAVE_GMTIME_R
- strftime (date_string, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime_r (&t, &tm_));
-#else
- strftime (date_string, len, "%a, %d %b %Y %H:%M:%S GMT", gmtime (&t));
-#endif
-}
-
-static GstRTSPResult
-write_bytes (gint fd, const guint8 * buffer, guint * idx, guint size)
-{
- guint left;
-
- if (G_UNLIKELY (*idx > size))
- return GST_RTSP_ERROR;
-
- left = size - *idx;
-
- while (left) {
- gint r;
-
- r = WRITE_SOCKET (fd, &buffer[*idx], left);
- if (G_UNLIKELY (r == 0)) {
- return GST_RTSP_EINTR;
- } else if (G_UNLIKELY (r < 0)) {
- if (ERRNO_IS_EAGAIN)
- return GST_RTSP_EINTR;
- if (!ERRNO_IS_EINTR)
- return GST_RTSP_ESYS;
- } else {
- left -= r;
- *idx += r;
- }
- }
- return GST_RTSP_OK;
-}
-
-static gint
-fill_raw_bytes (GstRTSPConnection * conn, guint8 * buffer, guint size)
-{
- gint out = 0;
-
- if (G_UNLIKELY (conn->initial_buffer != NULL)) {
- gsize left = strlen (&conn->initial_buffer[conn->initial_buffer_offset]);
-
- out = MIN (left, size);
- memcpy (buffer, &conn->initial_buffer[conn->initial_buffer_offset], out);
-
- if (left == (gsize) out) {
- g_free (conn->initial_buffer);
- conn->initial_buffer = NULL;
- conn->initial_buffer_offset = 0;
- } else
- conn->initial_buffer_offset += out;
- }
-
- if (G_LIKELY (size > (guint) out)) {
- gint r;
-
- r = READ_SOCKET (conn->readfd->fd, &buffer[out], size - out);
- if (r <= 0) {
- if (out == 0)
- out = r;
- } else
- out += r;
- }
-
- return out;
-}
-
-static gint
-fill_bytes (GstRTSPConnection * conn, guint8 * buffer, guint size)
-{
- DecodeCtx *ctx = conn->ctxp;
- gint out = 0;
-
- if (ctx) {
- while (size > 0) {
- guint8 in[sizeof (ctx->out) * 4 / 3];
- gint r;
-
- while (size > 0 && ctx->cout < ctx->coutl) {
- /* we have some leftover bytes */
- *buffer++ = ctx->out[ctx->cout++];
- size--;
- out++;
- }
-
- /* got what we needed? */
- if (size == 0)
- break;
-
- /* try to read more bytes */
- r = fill_raw_bytes (conn, in, sizeof (in));
- if (r <= 0) {
- if (out == 0)
- out = r;
- break;
- }
-
- ctx->cout = 0;
- ctx->coutl =
- g_base64_decode_step ((gchar *) in, r, ctx->out, &ctx->state,
- &ctx->save);
- }
- } else {
- out = fill_raw_bytes (conn, buffer, size);
- }
-
- return out;
-}
-
-static GstRTSPResult
-read_bytes (GstRTSPConnection * conn, guint8 * buffer, guint * idx, guint size)
-{
- guint left;
-
- if (G_UNLIKELY (*idx > size))
- return GST_RTSP_ERROR;
-
- left = size - *idx;
-
- while (left) {
- gint r;
-
- r = fill_bytes (conn, &buffer[*idx], left);
- if (G_UNLIKELY (r == 0)) {
- return GST_RTSP_EEOF;
- } else if (G_UNLIKELY (r < 0)) {
- if (ERRNO_IS_EAGAIN)
- return GST_RTSP_EINTR;
- if (!ERRNO_IS_EINTR)
- return GST_RTSP_ESYS;
- } else {
- left -= r;
- *idx += r;
- }
- }
- return GST_RTSP_OK;
-}
-
-/* The code below tries to handle clients using \r, \n or \r\n to indicate the
- * end of a line. It even does its best to handle clients which mix them (even
- * though this is a really stupid idea (tm).) It also handles Line White Space
- * (LWS), where a line end followed by whitespace is considered LWS. This is
- * the method used in RTSP (and HTTP) to break long lines.
- */
-static GstRTSPResult
-read_line (GstRTSPConnection * conn, guint8 * buffer, guint * idx, guint size)
-{
- while (TRUE) {
- guint8 c;
- gint r;
-
- if (conn->read_ahead == READ_AHEAD_EOH) {
- /* the last call to read_line() already determined that we have reached
- * the end of the headers, so convey that information now */
- conn->read_ahead = 0;
- break;
- } else if (conn->read_ahead == READ_AHEAD_CRLF) {
- /* the last call to read_line() left off after having read \r\n */
- c = '\n';
- } else if (conn->read_ahead == READ_AHEAD_CRLFCR) {
- /* the last call to read_line() left off after having read \r\n\r */
- c = '\r';
- } else if (conn->read_ahead != 0) {
- /* the last call to read_line() left us with a character to start with */
- c = (guint8) conn->read_ahead;
- conn->read_ahead = 0;
- } else {
- /* read the next character */
- r = fill_bytes (conn, &c, 1);
- if (G_UNLIKELY (r == 0)) {
- return GST_RTSP_EEOF;
- } else if (G_UNLIKELY (r < 0)) {
- if (ERRNO_IS_EAGAIN)
- return GST_RTSP_EINTR;
- if (!ERRNO_IS_EINTR)
- return GST_RTSP_ESYS;
- continue;
- }
- }
-
- /* special treatment of line endings */
- if (c == '\r' || c == '\n') {
- guint8 read_ahead;
-
- retry:
- /* need to read ahead one more character to know what to do... */
- r = fill_bytes (conn, &read_ahead, 1);
- if (G_UNLIKELY (r == 0)) {
- return GST_RTSP_EEOF;
- } else if (G_UNLIKELY (r < 0)) {
- if (ERRNO_IS_EAGAIN) {
- /* remember the original character we read and try again next time */
- if (conn->read_ahead == 0)
- conn->read_ahead = c;
- return GST_RTSP_EINTR;
- }
- if (!ERRNO_IS_EINTR)
- return GST_RTSP_ESYS;
- goto retry;
- }
-
- if (read_ahead == ' ' || read_ahead == '\t') {
- if (conn->read_ahead == READ_AHEAD_CRLFCR) {
- /* got \r\n\r followed by whitespace, treat it as a normal line
- * followed by one starting with LWS */
- conn->read_ahead = read_ahead;
- break;
- } else {
- /* got LWS, change the line ending to a space and continue */
- c = ' ';
- conn->read_ahead = read_ahead;
- }
- } else if (conn->read_ahead == READ_AHEAD_CRLFCR) {
- if (read_ahead == '\r' || read_ahead == '\n') {
- /* got \r\n\r\r or \r\n\r\n, treat it as the end of the headers */
- conn->read_ahead = READ_AHEAD_EOH;
- break;
- } else {
- /* got \r\n\r followed by something else, this is not really
- * supported since we have probably just eaten the first character
- * of the body or the next message, so just ignore the second \r
- * and live with it... */
- conn->read_ahead = read_ahead;
- break;
- }
- } else if (conn->read_ahead == READ_AHEAD_CRLF) {
- if (read_ahead == '\r') {
- /* got \r\n\r so far, need one more character... */
- conn->read_ahead = READ_AHEAD_CRLFCR;
- goto retry;
- } else if (read_ahead == '\n') {
- /* got \r\n\n, treat it as the end of the headers */
- conn->read_ahead = READ_AHEAD_EOH;
- break;
- } else {
- /* found the end of a line, keep read_ahead for the next line */
- conn->read_ahead = read_ahead;
- break;
- }
- } else if (c == read_ahead) {
- /* got double \r or \n, treat it as the end of the headers */
- conn->read_ahead = READ_AHEAD_EOH;
- break;
- } else if (c == '\r' && read_ahead == '\n') {
- /* got \r\n so far, still need more to know what to do... */
- conn->read_ahead = READ_AHEAD_CRLF;
- goto retry;
- } else {
- /* found the end of a line, keep read_ahead for the next line */
- conn->read_ahead = read_ahead;
- break;
- }
- }
-
- if (G_LIKELY (*idx < size - 1))
- buffer[(*idx)++] = c;
- }
- buffer[*idx] = '\0';
-
- return GST_RTSP_OK;
-}
-
-/**
- * gst_rtsp_connection_write:
- * @conn: a #GstRTSPConnection
- * @data: the data to write
- * @size: the size of @data
- * @timeout: a timeout value or #NULL
- *
- * Attempt to write @size bytes of @data to the connected @conn, blocking up to
- * the specified @timeout. @timeout can be #NULL, in which case this function
- * might block forever.
- *
- * This function can be cancelled with gst_rtsp_connection_flush().
- *
- * Returns: #GST_RTSP_OK on success.
- */
-GstRTSPResult
-gst_rtsp_connection_write (GstRTSPConnection * conn, const guint8 * data,
- guint size, GTimeVal * timeout)
-{
- guint offset;
- gint retval;
- GstClockTime to;
- GstRTSPResult res;
-
- g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (data != NULL || size == 0, GST_RTSP_EINVAL);
- g_return_val_if_fail (conn->writefd != NULL, GST_RTSP_EINVAL);
-
- gst_poll_set_controllable (conn->fdset, TRUE);
- gst_poll_fd_ctl_write (conn->fdset, conn->writefd, TRUE);
- gst_poll_fd_ctl_read (conn->fdset, conn->readfd, FALSE);
- /* clear all previous poll results */
- gst_poll_fd_ignored (conn->fdset, conn->writefd);
- gst_poll_fd_ignored (conn->fdset, conn->readfd);
-
- to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
-
- offset = 0;
-
- while (TRUE) {
- /* try to write */
- res = write_bytes (conn->writefd->fd, data, &offset, size);
- if (G_LIKELY (res == GST_RTSP_OK))
- break;
- if (G_UNLIKELY (res != GST_RTSP_EINTR))
- goto write_error;
-
- /* not all is written, wait until we can write more */
- do {
- retval = gst_poll_wait (conn->fdset, to);
- } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
-
- if (G_UNLIKELY (retval == 0))
- goto timeout;
-
- if (G_UNLIKELY (retval == -1)) {
- if (errno == EBUSY)
- goto stopped;
- else
- goto select_error;
- }
- }
- return GST_RTSP_OK;
-
- /* ERRORS */
-timeout:
- {
- return GST_RTSP_ETIMEOUT;
- }
-select_error:
- {
- return GST_RTSP_ESYS;
- }
-stopped:
- {
- return GST_RTSP_EINTR;
- }
-write_error:
- {
- return res;
- }
-}
-
-static GString *
-message_to_string (GstRTSPConnection * conn, GstRTSPMessage * message)
-{
- GString *str = NULL;
-
- str = g_string_new ("");
-
- switch (message->type) {
- case GST_RTSP_MESSAGE_REQUEST:
- /* create request string, add CSeq */
- g_string_append_printf (str, "%s %s RTSP/1.0\r\n"
- "CSeq: %d\r\n",
- gst_rtsp_method_as_text (message->type_data.request.method),
- message->type_data.request.uri, conn->cseq++);
- /* add session id if we have one */
- if (conn->session_id[0] != '\0') {
- gst_rtsp_message_remove_header (message, GST_RTSP_HDR_SESSION, -1);
- gst_rtsp_message_add_header (message, GST_RTSP_HDR_SESSION,
- conn->session_id);
- }
- /* add any authentication headers */
- add_auth_header (conn, message);
- break;
- case GST_RTSP_MESSAGE_RESPONSE:
- /* create response string */
- g_string_append_printf (str, "RTSP/1.0 %d %s\r\n",
- message->type_data.response.code, message->type_data.response.reason);
- break;
- case GST_RTSP_MESSAGE_HTTP_REQUEST:
- /* create request string */
- g_string_append_printf (str, "%s %s HTTP/%s\r\n",
- gst_rtsp_method_as_text (message->type_data.request.method),
- message->type_data.request.uri,
- gst_rtsp_version_as_text (message->type_data.request.version));
- /* add any authentication headers */
- add_auth_header (conn, message);
- break;
- case GST_RTSP_MESSAGE_HTTP_RESPONSE:
- /* create response string */
- g_string_append_printf (str, "HTTP/%s %d %s\r\n",
- gst_rtsp_version_as_text (message->type_data.request.version),
- message->type_data.response.code, message->type_data.response.reason);
- break;
- case GST_RTSP_MESSAGE_DATA:
- {
- guint8 data_header[4];
-
- /* prepare data header */
- data_header[0] = '$';
- data_header[1] = message->type_data.data.channel;
- data_header[2] = (message->body_size >> 8) & 0xff;
- data_header[3] = message->body_size & 0xff;
-
- /* create string with header and data */
- str = g_string_append_len (str, (gchar *) data_header, 4);
- str =
- g_string_append_len (str, (gchar *) message->body,
- message->body_size);
- break;
- }
- default:
- g_string_free (str, TRUE);
- g_return_val_if_reached (NULL);
- break;
- }
-
- /* append headers and body */
- if (message->type != GST_RTSP_MESSAGE_DATA) {
- gchar date_string[100];
-
- gen_date_string (date_string, sizeof (date_string));
-
- /* add date header */
- gst_rtsp_message_remove_header (message, GST_RTSP_HDR_DATE, -1);
- gst_rtsp_message_add_header (message, GST_RTSP_HDR_DATE, date_string);
-
- /* append headers */
- gst_rtsp_message_append_headers (message, str);
-
- /* append Content-Length and body if needed */
- if (message->body != NULL && message->body_size > 0) {
- gchar *len;
-
- len = g_strdup_printf ("%d", message->body_size);
- g_string_append_printf (str, "%s: %s\r\n",
- gst_rtsp_header_as_text (GST_RTSP_HDR_CONTENT_LENGTH), len);
- g_free (len);
- /* header ends here */
- g_string_append (str, "\r\n");
- str =
- g_string_append_len (str, (gchar *) message->body,
- message->body_size);
- } else {
- /* just end headers */
- g_string_append (str, "\r\n");
- }
- }
-
- return str;
-}
-
-/**
- * gst_rtsp_connection_send:
- * @conn: a #GstRTSPConnection
- * @message: the message to send
- * @timeout: a timeout value or #NULL
- *
- * Attempt to send @message to the connected @conn, blocking up to
- * the specified @timeout. @timeout can be #NULL, in which case this function
- * might block forever.
- *
- * This function can be cancelled with gst_rtsp_connection_flush().
- *
- * Returns: #GST_RTSP_OK on success.
- */
-GstRTSPResult
-gst_rtsp_connection_send (GstRTSPConnection * conn, GstRTSPMessage * message,
- GTimeVal * timeout)
-{
- GString *string = NULL;
- GstRTSPResult res;
- gchar *str;
- gsize len;
-
- g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
-
- if (G_UNLIKELY (!(string = message_to_string (conn, message))))
- goto no_message;
-
- if (conn->tunneled) {
- str = g_base64_encode ((const guchar *) string->str, string->len);
- g_string_free (string, TRUE);
- len = strlen (str);
- } else {
- str = string->str;
- len = string->len;
- g_string_free (string, FALSE);
- }
-
- /* write request */
- res = gst_rtsp_connection_write (conn, (guint8 *) str, len, timeout);
-
- g_free (str);
-
- return res;
-
-no_message:
- {
- g_warning ("Wrong message");
- return GST_RTSP_EINVAL;
- }
-}
-
-static GstRTSPResult
-parse_string (gchar * dest, gint size, gchar ** src)
-{
- GstRTSPResult res = GST_RTSP_OK;
- gint idx;
-
- idx = 0;
- /* skip spaces */
- while (g_ascii_isspace (**src))
- (*src)++;
-
- while (!g_ascii_isspace (**src) && **src != '\0') {
- if (idx < size - 1)
- dest[idx++] = **src;
- else
- res = GST_RTSP_EPARSE;
- (*src)++;
- }
- if (size > 0)
- dest[idx] = '\0';
-
- return res;
-}
-
-static GstRTSPResult
-parse_protocol_version (gchar * protocol, GstRTSPMsgType * type,
- GstRTSPVersion * version)
-{
- GstRTSPResult res = GST_RTSP_OK;
- gchar *ver;
-
- if (G_LIKELY ((ver = strchr (protocol, '/')) != NULL)) {
- guint major;
- guint minor;
- gchar dummychar;
-
- *ver++ = '\0';
-
- /* the version number must be formatted as X.Y with nothing following */
- if (sscanf (ver, "%u.%u%c", &major, &minor, &dummychar) != 2)
- res = GST_RTSP_EPARSE;
-
- if (g_ascii_strcasecmp (protocol, "RTSP") == 0) {
- if (major != 1 || minor != 0) {
- *version = GST_RTSP_VERSION_INVALID;
- res = GST_RTSP_ERROR;
- }
- } else if (g_ascii_strcasecmp (protocol, "HTTP") == 0) {
- if (*type == GST_RTSP_MESSAGE_REQUEST)
- *type = GST_RTSP_MESSAGE_HTTP_REQUEST;
- else if (*type == GST_RTSP_MESSAGE_RESPONSE)
- *type = GST_RTSP_MESSAGE_HTTP_RESPONSE;
-
- if (major == 1 && minor == 1) {
- *version = GST_RTSP_VERSION_1_1;
- } else if (major != 1 || minor != 0) {
- *version = GST_RTSP_VERSION_INVALID;
- res = GST_RTSP_ERROR;
- }
- } else
- res = GST_RTSP_EPARSE;
- } else
- res = GST_RTSP_EPARSE;
-
- return res;
-}
-
-static GstRTSPResult
-parse_response_status (guint8 * buffer, GstRTSPMessage * msg)
-{
- GstRTSPResult res = GST_RTSP_OK;
- GstRTSPResult res2;
- gchar versionstr[20];
- gchar codestr[4];
- gint code;
- gchar *bptr;
-
- bptr = (gchar *) buffer;
-
- if (parse_string (versionstr, sizeof (versionstr), &bptr) != GST_RTSP_OK)
- res = GST_RTSP_EPARSE;
-
- if (parse_string (codestr, sizeof (codestr), &bptr) != GST_RTSP_OK)
- res = GST_RTSP_EPARSE;
- code = atoi (codestr);
- if (G_UNLIKELY (*codestr == '\0' || code < 0 || code >= 600))
- res = GST_RTSP_EPARSE;
-
- while (g_ascii_isspace (*bptr))
- bptr++;
-
- if (G_UNLIKELY (gst_rtsp_message_init_response (msg, code, bptr,
- NULL) != GST_RTSP_OK))
- res = GST_RTSP_EPARSE;
-
- res2 = parse_protocol_version (versionstr, &msg->type,
- &msg->type_data.response.version);
- if (G_LIKELY (res == GST_RTSP_OK))
- res = res2;
-
- return res;
-}
-
-static GstRTSPResult
-parse_request_line (guint8 * buffer, GstRTSPMessage * msg)
-{
- GstRTSPResult res = GST_RTSP_OK;
- GstRTSPResult res2;
- gchar versionstr[20];
- gchar methodstr[20];
- gchar urlstr[4096];
- gchar *bptr;
- GstRTSPMethod method;
-
- bptr = (gchar *) buffer;
-
- if (parse_string (methodstr, sizeof (methodstr), &bptr) != GST_RTSP_OK)
- res = GST_RTSP_EPARSE;
- method = gst_rtsp_find_method (methodstr);
-
- if (parse_string (urlstr, sizeof (urlstr), &bptr) != GST_RTSP_OK)
- res = GST_RTSP_EPARSE;
- if (G_UNLIKELY (*urlstr == '\0'))
- res = GST_RTSP_EPARSE;
-
- if (parse_string (versionstr, sizeof (versionstr), &bptr) != GST_RTSP_OK)
- res = GST_RTSP_EPARSE;
-
- if (G_UNLIKELY (*bptr != '\0'))
- res = GST_RTSP_EPARSE;
-
- if (G_UNLIKELY (gst_rtsp_message_init_request (msg, method,
- urlstr) != GST_RTSP_OK))
- res = GST_RTSP_EPARSE;
-
- res2 = parse_protocol_version (versionstr, &msg->type,
- &msg->type_data.request.version);
- if (G_LIKELY (res == GST_RTSP_OK))
- res = res2;
-
- if (G_LIKELY (msg->type == GST_RTSP_MESSAGE_REQUEST)) {
- /* GET and POST are not allowed as RTSP methods */
- if (msg->type_data.request.method == GST_RTSP_GET ||
- msg->type_data.request.method == GST_RTSP_POST) {
- msg->type_data.request.method = GST_RTSP_INVALID;
- if (res == GST_RTSP_OK)
- res = GST_RTSP_ERROR;
- }
- } else if (msg->type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
- /* only GET and POST are allowed as HTTP methods */
- if (msg->type_data.request.method != GST_RTSP_GET &&
- msg->type_data.request.method != GST_RTSP_POST) {
- msg->type_data.request.method = GST_RTSP_INVALID;
- if (res == GST_RTSP_OK)
- res = GST_RTSP_ERROR;
- }
- }
-
- return res;
-}
-
-/* parsing lines means reading a Key: Value pair */
-static GstRTSPResult
-parse_line (guint8 * buffer, GstRTSPMessage * msg)
-{
- GstRTSPHeaderField field;
- gchar *line = (gchar *) buffer;
- gchar *value;
-
- if ((value = strchr (line, ':')) == NULL || value == line)
- goto parse_error;
-
- /* trim space before the colon */
- if (value[-1] == ' ')
- value[-1] = '\0';
-
- /* replace the colon with a NUL */
- *value++ = '\0';
-
- /* find the header */
- field = gst_rtsp_find_header_field (line);
- if (field == GST_RTSP_HDR_INVALID)
- goto done;
-
- /* split up the value in multiple key:value pairs if it contains comma(s) */
- while (*value != '\0') {
- gchar *next_value;
- gchar *comma = NULL;
- gboolean quoted = FALSE;
- guint comment = 0;
-
- /* trim leading space */
- if (*value == ' ')
- value++;
-
- /* for headers which may not appear multiple times, and thus may not
- * contain multiple values on the same line, we can short-circuit the loop
- * below and the entire value results in just one key:value pair*/
- if (!gst_rtsp_header_allow_multiple (field))
- next_value = value + strlen (value);
- else
- next_value = value;
-
- /* find the next value, taking special care of quotes and comments */
- while (*next_value != '\0') {
- if ((quoted || comment != 0) && *next_value == '\\' &&
- next_value[1] != '\0')
- next_value++;
- else if (comment == 0 && *next_value == '"')
- quoted = !quoted;
- else if (!quoted && *next_value == '(')
- comment++;
- else if (comment != 0 && *next_value == ')')
- comment--;
- else if (!quoted && comment == 0) {
- /* To quote RFC 2068: "User agents MUST take special care in parsing
- * the WWW-Authenticate field value if it contains more than one
- * challenge, or if more than one WWW-Authenticate header field is
- * provided, since the contents of a challenge may itself contain a
- * comma-separated list of authentication parameters."
- *
- * What this means is that we cannot just look for an unquoted comma
- * when looking for multiple values in Proxy-Authenticate and
- * WWW-Authenticate headers. Instead we need to look for the sequence
- * "comma [space] token space token" before we can split after the
- * comma...
- */
- if (field == GST_RTSP_HDR_PROXY_AUTHENTICATE ||
- field == GST_RTSP_HDR_WWW_AUTHENTICATE) {
- if (*next_value == ',') {
- if (next_value[1] == ' ') {
- /* skip any space following the comma so we do not mistake it for
- * separating between two tokens */
- next_value++;
- }
- comma = next_value;
- } else if (*next_value == ' ' && next_value[1] != ',' &&
- next_value[1] != '=' && comma != NULL) {
- next_value = comma;
- comma = NULL;
- break;
- }
- } else if (*next_value == ',')
- break;
- }
-
- next_value++;
- }
-
- /* trim space */
- if (value != next_value && next_value[-1] == ' ')
- next_value[-1] = '\0';
-
- if (*next_value != '\0')
- *next_value++ = '\0';
-
- /* add the key:value pair */
- if (*value != '\0')
- gst_rtsp_message_add_header (msg, field, value);
-
- value = next_value;
- }
-
-done:
- return GST_RTSP_OK;
-
- /* ERRORS */
-parse_error:
- {
- return GST_RTSP_EPARSE;
- }
-}
-
-/* convert all consecutive whitespace to a single space */
-static void
-normalize_line (guint8 * buffer)
-{
- while (*buffer) {
- if (g_ascii_isspace (*buffer)) {
- guint8 *tmp;
-
- *buffer++ = ' ';
- for (tmp = buffer; g_ascii_isspace (*tmp); tmp++) {
- }
- if (buffer != tmp)
- memmove (buffer, tmp, strlen ((gchar *) tmp) + 1);
- } else {
- buffer++;
- }
- }
-}
-
-/* returns:
- * GST_RTSP_OK when a complete message was read.
- * GST_RTSP_EEOF: when the socket is closed
- * GST_RTSP_EINTR: when more data is needed.
- * GST_RTSP_..: some other error occured.
- */
-static GstRTSPResult
-build_next (GstRTSPBuilder * builder, GstRTSPMessage * message,
- GstRTSPConnection * conn)
-{
- GstRTSPResult res;
-
- while (TRUE) {
- switch (builder->state) {
- case STATE_START:
- builder->offset = 0;
- res =
- read_bytes (conn, (guint8 *) builder->buffer, &builder->offset, 1);
- if (res != GST_RTSP_OK)
- goto done;
-
- /* we have 1 bytes now and we can see if this is a data message or
- * not */
- if (builder->buffer[0] == '$') {
- /* data message, prepare for the header */
- builder->state = STATE_DATA_HEADER;
- } else {
- builder->line = 0;
- builder->state = STATE_READ_LINES;
- }
- break;
- case STATE_DATA_HEADER:
- {
- res =
- read_bytes (conn, (guint8 *) builder->buffer, &builder->offset, 4);
- if (res != GST_RTSP_OK)
- goto done;
-
- gst_rtsp_message_init_data (message, builder->buffer[1]);
-
- builder->body_len = (builder->buffer[2] << 8) | builder->buffer[3];
- builder->body_data = g_malloc (builder->body_len + 1);
- builder->body_data[builder->body_len] = '\0';
- builder->offset = 0;
- builder->state = STATE_DATA_BODY;
- break;
- }
- case STATE_DATA_BODY:
- {
- res =
- read_bytes (conn, builder->body_data, &builder->offset,
- builder->body_len);
- if (res != GST_RTSP_OK)
- goto done;
-
- /* we have the complete body now, store in the message adjusting the
- * length to include the traling '\0' */
- gst_rtsp_message_take_body (message,
- (guint8 *) builder->body_data, builder->body_len + 1);
- builder->body_data = NULL;
- builder->body_len = 0;
-
- builder->state = STATE_END;
- break;
- }
- case STATE_READ_LINES:
- {
- res = read_line (conn, builder->buffer, &builder->offset,
- sizeof (builder->buffer));
- if (res != GST_RTSP_OK)
- goto done;
-
- /* we have a regular response */
- if (builder->buffer[0] == '\0') {
- gchar *hdrval;
-
- /* empty line, end of message header */
- /* see if there is a Content-Length header, but ignore it if this
- * is a POST request with an x-sessioncookie header */
- if (gst_rtsp_message_get_header (message,
- GST_RTSP_HDR_CONTENT_LENGTH, &hdrval, 0) == GST_RTSP_OK &&
- (message->type != GST_RTSP_MESSAGE_HTTP_REQUEST ||
- message->type_data.request.method != GST_RTSP_POST ||
- gst_rtsp_message_get_header (message,
- GST_RTSP_HDR_X_SESSIONCOOKIE, NULL, 0) != GST_RTSP_OK)) {
- /* there is, prepare to read the body */
- builder->body_len = atol (hdrval);
- builder->body_data = g_malloc (builder->body_len + 1);
- builder->body_data[builder->body_len] = '\0';
- builder->offset = 0;
- builder->state = STATE_DATA_BODY;
- } else {
- builder->state = STATE_END;
- }
- break;
- }
-
- /* we have a line */
- normalize_line (builder->buffer);
- if (builder->line == 0) {
- /* first line, check for response status */
- if (memcmp (builder->buffer, "RTSP", 4) == 0 ||
- memcmp (builder->buffer, "HTTP", 4) == 0) {
- builder->status = parse_response_status (builder->buffer, message);
- } else {
- builder->status = parse_request_line (builder->buffer, message);
- }
- } else {
- /* else just parse the line */
- res = parse_line (builder->buffer, message);
- if (res != GST_RTSP_OK)
- builder->status = res;
- }
- builder->line++;
- builder->offset = 0;
- break;
- }
- case STATE_END:
- {
- gchar *session_cookie;
- gchar *session_id;
-
- if (message->type == GST_RTSP_MESSAGE_DATA) {
- /* data messages don't have headers */
- res = GST_RTSP_OK;
- goto done;
- }
-
- /* save the tunnel session in the connection */
- if (message->type == GST_RTSP_MESSAGE_HTTP_REQUEST &&
- !conn->manual_http &&
- conn->tstate == TUNNEL_STATE_NONE &&
- gst_rtsp_message_get_header (message, GST_RTSP_HDR_X_SESSIONCOOKIE,
- &session_cookie, 0) == GST_RTSP_OK) {
- strncpy (conn->tunnelid, session_cookie, TUNNELID_LEN);
- conn->tunnelid[TUNNELID_LEN - 1] = '\0';
- conn->tunneled = TRUE;
- }
-
- /* save session id in the connection for further use */
- if (message->type == GST_RTSP_MESSAGE_RESPONSE &&
- gst_rtsp_message_get_header (message, GST_RTSP_HDR_SESSION,
- &session_id, 0) == GST_RTSP_OK) {
- gint maxlen, i;
-
- maxlen = sizeof (conn->session_id) - 1;
- /* the sessionid can have attributes marked with ;
- * Make sure we strip them */
- for (i = 0; session_id[i] != '\0'; i++) {
- if (session_id[i] == ';') {
- maxlen = i;
- /* parse timeout */
- do {
- i++;
- } while (g_ascii_isspace (session_id[i]));
- if (g_str_has_prefix (&session_id[i], "timeout=")) {
- gint to;
-
- /* if we parsed something valid, configure */
- if ((to = atoi (&session_id[i + 8])) > 0)
- conn->timeout = to;
- }
- break;
- }
- }
-
- /* make sure to not overflow */
- strncpy (conn->session_id, session_id, maxlen);
- conn->session_id[maxlen] = '\0';
- }
- res = builder->status;
- goto done;
- }
- default:
- res = GST_RTSP_ERROR;
- break;
- }
- }
-done:
- return res;
-}
-
-/**
- * gst_rtsp_connection_read:
- * @conn: a #GstRTSPConnection
- * @data: the data to read
- * @size: the size of @data
- * @timeout: a timeout value or #NULL
- *
- * Attempt to read @size bytes into @data from the connected @conn, blocking up to
- * the specified @timeout. @timeout can be #NULL, in which case this function
- * might block forever.
- *
- * This function can be cancelled with gst_rtsp_connection_flush().
- *
- * Returns: #GST_RTSP_OK on success.
- */
-GstRTSPResult
-gst_rtsp_connection_read (GstRTSPConnection * conn, guint8 * data, guint size,
- GTimeVal * timeout)
-{
- guint offset;
- gint retval;
- GstClockTime to;
- GstRTSPResult res;
-
- g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (conn->readfd != NULL, GST_RTSP_EINVAL);
-
- if (G_UNLIKELY (size == 0))
- return GST_RTSP_OK;
-
- offset = 0;
-
- /* configure timeout if any */
- to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
-
- gst_poll_set_controllable (conn->fdset, TRUE);
- gst_poll_fd_ctl_write (conn->fdset, conn->writefd, FALSE);
- gst_poll_fd_ctl_read (conn->fdset, conn->readfd, TRUE);
-
- while (TRUE) {
- res = read_bytes (conn, data, &offset, size);
- if (G_UNLIKELY (res == GST_RTSP_EEOF))
- goto eof;
- if (G_LIKELY (res == GST_RTSP_OK))
- break;
- if (G_UNLIKELY (res != GST_RTSP_EINTR))
- goto read_error;
-
- do {
- retval = gst_poll_wait (conn->fdset, to);
- } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
-
- /* check for timeout */
- if (G_UNLIKELY (retval == 0))
- goto select_timeout;
-
- if (G_UNLIKELY (retval == -1)) {
- if (errno == EBUSY)
- goto stopped;
- else
- goto select_error;
- }
- gst_poll_set_controllable (conn->fdset, FALSE);
- }
- return GST_RTSP_OK;
-
- /* ERRORS */
-select_error:
- {
- return GST_RTSP_ESYS;
- }
-select_timeout:
- {
- return GST_RTSP_ETIMEOUT;
- }
-stopped:
- {
- return GST_RTSP_EINTR;
- }
-eof:
- {
- return GST_RTSP_EEOF;
- }
-read_error:
- {
- return res;
- }
-}
-
-static GstRTSPMessage *
-gen_tunnel_reply (GstRTSPConnection * conn, GstRTSPStatusCode code,
- const GstRTSPMessage * request)
-{
- GstRTSPMessage *msg;
- GstRTSPResult res;
-
- if (gst_rtsp_status_as_text (code) == NULL)
- code = GST_RTSP_STS_INTERNAL_SERVER_ERROR;
-
- GST_RTSP_CHECK (gst_rtsp_message_new_response (&msg, code, NULL, request),
- no_message);
-
- gst_rtsp_message_add_header (msg, GST_RTSP_HDR_SERVER,
- "GStreamer RTSP Server");
- gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONNECTION, "close");
- gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CACHE_CONTROL, "no-store");
- gst_rtsp_message_add_header (msg, GST_RTSP_HDR_PRAGMA, "no-cache");
-
- if (code == GST_RTSP_STS_OK) {
- if (conn->ip)
- gst_rtsp_message_add_header (msg, GST_RTSP_HDR_X_SERVER_IP_ADDRESS,
- conn->ip);
- gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CONTENT_TYPE,
- "application/x-rtsp-tunnelled");
- }
-
- return msg;
-
- /* ERRORS */
-no_message:
- {
- return NULL;
- }
-}
-
-/**
- * gst_rtsp_connection_receive:
- * @conn: a #GstRTSPConnection
- * @message: the message to read
- * @timeout: a timeout value or #NULL
- *
- * Attempt to read into @message from the connected @conn, blocking up to
- * the specified @timeout. @timeout can be #NULL, in which case this function
- * might block forever.
- *
- * This function can be cancelled with gst_rtsp_connection_flush().
- *
- * Returns: #GST_RTSP_OK on success.
- */
-GstRTSPResult
-gst_rtsp_connection_receive (GstRTSPConnection * conn, GstRTSPMessage * message,
- GTimeVal * timeout)
-{
- GstRTSPResult res;
- GstRTSPBuilder builder;
- gint retval;
- GstClockTime to;
-
- g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (conn->readfd != NULL, GST_RTSP_EINVAL);
-
- /* configure timeout if any */
- to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
-
- gst_poll_set_controllable (conn->fdset, TRUE);
- gst_poll_fd_ctl_write (conn->fdset, conn->writefd, FALSE);
- gst_poll_fd_ctl_read (conn->fdset, conn->readfd, TRUE);
-
- memset (&builder, 0, sizeof (GstRTSPBuilder));
- while (TRUE) {
- res = build_next (&builder, message, conn);
- if (G_UNLIKELY (res == GST_RTSP_EEOF))
- goto eof;
- else if (G_LIKELY (res == GST_RTSP_OK)) {
- if (!conn->manual_http) {
- if (message->type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
- if (conn->tstate == TUNNEL_STATE_NONE &&
- message->type_data.request.method == GST_RTSP_GET) {
- GstRTSPMessage *response;
-
- conn->tstate = TUNNEL_STATE_GET;
-
- /* tunnel GET request, we can reply now */
- response = gen_tunnel_reply (conn, GST_RTSP_STS_OK, message);
- res = gst_rtsp_connection_send (conn, response, timeout);
- gst_rtsp_message_free (response);
- if (res == GST_RTSP_OK)
- res = GST_RTSP_ETGET;
- goto cleanup;
- } else if (conn->tstate == TUNNEL_STATE_NONE &&
- message->type_data.request.method == GST_RTSP_POST) {
- conn->tstate = TUNNEL_STATE_POST;
-
- /* tunnel POST request, the caller now has to link the two
- * connections. */
- res = GST_RTSP_ETPOST;
- goto cleanup;
- } else {
- res = GST_RTSP_EPARSE;
- goto cleanup;
- }
- } else if (message->type == GST_RTSP_MESSAGE_HTTP_RESPONSE) {
- res = GST_RTSP_EPARSE;
- goto cleanup;
- }
- }
-
- break;
- } else if (G_UNLIKELY (res != GST_RTSP_EINTR))
- goto read_error;
-
- do {
- retval = gst_poll_wait (conn->fdset, to);
- } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
-
- /* check for timeout */
- if (G_UNLIKELY (retval == 0))
- goto select_timeout;
-
- if (G_UNLIKELY (retval == -1)) {
- if (errno == EBUSY)
- goto stopped;
- else
- goto select_error;
- }
- gst_poll_set_controllable (conn->fdset, FALSE);
- }
-
- /* we have a message here */
- build_reset (&builder);
-
- return GST_RTSP_OK;
-
- /* ERRORS */
-select_error:
- {
- res = GST_RTSP_ESYS;
- goto cleanup;
- }
-select_timeout:
- {
- res = GST_RTSP_ETIMEOUT;
- goto cleanup;
- }
-stopped:
- {
- res = GST_RTSP_EINTR;
- goto cleanup;
- }
-eof:
- {
- res = GST_RTSP_EEOF;
- goto cleanup;
- }
-read_error:
-cleanup:
- {
- build_reset (&builder);
- gst_rtsp_message_unset (message);
- return res;
- }
-}
-
-/**
- * gst_rtsp_connection_close:
- * @conn: a #GstRTSPConnection
- *
- * Close the connected @conn. After this call, the connection is in the same
- * state as when it was first created.
- *
- * Returns: #GST_RTSP_OK on success.
- */
-GstRTSPResult
-gst_rtsp_connection_close (GstRTSPConnection * conn)
-{
- g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
-
- g_free (conn->ip);
- conn->ip = NULL;
-
- conn->read_ahead = 0;
-
- g_free (conn->initial_buffer);
- conn->initial_buffer = NULL;
- conn->initial_buffer_offset = 0;
-
- REMOVE_POLLFD (conn->fdset, &conn->fd0);
- REMOVE_POLLFD (conn->fdset, &conn->fd1);
- conn->writefd = NULL;
- conn->readfd = NULL;
- conn->tunneled = FALSE;
- conn->tstate = TUNNEL_STATE_NONE;
- conn->ctxp = NULL;
- g_free (conn->username);
- conn->username = NULL;
- g_free (conn->passwd);
- conn->passwd = NULL;
- gst_rtsp_connection_clear_auth_params (conn);
- conn->timeout = 60;
- conn->cseq = 0;
- conn->session_id[0] = '\0';
-
- return GST_RTSP_OK;
-}
-
-/**
- * gst_rtsp_connection_free:
- * @conn: a #GstRTSPConnection
- *
- * Close and free @conn.
- *
- * Returns: #GST_RTSP_OK on success.
- */
-GstRTSPResult
-gst_rtsp_connection_free (GstRTSPConnection * conn)
-{
- GstRTSPResult res;
-
- g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
-
- res = gst_rtsp_connection_close (conn);
- gst_poll_free (conn->fdset);
- g_timer_destroy (conn->timer);
- gst_rtsp_url_free (conn->url);
- g_free (conn->proxy_host);
- g_free (conn);
-#ifdef G_OS_WIN32
- WSACleanup ();
-#endif
-
- return res;
-}
-
-/**
- * gst_rtsp_connection_poll:
- * @conn: a #GstRTSPConnection
- * @events: a bitmask of #GstRTSPEvent flags to check
- * @revents: location for result flags
- * @timeout: a timeout
- *
- * Wait up to the specified @timeout for the connection to become available for
- * at least one of the operations specified in @events. When the function returns
- * with #GST_RTSP_OK, @revents will contain a bitmask of available operations on
- * @conn.
- *
- * @timeout can be #NULL, in which case this function might block forever.
- *
- * This function can be cancelled with gst_rtsp_connection_flush().
- *
- * Returns: #GST_RTSP_OK on success.
- *
- * Since: 0.10.15
- */
-GstRTSPResult
-gst_rtsp_connection_poll (GstRTSPConnection * conn, GstRTSPEvent events,
- GstRTSPEvent * revents, GTimeVal * timeout)
-{
- GstClockTime to;
- gint retval;
-
- g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (events != 0, GST_RTSP_EINVAL);
- g_return_val_if_fail (revents != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (conn->readfd != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (conn->writefd != NULL, GST_RTSP_EINVAL);
-
- gst_poll_set_controllable (conn->fdset, TRUE);
-
- /* add fd to writer set when asked to */
- gst_poll_fd_ctl_write (conn->fdset, conn->writefd,
- events & GST_RTSP_EV_WRITE);
-
- /* add fd to reader set when asked to */
- gst_poll_fd_ctl_read (conn->fdset, conn->readfd, events & GST_RTSP_EV_READ);
-
- /* configure timeout if any */
- to = timeout ? GST_TIMEVAL_TO_TIME (*timeout) : GST_CLOCK_TIME_NONE;
-
- do {
- retval = gst_poll_wait (conn->fdset, to);
- } while (retval == -1 && (errno == EINTR || errno == EAGAIN));
-
- if (G_UNLIKELY (retval == 0))
- goto select_timeout;
-
- if (G_UNLIKELY (retval == -1)) {
- if (errno == EBUSY)
- goto stopped;
- else
- goto select_error;
- }
-
- *revents = 0;
- if (events & GST_RTSP_EV_READ) {
- if (gst_poll_fd_can_read (conn->fdset, conn->readfd))
- *revents |= GST_RTSP_EV_READ;
- }
- if (events & GST_RTSP_EV_WRITE) {
- if (gst_poll_fd_can_write (conn->fdset, conn->writefd))
- *revents |= GST_RTSP_EV_WRITE;
- }
- return GST_RTSP_OK;
-
- /* ERRORS */
-select_timeout:
- {
- return GST_RTSP_ETIMEOUT;
- }
-select_error:
- {
- return GST_RTSP_ESYS;
- }
-stopped:
- {
- return GST_RTSP_EINTR;
- }
-}
-
-/**
- * gst_rtsp_connection_next_timeout:
- * @conn: a #GstRTSPConnection
- * @timeout: a timeout
- *
- * Calculate the next timeout for @conn, storing the result in @timeout.
- *
- * Returns: #GST_RTSP_OK.
- */
-GstRTSPResult
-gst_rtsp_connection_next_timeout (GstRTSPConnection * conn, GTimeVal * timeout)
-{
- gdouble elapsed;
- glong sec;
- gulong usec;
-
- g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (timeout != NULL, GST_RTSP_EINVAL);
-
- elapsed = g_timer_elapsed (conn->timer, &usec);
- if (elapsed >= conn->timeout) {
- sec = 0;
- usec = 0;
- } else {
- sec = conn->timeout - elapsed;
- }
-
- timeout->tv_sec = sec;
- timeout->tv_usec = usec;
-
- return GST_RTSP_OK;
-}
-
-/**
- * gst_rtsp_connection_reset_timeout:
- * @conn: a #GstRTSPConnection
- *
- * Reset the timeout of @conn.
- *
- * Returns: #GST_RTSP_OK.
- */
-GstRTSPResult
-gst_rtsp_connection_reset_timeout (GstRTSPConnection * conn)
-{
- g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
-
- g_timer_start (conn->timer);
-
- return GST_RTSP_OK;
-}
-
-/**
- * gst_rtsp_connection_flush:
- * @conn: a #GstRTSPConnection
- * @flush: start or stop the flush
- *
- * Start or stop the flushing action on @conn. When flushing, all current
- * and future actions on @conn will return #GST_RTSP_EINTR until the connection
- * is set to non-flushing mode again.
- *
- * Returns: #GST_RTSP_OK.
- */
-GstRTSPResult
-gst_rtsp_connection_flush (GstRTSPConnection * conn, gboolean flush)
-{
- g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
-
- gst_poll_set_flushing (conn->fdset, flush);
-
- return GST_RTSP_OK;
-}
-
-/**
- * gst_rtsp_connection_set_proxy:
- * @conn: a #GstRTSPConnection
- * @host: the proxy host
- * @port: the proxy port
- *
- * Set the proxy host and port.
- *
- * Returns: #GST_RTSP_OK.
- *
- * Since: 0.10.23
- */
-GstRTSPResult
-gst_rtsp_connection_set_proxy (GstRTSPConnection * conn,
- const gchar * host, guint port)
-{
- g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
-
- g_free (conn->proxy_host);
- conn->proxy_host = g_strdup (host);
- conn->proxy_port = port;
-
- return GST_RTSP_OK;
-}
-
-/**
- * gst_rtsp_connection_set_auth:
- * @conn: a #GstRTSPConnection
- * @method: authentication method
- * @user: the user
- * @pass: the password
- *
- * Configure @conn for authentication mode @method with @user and @pass as the
- * user and password respectively.
- *
- * Returns: #GST_RTSP_OK.
- */
-GstRTSPResult
-gst_rtsp_connection_set_auth (GstRTSPConnection * conn,
- GstRTSPAuthMethod method, const gchar * user, const gchar * pass)
-{
- g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
-
- if (method == GST_RTSP_AUTH_DIGEST && ((user == NULL || pass == NULL)
- || g_strrstr (user, ":") != NULL))
- return GST_RTSP_EINVAL;
-
- /* Make sure the username and passwd are being set for authentication */
- if (method == GST_RTSP_AUTH_NONE && (user == NULL || pass == NULL))
- return GST_RTSP_EINVAL;
-
- /* ":" chars are not allowed in usernames for basic auth */
- if (method == GST_RTSP_AUTH_BASIC && g_strrstr (user, ":") != NULL)
- return GST_RTSP_EINVAL;
-
- g_free (conn->username);
- g_free (conn->passwd);
-
- conn->auth_method = method;
- conn->username = g_strdup (user);
- conn->passwd = g_strdup (pass);
-
- return GST_RTSP_OK;
-}
-
-/**
- * str_case_hash:
- * @key: ASCII string to hash
- *
- * Hashes @key in a case-insensitive manner.
- *
- * Returns: the hash code.
- **/
-static guint
-str_case_hash (gconstpointer key)
-{
- const char *p = key;
- guint h = g_ascii_toupper (*p);
-
- if (h)
- for (p += 1; *p != '\0'; p++)
- h = (h << 5) - h + g_ascii_toupper (*p);
-
- return h;
-}
-
-/**
- * str_case_equal:
- * @v1: an ASCII string
- * @v2: another ASCII string
- *
- * Compares @v1 and @v2 in a case-insensitive manner
- *
- * Returns: %TRUE if they are equal (modulo case)
- **/
-static gboolean
-str_case_equal (gconstpointer v1, gconstpointer v2)
-{
- const char *string1 = v1;
- const char *string2 = v2;
-
- return g_ascii_strcasecmp (string1, string2) == 0;
-}
-
-/**
- * gst_rtsp_connection_set_auth_param:
- * @conn: a #GstRTSPConnection
- * @param: authentication directive
- * @value: value
- *
- * Setup @conn with authentication directives. This is not necesary for
- * methods #GST_RTSP_AUTH_NONE and #GST_RTSP_AUTH_BASIC. For
- * #GST_RTSP_AUTH_DIGEST, directives should be taken from the digest challenge
- * in the WWW-Authenticate response header and can include realm, domain,
- * nonce, opaque, stale, algorithm, qop as per RFC2617.
- *
- * Since: 0.10.20
- */
-void
-gst_rtsp_connection_set_auth_param (GstRTSPConnection * conn,
- const gchar * param, const gchar * value)
-{
- g_return_if_fail (conn != NULL);
- g_return_if_fail (param != NULL);
-
- if (conn->auth_params == NULL) {
- conn->auth_params =
- g_hash_table_new_full (str_case_hash, str_case_equal, g_free, g_free);
- }
- g_hash_table_insert (conn->auth_params, g_strdup (param), g_strdup (value));
-}
-
-/**
- * gst_rtsp_connection_clear_auth_params:
- * @conn: a #GstRTSPConnection
- *
- * Clear the list of authentication directives stored in @conn.
- *
- * Since: 0.10.20
- */
-void
-gst_rtsp_connection_clear_auth_params (GstRTSPConnection * conn)
-{
- g_return_if_fail (conn != NULL);
-
- if (conn->auth_params != NULL) {
- g_hash_table_destroy (conn->auth_params);
- conn->auth_params = NULL;
- }
-}
-
-static GstRTSPResult
-set_qos_dscp (gint fd, guint qos_dscp)
-{
- union gst_sockaddr sa;
- socklen_t slen = sizeof (sa);
- gint af;
- gint tos;
-
- if (fd == -1)
- return GST_RTSP_OK;
-
- if (getsockname (fd, &sa.sa, &slen) < 0)
- goto no_getsockname;
-
- af = sa.sa.sa_family;
-
- /* if this is an IPv4-mapped address then do IPv4 QoS */
- if (af == AF_INET6) {
- if (IN6_IS_ADDR_V4MAPPED (&sa.sa_in6.sin6_addr))
- af = AF_INET;
- }
-
- /* extract and shift 6 bits of the DSCP */
- tos = (qos_dscp & 0x3f) << 2;
-
- switch (af) {
- case AF_INET:
- if (SETSOCKOPT (fd, IPPROTO_IP, IP_TOS, &tos, sizeof (tos)) < 0)
- goto no_setsockopt;
- break;
- case AF_INET6:
-#ifdef IPV6_TCLASS
- if (SETSOCKOPT (fd, IPPROTO_IPV6, IPV6_TCLASS, &tos, sizeof (tos)) < 0)
- goto no_setsockopt;
- break;
-#endif
- default:
- goto wrong_family;
- }
-
- return GST_RTSP_OK;
-
- /* ERRORS */
-no_getsockname:
-no_setsockopt:
- {
- return GST_RTSP_ESYS;
- }
-
-wrong_family:
- {
- return GST_RTSP_ERROR;
- }
-}
-
-/**
- * gst_rtsp_connection_set_qos_dscp:
- * @conn: a #GstRTSPConnection
- * @qos_dscp: DSCP value
- *
- * Configure @conn to use the specified DSCP value.
- *
- * Returns: #GST_RTSP_OK on success.
- *
- * Since: 0.10.20
- */
-GstRTSPResult
-gst_rtsp_connection_set_qos_dscp (GstRTSPConnection * conn, guint qos_dscp)
-{
- GstRTSPResult res;
-
- g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (conn->readfd != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (conn->writefd != NULL, GST_RTSP_EINVAL);
-
- res = set_qos_dscp (conn->fd0.fd, qos_dscp);
- if (res == GST_RTSP_OK)
- res = set_qos_dscp (conn->fd1.fd, qos_dscp);
-
- return res;
-}
-
-
-/**
- * gst_rtsp_connection_get_url:
- * @conn: a #GstRTSPConnection
- *
- * Retrieve the URL of the other end of @conn.
- *
- * Returns: The URL. This value remains valid until the
- * connection is freed.
- *
- * Since: 0.10.23
- */
-GstRTSPUrl *
-gst_rtsp_connection_get_url (const GstRTSPConnection * conn)
-{
- g_return_val_if_fail (conn != NULL, NULL);
-
- return conn->url;
-}
-
-/**
- * gst_rtsp_connection_get_ip:
- * @conn: a #GstRTSPConnection
- *
- * Retrieve the IP address of the other end of @conn.
- *
- * Returns: The IP address as a string. this value remains valid until the
- * connection is closed.
- *
- * Since: 0.10.20
- */
-const gchar *
-gst_rtsp_connection_get_ip (const GstRTSPConnection * conn)
-{
- g_return_val_if_fail (conn != NULL, NULL);
-
- return conn->ip;
-}
-
-/**
- * gst_rtsp_connection_set_ip:
- * @conn: a #GstRTSPConnection
- * @ip: an ip address
- *
- * Set the IP address of the server.
- *
- * Since: 0.10.23
- */
-void
-gst_rtsp_connection_set_ip (GstRTSPConnection * conn, const gchar * ip)
-{
- g_return_if_fail (conn != NULL);
-
- g_free (conn->ip);
- conn->ip = g_strdup (ip);
-}
-
-/**
- * gst_rtsp_connection_get_readfd:
- * @conn: a #GstRTSPConnection
- *
- * Get the file descriptor for reading.
- *
- * Returns: the file descriptor used for reading or -1 on error. The file
- * descriptor remains valid until the connection is closed.
- *
- * Since: 0.10.23
- */
-gint
-gst_rtsp_connection_get_readfd (const GstRTSPConnection * conn)
-{
- g_return_val_if_fail (conn != NULL, -1);
- g_return_val_if_fail (conn->readfd != NULL, -1);
-
- return conn->readfd->fd;
-}
-
-/**
- * gst_rtsp_connection_get_writefd:
- * @conn: a #GstRTSPConnection
- *
- * Get the file descriptor for writing.
- *
- * Returns: the file descriptor used for writing or -1 on error. The file
- * descriptor remains valid until the connection is closed.
- *
- * Since: 0.10.23
- */
-gint
-gst_rtsp_connection_get_writefd (const GstRTSPConnection * conn)
-{
- g_return_val_if_fail (conn != NULL, -1);
- g_return_val_if_fail (conn->writefd != NULL, -1);
-
- return conn->writefd->fd;
-}
-
-/**
- * gst_rtsp_connection_set_http_mode:
- * @conn: a #GstRTSPConnection
- * @enable: %TRUE to enable manual HTTP mode
- *
- * By setting the HTTP mode to %TRUE the message parsing will support HTTP
- * messages in addition to the RTSP messages. It will also disable the
- * automatic handling of setting up an HTTP tunnel.
- *
- * Since: 0.10.25
- */
-void
-gst_rtsp_connection_set_http_mode (GstRTSPConnection * conn, gboolean enable)
-{
- g_return_if_fail (conn != NULL);
-
- conn->manual_http = enable;
-}
-
-/**
- * gst_rtsp_connection_set_tunneled:
- * @conn: a #GstRTSPConnection
- * @tunneled: the new state
- *
- * Set the HTTP tunneling state of the connection. This must be configured before
- * the @conn is connected.
- *
- * Since: 0.10.23
- */
-void
-gst_rtsp_connection_set_tunneled (GstRTSPConnection * conn, gboolean tunneled)
-{
- g_return_if_fail (conn != NULL);
- g_return_if_fail (conn->readfd == NULL);
- g_return_if_fail (conn->writefd == NULL);
-
- conn->tunneled = tunneled;
-}
-
-/**
- * gst_rtsp_connection_is_tunneled:
- * @conn: a #GstRTSPConnection
- *
- * Get the tunneling state of the connection.
- *
- * Returns: if @conn is using HTTP tunneling.
- *
- * Since: 0.10.23
- */
-gboolean
-gst_rtsp_connection_is_tunneled (const GstRTSPConnection * conn)
-{
- g_return_val_if_fail (conn != NULL, FALSE);
-
- return conn->tunneled;
-}
-
-/**
- * gst_rtsp_connection_get_tunnelid:
- * @conn: a #GstRTSPConnection
- *
- * Get the tunnel session id the connection.
- *
- * Returns: returns a non-empty string if @conn is being tunneled over HTTP.
- *
- * Since: 0.10.23
- */
-const gchar *
-gst_rtsp_connection_get_tunnelid (const GstRTSPConnection * conn)
-{
- g_return_val_if_fail (conn != NULL, NULL);
-
- if (!conn->tunneled)
- return NULL;
-
- return conn->tunnelid;
-}
-
-/**
- * gst_rtsp_connection_do_tunnel:
- * @conn: a #GstRTSPConnection
- * @conn2: a #GstRTSPConnection or %NULL
- *
- * If @conn received the first tunnel connection and @conn2 received
- * the second tunnel connection, link the two connections together so that
- * @conn manages the tunneled connection.
- *
- * After this call, @conn2 cannot be used anymore and must be freed with
- * gst_rtsp_connection_free().
- *
- * If @conn2 is %NULL then only the base64 decoding context will be setup for
- * @conn.
- *
- * Returns: return GST_RTSP_OK on success.
- *
- * Since: 0.10.23
- */
-GstRTSPResult
-gst_rtsp_connection_do_tunnel (GstRTSPConnection * conn,
- GstRTSPConnection * conn2)
-{
- g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
-
- if (conn2 != NULL) {
- g_return_val_if_fail (conn->tstate == TUNNEL_STATE_GET, GST_RTSP_EINVAL);
- g_return_val_if_fail (conn2->tstate == TUNNEL_STATE_POST, GST_RTSP_EINVAL);
- g_return_val_if_fail (!memcmp (conn2->tunnelid, conn->tunnelid,
- TUNNELID_LEN), GST_RTSP_EINVAL);
-
- /* both connections have fd0 as the read/write socket. start by taking the
- * socket from conn2 and set it as the socket in conn */
- conn->fd1 = conn2->fd0;
-
- /* clean up some of the state of conn2 */
- gst_poll_remove_fd (conn2->fdset, &conn2->fd0);
- conn2->fd0.fd = -1;
- conn2->readfd = conn2->writefd = NULL;
-
- /* We make fd0 the write socket and fd1 the read socket. */
- conn->writefd = &conn->fd0;
- conn->readfd = &conn->fd1;
-
- conn->tstate = TUNNEL_STATE_COMPLETE;
- }
-
- /* we need base64 decoding for the readfd */
- conn->ctx.state = 0;
- conn->ctx.save = 0;
- conn->ctx.cout = 0;
- conn->ctx.coutl = 0;
- conn->ctxp = &conn->ctx;
-
- return GST_RTSP_OK;
-}
-
-#define READ_COND (G_IO_IN | G_IO_HUP | G_IO_ERR)
-#define WRITE_COND (G_IO_OUT | G_IO_ERR)
-
-typedef struct
-{
- guint8 *data;
- guint size;
- guint id;
-} GstRTSPRec;
-
-/* async functions */
-struct _GstRTSPWatch
-{
- GSource source;
-
- GstRTSPConnection *conn;
-
- GstRTSPBuilder builder;
- GstRTSPMessage message;
-
- GPollFD readfd;
- GPollFD writefd;
- gboolean write_added;
-
- /* queued message for transmission */
- guint id;
- GMutex *mutex;
- GQueue *messages;
- guint8 *write_data;
- guint write_off;
- guint write_size;
- guint write_id;
-
- GstRTSPWatchFuncs funcs;
-
- gpointer user_data;
- GDestroyNotify notify;
-};
-
-static gboolean
-gst_rtsp_source_prepare (GSource * source, gint * timeout)
-{
- GstRTSPWatch *watch = (GstRTSPWatch *) source;
-
- if (watch->conn->initial_buffer != NULL)
- return TRUE;
-
- *timeout = (watch->conn->timeout * 1000);
-
- return FALSE;
-}
-
-static gboolean
-gst_rtsp_source_check (GSource * source)
-{
- GstRTSPWatch *watch = (GstRTSPWatch *) source;
-
- if (watch->readfd.revents & READ_COND)
- return TRUE;
-
- if (watch->writefd.revents & WRITE_COND)
- return TRUE;
-
- return FALSE;
-}
-
-static gboolean
-gst_rtsp_source_dispatch (GSource * source, GSourceFunc callback G_GNUC_UNUSED,
- gpointer user_data G_GNUC_UNUSED)
-{
- GstRTSPWatch *watch = (GstRTSPWatch *) source;
- GstRTSPResult res;
-
- /* first read as much as we can */
- if (watch->readfd.revents & READ_COND || watch->conn->initial_buffer != NULL) {
- do {
- res = build_next (&watch->builder, &watch->message, watch->conn);
- if (res == GST_RTSP_EINTR)
- break;
- else if (G_UNLIKELY (res == GST_RTSP_EEOF))
- goto eof;
- else if (G_LIKELY (res == GST_RTSP_OK)) {
- if (!watch->conn->manual_http &&
- watch->message.type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
- if (watch->conn->tstate == TUNNEL_STATE_NONE &&
- watch->message.type_data.request.method == GST_RTSP_GET) {
- GstRTSPMessage *response;
- GstRTSPStatusCode code;
-
- watch->conn->tstate = TUNNEL_STATE_GET;
-
- if (watch->funcs.tunnel_start)
- code = watch->funcs.tunnel_start (watch, watch->user_data);
- else
- code = GST_RTSP_STS_OK;
-
- /* queue the response */
- response = gen_tunnel_reply (watch->conn, code, &watch->message);
- gst_rtsp_watch_send_message (watch, response, NULL);
- gst_rtsp_message_free (response);
- goto read_done;
- } else if (watch->conn->tstate == TUNNEL_STATE_NONE &&
- watch->message.type_data.request.method == GST_RTSP_POST) {
- watch->conn->tstate = TUNNEL_STATE_POST;
-
- /* in the callback the connection should be tunneled with the
- * GET connection */
- if (watch->funcs.tunnel_complete)
- watch->funcs.tunnel_complete (watch, watch->user_data);
- goto read_done;
- }
- }
- }
-
- if (!watch->conn->manual_http) {
- /* if manual HTTP support is not enabled, then restore the message to
- * what it would have looked like without the support for parsing HTTP
- * messages being present */
- if (watch->message.type == GST_RTSP_MESSAGE_HTTP_REQUEST) {
- watch->message.type = GST_RTSP_MESSAGE_REQUEST;
- watch->message.type_data.request.method = GST_RTSP_INVALID;
- if (watch->message.type_data.request.version != GST_RTSP_VERSION_1_0)
- watch->message.type_data.request.version = GST_RTSP_VERSION_INVALID;
- res = GST_RTSP_EPARSE;
- } else if (watch->message.type == GST_RTSP_MESSAGE_HTTP_RESPONSE) {
- watch->message.type = GST_RTSP_MESSAGE_RESPONSE;
- if (watch->message.type_data.response.version != GST_RTSP_VERSION_1_0)
- watch->message.type_data.response.version =
- GST_RTSP_VERSION_INVALID;
- res = GST_RTSP_EPARSE;
- }
- }
-
- if (G_LIKELY (res == GST_RTSP_OK)) {
- if (watch->funcs.message_received)
- watch->funcs.message_received (watch, &watch->message,
- watch->user_data);
- } else {
- if (watch->funcs.error_full)
- GST_RTSP_CHECK (watch->funcs.error_full (watch, res, &watch->message,
- 0, watch->user_data), error);
- else
- goto error;
- }
-
- read_done:
- gst_rtsp_message_unset (&watch->message);
- build_reset (&watch->builder);
- } while (FALSE);
- }
-
- if (watch->writefd.revents & WRITE_COND) {
- g_mutex_lock (watch->mutex);
- do {
- if (watch->write_data == NULL) {
- GstRTSPRec *rec;
-
- /* get a new message from the queue */
- rec = g_queue_pop_tail (watch->messages);
- if (rec == NULL)
- goto done;
-
- watch->write_off = 0;
- watch->write_data = rec->data;
- watch->write_size = rec->size;
- watch->write_id = rec->id;
-
- g_slice_free (GstRTSPRec, rec);
- }
-
- res = write_bytes (watch->writefd.fd, watch->write_data,
- &watch->write_off, watch->write_size);
- g_mutex_unlock (watch->mutex);
- if (res == GST_RTSP_EINTR)
- goto write_blocked;
- else if (G_LIKELY (res == GST_RTSP_OK)) {
- if (watch->funcs.message_sent)
- watch->funcs.message_sent (watch, watch->write_id, watch->user_data);
- } else {
- if (watch->funcs.error_full)
- GST_RTSP_CHECK (watch->funcs.error_full (watch, res, NULL,
- watch->write_id, watch->user_data), error);
- else
- goto error;
- }
- g_mutex_lock (watch->mutex);
-
- g_free (watch->write_data);
- watch->write_data = NULL;
- } while (TRUE);
-
- done:
- if (watch->write_added) {
- g_source_remove_poll ((GSource *) watch, &watch->writefd);
- watch->write_added = FALSE;
- watch->writefd.revents = 0;
- }
-
- g_mutex_unlock (watch->mutex);
- }
-
-write_blocked:
- return TRUE;
-
- /* ERRORS */
-eof:
- {
- if (watch->funcs.closed)
- watch->funcs.closed (watch, watch->user_data);
- return FALSE;
- }
-error:
- {
- if (watch->funcs.error)
- watch->funcs.error (watch, res, watch->user_data);
- return FALSE;
- }
-}
-
-static void
-gst_rtsp_rec_free (gpointer data)
-{
- GstRTSPRec *rec = data;
-
- g_free (rec->data);
- g_slice_free (GstRTSPRec, rec);
-}
-
-static void
-gst_rtsp_source_finalize (GSource * source)
-{
- GstRTSPWatch *watch = (GstRTSPWatch *) source;
-
- build_reset (&watch->builder);
- gst_rtsp_message_unset (&watch->message);
-
- g_queue_foreach (watch->messages, (GFunc) gst_rtsp_rec_free, NULL);
- g_queue_free (watch->messages);
- watch->messages = NULL;
-
- g_mutex_free (watch->mutex);
-
- g_free (watch->write_data);
-
- if (watch->notify)
- watch->notify (watch->user_data);
-}
-
-static GSourceFuncs gst_rtsp_source_funcs = {
- gst_rtsp_source_prepare,
- gst_rtsp_source_check,
- gst_rtsp_source_dispatch,
- gst_rtsp_source_finalize,
- NULL,
- NULL
-};
-
-/**
- * gst_rtsp_watch_new:
- * @conn: a #GstRTSPConnection
- * @funcs: watch functions
- * @user_data: user data to pass to @funcs
- * @notify: notify when @user_data is not referenced anymore
- *
- * Create a watch object for @conn. The functions provided in @funcs will be
- * called with @user_data when activity happened on the watch.
- *
- * The new watch is usually created so that it can be attached to a
- * maincontext with gst_rtsp_watch_attach().
- *
- * @conn must exist for the entire lifetime of the watch.
- *
- * Returns: a #GstRTSPWatch that can be used for asynchronous RTSP
- * communication. Free with gst_rtsp_watch_unref () after usage.
- *
- * Since: 0.10.23
- */
-GstRTSPWatch *
-gst_rtsp_watch_new (GstRTSPConnection * conn,
- GstRTSPWatchFuncs * funcs, gpointer user_data, GDestroyNotify notify)
-{
- GstRTSPWatch *result;
-
- g_return_val_if_fail (conn != NULL, NULL);
- g_return_val_if_fail (funcs != NULL, NULL);
- g_return_val_if_fail (conn->readfd != NULL, NULL);
- g_return_val_if_fail (conn->writefd != NULL, NULL);
-
- result = (GstRTSPWatch *) g_source_new (&gst_rtsp_source_funcs,
- sizeof (GstRTSPWatch));
-
- result->conn = conn;
- result->builder.state = STATE_START;
-
- result->mutex = g_mutex_new ();
- result->messages = g_queue_new ();
-
- result->readfd.fd = -1;
- result->writefd.fd = -1;
-
- gst_rtsp_watch_reset (result);
-
- result->funcs = *funcs;
- result->user_data = user_data;
- result->notify = notify;
-
- /* only add the read fd, the write fd is only added when we have data
- * to send. */
- g_source_add_poll ((GSource *) result, &result->readfd);
-
- return result;
-}
-
-/**
- * gst_rtsp_watch_reset:
- * @watch: a #GstRTSPWatch
- *
- * Reset @watch, this is usually called after gst_rtsp_connection_do_tunnel()
- * when the file descriptors of the connection might have changed.
- *
- * Since: 0.10.23
- */
-void
-gst_rtsp_watch_reset (GstRTSPWatch * watch)
-{
- if (watch->readfd.fd != -1)
- g_source_remove_poll ((GSource *) watch, &watch->readfd);
- if (watch->writefd.fd != -1)
- g_source_remove_poll ((GSource *) watch, &watch->writefd);
-
- watch->readfd.fd = watch->conn->readfd->fd;
- watch->readfd.events = READ_COND;
- watch->readfd.revents = 0;
-
- watch->writefd.fd = watch->conn->writefd->fd;
- watch->writefd.events = WRITE_COND;
- watch->writefd.revents = 0;
- watch->write_added = FALSE;
-
- g_source_add_poll ((GSource *) watch, &watch->readfd);
-}
-
-/**
- * gst_rtsp_watch_attach:
- * @watch: a #GstRTSPWatch
- * @context: a GMainContext (if NULL, the default context will be used)
- *
- * Adds a #GstRTSPWatch to a context so that it will be executed within that context.
- *
- * Returns: the ID (greater than 0) for the watch within the GMainContext.
- *
- * Since: 0.10.23
- */
-guint
-gst_rtsp_watch_attach (GstRTSPWatch * watch, GMainContext * context)
-{
- g_return_val_if_fail (watch != NULL, 0);
-
- return g_source_attach ((GSource *) watch, context);
-}
-
-/**
- * gst_rtsp_watch_unref:
- * @watch: a #GstRTSPWatch
- *
- * Decreases the reference count of @watch by one. If the resulting reference
- * count is zero the watch and associated memory will be destroyed.
- *
- * Since: 0.10.23
- */
-void
-gst_rtsp_watch_unref (GstRTSPWatch * watch)
-{
- g_return_if_fail (watch != NULL);
-
- g_source_unref ((GSource *) watch);
-}
-
-/**
- * gst_rtsp_watch_write_data:
- * @watch: a #GstRTSPWatch
- * @data: the data to queue
- * @size: the size of @data
- * @id: location for a message ID or %NULL
- *
- * Write @data using the connection of the @watch. If it cannot be sent
- * immediately, it will be queued for transmission in @watch. The contents of
- * @message will then be serialized and transmitted when the connection of the
- * @watch becomes writable. In case the @message is queued, the ID returned in
- * @id will be non-zero and used as the ID argument in the message_sent
- * callback.
- *
- * This function will take ownership of @data and g_free() it after use.
- *
- * Returns: #GST_RTSP_OK on success.
- *
- * Since: 0.10.25
- */
-GstRTSPResult
-gst_rtsp_watch_write_data (GstRTSPWatch * watch, const guint8 * data,
- guint size, guint * id)
-{
- GstRTSPResult res;
- GstRTSPRec *rec;
- guint off = 0;
-
- g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (size != 0, GST_RTSP_EINVAL);
-
- g_mutex_lock (watch->mutex);
-
- if (watch->messages->length == 0) {
- res = write_bytes (watch->writefd.fd, data, &off, size);
- if (res != GST_RTSP_EINTR) {
- if (id != NULL)
- *id = 0;
- g_free ((gpointer) data);
- goto done;
- }
- }
-
- /* make a record with the data and id */
- rec = g_slice_new (GstRTSPRec);
- if (off == 0) {
- rec->data = (guint8 *) data;
- rec->size = size;
- } else {
- rec->data = g_memdup (data + off, size - off);
- rec->size = size - off;
- g_free ((gpointer) data);
- }
-
- do {
- /* make sure rec->id is never 0 */
- rec->id = ++watch->id;
- } while (G_UNLIKELY (rec->id == 0));
-
- /* add the record to a queue. FIXME we would like to have an upper limit here */
- g_queue_push_head (watch->messages, rec);
-
- /* make sure the main context will now also check for writability on the
- * socket */
- if (!watch->write_added) {
- g_source_add_poll ((GSource *) watch, &watch->writefd);
- watch->write_added = TRUE;
- }
-
- if (id != NULL)
- *id = rec->id;
- res = GST_RTSP_OK;
-
-done:
- g_mutex_unlock (watch->mutex);
- return res;
-}
-
-/**
- * gst_rtsp_watch_send_message:
- * @watch: a #GstRTSPWatch
- * @message: a #GstRTSPMessage
- * @id: location for a message ID or %NULL
- *
- * Send a @message using the connection of the @watch. If it cannot be sent
- * immediately, it will be queued for transmission in @watch. The contents of
- * @message will then be serialized and transmitted when the connection of the
- * @watch becomes writable. In case the @message is queued, the ID returned in
- * @id will be non-zero and used as the ID argument in the message_sent
- * callback.
- *
- * Returns: #GST_RTSP_OK on success.
- *
- * Since: 0.10.25
- */
-GstRTSPResult
-gst_rtsp_watch_send_message (GstRTSPWatch * watch, GstRTSPMessage * message,
- guint * id)
-{
- GString *str;
- guint size;
-
- g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
-
- /* make a record with the message as a string and id */
- str = message_to_string (watch->conn, message);
- size = str->len;
- return gst_rtsp_watch_write_data (watch,
- (guint8 *) g_string_free (str, FALSE), size, id);
-}
-
-/**
- * gst_rtsp_watch_queue_data:
- * @watch: a #GstRTSPWatch
- * @data: the data to queue
- * @size: the size of @data
- *
- * Queue @data for transmission in @watch. It will be transmitted when the
- * connection of the @watch becomes writable.
- *
- * This function will take ownership of @data and g_free() it after use.
- *
- * The return value of this function will be used as the id argument in the
- * message_sent callback.
- *
- * Deprecated: Use gst_rtsp_watch_write_data()
- *
- * Returns: an id.
- *
- * Since: 0.10.24
- */
-#ifndef GST_REMOVE_DEPRECATED
-guint
-gst_rtsp_watch_queue_data (GstRTSPWatch * watch, const guint8 * data,
- guint size)
-{
- GstRTSPRec *rec;
-
- g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (size != 0, GST_RTSP_EINVAL);
-
- g_mutex_lock (watch->mutex);
-
- /* make a record with the data and id */
- rec = g_slice_new (GstRTSPRec);
- rec->data = (guint8 *) data;
- rec->size = size;
- do {
- /* make sure rec->id is never 0 */
- rec->id = ++watch->id;
- } while (G_UNLIKELY (rec->id == 0));
-
- /* add the record to a queue. FIXME we would like to have an upper limit here */
- g_queue_push_head (watch->messages, rec);
-
- /* make sure the main context will now also check for writability on the
- * socket */
- if (!watch->write_added) {
- g_source_add_poll ((GSource *) watch, &watch->writefd);
- watch->write_added = TRUE;
- }
-
- g_mutex_unlock (watch->mutex);
- return rec->id;
-}
-#endif /* GST_REMOVE_DEPRECATED */
-
-/**
- * gst_rtsp_watch_queue_message:
- * @watch: a #GstRTSPWatch
- * @message: a #GstRTSPMessage
- *
- * Queue a @message for transmission in @watch. The contents of this
- * message will be serialized and transmitted when the connection of the
- * @watch becomes writable.
- *
- * The return value of this function will be used as the id argument in the
- * message_sent callback.
- *
- * Deprecated: Use gst_rtsp_watch_send_message()
- *
- * Returns: an id.
- *
- * Since: 0.10.23
- */
-#ifndef GST_REMOVE_DEPRECATED
-guint
-gst_rtsp_watch_queue_message (GstRTSPWatch * watch, GstRTSPMessage * message)
-{
- GString *str;
- guint size;
-
- g_return_val_if_fail (watch != NULL, GST_RTSP_EINVAL);
- g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
-
- /* make a record with the message as a string and id */
- str = message_to_string (watch->conn, message);
- size = str->len;
- return gst_rtsp_watch_queue_data (watch,
- (guint8 *) g_string_free (str, FALSE), size);
-}
-#endif /* GST_REMOVE_DEPRECATED */
+++ /dev/null
-#include "rtsp-marshal.h"
-
-#include <glib-object.h>
-
-
-#ifdef G_ENABLE_DEBUG
-#define g_marshal_value_peek_boolean(v) g_value_get_boolean (v)
-#define g_marshal_value_peek_char(v) g_value_get_char (v)
-#define g_marshal_value_peek_uchar(v) g_value_get_uchar (v)
-#define g_marshal_value_peek_int(v) g_value_get_int (v)
-#define g_marshal_value_peek_uint(v) g_value_get_uint (v)
-#define g_marshal_value_peek_long(v) g_value_get_long (v)
-#define g_marshal_value_peek_ulong(v) g_value_get_ulong (v)
-#define g_marshal_value_peek_int64(v) g_value_get_int64 (v)
-#define g_marshal_value_peek_uint64(v) g_value_get_uint64 (v)
-#define g_marshal_value_peek_enum(v) g_value_get_enum (v)
-#define g_marshal_value_peek_flags(v) g_value_get_flags (v)
-#define g_marshal_value_peek_float(v) g_value_get_float (v)
-#define g_marshal_value_peek_double(v) g_value_get_double (v)
-#define g_marshal_value_peek_string(v) (char*) g_value_get_string (v)
-#define g_marshal_value_peek_param(v) g_value_get_param (v)
-#define g_marshal_value_peek_boxed(v) g_value_get_boxed (v)
-#define g_marshal_value_peek_pointer(v) g_value_get_pointer (v)
-#define g_marshal_value_peek_object(v) g_value_get_object (v)
-#else /* !G_ENABLE_DEBUG */
-/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
- * Do not access GValues directly in your code. Instead, use the
- * g_value_get_*() functions
- */
-#define g_marshal_value_peek_boolean(v) (v)->data[0].v_int
-#define g_marshal_value_peek_char(v) (v)->data[0].v_int
-#define g_marshal_value_peek_uchar(v) (v)->data[0].v_uint
-#define g_marshal_value_peek_int(v) (v)->data[0].v_int
-#define g_marshal_value_peek_uint(v) (v)->data[0].v_uint
-#define g_marshal_value_peek_long(v) (v)->data[0].v_long
-#define g_marshal_value_peek_ulong(v) (v)->data[0].v_ulong
-#define g_marshal_value_peek_int64(v) (v)->data[0].v_int64
-#define g_marshal_value_peek_uint64(v) (v)->data[0].v_uint64
-#define g_marshal_value_peek_enum(v) (v)->data[0].v_long
-#define g_marshal_value_peek_flags(v) (v)->data[0].v_ulong
-#define g_marshal_value_peek_float(v) (v)->data[0].v_float
-#define g_marshal_value_peek_double(v) (v)->data[0].v_double
-#define g_marshal_value_peek_string(v) (v)->data[0].v_pointer
-#define g_marshal_value_peek_param(v) (v)->data[0].v_pointer
-#define g_marshal_value_peek_boxed(v) (v)->data[0].v_pointer
-#define g_marshal_value_peek_pointer(v) (v)->data[0].v_pointer
-#define g_marshal_value_peek_object(v) (v)->data[0].v_pointer
-#endif /* !G_ENABLE_DEBUG */
-
-
-/* ENUM:POINTER,POINTER (rtsp-marshal.list:1) */
-void
-gst_rtsp_marshal_ENUM__POINTER_POINTER (GClosure * closure,
- GValue * return_value G_GNUC_UNUSED,
- guint n_param_values,
- const GValue * param_values,
- gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data)
-{
- typedef gint (*GMarshalFunc_ENUM__POINTER_POINTER) (gpointer data1,
- gpointer arg_1, gpointer arg_2, gpointer data2);
- register GMarshalFunc_ENUM__POINTER_POINTER callback;
- register GCClosure *cc = (GCClosure *) closure;
- register gpointer data1, data2;
- gint v_return;
-
- g_return_if_fail (return_value != NULL);
- g_return_if_fail (n_param_values == 3);
-
- if (G_CCLOSURE_SWAP_DATA (closure)) {
- data1 = closure->data;
- data2 = g_value_peek_pointer (param_values + 0);
- } else {
- data1 = g_value_peek_pointer (param_values + 0);
- data2 = closure->data;
- }
- callback =
- (GMarshalFunc_ENUM__POINTER_POINTER) (marshal_data ? marshal_data :
- cc->callback);
-
- v_return = callback (data1,
- g_marshal_value_peek_pointer (param_values + 1),
- g_marshal_value_peek_pointer (param_values + 2), data2);
-
- g_value_set_enum (return_value, v_return);
-}
+++ /dev/null
-
-#ifndef __gst_rtsp_marshal_MARSHAL_H__
-#define __gst_rtsp_marshal_MARSHAL_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-/* ENUM:POINTER,POINTER (rtsp-marshal.list:1) */
-extern void gst_rtsp_marshal_ENUM__POINTER_POINTER (GClosure *closure,
- GValue *return_value,
- guint n_param_values,
- const GValue *param_values,
- gpointer invocation_hint,
- gpointer marshal_data);
-
-G_END_DECLS
-
-#endif /* __gst_rtsp_marshal_MARSHAL_H__ */
-
+++ /dev/null
-commit bf5ef87699b8ef602548eec131312d7a733e278e
-Author: Josep Torra <n770galaxy@gmail.com>
-Date: Tue Apr 14 18:03:09 2009 +0200
-
- Added RTSP headers related to Windows Media extension.
-
-diff --git a/gst-libs/gst/rtsp/gstrtspdefs.c b/gst-libs/gst/rtsp/gstrtspdefs.c
-index 0ab2b95..8b086e5 100644
---- a/gst-libs/gst/rtsp/gstrtspdefs.c
-+++ b/gst-libs/gst/rtsp/gstrtspdefs.c
-@@ -164,6 +164,27 @@ static const gchar *rtsp_headers[] = {
- "ETag", /* ETag */
- "If-Match", /* If-Match */
-
-+ /* WM extensions [MS-RTSP] */
-+ "Accept-Charset", /* Accept-Charset */
-+ "Supported", /* Supported */
-+ "Vary", /* Vary */
-+ "X-Accelerate-Streaming", /* X-Accelerate-Streaming */
-+ "X-Accept-Authentication", /* X-Accept-Authentication */
-+ "X-Accept-Proxy-Authentication", /* X-Accept-Proxy-Authentication */
-+ "X-Broadcast-Id", /* X-Broadcast-Id */
-+ "X-Burst-Streaming", /* X-Burst-Streaming */
-+ "X-Notice", /* X-Notice */
-+ "X-Player-Lag-Time", /* X-Player-Lag-Time */
-+ "X-Playlist", /* X-Playlist */
-+ "X-Playlist-Change-Notice", /* X-Playlist-Change-Notice */
-+ "X-Playlist-Gen-Id", /* X-Playlist-Gen-Id */
-+ "X-Playlist-Seek-Id", /* X-Playlist-Seek-Id */
-+ "X-Proxy-Client-Agent", /* X-Proxy-Client-Agent */
-+ "X-Proxy-Client-Verb", /* X-Proxy-Client-Verb */
-+ "X-Receding-PlaylistChange", /* X-Receding-PlaylistChange */
-+ "X-RTP-Info", /* X-RTP-Info */
-+ "X-StartupProfile", /* X-StartupProfile */
-+
- NULL
- };
-
-diff --git a/gst-libs/gst/rtsp/gstrtspdefs.h b/gst-libs/gst/rtsp/gstrtspdefs.h
-index dd4b531..ae3b105 100644
---- a/gst-libs/gst/rtsp/gstrtspdefs.h
-+++ b/gst-libs/gst/rtsp/gstrtspdefs.h
-@@ -287,7 +287,29 @@ typedef enum {
-
- /* Since 0.10.23 */
- GST_RTSP_HDR_ETAG, /* ETag */
-- GST_RTSP_HDR_IF_MATCH /* If-Match */
-+ GST_RTSP_HDR_IF_MATCH, /* If-Match */
-+
-+ /* WM extensions [MS-RTSP] */
-+ GST_RTSP_HDR_ACCEPT_CHARSET, /* Accept-Charset */
-+ GST_RTSP_HDR_SUPPORTED, /* Supported */
-+ GST_RTSP_HDR_VARY, /* Vary */
-+ GST_RTSP_HDR_X_ACCELERATE_STREAMING, /* X-Accelerate-Streaming */
-+ GST_RTSP_HDR_X_ACCEPT_AUTHENT, /* X-Accept-Authentication */
-+ GST_RTSP_HDR_X_ACCEPT_PROXY_AUTHENT, /* X-Accept-Proxy-Authentication */
-+ GST_RTSP_HDR_X_BROADCAST_ID, /* X-Broadcast-Id */
-+ GST_RTSP_HDR_X_BURST_STREAMING, /* X-Burst-Streaming */
-+ GST_RTSP_HDR_X_NOTICE, /* X-Notice */
-+ GST_RTSP_HDR_X_PLAYER_LAG_TIME, /* X-Player-Lag-Time */
-+ GST_RTSP_HDR_X_PLAYLIST, /* X-Playlist */
-+ GST_RTSP_HDR_X_PLAYLIST_CHANGE_NOTICE, /* X-Playlist-Change-Notice */
-+ GST_RTSP_HDR_X_PLAYLIST_GEN_ID, /* X-Playlist-Gen-Id */
-+ GST_RTSP_HDR_X_PLAYLIST_SEEK_ID, /* X-Playlist-Seek-Id */
-+ GST_RTSP_HDR_X_PROXY_CLIENT_AGENT, /* X-Proxy-Client-Agent */
-+ GST_RTSP_HDR_X_PROXY_CLIENT_VERB, /* X-Proxy-Client-Verb */
-+ GST_RTSP_HDR_X_RECEDING_PLAYLISTCHANGE, /* X-Receding-PlaylistChange */
-+ GST_RTSP_HDR_X_RTP_INFO, /* X-RTP-Info */
-+ GST_RTSP_HDR_X_STARTUPPROFILE /* X-StartupProfile */
-+
- } GstRTSPHeaderField;
-
- typedef enum {
+++ /dev/null
-diff --git a/gst/videorate/gstvideorate.c b/gst/videorate/gstvideorate.c
-index 8d22186..7afcfdd 100644
---- a/gst/videorate/gstvideorate.c
-+++ b/gst/videorate/gstvideorate.c
-@@ -357,6 +357,7 @@ gst_video_rate_reset (GstVideoRate * videorate)
- videorate->drop = 0;
- videorate->dup = 0;
- videorate->next_ts = GST_CLOCK_TIME_NONE;
-+ videorate->discont = TRUE;
- gst_video_rate_swap_prev (videorate, NULL, 0);
-
- gst_segment_init (&videorate->segment, GST_FORMAT_TIME);
-@@ -409,6 +410,13 @@ gst_video_rate_flush_prev (GstVideoRate * videorate)
- GST_BUFFER_OFFSET (outbuf) = videorate->out;
- GST_BUFFER_OFFSET_END (outbuf) = videorate->out + 1;
-
-+ if (videorate->discont) {
-+ GST_BUFFER_FLAG_SET (outbuf, GST_BUFFER_FLAG_DISCONT);
-+ videorate->discont = FALSE;
-+ }
-+ else
-+ GST_BUFFER_FLAG_UNSET (outbuf, GST_BUFFER_FLAG_DISCONT);
-+
- /* this is the timestamp we put on the buffer */
- push_ts = videorate->next_ts;
-
-@@ -810,6 +818,9 @@ gst_video_rate_change_state (GstElement * element, GstStateChange transition)
- videorate = GST_VIDEO_RATE (element);
-
- switch (transition) {
-+ case GST_STATE_CHANGE_READY_TO_PAUSED:
-+ videorate->discont = TRUE;
-+ break;
- default:
- break;
- }
-diff --git a/gst/videorate/gstvideorate.h b/gst/videorate/gstvideorate.h
-index ea6063b..fe7feb6 100644
---- a/gst/videorate/gstvideorate.h
-+++ b/gst/videorate/gstvideorate.h
-@@ -56,6 +56,7 @@ struct _GstVideoRate
- GstBuffer *prevbuf;
- guint64 prev_ts; /* Previous buffer timestamp */
- guint64 segment_out; /* in-segment counting */
-+ gboolean discont;
-
- /* segment handling */
- GstSegment segment;