gstrtpjitterbuffer.c 107 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-rtpjitterbuffer
28
29
 *
 * This element reorders and removes duplicate RTP packets as they are received
Wim Taymans's avatar
Wim Taymans committed
30
 * from a network source.
31
 *
Wim Taymans's avatar
Wim Taymans committed
32
33
 * 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,
34
35
 * 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.
36
 *
Wim Taymans's avatar
Wim Taymans committed
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
 * The rtpjitterbuffer will wait for missing packets up to a configurable time
 * limit using the #GstRtpJitterBuffer:latency property. Packets arriving too
 * late are considered to be lost packets. If the #GstRtpJitterBuffer:do-lost
 * property is set, lost packets will result in a custom serialized downstream
 * event of name GstRTPPacketLost. The lost packet events are usually used by a
 * depayloader or other element to create concealment data or some other logic
 * to gracefully handle the missing packets.
 *
 * The jitterbuffer will use the DTS (or PTS if no DTS is set) of the incomming
 * buffer and the rtptime inside the RTP packet to create a PTS on the outgoing
 * buffer.
 *
 * The jitterbuffer can also be configured to send early retransmission events
 * upstream by setting the #GstRtpJitterBuffer:do-retransmission property. In
 * this mode, the jitterbuffer tries to estimate when a packet should arrive and
 * sends a custom upstream event named GstRTPRetransmissionRequest when the
 * packet is considered late. The initial expected packet arrival time is
 * calculated as follows:
 *
 * - If seqnum N arrived at time T, seqnum N+1 is expected to arrive at
 *     T + packet-spacing + #GstRtpJitterBuffer:rtx-delay. The packet spacing is
 *     calculated from the DTS (or PTS is no DTS) of two consecutive RTP
 *     packets with different rtptime.
 *
 * - If seqnum N0 arrived at time T0 and seqnum Nm arrived at time Tm,
 *     seqnum Ni is expected at time Ti = T0 + i*(Tm - T0)/(Nm - N0). Any
 *     previously scheduled timeout is overwritten.
 *
 * - If seqnum N arrived, all seqnum older than
 *     N - #GstRtpJitterBuffer:rtx-delay-reorder are considered late
 *     immediately. This is to request fast feedback for abonormally reorder
 *     packets before any of the previous timeouts is triggered.
 *
 * A late packet triggers the GstRTPRetransmissionRequest custom upstream
 * event. After the initial timeout expires and the retransmission event is
 * sent, the timeout is scheduled for
 * T + #GstRtpJitterBuffer:rtx-retry-timeout. If the missing packet did not
 * arrive after #GstRtpJitterBuffer:rtx-retry-timeout, a new
 * GstRTPRetransmissionRequest is sent upstream and the timeout is rescheduled
 * again for T + #GstRtpJitterBuffer:rtx-retry-timeout. This repeats until
 * #GstRtpJitterBuffer:rtx-retry-period elapsed, at which point no further
 * retransmission requests are sent and the regular logic is performed to
 * schedule a lost packet as discussed above.
 *
 * This element acts as a live element and so adds #GstRtpJitterBuffer:latency
 * to the pipeline.
 *
84
 * This element will automatically be used inside rtpbin.
85
 *
86
 * <refsect2>
87
 * <title>Example pipelines</title>
88
 * |[
89
 * gst-launch-1.0 rtspsrc location=rtsp://192.168.1.133:8554/mpeg1or2AudioVideoTest ! rtpjitterbuffer ! rtpmpvdepay ! mpeg2dec ! xvimagesink
90
 * ]| Connect to a streaming server and decode the MPEG video. The jitterbuffer is
91
92
93
94
 * inserted into the pipeline to smooth out network jitter and to reorder the
 * out-of-order RTP packets.
 * </refsect2>
 *
95
 * Last reviewed on 2007-05-28 (0.10.5)
96
97
98
99
100
101
 */

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

102
#include <stdlib.h>
103
104
105
#include <string.h>
#include <gst/rtp/gstrtpbuffer.h>

106
#include "gstrtpjitterbuffer.h"
107
#include "rtpjitterbuffer.h"
108
#include "rtpstats.h"
109

110
111
#include <gst/glib-compat-private.h>

112
113
114
115
116
117
GST_DEBUG_CATEGORY (rtpjitterbuffer_debug);
#define GST_CAT_DEFAULT (rtpjitterbuffer_debug)

/* RTPJitterBuffer signals and args */
enum
{
118
  SIGNAL_REQUEST_PT_MAP,
Wim Taymans's avatar
Wim Taymans committed
119
  SIGNAL_CLEAR_PT_MAP,
120
  SIGNAL_HANDLE_SYNC,
Wim Taymans's avatar
Wim Taymans committed
121
  SIGNAL_ON_NPT_STOP,
Wim Taymans's avatar
Wim Taymans committed
122
  SIGNAL_SET_ACTIVE,
123
124
125
  LAST_SIGNAL
};

Wim Taymans's avatar
Wim Taymans committed
126
127
128
129
130
131
132
#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
133
#define DEFAULT_RTX_DELAY           -1
Wim Taymans's avatar
Wim Taymans committed
134
#define DEFAULT_RTX_DELAY_REORDER   3
135
136
137
138
139
#define DEFAULT_RTX_RETRY_TIMEOUT   -1
#define DEFAULT_RTX_RETRY_PERIOD    -1

#define DEFAULT_AUTO_RTX_DELAY (20 * GST_MSECOND)
#define DEFAULT_AUTO_RTX_TIMEOUT (40 * GST_MSECOND)
140
141
142

enum
{
143
144
  PROP_0,
  PROP_LATENCY,
145
  PROP_DROP_ON_LATENCY,
146
147
  PROP_TS_OFFSET,
  PROP_DO_LOST,
148
  PROP_MODE,
Wim Taymans's avatar
Wim Taymans committed
149
  PROP_PERCENT,
Wim Taymans's avatar
Wim Taymans committed
150
151
152
  PROP_DO_RETRANSMISSION,
  PROP_RTX_DELAY,
  PROP_RTX_DELAY_REORDER,
153
154
  PROP_RTX_RETRY_TIMEOUT,
  PROP_RTX_RETRY_PERIOD,
155
  PROP_STATS,
156
  PROP_LAST
157
158
};

Wim Taymans's avatar
Wim Taymans committed
159
#define JBUF_LOCK(priv)   (g_mutex_lock (&(priv)->jbuf_lock))
160
161
162

#define JBUF_LOCK_CHECK(priv,label) G_STMT_START {    \
  JBUF_LOCK (priv);                                   \
163
  if (G_UNLIKELY (priv->srcresult != GST_FLOW_OK))    \
164
165
    goto label;                                       \
} G_STMT_END
Wim Taymans's avatar
Wim Taymans committed
166
#define JBUF_UNLOCK(priv) (g_mutex_unlock (&(priv)->jbuf_lock))
167

168
#define JBUF_WAIT_TIMER(priv)   G_STMT_START {            \
Wim Taymans's avatar
Wim Taymans committed
169
  GST_DEBUG ("waiting timer");                            \
170
171
172
  (priv)->waiting_timer = TRUE;                           \
  g_cond_wait (&(priv)->jbuf_timer, &(priv)->jbuf_lock);  \
  (priv)->waiting_timer = FALSE;                          \
Wim Taymans's avatar
Wim Taymans committed
173
  GST_DEBUG ("waiting timer done");                       \
174
} G_STMT_END
Wim Taymans's avatar
Wim Taymans committed
175
176
177
178
179
#define JBUF_SIGNAL_TIMER(priv) G_STMT_START {            \
  if (G_UNLIKELY ((priv)->waiting_timer)) {               \
    GST_DEBUG ("signal timer");                           \
    g_cond_signal (&(priv)->jbuf_timer);                  \
  }                                                       \
180
181
} G_STMT_END

182
#define JBUF_WAIT_EVENT(priv,label) G_STMT_START {       \
Wim Taymans's avatar
Wim Taymans committed
183
  GST_DEBUG ("waiting event");                           \
184
185
186
  (priv)->waiting_event = TRUE;                          \
  g_cond_wait (&(priv)->jbuf_event, &(priv)->jbuf_lock); \
  (priv)->waiting_event = FALSE;                         \
Wim Taymans's avatar
Wim Taymans committed
187
  GST_DEBUG ("waiting event done");                      \
188
189
190
  if (G_UNLIKELY (priv->srcresult != GST_FLOW_OK))       \
    goto label;                                          \
} G_STMT_END
Wim Taymans's avatar
Wim Taymans committed
191
192
#define JBUF_SIGNAL_EVENT(priv) G_STMT_START {           \
  if (G_UNLIKELY ((priv)->waiting_event)) {              \
193
    GST_DEBUG ("signal event");                          \
Wim Taymans's avatar
Wim Taymans committed
194
195
    g_cond_signal (&(priv)->jbuf_event);                 \
  }                                                      \
196
} G_STMT_END
197

198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
#define JBUF_WAIT_QUERY(priv,label) G_STMT_START {       \
  GST_DEBUG ("waiting query");                           \
  (priv)->waiting_query = TRUE;                          \
  g_cond_wait (&(priv)->jbuf_query, &(priv)->jbuf_lock); \
  (priv)->waiting_query = FALSE;                         \
  GST_DEBUG ("waiting query done");                      \
  if (G_UNLIKELY (priv->srcresult != GST_FLOW_OK))       \
    goto label;                                          \
} G_STMT_END
#define JBUF_SIGNAL_QUERY(priv,res) G_STMT_START {       \
  (priv)->last_query = res;                              \
  if (G_UNLIKELY ((priv)->waiting_query)) {              \
    GST_DEBUG ("signal query");                          \
    g_cond_signal (&(priv)->jbuf_query);                 \
  }                                                      \
} G_STMT_END


216
struct _GstRtpJitterBufferPrivate
217
218
{
  GstPad *sinkpad, *srcpad;
219
  GstPad *rtcpsinkpad;
220

221
  RTPJitterBuffer *jbuf;
Wim Taymans's avatar
Wim Taymans committed
222
  GMutex jbuf_lock;
223
224
225
226
  gboolean waiting_timer;
  GCond jbuf_timer;
  gboolean waiting_event;
  GCond jbuf_event;
227
228
229
  gboolean waiting_query;
  GCond jbuf_query;
  gboolean last_query;
230
  gboolean discont;
231
  gboolean ts_discont;
Wim Taymans's avatar
Wim Taymans committed
232
  gboolean active;
233
  guint64 out_offset;
234

235
236
237
  gboolean timer_running;
  GThread *timer_thread;

238
239
  /* properties */
  guint latency_ms;
240
  guint64 latency_ns;
241
  gboolean drop_on_latency;
242
  gint64 ts_offset;
243
  gboolean do_lost;
Wim Taymans's avatar
Wim Taymans committed
244
245
246
  gboolean do_retransmission;
  gint rtx_delay;
  gint rtx_delay_reorder;
247
248
  gint rtx_retry_timeout;
  gint rtx_retry_period;
249
250
251

  /* the last seqnum we pushed out */
  guint32 last_popped_seqnum;
252
  /* the next expected seqnum we push */
253
  guint32 next_seqnum;
254
255
  /* last output time */
  GstClockTime last_out_time;
256
  /* last valid input timestamp and rtptime pair */
257
  GstClockTime ips_dts;
Wim Taymans's avatar
Wim Taymans committed
258
  guint64 ips_rtptime;
259
  GstClockTime packet_spacing;
260

261
  /* the next expected seqnum we receive */
262
263
  GstClockTime last_in_dts;
  guint32 last_in_seqnum;
264
  guint32 next_in_seqnum;
265

266
267
  GArray *timers;

Wim Taymans's avatar
Wim Taymans committed
268
269
270
271
272
273
274
275
  /* start and stop ranges */
  GstClockTime npt_start;
  GstClockTime npt_stop;
  guint64 ext_timestamp;
  guint64 last_elapsed;
  guint64 estimated_eos;
  GstClockID eos_id;

276
277
278
  /* state */
  gboolean eos;

279
  /* clock rate and rtp timestamp offset */
280
  gint last_pt;
281
  gint32 clock_rate;
282
  gint64 clock_base;
283
  gint64 prev_ts_offset;
284
285
286

  /* when we are shutting down */
  GstFlowReturn srcresult;
287
  gboolean blocked;
288
289
290
291

  /* for sync */
  GstSegment segment;
  GstClockID clock_id;
292
  GstClockTime timer_timeout;
293
  guint16 timer_seqnum;
294
295
296
  /* the latency of the upstream peer, we have to take this into account when
   * synchronizing the buffers. */
  GstClockTime peer_latency;
297
298
  guint64 ext_rtptime;
  GstBuffer *last_sr;
299
300
301
302

  /* some accounting */
  guint64 num_late;
  guint64 num_duplicates;
303
304
305
306
307
  guint64 num_rtx_requests;
  guint64 num_rtx_success;
  guint64 num_rtx_failed;
  gdouble avg_rtx_num;
  guint64 avg_rtx_rtt;
308
309
310
311
312

  /* for the jitter */
  GstClockTime last_dts;
  guint64 last_rtptime;
  GstClockTime avg_jitter;
313
314
};

315
316
317
318
319
320
321
322
323
324
325
326
typedef enum
{
  TIMER_TYPE_EXPECTED,
  TIMER_TYPE_LOST,
  TIMER_TYPE_DEADLINE,
  TIMER_TYPE_EOS
} TimerType;

typedef struct
{
  guint idx;
  guint16 seqnum;
327
  guint num;
328
  TimerType type;
329
  GstClockTime timeout;
330
  GstClockTime duration;
331
  GstClockTime rtx_base;
332
  GstClockTime rtx_delay;
333
  GstClockTime rtx_retry;
334
335
  GstClockTime rtx_last;
  guint num_rtx_retry;
336
337
} TimerData;

338
339
#define GST_RTP_JITTER_BUFFER_GET_PRIVATE(o) \
  (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_RTP_JITTER_BUFFER, \
340
                                GstRtpJitterBufferPrivate))
341
342
343
344
345
346
347
348
349
350
351
352

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) "
         */ )
    );

353
354
355
356
357
358
359
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")
    );

360
361
362
363
364
365
366
367
368
369
370
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) "
         */ )
    );

371
372
static guint gst_rtp_jitter_buffer_signals[LAST_SIGNAL] = { 0 };

Wim Taymans's avatar
Wim Taymans committed
373
374
#define gst_rtp_jitter_buffer_parent_class parent_class
G_DEFINE_TYPE (GstRtpJitterBuffer, gst_rtp_jitter_buffer, GST_TYPE_ELEMENT);
375
376
377
378
379
380

/* 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);
381
static void gst_rtp_jitter_buffer_finalize (GObject * object);
382
383
384
385

/* element overrides */
static GstStateChangeReturn gst_rtp_jitter_buffer_change_state (GstElement
    * element, GstStateChange transition);
386
static GstPad *gst_rtp_jitter_buffer_request_new_pad (GstElement * element,
Wim Taymans's avatar
Wim Taymans committed
387
    GstPadTemplate * templ, const gchar * name, const GstCaps * filter);
388
389
static void gst_rtp_jitter_buffer_release_pad (GstElement * element,
    GstPad * pad);
Wim Taymans's avatar
Wim Taymans committed
390
static GstClock *gst_rtp_jitter_buffer_provide_clock (GstElement * element);
391
392

/* pad overrides */
Wim Taymans's avatar
Wim Taymans committed
393
static GstCaps *gst_rtp_jitter_buffer_getcaps (GstPad * pad, GstCaps * filter);
Wim Taymans's avatar
Wim Taymans committed
394
395
static GstIterator *gst_rtp_jitter_buffer_iterate_internal_links (GstPad * pad,
    GstObject * parent);
396
397
398

/* sinkpad overrides */
static gboolean gst_rtp_jitter_buffer_sink_event (GstPad * pad,
Wim Taymans's avatar
Wim Taymans committed
399
    GstObject * parent, GstEvent * event);
400
static GstFlowReturn gst_rtp_jitter_buffer_chain (GstPad * pad,
Wim Taymans's avatar
Wim Taymans committed
401
    GstObject * parent, GstBuffer * buffer);
402

403
static gboolean gst_rtp_jitter_buffer_sink_rtcp_event (GstPad * pad,
Wim Taymans's avatar
Wim Taymans committed
404
    GstObject * parent, GstEvent * event);
405
static GstFlowReturn gst_rtp_jitter_buffer_chain_rtcp (GstPad * pad,
Wim Taymans's avatar
Wim Taymans committed
406
    GstObject * parent, GstBuffer * buffer);
407

Wim Taymans's avatar
Wim Taymans committed
408
static gboolean gst_rtp_jitter_buffer_sink_query (GstPad * pad,
Wim Taymans's avatar
Wim Taymans committed
409
    GstObject * parent, GstQuery * query);
Wim Taymans's avatar
Wim Taymans committed
410

411
/* srcpad overrides */
412
static gboolean gst_rtp_jitter_buffer_src_event (GstPad * pad,
Wim Taymans's avatar
Wim Taymans committed
413
    GstObject * parent, GstEvent * event);
Wim Taymans's avatar
Wim Taymans committed
414
415
static gboolean gst_rtp_jitter_buffer_src_activate_mode (GstPad * pad,
    GstObject * parent, GstPadMode mode, gboolean active);
416
static void gst_rtp_jitter_buffer_loop (GstRtpJitterBuffer * jitterbuffer);
Wim Taymans's avatar
Wim Taymans committed
417
static gboolean gst_rtp_jitter_buffer_src_query (GstPad * pad,
Wim Taymans's avatar
Wim Taymans committed
418
    GstObject * parent, GstQuery * query);
419

Wim Taymans's avatar
Wim Taymans committed
420
static void
421
gst_rtp_jitter_buffer_clear_pt_map (GstRtpJitterBuffer * jitterbuffer);
422
static GstClockTime
Wim Taymans's avatar
Wim Taymans committed
423
424
gst_rtp_jitter_buffer_set_active (GstRtpJitterBuffer * jitterbuffer,
    gboolean active, guint64 base_time);
425
static void do_handle_sync (GstRtpJitterBuffer * jitterbuffer);
426
427

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

430
431
static void wait_next_timeout (GstRtpJitterBuffer * jitterbuffer);

432
433
434
static GstStructure *gst_rtp_jitter_buffer_create_stats (GstRtpJitterBuffer *
    jitterbuffer);

435
static void
436
gst_rtp_jitter_buffer_class_init (GstRtpJitterBufferClass * klass)
437
438
439
440
441
442
443
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

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

444
  g_type_class_add_private (klass, sizeof (GstRtpJitterBufferPrivate));
445

446
  gobject_class->finalize = gst_rtp_jitter_buffer_finalize;
447
448
449
450

  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
451
  /**
452
   * GstRtpJitterBuffer:latency:
453
   *
Wim Taymans's avatar
Wim Taymans committed
454
455
456
   * The maximum latency of the jitterbuffer. Packets will be kept in the buffer
   * for at most this time.
   */
457
  g_object_class_install_property (gobject_class, PROP_LATENCY,
458
459
      g_param_spec_uint ("latency", "Buffer latency in ms",
          "Amount of ms to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS,
460
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Wim Taymans's avatar
Wim Taymans committed
461
  /**
462
   * GstRtpJitterBuffer:drop-on-latency:
463
464
   *
   * Drop oldest buffers when the queue is completely filled.
Wim Taymans's avatar
Wim Taymans committed
465
   */
466
  g_object_class_install_property (gobject_class, PROP_DROP_ON_LATENCY,
Wim Taymans's avatar
Wim Taymans committed
467
      g_param_spec_boolean ("drop-on-latency",
468
469
          "Drop buffers when maximum latency is reached",
          "Tells the jitterbuffer to never exceed the given latency in size",
470
          DEFAULT_DROP_ON_LATENCY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
471
  /**
472
   * GstRtpJitterBuffer:ts-offset:
473
   *
474
475
   * Adjust GStreamer output buffer timestamps in the jitterbuffer with offset.
   * This is mainly used to ensure interstream synchronisation.
476
477
   */
  g_object_class_install_property (gobject_class, PROP_TS_OFFSET,
478
479
480
481
482
483
      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));

  /**
484
   * GstRtpJitterBuffer:do-lost:
485
   *
486
487
488
489
490
491
492
   * 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));
493
494

  /**
495
   * GstRtpJitterBuffer:mode:
496
497
498
499
500
501
502
   *
   * 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
503
  /**
504
   * GstRtpJitterBuffer:percent:
Wim Taymans's avatar
Wim Taymans committed
505
506
507
508
509
510
511
   *
   * The percent of the jitterbuffer that is filled.
   */
  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
512
  /**
513
   * GstRtpJitterBuffer:do-retransmission:
Wim Taymans's avatar
Wim Taymans committed
514
515
516
517
518
519
520
521
522
523
524
525
526
   *
   * 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));

  /**
527
   * GstRtpJitterBuffer:rtx-delay:
Wim Taymans's avatar
Wim Taymans committed
528
529
530
531
532
533
534
535
536
537
538
   *
   * 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 "
539
          "event (-1 automatic)", -1, G_MAXINT, DEFAULT_RTX_DELAY,
540
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
Wim Taymans's avatar
Wim Taymans committed
541
  /**
542
   * GstRtpJitterBuffer:rtx-delay-reorder:
Wim Taymans's avatar
Wim Taymans committed
543
544
545
546
547
548
549
550
551
552
553
554
   *
   * 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)",
555
          -1, G_MAXINT, DEFAULT_RTX_DELAY_REORDER,
556
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
557
558
559
560
561
562
563
564
565
566
567
568
569
570
  /**
   * 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 "
571
          "ms (-1 automatic)", -1, G_MAXINT, DEFAULT_RTX_RETRY_TIMEOUT,
572
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
573
  /**
574
   * GstRtpJitterBuffer:rtx-retry-period:
575
576
577
578
579
580
581
582
583
584
585
   *
   * 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 "
586
          "(-1 automatic)", -1, G_MAXINT, DEFAULT_RTX_RETRY_PERIOD,
587
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
588
  /**
589
   * GstRtpJitterBuffer:stats:
590
   *
591
   * Various jitterbuffer statistics. This property returns a GstStructure
592
593
   * with name application/x-rtp-jitterbuffer-stats with the following fields:
   *
594
595
596
597
   *  "rtx-count"         G_TYPE_UINT64 The number of retransmissions requested
   *  "rtx-success-count" G_TYPE_UINT64 The number of successful retransmissions
   *  "rtx-per-packet"    G_TYPE_DOUBLE Average number of RTX per packet
   *  "rtx-rtt"           G_TYPE_UINT64 Average round trip time per RTX
598
   *
599
   * Since: 1.4
600
   */
601
602
603
  g_object_class_install_property (gobject_class, PROP_STATS,
      g_param_spec_boxed ("stats", "Statistics",
          "Various statistics", GST_TYPE_STRUCTURE,
604
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
Wim Taymans's avatar
Wim Taymans committed
605

606
  /**
607
   * GstRtpJitterBuffer::request-pt-map:
608
609
610
611
612
   * @buffer: the object which received the signal
   * @pt: the pt
   *
   * Request the payload type as #GstCaps for @pt.
   */
613
614
  gst_rtp_jitter_buffer_signals[SIGNAL_REQUEST_PT_MAP] =
      g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
615
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpJitterBufferClass,
616
          request_pt_map), NULL, NULL, g_cclosure_marshal_generic,
617
      GST_TYPE_CAPS, 1, G_TYPE_UINT);
618
619
620
621
622
623
624
625
626
627
628
  /**
   * 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,
629
      G_TYPE_NONE, 1, GST_TYPE_STRUCTURE | G_SIGNAL_TYPE_STATIC_SCOPE);
630

Wim Taymans's avatar
Wim Taymans committed
631
  /**
632
   * GstRtpJitterBuffer::on-npt-stop:
Wim Taymans's avatar
Wim Taymans committed
633
634
635
636
637
638
639
640
641
642
643
   * @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
644
  /**
645
   * GstRtpJitterBuffer::clear-pt-map:
Wim Taymans's avatar
Wim Taymans committed
646
647
   * @buffer: the object which received the signal
   *
Stefan Kost's avatar
Stefan Kost committed
648
649
   * Invalidate the clock-rate as obtained with the
   * #GstRtpJitterBuffer::request-pt-map signal.
Wim Taymans's avatar
Wim Taymans committed
650
651
652
   */
  gst_rtp_jitter_buffer_signals[SIGNAL_CLEAR_PT_MAP] =
      g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
653
654
655
      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);
656

Wim Taymans's avatar
Wim Taymans committed
657
658
659
660
661
662
  /**
   * 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.
663
664
   *
   * Returns: the time of the last pushed packet.
Wim Taymans's avatar
Wim Taymans committed
665
666
667
668
669
   */
  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,
670
      g_cclosure_marshal_generic, G_TYPE_UINT64, 2, G_TYPE_BOOLEAN,
Wim Taymans's avatar
Wim Taymans committed
671
672
      G_TYPE_UINT64);

673
674
675
676
677
678
  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
679
680
  gstelement_class->provide_clock =
      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_provide_clock);
681

Wim Taymans's avatar
Wim Taymans committed
682
683
684
685
686
687
688
  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));

689
  gst_element_class_set_static_metadata (gstelement_class,
Wim Taymans's avatar
Wim Taymans committed
690
691
692
693
694
      "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
695
  klass->clear_pt_map = GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_clear_pt_map);
Wim Taymans's avatar
Wim Taymans committed
696
  klass->set_active = GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_set_active);
Wim Taymans's avatar
Wim Taymans committed
697

698
  GST_DEBUG_CATEGORY_INIT
699
      (rtpjitterbuffer_debug, "rtpjitterbuffer", 0, "RTP Jitter Buffer");
700
701
702
}

static void
Wim Taymans's avatar
Wim Taymans committed
703
gst_rtp_jitter_buffer_init (GstRtpJitterBuffer * jitterbuffer)
704
{
705
  GstRtpJitterBufferPrivate *priv;
706
707
708
709
710

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

  priv->latency_ms = DEFAULT_LATENCY_MS;
711
  priv->latency_ns = priv->latency_ms * GST_MSECOND;
712
  priv->drop_on_latency = DEFAULT_DROP_ON_LATENCY;
713
  priv->do_lost = DEFAULT_DO_LOST;
Wim Taymans's avatar
Wim Taymans committed
714
715
716
  priv->do_retransmission = DEFAULT_DO_RETRANSMISSION;
  priv->rtx_delay = DEFAULT_RTX_DELAY;
  priv->rtx_delay_reorder = DEFAULT_RTX_DELAY_REORDER;
717
718
  priv->rtx_retry_timeout = DEFAULT_RTX_RETRY_TIMEOUT;
  priv->rtx_retry_period = DEFAULT_RTX_RETRY_PERIOD;
719

720
721
722
  priv->last_dts = -1;
  priv->last_rtptime = -1;
  priv->avg_jitter = 0;
Wim Taymans's avatar
Wim Taymans committed
723
  priv->timers = g_array_new (FALSE, TRUE, sizeof (TimerData));
724
  priv->jbuf = rtp_jitter_buffer_new ();
Wim Taymans's avatar
Wim Taymans committed
725
  g_mutex_init (&priv->jbuf_lock);
726
727
  g_cond_init (&priv->jbuf_timer);
  g_cond_init (&priv->jbuf_event);
728
  g_cond_init (&priv->jbuf_query);
729

730
731
732
733
  /* 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);
734
  priv->active = TRUE;
735

736
737
738
739
  priv->srcpad =
      gst_pad_new_from_static_template (&gst_rtp_jitter_buffer_src_template,
      "src");

Wim Taymans's avatar
Wim Taymans committed
740
741
  gst_pad_set_activatemode_function (priv->srcpad,
      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_src_activate_mode));
742
  gst_pad_set_query_function (priv->srcpad,
Wim Taymans's avatar
Wim Taymans committed
743
      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_src_query));
744
745
  gst_pad_set_event_function (priv->srcpad,
      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_src_event));
746
747
748
749
750
751
752
753
754

  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
755
756
  gst_pad_set_query_function (priv->sinkpad,
      GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_sink_query));
757
758
759

  gst_element_add_pad (GST_ELEMENT (jitterbuffer), priv->srcpad);
  gst_element_add_pad (GST_ELEMENT (jitterbuffer), priv->sinkpad);
760
761

  GST_OBJECT_FLAG_SET (jitterbuffer, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
762
763
}

764
765
#define IS_DROPABLE(it) (((it)->type == ITEM_TYPE_BUFFER) || ((it)->type == ITEM_TYPE_LOST))

766
767
#define ITEM_TYPE_BUFFER        0
#define ITEM_TYPE_LOST          1
768
#define ITEM_TYPE_EVENT         2
769
#define ITEM_TYPE_QUERY         3
770

Wim Taymans's avatar
Wim Taymans committed
771
static RTPJitterBufferItem *
772
alloc_item (gpointer data, guint type, GstClockTime dts, GstClockTime pts,
773
    guint seqnum, guint count, guint rtptime)
Wim Taymans's avatar
Wim Taymans committed
774
{
775
776
777
778
779
780
781
782
783
784
  RTPJitterBufferItem *item;

  item = g_slice_new (RTPJitterBufferItem);
  item->data = data;
  item->next = NULL;
  item->prev = NULL;
  item->type = type;
  item->dts = dts;
  item->pts = pts;
  item->seqnum = seqnum;
785
  item->count = count;
786
787
788
  item->rtptime = rtptime;

  return item;
Wim Taymans's avatar
Wim Taymans committed
789
790
791
792
793
}

static void
free_item (RTPJitterBufferItem * item)
{
794
  if (item->data && item->type != ITEM_TYPE_QUERY)
Wim Taymans's avatar
Wim Taymans committed
795
796
797
798
    gst_mini_object_unref (item->data);
  g_slice_free (RTPJitterBufferItem, item);
}

799
static void
800
gst_rtp_jitter_buffer_finalize (GObject * object)
801
{
802
  GstRtpJitterBuffer *jitterbuffer;
Wim Taymans's avatar
Wim Taymans committed
803
  GstRtpJitterBufferPrivate *priv;
804
805

  jitterbuffer = GST_RTP_JITTER_BUFFER (object);
Wim Taymans's avatar
Wim Taymans committed
806
  priv = jitterbuffer->priv;
807

Wim Taymans's avatar
Wim Taymans committed
808
809
810
811
  g_array_free (priv->timers, TRUE);
  g_mutex_clear (&priv->jbuf_lock);
  g_cond_clear (&priv->jbuf_timer);
  g_cond_clear (&priv->jbuf_event);
812
  g_cond_clear (&priv->jbuf_query);
813

Wim Taymans's avatar
Wim Taymans committed
814
815
  rtp_jitter_buffer_flush (priv->jbuf, (GFunc) free_item, NULL);
  g_object_unref (priv->jbuf);
816
817

  G_OBJECT_CLASS (parent_class)->finalize (object);
818
819
}

820
static GstIterator *
Wim Taymans's avatar
Wim Taymans committed
821
gst_rtp_jitter_buffer_iterate_internal_links (GstPad * pad, GstObject * parent)
822
823
{
  GstRtpJitterBuffer *jitterbuffer;
824
825
  GstPad *otherpad = NULL;
  GstIterator *it;
Wim Taymans's avatar
Wim Taymans committed
826
  GValue val = { 0, };
827

Wim Taymans's avatar
Wim Taymans committed
828
  jitterbuffer = GST_RTP_JITTER_BUFFER (parent);
829

830
831
832
833
834
835
836
837
  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
838
839
840
841
  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);
842

843
  return it;
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
}

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);
862
863
  gst_pad_set_iterate_internal_links_function (priv->rtcpsinkpad,
      gst_rtp_jitter_buffer_iterate_internal_links);
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
  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
887
    GstPadTemplate * templ, const gchar * name, const GstCaps * filter)
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
{
  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:
  {
917
    g_warning ("rtpjitterbuffer: this is not our template");
918
919
920
921
    return NULL;
  }
exists:
  {
922
    g_warning ("rtpjitterbuffer: pad already requested");
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
    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
956
957
958
959
960
961
static GstClock *
gst_rtp_jitter_buffer_provide_clock (GstElement * element)
{
  return gst_system_clock_obtain ();
}

Wim Taymans's avatar
Wim Taymans committed
962
static void
963
gst_rtp_jitter_buffer_clear_pt_map (GstRtpJitterBuffer * jitterbuffer)
Wim Taymans's avatar
Wim Taymans committed
964
{
965
  GstRtpJitterBufferPrivate *priv;
Wim Taymans's avatar
Wim Taymans committed
966
967
968
969

  priv = jitterbuffer->priv;

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

  JBUF_LOCK (priv);
Wim Taymans's avatar
Wim Taymans committed
972
  priv->clock_rate = -1;
973
974
975
  /* do not clear current content, but refresh state for new arrival */
  GST_DEBUG_OBJECT (jitterbuffer, "reset jitterbuffer");
  rtp_jitter_buffer_reset_skew (priv->jbuf);
976
  JBUF_UNLOCK (priv);
Wim Taymans's avatar
Wim Taymans committed
977
978
}

979
static GstClockTime
Wim Taymans's avatar
Wim Taymans committed
980
gst_rtp_jitter_buffer_set_active (GstRtpJitterBuffer * jbuf, gboolean active,
981
    guint64 offset)
Wim Taymans's avatar
Wim Taymans committed
982
983
{
  GstRtpJitterBufferPrivate *priv;
984
  GstClockTime last_out;
985
  RTPJitterBufferItem *item;
Wim Taymans's avatar
Wim Taymans committed
986
987
988
989

  priv = jbuf->priv;

  JBUF_LOCK (priv);
990
991
  GST_DEBUG_OBJECT (jbuf, "setting active %d with offset %" GST_TIME_FORMAT,
      active, GST_TIME_ARGS (offset));
992
993
994
995
996

  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. */
997
    priv->out_offset = offset;
998
999
1000
    GST_DEBUG_OBJECT (jbuf, "out offset %" GST_TIME_FORMAT,
        GST_TIME_ARGS (priv->out_offset));
    priv->active = active;
1001
    JBUF_SIGNAL_EVENT (priv);
1002
  }
Wim Taymans's avatar
Wim Taymans committed
1003
1004
1005
  if (!active) {
    rtp_jitter_buffer_set_buffering (priv->jbuf, TRUE);
  }
1006
  if ((item = rtp_jitter_buffer_peek (priv->jbuf))) {
1007
    /* head buffer timestamp and offset gives our output time */
1008
    last_out = item->dts + priv->ts_offset;
1009
1010
  } else {
    /* use last known time when the buffer is empty */
1011
    last_out = priv->last_out_time;
1012
  }
Wim Taymans's avatar
Wim Taymans committed
1013
  JBUF_UNLOCK (priv);
1014
1015

  return last_out;
Wim Taymans's avatar
Wim Taymans committed
1016
1017
}

1018
static GstCaps *
Wim Taymans's avatar
Wim Taymans committed
1019
gst_rtp_jitter_buffer_getcaps (GstPad * pad, GstCaps * filter)
1020
{
1021
1022
  GstRtpJitterBuffer *jitterbuffer;
  GstRtpJitterBufferPrivate *priv;
1023
1024
  GstPad *other;
  GstCaps *caps;
Wim Taymans's avatar
Wim Taymans committed
1025
  GstCaps *templ;
1026
1027
1028
1029
1030
1031

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

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

1032
  caps = gst_pad_peer_query_caps (other, filter);
1033
1034
1035

  templ = gst_pad_get_pad_template_caps (pad);
  if (caps == NULL) {
Wim Taymans's avatar
Wim Taymans committed
1036
1037
    GST_DEBUG_OBJECT (jitterbuffer, "use template");
    caps = templ;
1038
1039
1040
1041
1042
1043
1044
  } 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
1045
    gst_caps_unref (templ);
1046
1047
1048
1049
1050
1051
1052
1053

    caps = intersect;
  }
  gst_object_unref (jitterbuffer);

  return caps;
}

1054
1055
1056
1057
/*
 * Must be called with JBUF_LOCK held
 */

1058
static gboolean
1059
gst_jitter_buffer_sink_parse_caps (GstRtpJitterBuffer * jitterbuffer,
1060
    GstCaps * caps)
1061
{
1062
  GstRtpJitterBufferPrivate *priv;
1063
  GstStructure *caps_struct;
1064
  guint val;
Wim Taymans's avatar
Wim Taymans committed
1065
  GstClockTime tval;
1066
1067
1068
1069
1070
1071

  priv = jitterbuffer->priv;

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

1072
1073
  GST_DEBUG_OBJECT (jitterbuffer, "got caps");

1074
1075
1076
1077
1078
1079
1080
1081
  /* 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;

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

1084
1085
  rtp_jitter_buffer_set_clock_rate (priv->jbuf, priv->clock_rate);

Wim Taymans's avatar
Wim Taymans committed
1086
1087
  /* 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. */
1088
1089
1090
  if (gst_structure_get_uint (caps_struct, "clock-base", &val))
    priv->clock_base = val;
  else
1091
1092