gstrtpjitterbuffer.c 91 KB
Newer Older
1 2 3
/*
 * Farsight Voice+Video library
 *
4
 *  Copyright 2007 Collabora Ltd,
5 6
 *  Copyright 2007 Nokia Corporation
 *   @author: Philippe Kalaf <philippe.kalaf@collabora.co.uk>.
7
 *  Copyright 2007 Wim Taymans <wim.taymans@gmail.com>
8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * 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
Tim-Philipp Müller's avatar
Tim-Philipp Müller committed
21 22
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
23 24 25 26
 *
 */

/**
27
 * SECTION:element-gstrtpjitterbuffer
28 29 30
 *
 * This element reorders and removes duplicate RTP packets as they are received
 * from a network source. It will also wait for missing packets up to a
31 32
 * configurable time limit using the #GstRtpJitterBuffer:latency property.
 * Packets arriving too late are considered to be lost packets.
33
 *
34 35
 * This element acts as a live element and so adds #GstRtpJitterBuffer:latency
 * to the pipeline.
36
 *
Wim Taymans's avatar
Wim Taymans committed
37 38
 * The element needs the clock-rate of the RTP payload in order to estimate the
 * delay. This information is obtained either from the caps on the sink pad or,
39 40
 * when no caps are present, from the #GstRtpJitterBuffer::request-pt-map signal.
 * To clear the previous pt-map use the #GstRtpJitterBuffer::clear-pt-map signal.
41
 *
42
 * This element will automatically be used inside gstrtpbin.
43
 *
44
 * <refsect2>
45
 * <title>Example pipelines</title>
46
 * |[
47
 * gst-launch-1.0 rtspsrc location=rtsp://192.168.1.133:8554/mpeg1or2AudioVideoTest ! gstrtpjitterbuffer ! rtpmpvdepay ! mpeg2dec ! xvimagesink
48
 * ]| Connect to a streaming server and decode the MPEG video. The jitterbuffer is
49 50 51 52
 * inserted into the pipeline to smooth out network jitter and to reorder the
 * out-of-order RTP packets.
 * </refsect2>
 *
53
 * Last reviewed on 2007-05-28 (0.10.5)
54 55 56 57 58 59
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

60
#include <stdlib.h>
61 62 63
#include <string.h>
#include <gst/rtp/gstrtpbuffer.h>

64
#include "gstrtpjitterbuffer.h"
65
#include "rtpjitterbuffer.h"
66
#include "rtpstats.h"
67

68 69
#include <gst/glib-compat-private.h>

70 71 72 73 74 75
GST_DEBUG_CATEGORY (rtpjitterbuffer_debug);
#define GST_CAT_DEFAULT (rtpjitterbuffer_debug)

/* RTPJitterBuffer signals and args */
enum
{
76
  SIGNAL_REQUEST_PT_MAP,
Wim Taymans's avatar
Wim Taymans committed
77
  SIGNAL_CLEAR_PT_MAP,
78
  SIGNAL_HANDLE_SYNC,
Wim Taymans's avatar
Wim Taymans committed
79
  SIGNAL_ON_NPT_STOP,
Wim Taymans's avatar
Wim Taymans committed
80
  SIGNAL_SET_ACTIVE,
81 82 83
  LAST_SIGNAL
};

Wim Taymans's avatar
Wim Taymans committed
84 85 86 87 88 89 90 91 92
#define DEFAULT_LATENCY_MS          200
#define DEFAULT_DROP_ON_LATENCY     FALSE
#define DEFAULT_TS_OFFSET           0
#define DEFAULT_DO_LOST             FALSE
#define DEFAULT_MODE                RTP_JITTER_BUFFER_MODE_SLAVE
#define DEFAULT_PERCENT             0
#define DEFAULT_DO_RETRANSMISSION   FALSE
#define DEFAULT_RTX_DELAY           20
#define DEFAULT_RTX_DELAY_REORDER   3
93
#define DEFAULT_RTX_RETRY_TIMEOUT   40
94
#define DEFAULT_RTX_RETRY_PERIOD    160
95 96 97

enum
{
98 99
  PROP_0,
  PROP_LATENCY,
100
  PROP_DROP_ON_LATENCY,
101 102
  PROP_TS_OFFSET,
  PROP_DO_LOST,
103
  PROP_MODE,
Wim Taymans's avatar
Wim Taymans committed
104
  PROP_PERCENT,
Wim Taymans's avatar
Wim Taymans committed
105 106 107
  PROP_DO_RETRANSMISSION,
  PROP_RTX_DELAY,
  PROP_RTX_DELAY_REORDER,
108 109
  PROP_RTX_RETRY_TIMEOUT,
  PROP_RTX_RETRY_PERIOD,
110
  PROP_LAST
111 112
};

Wim Taymans's avatar
Wim Taymans committed
113
#define JBUF_LOCK(priv)   (g_mutex_lock (&(priv)->jbuf_lock))
114 115 116

#define JBUF_LOCK_CHECK(priv,label) G_STMT_START {    \
  JBUF_LOCK (priv);                                   \
117
  if (G_UNLIKELY (priv->srcresult != GST_FLOW_OK))    \
118 119
    goto label;                                       \
} G_STMT_END
Wim Taymans's avatar
Wim Taymans committed
120
#define JBUF_UNLOCK(priv) (g_mutex_unlock (&(priv)->jbuf_lock))
121

122 123 124 125 126 127 128 129
#define JBUF_WAIT_TIMER(priv)   G_STMT_START {            \
  (priv)->waiting_timer = TRUE;                           \
  g_cond_wait (&(priv)->jbuf_timer, &(priv)->jbuf_lock);  \
  (priv)->waiting_timer = FALSE;                          \
} G_STMT_END
#define JBUF_SIGNAL_TIMER(priv) G_STMT_START {    \
  if (G_UNLIKELY ((priv)->waiting_timer))         \
    g_cond_signal (&(priv)->jbuf_timer);          \
130 131
} G_STMT_END

132 133 134 135 136 137 138 139 140 141 142
#define JBUF_WAIT_EVENT(priv,label) G_STMT_START {       \
  (priv)->waiting_event = TRUE;                          \
  g_cond_wait (&(priv)->jbuf_event, &(priv)->jbuf_lock); \
  (priv)->waiting_event = FALSE;                         \
  if (G_UNLIKELY (priv->srcresult != GST_FLOW_OK))       \
    goto label;                                          \
} G_STMT_END
#define JBUF_SIGNAL_EVENT(priv) G_STMT_START {    \
  if (G_UNLIKELY ((priv)->waiting_event))         \
    g_cond_signal (&(priv)->jbuf_event);          \
} G_STMT_END
143

144
struct _GstRtpJitterBufferPrivate
145 146
{
  GstPad *sinkpad, *srcpad;
147
  GstPad *rtcpsinkpad;
148

149
  RTPJitterBuffer *jbuf;
Wim Taymans's avatar
Wim Taymans committed
150
  GMutex jbuf_lock;
151 152 153 154
  gboolean waiting_timer;
  GCond jbuf_timer;
  gboolean waiting_event;
  GCond jbuf_event;
155
  gboolean discont;
156
  gboolean ts_discont;
Wim Taymans's avatar
Wim Taymans committed
157
  gboolean active;
158
  guint64 out_offset;
159

160 161 162
  gboolean timer_running;
  GThread *timer_thread;

163 164
  /* properties */
  guint latency_ms;
165
  guint64 latency_ns;
166
  gboolean drop_on_latency;
167
  gint64 ts_offset;
168
  gboolean do_lost;
Wim Taymans's avatar
Wim Taymans committed
169 170 171
  gboolean do_retransmission;
  gint rtx_delay;
  gint rtx_delay_reorder;
172 173
  gint rtx_retry_timeout;
  gint rtx_retry_period;
174 175 176

  /* the last seqnum we pushed out */
  guint32 last_popped_seqnum;
177
  /* the next expected seqnum we push */
178
  guint32 next_seqnum;
179 180
  /* last output time */
  GstClockTime last_out_time;
181
  /* last valid input timestamp and rtptime pair */
182
  GstClockTime ips_dts;
Wim Taymans's avatar
Wim Taymans committed
183
  guint64 ips_rtptime;
184
  GstClockTime packet_spacing;
185

186
  /* the next expected seqnum we receive */
187 188
  GstClockTime last_in_dts;
  guint32 last_in_seqnum;
189
  guint32 next_in_seqnum;
190

191 192
  GArray *timers;

Wim Taymans's avatar
Wim Taymans committed
193 194 195 196 197 198 199 200
  /* start and stop ranges */
  GstClockTime npt_start;
  GstClockTime npt_stop;
  guint64 ext_timestamp;
  guint64 last_elapsed;
  guint64 estimated_eos;
  GstClockID eos_id;

201 202 203
  /* state */
  gboolean eos;

204
  /* clock rate and rtp timestamp offset */
205
  gint last_pt;
206
  gint32 clock_rate;
207
  gint64 clock_base;
208
  gint64 prev_ts_offset;
209 210 211

  /* when we are shutting down */
  GstFlowReturn srcresult;
212
  gboolean blocked;
213 214 215 216

  /* for sync */
  GstSegment segment;
  GstClockID clock_id;
217
  GstClockTime timer_timeout;
218
  guint16 timer_seqnum;
219 220 221
  /* the latency of the upstream peer, we have to take this into account when
   * synchronizing the buffers. */
  GstClockTime peer_latency;
222 223
  guint64 ext_rtptime;
  GstBuffer *last_sr;
224 225 226 227 228 229

  /* some accounting */
  guint64 num_late;
  guint64 num_duplicates;
};

230 231 232 233 234 235 236 237 238 239 240 241
typedef enum
{
  TIMER_TYPE_EXPECTED,
  TIMER_TYPE_LOST,
  TIMER_TYPE_DEADLINE,
  TIMER_TYPE_EOS
} TimerType;

typedef struct
{
  guint idx;
  guint16 seqnum;
242
  guint num;
243
  TimerType type;
244
  GstClockTime timeout;
245
  GstClockTime duration;
246 247
  GstClockTime rtx_base;
  GstClockTime rtx_retry;
248 249
} TimerData;

250 251
#define GST_RTP_JITTER_BUFFER_GET_PRIVATE(o) \
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_RTP_JITTER_BUFFER, \
252
                                GstRtpJitterBufferPrivate))
253 254 255 256 257 258 259 260 261 262 263 264

static GstStaticPadTemplate gst_rtp_jitter_buffer_sink_template =
GST_STATIC_PAD_TEMPLATE ("sink",
    GST_PAD_SINK,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("application/x-rtp, "
        "clock-rate = (int) [ 1, 2147483647 ]"
        /* "payload = (int) , "
         * "encoding-name = (string) "
         */ )
    );

265 266 267 268 269 270 271
static GstStaticPadTemplate gst_rtp_jitter_buffer_sink_rtcp_template =
GST_STATIC_PAD_TEMPLATE ("sink_rtcp",
    GST_PAD_SINK,
    GST_PAD_REQUEST,
    GST_STATIC_CAPS ("application/x-rtcp")
    );

272 273 274 275 276 277 278 279 280 281 282
static GstStaticPadTemplate gst_rtp_jitter_buffer_src_template =
GST_STATIC_PAD_TEMPLATE ("src",
    GST_PAD_SRC,
    GST_PAD_ALWAYS,
    GST_STATIC_CAPS ("application/x-rtp"
        /* "payload = (int) , "
         * "clock-rate = (int) , "
         * "encoding-name = (string) "
         */ )
    );

283 284
static guint gst_rtp_jitter_buffer_signals[LAST_SIGNAL] = { 0 };

Wim Taymans's avatar
Wim Taymans committed
285 286
#define gst_rtp_jitter_buffer_parent_class parent_class
G_DEFINE_TYPE (GstRtpJitterBuffer, gst_rtp_jitter_buffer, GST_TYPE_ELEMENT);
287 288 289 290 291 292

/* object overrides */
static void gst_rtp_jitter_buffer_set_property (GObject * object,
    guint prop_id, const GValue * value, GParamSpec * pspec);
static void gst_rtp_jitter_buffer_get_property (GObject * object,
    guint prop_id, GValue * value, GParamSpec * pspec);
293
static void gst_rtp_jitter_buffer_finalize (GObject * object);
294 295 296 297

/* element overrides */
static GstStateChangeReturn gst_rtp_jitter_buffer_change_state (GstElement
    * element, GstStateChange transition);
298
static GstPad *gst_rtp_jitter_buffer_request_new_pad (GstElement * element,
Wim Taymans's avatar
Wim Taymans committed
299
    GstPadTemplate * templ, const gchar * name, const GstCaps * filter);
300 301
static void gst_rtp_jitter_buffer_release_pad (GstElement * element,
    GstPad * pad);
Wim Taymans's avatar
Wim Taymans committed
302
static GstClock *gst_rtp_jitter_buffer_provide_clock (GstElement * element);
303 304

/* pad overrides */
Wim Taymans's avatar
Wim Taymans committed
305
static GstCaps *gst_rtp_jitter_buffer_getcaps (GstPad * pad, GstCaps * filter);
Wim Taymans's avatar
Wim Taymans committed
306 307
static GstIterator *gst_rtp_jitter_buffer_iterate_internal_links (GstPad * pad,
    GstObject * parent);
308 309 310

/* sinkpad overrides */
static gboolean gst_rtp_jitter_buffer_sink_event (GstPad * pad,
Wim Taymans's avatar
Wim Taymans committed
311
    GstObject * parent, GstEvent * event);
312
static GstFlowReturn gst_rtp_jitter_buffer_chain (GstPad * pad,
Wim Taymans's avatar
Wim Taymans committed
313
    GstObject * parent, GstBuffer * buffer);
314

315
static gboolean gst_rtp_jitter_buffer_sink_rtcp_event (GstPad * pad,
Wim Taymans's avatar
Wim Taymans committed
316
    GstObject * parent, GstEvent * event);
317
static GstFlowReturn gst_rtp_jitter_buffer_chain_rtcp (GstPad * pad,
Wim Taymans's avatar
Wim Taymans committed
318
    GstObject * parent, GstBuffer * buffer);
319

Wim Taymans's avatar
Wim Taymans committed
320
static gboolean gst_rtp_jitter_buffer_sink_query (GstPad * pad,
Wim Taymans's avatar
Wim Taymans committed
321
    GstObject * parent, GstQuery * query);
Wim Taymans's avatar
Wim Taymans committed
322

323
/* srcpad overrides */
324
static gboolean gst_rtp_jitter_buffer_src_event (GstPad * pad,
Wim Taymans's avatar
Wim Taymans committed
325
    GstObject * parent, GstEvent * event);
Wim Taymans's avatar
Wim Taymans committed
326 327
static gboolean gst_rtp_jitter_buffer_src_activate_mode (GstPad * pad,
    GstObject * parent, GstPadMode mode, gboolean active);
328
static void gst_rtp_jitter_buffer_loop (GstRtpJitterBuffer * jitterbuffer);
Wim Taymans's avatar
Wim Taymans committed
329
static gboolean gst_rtp_jitter_buffer_src_query (GstPad * pad,
Wim Taymans's avatar
Wim Taymans committed
330
    GstObject * parent, GstQuery * query);
331

Wim Taymans's avatar
Wim Taymans committed
332
static void
333
gst_rtp_jitter_buffer_clear_pt_map (GstRtpJitterBuffer * jitterbuffer);
334
static GstClockTime
Wim Taymans's avatar
Wim Taymans committed
335 336
gst_rtp_jitter_buffer_set_active (GstRtpJitterBuffer * jitterbuffer,
    gboolean active, guint64 base_time);
337
static void do_handle_sync (GstRtpJitterBuffer * jitterbuffer);
338 339

static void unschedule_current_timer (GstRtpJitterBuffer * jitterbuffer);
340
static void remove_all_timers (GstRtpJitterBuffer * jitterbuffer);
Wim Taymans's avatar
Wim Taymans committed
341

342 343
static void wait_next_timeout (GstRtpJitterBuffer * jitterbuffer);

344
static void
345
gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass)
346 347 348 349 350 351 352
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

  gobject_class = (GObjectClass *) klass;
  gstelement_class = (GstElementClass *) klass;

353
  g_type_class_add_private (klass, sizeof (GstRtpJitterBufferPrivate));
354

355
  gobject_class->finalize = gst_rtp_jitter_buffer_finalize;
356 357 358 359

  gobject_class->set_property = gst_rtp_jitter_buffer_set_property;
  gobject_class->get_property = gst_rtp_jitter_buffer_get_property;

Wim Taymans's avatar
Wim Taymans committed
360
  /**
361
   * GstRtpJitterBuffer::latency:
362
   *
Wim Taymans's avatar
Wim Taymans committed
363 364 365
   * The maximum latency of the jitterbuffer. Packets will be kept in the buffer
   * for at most this time.
   */
366
  g_object_class_install_property (gobject_class, PROP_LATENCY,
367 368
      g_param_spec_uint ("latency", "Buffer latency in ms",
          "Amount of ms to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS,
369
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Wim Taymans's avatar
Wim Taymans committed
370
  /**
371
   * GstRtpJitterBuffer::drop-on-latency:
372 373
   *
   * Drop oldest buffers when the queue is completely filled.
Wim Taymans's avatar
Wim Taymans committed
374
   */
375
  g_object_class_install_property (gobject_class, PROP_DROP_ON_LATENCY,
Wim Taymans's avatar
Wim Taymans committed
376
      g_param_spec_boolean ("drop-on-latency",
377 378
          "Drop buffers when maximum latency is reached",
          "Tells the jitterbuffer to never exceed the given latency in size",
379
          DEFAULT_DROP_ON_LATENCY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
380 381
  /**
   * GstRtpJitterBuffer::ts-offset:
382
   *
383 384
   * Adjust GStreamer output buffer timestamps in the jitterbuffer with offset.
   * This is mainly used to ensure interstream synchronisation.
385 386
   */
  g_object_class_install_property (gobject_class, PROP_TS_OFFSET,
387 388 389 390 391 392 393
      g_param_spec_int64 ("ts-offset", "Timestamp Offset",
          "Adjust buffer timestamps with offset in nanoseconds", G_MININT64,
          G_MAXINT64, DEFAULT_TS_OFFSET,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

  /**
   * GstRtpJitterBuffer::do-lost:
394
   *
395 396 397 398 399 400 401
   * Send out a GstRTPPacketLost event downstream when a packet is considered
   * lost.
   */
  g_object_class_install_property (gobject_class, PROP_DO_LOST,
      g_param_spec_boolean ("do-lost", "Do Lost",
          "Send an event downstream when a packet is lost", DEFAULT_DO_LOST,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
402 403 404 405 406 407 408 409 410 411

  /**
   * GstRtpJitterBuffer::mode:
   *
   * Control the buffering and timestamping mode used by the jitterbuffer.
   */
  g_object_class_install_property (gobject_class, PROP_MODE,
      g_param_spec_enum ("mode", "Mode",
          "Control the buffering algorithm in use", RTP_TYPE_JITTER_BUFFER_MODE,
          DEFAULT_MODE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Wim Taymans's avatar
Wim Taymans committed
412 413 414 415
  /**
   * GstRtpJitterBuffer::percent:
   *
   * The percent of the jitterbuffer that is filled.
416 417
   *
   * Since: 0.10.19
Wim Taymans's avatar
Wim Taymans committed
418 419 420 421 422
   */
  g_object_class_install_property (gobject_class, PROP_PERCENT,
      g_param_spec_int ("percent", "percent",
          "The buffer filled percent", 0, 100,
          0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Wim Taymans's avatar
Wim Taymans committed
423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
  /**
   * GstRtpJitterBuffer::do-retransmission:
   *
   * Send out a GstRTPRetransmission event upstream when a packet is considered
   * late and should be retransmitted.
   *
   * Since: 1.2
   */
  g_object_class_install_property (gobject_class, PROP_DO_RETRANSMISSION,
      g_param_spec_boolean ("do-retransmission", "Do Retransmission",
          "Send retransmission events upstream when a packet is late",
          DEFAULT_DO_RETRANSMISSION,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

  /**
   * GstRtpJitterBuffer::rtx-delay:
   *
   * When a packet did not arrive at the expected time, wait this extra amount
   * of time before sending a retransmission event.
   *
   * When -1 is used, the max jitter will be used as extra delay.
   *
   * Since: 1.2
   */
  g_object_class_install_property (gobject_class, PROP_RTX_DELAY,
      g_param_spec_int ("rtx-delay", "RTX Delay",
          "Extra time in ms to wait before sending retransmission "
450
          "event (-1 automatic)", -1, G_MAXINT, DEFAULT_RTX_DELAY,
Wim Taymans's avatar
Wim Taymans committed
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
  /**
   * GstRtpJitterBuffer::rtx-delay-reorder:
   *
   * Assume that a retransmission event should be sent when we see
   * this much packet reordering.
   *
   * When -1 is used, the value will be estimated based on observed packet
   * reordering.
   *
   * Since: 1.2
   */
  g_object_class_install_property (gobject_class, PROP_RTX_DELAY_REORDER,
      g_param_spec_int ("rtx-delay-reorder", "RTX Delay Reorder",
          "Sending retransmission event when this much reordering (-1 automatic)",
466
          -1, G_MAXINT, DEFAULT_RTX_DELAY_REORDER,
Wim Taymans's avatar
Wim Taymans committed
467
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
468 469 470 471 472 473 474 475 476 477 478 479 480 481
  /**
   * GstRtpJitterBuffer::rtx-retry-timeout:
   *
   * When no packet has been received after sending a retransmission event
   * for this time, retry sending a retransmission event.
   *
   * When -1 is used, the value will be estimated based on observed round
   * trip time.
   *
   * Since: 1.2
   */
  g_object_class_install_property (gobject_class, PROP_RTX_RETRY_TIMEOUT,
      g_param_spec_int ("rtx-retry-timeout", "RTX Retry Timeout",
          "Retry sending a transmission event after this timeout in "
482
          "ms (-1 automatic)", -1, G_MAXINT, DEFAULT_RTX_RETRY_TIMEOUT,
483 484 485 486 487 488 489 490 491 492 493 494 495 496
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
  /**
   * GstRtpJitterBuffer::rtx-retry-period:
   *
   * The amount of time to try to get a retransmission.
   *
   * When -1 is used, the value will be estimated based on the jitterbuffer
   * latency and the observed round trip time.
   *
   * Since: 1.2
   */
  g_object_class_install_property (gobject_class, PROP_RTX_RETRY_PERIOD,
      g_param_spec_int ("rtx-retry-period", "RTX Retry Period",
          "Try to get a retransmission for this many ms "
497
          "(-1 automatic)", -1, G_MAXINT, DEFAULT_RTX_RETRY_PERIOD,
498
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Wim Taymans's avatar
Wim Taymans committed
499

500
  /**
501
   * GstRtpJitterBuffer::request-pt-map:
502 503 504 505 506
   * @buffer: the object which received the signal
   * @pt: the pt
   *
   * Request the payload type as #GstCaps for @pt.
   */
507 508
  gst_rtp_jitter_buffer_signals[SIGNAL_REQUEST_PT_MAP] =
      g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
509
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpJitterBufferClass,
510
          request_pt_map), NULL, NULL, g_cclosure_marshal_generic,
511
      GST_TYPE_CAPS, 1, G_TYPE_UINT);
512 513 514 515 516 517 518 519 520 521 522
  /**
   * GstRtpJitterBuffer::handle-sync:
   * @buffer: the object which received the signal
   * @struct: a GstStructure containing sync values.
   *
   * Be notified of new sync values.
   */
  gst_rtp_jitter_buffer_signals[SIGNAL_HANDLE_SYNC] =
      g_signal_new ("handle-sync", G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpJitterBufferClass,
          handle_sync), NULL, NULL, g_cclosure_marshal_VOID__BOXED,
523
      G_TYPE_NONE, 1, GST_TYPE_STRUCTURE | G_SIGNAL_TYPE_STATIC_SCOPE);
524

Wim Taymans's avatar
Wim Taymans committed
525 526 527 528 529 530 531 532 533 534 535 536 537
  /**
   * GstRtpJitterBuffer::on-npt-stop
   * @buffer: the object which received the signal
   *
   * Signal that the jitterbufer has pushed the RTP packet that corresponds to
   * the npt-stop position.
   */
  gst_rtp_jitter_buffer_signals[SIGNAL_ON_NPT_STOP] =
      g_signal_new ("on-npt-stop", G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpJitterBufferClass,
          on_npt_stop), NULL, NULL, g_cclosure_marshal_VOID__VOID,
      G_TYPE_NONE, 0, G_TYPE_NONE);

Wim Taymans's avatar
Wim Taymans committed
538
  /**
539
   * GstRtpJitterBuffer::clear-pt-map:
Wim Taymans's avatar
Wim Taymans committed
540 541
   * @buffer: the object which received the signal
   *
Stefan Kost's avatar
Stefan Kost committed
542 543
   * Invalidate the clock-rate as obtained with the
   * #GstRtpJitterBuffer::request-pt-map signal.
Wim Taymans's avatar
Wim Taymans committed
544 545 546
   */
  gst_rtp_jitter_buffer_signals[SIGNAL_CLEAR_PT_MAP] =
      g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
547 548 549
      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
      G_STRUCT_OFFSET (GstRtpJitterBufferClass, clear_pt_map), NULL, NULL,
      g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
550

Wim Taymans's avatar
Wim Taymans committed
551 552 553 554 555 556
  /**
   * GstRtpJitterBuffer::set-active:
   * @buffer: the object which received the signal
   *
   * Start pushing out packets with the given base time. This signal is only
   * useful in buffering mode.
557 558
   *
   * Returns: the time of the last pushed packet.
559 560
   *
   * Since: 0.10.19
Wim Taymans's avatar
Wim Taymans committed
561 562 563 564 565
   */
  gst_rtp_jitter_buffer_signals[SIGNAL_SET_ACTIVE] =
      g_signal_new ("set-active", G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
      G_STRUCT_OFFSET (GstRtpJitterBufferClass, set_active), NULL, NULL,
566
      g_cclosure_marshal_generic, G_TYPE_UINT64, 2, G_TYPE_BOOLEAN,
Wim Taymans's avatar
Wim Taymans committed
567 568
      G_TYPE_UINT64);

569 570 571 572 573 574
  gstelement_class->change_state =
      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_change_state);
  gstelement_class->request_new_pad =
      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_request_new_pad);
  gstelement_class->release_pad =
      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_release_pad);
Wim Taymans's avatar
Wim Taymans committed
575 576
  gstelement_class->provide_clock =
      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_provide_clock);
577

Wim Taymans's avatar
Wim Taymans committed
578 579 580 581 582 583 584
  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&gst_rtp_jitter_buffer_src_template));
  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&gst_rtp_jitter_buffer_sink_template));
  gst_element_class_add_pad_template (gstelement_class,
      gst_static_pad_template_get (&gst_rtp_jitter_buffer_sink_rtcp_template));

585
  gst_element_class_set_static_metadata (gstelement_class,
Wim Taymans's avatar
Wim Taymans committed
586 587 588 589 590
      "RTP packet jitter-buffer", "Filter/Network/RTP",
      "A buffer that deals with network jitter and other transmission faults",
      "Philippe Kalaf <philippe.kalaf@collabora.co.uk>, "
      "Wim Taymans <wim.taymans@gmail.com>");

Wim Taymans's avatar
Wim Taymans committed
591
  klass->clear_pt_map = GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_clear_pt_map);
Wim Taymans's avatar
Wim Taymans committed
592
  klass->set_active = GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_set_active);
Wim Taymans's avatar
Wim Taymans committed
593

594
  GST_DEBUG_CATEGORY_INIT
595
      (rtpjitterbuffer_debug, "gstrtpjitterbuffer", 0, "RTP Jitter Buffer");
596 597 598
}

static void
Wim Taymans's avatar
Wim Taymans committed
599
gst_rtp_jitter_buffer_init (GstRtpJitterBuffer * jitterbuffer)
600
{
601
  GstRtpJitterBufferPrivate *priv;
602 603 604 605 606

  priv = GST_RTP_JITTER_BUFFER_GET_PRIVATE (jitterbuffer);
  jitterbuffer->priv = priv;

  priv->latency_ms = DEFAULT_LATENCY_MS;
607
  priv->latency_ns = priv->latency_ms * GST_MSECOND;
608
  priv->drop_on_latency = DEFAULT_DROP_ON_LATENCY;
609
  priv->do_lost = DEFAULT_DO_LOST;
Wim Taymans's avatar
Wim Taymans committed
610 611 612
  priv->do_retransmission = DEFAULT_DO_RETRANSMISSION;
  priv->rtx_delay = DEFAULT_RTX_DELAY;
  priv->rtx_delay_reorder = DEFAULT_RTX_DELAY_REORDER;
613 614
  priv->rtx_retry_timeout = DEFAULT_RTX_RETRY_TIMEOUT;
  priv->rtx_retry_period = DEFAULT_RTX_RETRY_PERIOD;
615

Wim Taymans's avatar
Wim Taymans committed
616
  priv->timers = g_array_new (FALSE, TRUE, sizeof (TimerData));
617
  priv->jbuf = rtp_jitter_buffer_new ();
Wim Taymans's avatar
Wim Taymans committed
618
  g_mutex_init (&priv->jbuf_lock);
619 620
  g_cond_init (&priv->jbuf_timer);
  g_cond_init (&priv->jbuf_event);
621

622 623 624 625
  /* reset skew detection initialy */
  rtp_jitter_buffer_reset_skew (priv->jbuf);
  rtp_jitter_buffer_set_delay (priv->jbuf, priv->latency_ns);
  rtp_jitter_buffer_set_buffering (priv->jbuf, FALSE);
626
  priv->active = TRUE;
627

628 629 630 631
  priv->srcpad =
      gst_pad_new_from_static_template (&gst_rtp_jitter_buffer_src_template,
      "src");

Wim Taymans's avatar
Wim Taymans committed
632 633
  gst_pad_set_activatemode_function (priv->srcpad,
      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_src_activate_mode));
634
  gst_pad_set_query_function (priv->srcpad,
Wim Taymans's avatar
Wim Taymans committed
635
      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_src_query));
636 637
  gst_pad_set_event_function (priv->srcpad,
      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_src_event));
638 639 640 641 642 643 644 645 646

  priv->sinkpad =
      gst_pad_new_from_static_template (&gst_rtp_jitter_buffer_sink_template,
      "sink");

  gst_pad_set_chain_function (priv->sinkpad,
      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_chain));
  gst_pad_set_event_function (priv->sinkpad,
      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_sink_event));
Wim Taymans's avatar
Wim Taymans committed
647 648
  gst_pad_set_query_function (priv->sinkpad,
      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_sink_query));
649 650 651

  gst_element_add_pad (GST_ELEMENT (jitterbuffer), priv->srcpad);
  gst_element_add_pad (GST_ELEMENT (jitterbuffer), priv->sinkpad);
652 653

  GST_OBJECT_FLAG_SET (jitterbuffer, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
654 655 656
}

static void
657
gst_rtp_jitter_buffer_finalize (GObject * object)
658
{
659
  GstRtpJitterBuffer *jitterbuffer;
660 661 662

  jitterbuffer = GST_RTP_JITTER_BUFFER (object);

663
  g_array_free (jitterbuffer->priv->timers, TRUE);
Wim Taymans's avatar
Wim Taymans committed
664
  g_mutex_clear (&jitterbuffer->priv->jbuf_lock);
665 666
  g_cond_clear (&jitterbuffer->priv->jbuf_timer);
  g_cond_clear (&jitterbuffer->priv->jbuf_event);
667 668 669 670

  g_object_unref (jitterbuffer->priv->jbuf);

  G_OBJECT_CLASS (parent_class)->finalize (object);
671 672
}

673
static GstIterator *
Wim Taymans's avatar
Wim Taymans committed
674
gst_rtp_jitter_buffer_iterate_internal_links (GstPad * pad, GstObject * parent)
675 676
{
  GstRtpJitterBuffer *jitterbuffer;
677 678
  GstPad *otherpad = NULL;
  GstIterator *it;
Wim Taymans's avatar
Wim Taymans committed
679
  GValue val = { 0, };
680

Wim Taymans's avatar
Wim Taymans committed
681
  jitterbuffer = GST_RTP_JITTER_BUFFER (parent);
682

683 684 685 686 687 688 689 690
  if (pad == jitterbuffer->priv->sinkpad) {
    otherpad = jitterbuffer->priv->srcpad;
  } else if (pad == jitterbuffer->priv->srcpad) {
    otherpad = jitterbuffer->priv->sinkpad;
  } else if (pad == jitterbuffer->priv->rtcpsinkpad) {
    otherpad = NULL;
  }

Wim Taymans's avatar
Wim Taymans committed
691 692 693 694
  g_value_init (&val, GST_TYPE_PAD);
  g_value_set_object (&val, otherpad);
  it = gst_iterator_new_single (GST_TYPE_PAD, &val);
  g_value_unset (&val);
695

696
  return it;
697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714
}

static GstPad *
create_rtcp_sink (GstRtpJitterBuffer * jitterbuffer)
{
  GstRtpJitterBufferPrivate *priv;

  priv = jitterbuffer->priv;

  GST_DEBUG_OBJECT (jitterbuffer, "creating RTCP sink pad");

  priv->rtcpsinkpad =
      gst_pad_new_from_static_template
      (&gst_rtp_jitter_buffer_sink_rtcp_template, "sink_rtcp");
  gst_pad_set_chain_function (priv->rtcpsinkpad,
      gst_rtp_jitter_buffer_chain_rtcp);
  gst_pad_set_event_function (priv->rtcpsinkpad,
      (GstPadEventFunction) gst_rtp_jitter_buffer_sink_rtcp_event);
715 716
  gst_pad_set_iterate_internal_links_function (priv->rtcpsinkpad,
      gst_rtp_jitter_buffer_iterate_internal_links);
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
  gst_pad_set_active (priv->rtcpsinkpad, TRUE);
  gst_element_add_pad (GST_ELEMENT_CAST (jitterbuffer), priv->rtcpsinkpad);

  return priv->rtcpsinkpad;
}

static void
remove_rtcp_sink (GstRtpJitterBuffer * jitterbuffer)
{
  GstRtpJitterBufferPrivate *priv;

  priv = jitterbuffer->priv;

  GST_DEBUG_OBJECT (jitterbuffer, "removing RTCP sink pad");

  gst_pad_set_active (priv->rtcpsinkpad, FALSE);

  gst_element_remove_pad (GST_ELEMENT_CAST (jitterbuffer), priv->rtcpsinkpad);
  priv->rtcpsinkpad = NULL;
}

static GstPad *
gst_rtp_jitter_buffer_request_new_pad (GstElement * element,
Wim Taymans's avatar
Wim Taymans committed
740
    GstPadTemplate * templ, const gchar * name, const GstCaps * filter)
741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808
{
  GstRtpJitterBuffer *jitterbuffer;
  GstElementClass *klass;
  GstPad *result;
  GstRtpJitterBufferPrivate *priv;

  g_return_val_if_fail (templ != NULL, NULL);
  g_return_val_if_fail (GST_IS_RTP_JITTER_BUFFER (element), NULL);

  jitterbuffer = GST_RTP_JITTER_BUFFER (element);
  priv = jitterbuffer->priv;
  klass = GST_ELEMENT_GET_CLASS (element);

  GST_DEBUG_OBJECT (element, "requesting pad %s", GST_STR_NULL (name));

  /* figure out the template */
  if (templ == gst_element_class_get_pad_template (klass, "sink_rtcp")) {
    if (priv->rtcpsinkpad != NULL)
      goto exists;

    result = create_rtcp_sink (jitterbuffer);
  } else
    goto wrong_template;

  return result;

  /* ERRORS */
wrong_template:
  {
    g_warning ("gstrtpjitterbuffer: this is not our template");
    return NULL;
  }
exists:
  {
    g_warning ("gstrtpjitterbuffer: pad already requested");
    return NULL;
  }
}

static void
gst_rtp_jitter_buffer_release_pad (GstElement * element, GstPad * pad)
{
  GstRtpJitterBuffer *jitterbuffer;
  GstRtpJitterBufferPrivate *priv;

  g_return_if_fail (GST_IS_RTP_JITTER_BUFFER (element));
  g_return_if_fail (GST_IS_PAD (pad));

  jitterbuffer = GST_RTP_JITTER_BUFFER (element);
  priv = jitterbuffer->priv;

  GST_DEBUG_OBJECT (element, "releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));

  if (priv->rtcpsinkpad == pad) {
    remove_rtcp_sink (jitterbuffer);
  } else
    goto wrong_pad;

  return;

  /* ERRORS */
wrong_pad:
  {
    g_warning ("gstjitterbuffer: asked to release an unknown pad");
    return;
  }
}

Wim Taymans's avatar
Wim Taymans committed
809 810 811 812 813 814
static GstClock *
gst_rtp_jitter_buffer_provide_clock (GstElement * element)
{
  return gst_system_clock_obtain ();
}

Wim Taymans's avatar
Wim Taymans committed
815
static void
816
gst_rtp_jitter_buffer_clear_pt_map (GstRtpJitterBuffer * jitterbuffer)
Wim Taymans's avatar
Wim Taymans committed
817
{
818
  GstRtpJitterBufferPrivate *priv;
Wim Taymans's avatar
Wim Taymans committed
819 820 821 822

  priv = jitterbuffer->priv;

  /* this will trigger a new pt-map request signal, FIXME, do something better. */
823 824

  JBUF_LOCK (priv);
Wim Taymans's avatar
Wim Taymans committed
825
  priv->clock_rate = -1;
826 827 828 829 830
  /* do not clear current content, but refresh state for new arrival */
  GST_DEBUG_OBJECT (jitterbuffer, "reset jitterbuffer");
  rtp_jitter_buffer_reset_skew (priv->jbuf);
  priv->last_popped_seqnum = -1;
  priv->next_seqnum = -1;
831
  JBUF_UNLOCK (priv);
Wim Taymans's avatar
Wim Taymans committed
832 833
}

834
static GstClockTime
Wim Taymans's avatar
Wim Taymans committed
835
gst_rtp_jitter_buffer_set_active (GstRtpJitterBuffer * jbuf, gboolean active,
836
    guint64 offset)
Wim Taymans's avatar
Wim Taymans committed
837 838
{
  GstRtpJitterBufferPrivate *priv;
839 840
  GstClockTime last_out;
  GstBuffer *head;
Wim Taymans's avatar
Wim Taymans committed
841 842 843 844

  priv = jbuf->priv;

  JBUF_LOCK (priv);
845 846
  GST_DEBUG_OBJECT (jbuf, "setting active %d with offset %" GST_TIME_FORMAT,
      active, GST_TIME_ARGS (offset));
847 848 849 850 851

  if (active != priv->active) {
    /* add the amount of time spent in paused to the output offset. All
     * outgoing buffers will have this offset applied to their timestamps in
     * order to make them arrive in time in the sink. */
852
    priv->out_offset = offset;
853 854 855
    GST_DEBUG_OBJECT (jbuf, "out offset %" GST_TIME_FORMAT,
        GST_TIME_ARGS (priv->out_offset));
    priv->active = active;
856
    JBUF_SIGNAL_EVENT (priv);
857
  }
Wim Taymans's avatar
Wim Taymans committed
858 859 860
  if (!active) {
    rtp_jitter_buffer_set_buffering (priv->jbuf, TRUE);
  }
861
  if ((head = rtp_jitter_buffer_peek (priv->jbuf))) {
862
    /* head buffer timestamp and offset gives our output time */
Wim Taymans's avatar
Wim Taymans committed
863
    last_out = GST_BUFFER_DTS (head) + priv->ts_offset;
864 865
  } else {
    /* use last known time when the buffer is empty */
866
    last_out = priv->last_out_time;
867
  }
Wim Taymans's avatar
Wim Taymans committed
868
  JBUF_UNLOCK (priv);
869 870

  return last_out;
Wim Taymans's avatar
Wim Taymans committed
871 872
}

873
static GstCaps *
Wim Taymans's avatar
Wim Taymans committed
874
gst_rtp_jitter_buffer_getcaps (GstPad * pad, GstCaps * filter)
875
{
876 877
  GstRtpJitterBuffer *jitterbuffer;
  GstRtpJitterBufferPrivate *priv;
878 879
  GstPad *other;
  GstCaps *caps;
Wim Taymans's avatar
Wim Taymans committed
880
  GstCaps *templ;
881 882 883 884 885 886

  jitterbuffer = GST_RTP_JITTER_BUFFER (gst_pad_get_parent (pad));
  priv = jitterbuffer->priv;

  other = (pad == priv->srcpad ? priv->sinkpad : priv->srcpad);

887
  caps = gst_pad_peer_query_caps (other, filter);
888 889 890

  templ = gst_pad_get_pad_template_caps (pad);
  if (caps == NULL) {
Wim Taymans's avatar
Wim Taymans committed
891 892
    GST_DEBUG_OBJECT (jitterbuffer, "use template");
    caps = templ;
893 894 895 896 897 898 899
  } else {
    GstCaps *intersect;

    GST_DEBUG_OBJECT (jitterbuffer, "intersect with template");

    intersect = gst_caps_intersect (caps, templ);
    gst_caps_unref (caps);
Wim Taymans's avatar
Wim Taymans committed
900
    gst_caps_unref (templ);
901 902 903 904 905 906 907 908

    caps = intersect;
  }
  gst_object_unref (jitterbuffer);

  return caps;
}

909 910 911 912
/*
 * Must be called with JBUF_LOCK held
 */

913
static gboolean
914
gst_jitter_buffer_sink_parse_caps (GstRtpJitterBuffer * jitterbuffer,
915
    GstCaps * caps)
916
{
917
  GstRtpJitterBufferPrivate *priv;
918
  GstStructure *caps_struct;
919
  guint val;
Wim Taymans's avatar
Wim Taymans committed
920
  GstClockTime tval;
921 922 923 924 925 926

  priv = jitterbuffer->priv;

  /* first parse the caps */
  caps_struct = gst_caps_get_structure (caps, 0);

927 928
  GST_DEBUG_OBJECT (jitterbuffer, "got caps");

929 930 931 932 933 934 935 936
  /* we need a clock-rate to convert the rtp timestamps to GStreamer time and to
   * measure the amount of data in the buffer */
  if (!gst_structure_get_int (caps_struct, "clock-rate", &priv->clock_rate))
    goto error;

  if (priv->clock_rate <= 0)
    goto wrong_rate;

937 938
  GST_DEBUG_OBJECT (jitterbuffer, "got clock-rate %d", priv->clock_rate);

Wim Taymans's avatar
Wim Taymans committed
939 940
  /* The clock base is the RTP timestamp corrsponding to the npt-start value. We
   * can use this to track the amount of time elapsed on the sender. */
941 942 943
  if (gst_structure_get_uint (caps_struct, "clock-base", &val))
    priv->clock_base = val;
  else
944 945
    priv->clock_base = -1;

Wim Taymans's avatar
Wim Taymans committed
946 947
  priv->ext_timestamp = priv->clock_base;

948 949 950
  GST_DEBUG_OBJECT (jitterbuffer, "got clock-base %" G_GINT64_FORMAT,
      priv->clock_base);

951 952 953
  if (gst_structure_get_uint (caps_struct, "seqnum-base", &val)) {
    /* first expected seqnum, only update when we didn't have a previous base. */
    if (priv->next_in_seqnum == -1)
954
      priv->next_in_seqnum = val;
955 956
    if (priv->next_seqnum == -1)
      priv->next_seqnum = val;
957
  }
958