summaryrefslogtreecommitdiffstats
path: root/gst/rtpmanager/rtpjitterbuffer.c
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@gmail.com>2007-08-10 17:16:53 +0000
committerTim-Philipp Müller <tim.muller@collabora.co.uk>2009-08-11 02:30:28 +0100
commitcdd82f2a95855f0a3cc0b7be2f1b69d99eaba729 (patch)
tree22c5df70e58fd7909bb61dba11b25cbfc53ecbcb /gst/rtpmanager/rtpjitterbuffer.c
parent366a7565525789adedcef38236e7ee81b590c981 (diff)
gst/rtpmanager/: Remove complicated async queue and replace with more simple jitterbuffer code while also fixing some...
Original commit message from CVS: * gst/rtpmanager/Makefile.am: * gst/rtpmanager/async_jitter_queue.c: * gst/rtpmanager/async_jitter_queue.h: * gst/rtpmanager/rtpjitterbuffer.c: (rtp_jitter_buffer_class_init), (rtp_jitter_buffer_init), (rtp_jitter_buffer_finalize), (rtp_jitter_buffer_new), (compare_seqnum), (rtp_jitter_buffer_insert), (rtp_jitter_buffer_pop), (rtp_jitter_buffer_flush), (rtp_jitter_buffer_num_packets), (rtp_jitter_buffer_get_ts_diff): * gst/rtpmanager/rtpjitterbuffer.h: Remove complicated async queue and replace with more simple jitterbuffer code while also fixing some bugs. * gst/rtpmanager/gstrtpbin-marshal.list: * gst/rtpmanager/gstrtpbin.c: (on_new_ssrc), (on_ssrc_collision), (on_ssrc_validated), (on_bye_ssrc), (on_bye_timeout), (on_timeout), (create_session), (gst_rtp_bin_class_init), (create_recv_rtp), (create_send_rtp): * gst/rtpmanager/gstrtpbin.h: * gst/rtpmanager/gstrtpjitterbuffer.c: (gst_rtp_jitter_buffer_init), (gst_rtp_jitter_buffer_dispose), (gst_jitter_buffer_sink_parse_caps), (gst_rtp_jitter_buffer_flush_start), (gst_rtp_jitter_buffer_flush_stop), (gst_rtp_jitter_buffer_change_state), (gst_rtp_jitter_buffer_sink_event), (gst_rtp_jitter_buffer_chain), (gst_rtp_jitter_buffer_loop), (gst_rtp_jitter_buffer_set_property): * gst/rtpmanager/gstrtpsession.c: (on_new_ssrc), (on_ssrc_collision), (on_ssrc_validated), (on_bye_ssrc), (on_bye_timeout), (on_timeout), (gst_rtp_session_class_init), (gst_rtp_session_init): * gst/rtpmanager/gstrtpsession.h: * gst/rtpmanager/rtpsession.c: (on_bye_ssrc), (session_cleanup): Use new jitterbuffer code. Expose some new signals in preparation for handling EOS.
Diffstat (limited to 'gst/rtpmanager/rtpjitterbuffer.c')
-rw-r--r--gst/rtpmanager/rtpjitterbuffer.c237
1 files changed, 237 insertions, 0 deletions
diff --git a/gst/rtpmanager/rtpjitterbuffer.c b/gst/rtpmanager/rtpjitterbuffer.c
new file mode 100644
index 00000000..f90811b4
--- /dev/null
+++ b/gst/rtpmanager/rtpjitterbuffer.c
@@ -0,0 +1,237 @@
+/* GStreamer
+ * Copyright (C) <2007> 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.
+ */
+#include <string.h>
+
+#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/rtp/gstrtcpbuffer.h>
+
+#include "rtpjitterbuffer.h"
+
+GST_DEBUG_CATEGORY_STATIC (rtp_jitter_buffer_debug);
+#define GST_CAT_DEFAULT rtp_jitter_buffer_debug
+
+/* signals and args */
+enum
+{
+ LAST_SIGNAL
+};
+
+enum
+{
+ PROP_0
+};
+
+/* GObject vmethods */
+static void rtp_jitter_buffer_finalize (GObject * object);
+
+/* static guint rtp_jitter_buffer_signals[LAST_SIGNAL] = { 0 }; */
+
+G_DEFINE_TYPE (RTPJitterBuffer, rtp_jitter_buffer, G_TYPE_OBJECT);
+
+static void
+rtp_jitter_buffer_class_init (RTPJitterBufferClass * klass)
+{
+ GObjectClass *gobject_class;
+
+ gobject_class = (GObjectClass *) klass;
+
+ gobject_class->finalize = rtp_jitter_buffer_finalize;
+
+ GST_DEBUG_CATEGORY_INIT (rtp_jitter_buffer_debug, "rtpjitterbuffer", 0,
+ "RTP Jitter Buffer");
+}
+
+static void
+rtp_jitter_buffer_init (RTPJitterBuffer * jbuf)
+{
+ jbuf->packets = g_queue_new ();
+}
+
+static void
+rtp_jitter_buffer_finalize (GObject * object)
+{
+ RTPJitterBuffer *jbuf;
+
+ jbuf = RTP_JITTER_BUFFER_CAST (object);
+
+ rtp_jitter_buffer_flush (jbuf);
+ g_queue_free (jbuf->packets);
+
+ G_OBJECT_CLASS (rtp_jitter_buffer_parent_class)->finalize (object);
+}
+
+/**
+ * rtp_jitter_buffer_new:
+ *
+ * Create an #RTPJitterBuffer.
+ *
+ * Returns: a new #RTPJitterBuffer. Use g_object_unref() after usage.
+ */
+RTPJitterBuffer *
+rtp_jitter_buffer_new (void)
+{
+ RTPJitterBuffer *jbuf;
+
+ jbuf = g_object_new (RTP_TYPE_JITTER_BUFFER, NULL);
+
+ return jbuf;
+}
+
+static gint
+compare_seqnum (GstBuffer * a, GstBuffer * b, RTPJitterBuffer * jbuf)
+{
+ guint16 seq1, seq2;
+
+ seq1 = gst_rtp_buffer_get_seq (a);
+ seq2 = gst_rtp_buffer_get_seq (b);
+
+ /* check if diff more than half of the 16bit range */
+ if (abs (seq2 - seq1) > (1 << 15)) {
+ /* one of a/b has wrapped */
+ return seq1 - seq2;
+ } else {
+ return seq2 - seq1;
+ }
+}
+
+/**
+ * rtp_jitter_buffer_insert:
+ * @jbuf: an #RTPJitterBuffer
+ * @buf: a buffer
+ *
+ * Inserts @buf into the packet queue of @jbuf. The sequence number of the
+ * packet will be used to sort the packets. This function takes ownerhip of
+ * @buf when the function returns %TRUE.
+ *
+ * Returns: %FALSE if a packet with the same number already existed.
+ */
+gboolean
+rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, GstBuffer * buf)
+{
+ GList *list;
+ gint func_ret = 1;
+
+ g_return_val_if_fail (jbuf != NULL, FALSE);
+ g_return_val_if_fail (buf != NULL, FALSE);
+
+ /* loop the list to skip strictly smaller seqnum buffers */
+ list = jbuf->packets->head;
+ while (list
+ && (func_ret =
+ compare_seqnum (GST_BUFFER_CAST (list->data), buf, jbuf)) < 0)
+ list = list->next;
+
+ /* we hit a packet with the same seqnum, return FALSE to notify a duplicate */
+ if (func_ret == 0)
+ return FALSE;
+
+ if (list)
+ g_queue_insert_before (jbuf->packets, list, buf);
+ else
+ g_queue_push_tail (jbuf->packets, buf);
+
+ return TRUE;
+}
+
+/**
+ * rtp_jitter_buffer_pop:
+ * @jbuf: an #RTPJitterBuffer
+ *
+ * Pops the oldest buffer from the packet queue of @jbuf.
+ *
+ * Returns: a #GstBuffer or %NULL when there was no packet in the queue.
+ */
+GstBuffer *
+rtp_jitter_buffer_pop (RTPJitterBuffer * jbuf)
+{
+ GstBuffer *buf;
+
+ g_return_val_if_fail (jbuf != NULL, FALSE);
+
+ buf = g_queue_pop_tail (jbuf->packets);
+
+ return buf;
+}
+
+/**
+ * rtp_jitter_buffer_flush:
+ * @jbuf: an #RTPJitterBuffer
+ *
+ * Flush all packets from the jitterbuffer.
+ */
+void
+rtp_jitter_buffer_flush (RTPJitterBuffer * jbuf)
+{
+ GstBuffer *buffer;
+
+ g_return_if_fail (jbuf != NULL);
+
+ while ((buffer = g_queue_pop_head (jbuf->packets)))
+ gst_buffer_unref (buffer);
+}
+
+/**
+ * rtp_jitter_buffer_num_packets:
+ * @jbuf: an #RTPJitterBuffer
+ *
+ * Get the number of packets currently in "jbuf.
+ *
+ * Returns: The number of packets in @jbuf.
+ */
+guint
+rtp_jitter_buffer_num_packets (RTPJitterBuffer * jbuf)
+{
+ g_return_val_if_fail (jbuf != NULL, 0);
+
+ return jbuf->packets->length;
+}
+
+/**
+ * rtp_jitter_buffer_get_ts_diff:
+ * @jbuf: an #RTPJitterBuffer
+ *
+ * Get the difference between the timestamps of first and last packet in the
+ * jitterbuffer.
+ *
+ * Returns: The difference expressed in the timestamp units of the packets.
+ */
+guint32
+rtp_jitter_buffer_get_ts_diff (RTPJitterBuffer * jbuf)
+{
+ guint32 high_ts, low_ts;
+ GstBuffer *high_buf, *low_buf;
+
+ g_return_val_if_fail (jbuf != NULL, 0);
+
+ high_buf = g_queue_peek_head (jbuf->packets);
+ low_buf = g_queue_peek_tail (jbuf->packets);
+
+ if (!high_buf || !low_buf || high_buf == low_buf)
+ return 0;
+
+ high_ts = gst_rtp_buffer_get_timestamp (high_buf);
+ low_ts = gst_rtp_buffer_get_timestamp (low_buf);
+
+ /* it needs to work if ts wraps */
+ if (high_ts >= low_ts) {
+ return high_ts - low_ts;
+ } else {
+ return high_ts + G_MAXUINT32 + 1 - low_ts;
+ }
+}