gstrtpsession.c 84.8 KB
Newer Older
1
/* GStreamer
2
 * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
3 4 5 6 7 8 9 10 11 12 13 14 15
 *
 * 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
16 17
 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
 * Boston, MA 02110-1301, USA.
18 19 20
 */

/**
21 22
 * SECTION:element-rtpsession
 * @see_also: rtpjitterbuffer, rtpbin, rtpptdemux, rtpssrcdemux
23
 *
Wim Taymans's avatar
Wim Taymans committed
24
 * The RTP session manager models participants with unique SSRC in an RTP
Wim Taymans's avatar
Wim Taymans committed
25 26 27
 * session. This session can be used to send and receive RTP and RTCP packets.
 * Based on what REQUEST pads are requested from the session manager, specific
 * functionality can be activated.
28
 *
Wim Taymans's avatar
Wim Taymans committed
29 30 31 32 33 34 35 36 37 38 39 40 41 42
 * The session manager currently implements RFC 3550 including:
 * <itemizedlist>
 *   <listitem>
 *     <para>RTP packet validation based on consecutive sequence numbers.</para>
 *   </listitem>
 *   <listitem>
 *     <para>Maintainance of the SSRC participant database.</para>
 *   </listitem>
 *   <listitem>
 *     <para>Keeping per participant statistics based on received RTCP packets.</para>
 *   </listitem>
 *   <listitem>
 *     <para>Scheduling of RR/SR RTCP packets.</para>
 *   </listitem>
Wim Taymans's avatar
Wim Taymans committed
43 44 45
 *   <listitem>
 *     <para>Support for multiple sender SSRC.</para>
 *   </listitem>
Wim Taymans's avatar
Wim Taymans committed
46
 * </itemizedlist>
47
 *
48
 * The rtpsession will not demux packets based on SSRC or payload type, nor will
49 50 51 52
 * it correct for packet reordering and jitter. Use #GstRtpsSrcDemux,
 * #GstRtpPtDemux and GstRtpJitterBuffer in addition to #GstRtpSession to
 * perform these tasks. It is usually a good idea to use #GstRtpBin, which
 * combines all these features in one element.
53
 *
54
 * To use #GstRtpSession as an RTP receiver, request a recv_rtp_sink pad, which will
Wim Taymans's avatar
Wim Taymans committed
55 56 57
 * automatically create recv_rtp_src pad. Data received on the recv_rtp_sink pad
 * will be processed in the session and after being validated forwarded on the
 * recv_rtp_src pad.
58
 *
59
 * To also use #GstRtpSession as an RTCP receiver, request a recv_rtcp_sink pad,
Wim Taymans's avatar
Wim Taymans committed
60 61 62 63
 * which will automatically create a sync_src pad. Packets received on the RTCP
 * pad will be used by the session manager to update the stats and database of
 * the other participants. SR packets will be forwarded on the sync_src pad
 * so that they can be used to perform inter-stream synchronisation when needed.
64
 *
Wim Taymans's avatar
Wim Taymans committed
65 66 67
 * If you want the session manager to generate and send RTCP packets, request
 * the send_rtcp_src pad. Packet pushed on this pad contain SR/RR RTCP reports
 * that should be sent to all participants in the session.
68
 *
69
 * To use #GstRtpSession as a sender, request a send_rtp_sink pad, which will
Wim Taymans's avatar
Wim Taymans committed
70 71
 * automatically create a send_rtp_src pad. The session manager will
 * forward the packets on the send_rtp_src pad after updating its internal state.
72
 *
Wim Taymans's avatar
Wim Taymans committed
73
 * The session manager needs the clock-rate of the payload types it is handling
74 75
 * and will signal the #GstRtpSession::request-pt-map signal when it needs such a
 * mapping. One can clear the cached values with the #GstRtpSession::clear-pt-map
Wim Taymans's avatar
Wim Taymans committed
76
 * signal.
77
 *
78
 * <refsect2>
79
 * <title>Example pipelines</title>
80
 * |[
81
 * gst-launch-1.0 udpsrc port=5000 caps="application/x-rtp, ..." ! .recv_rtp_sink rtpsession .recv_rtp_src ! rtptheoradepay ! theoradec ! xvimagesink
82
 * ]| Receive theora RTP packets from port 5000 and send them to the depayloader,
Wim Taymans's avatar
Wim Taymans committed
83 84 85
 * decoder and display. Note that the application/x-rtp caps on udpsrc should be
 * configured based on some negotiation process such as RTSP for this pipeline
 * to work correctly.
86
 * |[
87
 * gst-launch-1.0 udpsrc port=5000 caps="application/x-rtp, ..." ! .recv_rtp_sink rtpsession name=session \
Wim Taymans's avatar
Wim Taymans committed
88 89
 *        .recv_rtp_src ! rtptheoradepay ! theoradec ! xvimagesink \
 *     udpsrc port=5001 caps="application/x-rtcp" ! session.recv_rtcp_sink
90
 * ]| Receive theora RTP packets from port 5000 and send them to the depayloader,
Wim Taymans's avatar
Wim Taymans committed
91 92 93 94 95
 * decoder and display. Receive RTCP packets from port 5001 and process them in
 * the session manager.
 * Note that the application/x-rtp caps on udpsrc should be
 * configured based on some negotiation process such as RTSP for this pipeline
 * to work correctly.
96
 * |[
97
 * gst-launch-1.0 videotestsrc ! theoraenc ! rtptheorapay ! .send_rtp_sink rtpsession .send_rtp_src ! udpsink port=5000
98 99 100
 * ]| Send theora RTP packets through the session manager and out on UDP port
 * 5000.
 * |[
101
 * gst-launch-1.0 videotestsrc ! theoraenc ! rtptheorapay ! .send_rtp_sink rtpsession name=session .send_rtp_src \
Wim Taymans's avatar
Wim Taymans committed
102
 *     ! udpsink port=5000  session.send_rtcp_src ! udpsink port=5001
103 104
 * ]| Send theora RTP packets through the session manager and out on UDP port
 * 5000. Send RTCP packets on port 5001. Note that this pipeline will not preroll
Wim Taymans's avatar
Wim Taymans committed
105 106
 * correctly because the second udpsink will not preroll correctly (no RTCP
 * packets are sent in the PAUSED state). Applications should manually set and
107
 * keep (see gst_element_set_locked_state()) the RTCP udpsink to the PLAYING state.
108 109 110 111 112 113
 * </refsect2>
 */

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

115 116
#include <gst/rtp/gstrtpbuffer.h>

117 118
#include <gst/glib-compat-private.h>

119
#include "gstrtpsession.h"
120
#include "rtpsession.h"
121

122 123 124
GST_DEBUG_CATEGORY_STATIC (gst_rtp_session_debug);
#define GST_CAT_DEFAULT gst_rtp_session_debug

125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
GType
gst_rtp_ntp_time_source_get_type (void)
{
  static GType type = 0;
  static const GEnumValue values[] = {
    {GST_RTP_NTP_TIME_SOURCE_NTP, "NTP time based on realtime clock", "ntp"},
    {GST_RTP_NTP_TIME_SOURCE_UNIX, "UNIX time based on realtime clock", "unix"},
    {GST_RTP_NTP_TIME_SOURCE_RUNNING_TIME,
          "Running time based on pipeline clock",
        "running-time"},
    {GST_RTP_NTP_TIME_SOURCE_CLOCK_TIME, "Pipeline clock time", "clock-time"},
    {0, NULL, NULL},
  };

  if (!type) {
    type = g_enum_register_static ("GstRtpNtpTimeSource", values);
  }
  return type;
}

145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
/* sink pads */
static GstStaticPadTemplate rtpsession_recv_rtp_sink_template =
GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink",
    GST_PAD_SINK,
    GST_PAD_REQUEST,
    GST_STATIC_CAPS ("application/x-rtp")
    );

static GstStaticPadTemplate rtpsession_recv_rtcp_sink_template =
GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink",
    GST_PAD_SINK,
    GST_PAD_REQUEST,
    GST_STATIC_CAPS ("application/x-rtcp")
    );

static GstStaticPadTemplate rtpsession_send_rtp_sink_template =
GST_STATIC_PAD_TEMPLATE ("send_rtp_sink",
    GST_PAD_SINK,
    GST_PAD_REQUEST,
    GST_STATIC_CAPS ("application/x-rtp")
    );

/* src pads */
static GstStaticPadTemplate rtpsession_recv_rtp_src_template =
GST_STATIC_PAD_TEMPLATE ("recv_rtp_src",
    GST_PAD_SRC,
    GST_PAD_SOMETIMES,
    GST_STATIC_CAPS ("application/x-rtp")
    );

static GstStaticPadTemplate rtpsession_sync_src_template =
GST_STATIC_PAD_TEMPLATE ("sync_src",
    GST_PAD_SRC,
    GST_PAD_SOMETIMES,
    GST_STATIC_CAPS ("application/x-rtcp")
    );

static GstStaticPadTemplate rtpsession_send_rtp_src_template =
GST_STATIC_PAD_TEMPLATE ("send_rtp_src",
    GST_PAD_SRC,
    GST_PAD_SOMETIMES,
    GST_STATIC_CAPS ("application/x-rtp")
    );

189 190
static GstStaticPadTemplate rtpsession_send_rtcp_src_template =
GST_STATIC_PAD_TEMPLATE ("send_rtcp_src",
191 192 193 194 195 196 197 198
    GST_PAD_SRC,
    GST_PAD_REQUEST,
    GST_STATIC_CAPS ("application/x-rtcp")
    );

/* signals and args */
enum
{
199
  SIGNAL_REQUEST_PT_MAP,
Wim Taymans's avatar
Wim Taymans committed
200
  SIGNAL_CLEAR_PT_MAP,
201 202 203 204

  SIGNAL_ON_NEW_SSRC,
  SIGNAL_ON_SSRC_COLLISION,
  SIGNAL_ON_SSRC_VALIDATED,
205
  SIGNAL_ON_SSRC_ACTIVE,
206
  SIGNAL_ON_SSRC_SDES,
207 208 209
  SIGNAL_ON_BYE_SSRC,
  SIGNAL_ON_BYE_TIMEOUT,
  SIGNAL_ON_TIMEOUT,
210
  SIGNAL_ON_SENDER_TIMEOUT,
211 212
  SIGNAL_ON_NEW_SENDER_SSRC,
  SIGNAL_ON_SENDER_SSRC_ACTIVE,
213 214 215
  LAST_SIGNAL
};

216 217
#define DEFAULT_BANDWIDTH            0
#define DEFAULT_RTCP_FRACTION        RTP_STATS_RTCP_FRACTION
218 219
#define DEFAULT_RTCP_RR_BANDWIDTH    -1
#define DEFAULT_RTCP_RS_BANDWIDTH    -1
Wim Taymans's avatar
Wim Taymans committed
220
#define DEFAULT_SDES                 NULL
221 222
#define DEFAULT_NUM_SOURCES          0
#define DEFAULT_NUM_ACTIVE_SOURCES   0
223
#define DEFAULT_USE_PIPELINE_CLOCK   FALSE
224
#define DEFAULT_RTCP_MIN_INTERVAL    (RTP_STATS_MIN_INTERVAL * GST_SECOND)
225
#define DEFAULT_PROBATION            RTP_DEFAULT_PROBATION
226 227
#define DEFAULT_MAX_DROPOUT_TIME     60000
#define DEFAULT_MAX_MISORDER_TIME    2000
228
#define DEFAULT_RTP_PROFILE          GST_RTP_PROFILE_AVP
229
#define DEFAULT_NTP_TIME_SOURCE      GST_RTP_NTP_TIME_SOURCE_NTP
230
#define DEFAULT_RTCP_SYNC_SEND_TIME  TRUE
231

232 233
enum
{
234
  PROP_0,
235 236
  PROP_BANDWIDTH,
  PROP_RTCP_FRACTION,
237 238
  PROP_RTCP_RR_BANDWIDTH,
  PROP_RTCP_RS_BANDWIDTH,
Wim Taymans's avatar
Wim Taymans committed
239
  PROP_SDES,
240 241
  PROP_NUM_SOURCES,
  PROP_NUM_ACTIVE_SOURCES,
242
  PROP_INTERNAL_SESSION,
243
  PROP_USE_PIPELINE_CLOCK,
244
  PROP_RTCP_MIN_INTERVAL,
245
  PROP_PROBATION,
246 247
  PROP_MAX_DROPOUT_TIME,
  PROP_MAX_MISORDER_TIME,
248
  PROP_STATS,
249
  PROP_RTP_PROFILE,
250 251
  PROP_NTP_TIME_SOURCE,
  PROP_RTCP_SYNC_SEND_TIME
252 253
};

Wim Taymans's avatar
Wim Taymans committed
254 255
#define GST_RTP_SESSION_LOCK(sess)   g_mutex_lock (&(sess)->priv->lock)
#define GST_RTP_SESSION_UNLOCK(sess) g_mutex_unlock (&(sess)->priv->lock)
256

257 258 259
#define GST_RTP_SESSION_WAIT(sess)   g_cond_wait (&(sess)->priv->cond, &(sess)->priv->lock)
#define GST_RTP_SESSION_SIGNAL(sess) g_cond_signal (&(sess)->priv->cond)

260
struct _GstRtpSessionPrivate
261
{
Wim Taymans's avatar
Wim Taymans committed
262
  GMutex lock;
263
  GCond cond;
264
  GstClock *sysclock;
265

266
  RTPSession *session;
267

268 269 270 271
  /* thread for sending out RTCP */
  GstClockID id;
  gboolean stop_thread;
  GThread *thread;
272
  gboolean thread_stopped;
273
  gboolean wait_send;
274 275

  /* caps mapping */
276 277
  GHashTable *ptmap;

278 279
  GstClockTime send_latency;

280
  gboolean use_pipeline_clock;
281
  GstRtpNtpTimeSource ntp_time_source;
282
  gboolean rtcp_sync_send_time;
283 284

  guint rtx_count;
285 286 287 288 289 290
};

/* callbacks to handle actions from the session manager */
static GstFlowReturn gst_rtp_session_process_rtp (RTPSession * sess,
    RTPSource * src, GstBuffer * buffer, gpointer user_data);
static GstFlowReturn gst_rtp_session_send_rtp (RTPSession * sess,
291
    RTPSource * src, gpointer data, gpointer user_data);
292
static GstFlowReturn gst_rtp_session_send_rtcp (RTPSession * sess,
293
    RTPSource * src, GstBuffer * buffer, gboolean eos, gpointer user_data);
294
static GstFlowReturn gst_rtp_session_sync_rtcp (RTPSession * sess,
295
    GstBuffer * buffer, gpointer user_data);
296 297
static gint gst_rtp_session_clock_rate (RTPSession * sess, guint8 payload,
    gpointer user_data);
298
static void gst_rtp_session_reconsider (RTPSession * sess, gpointer user_data);
299
static void gst_rtp_session_request_key_unit (RTPSession * sess, guint32 ssrc,
300
    gboolean all_headers, gpointer user_data);
301 302
static GstClockTime gst_rtp_session_request_time (RTPSession * session,
    gpointer user_data);
303
static void gst_rtp_session_notify_nack (RTPSession * sess,
304
    guint16 seqnum, guint16 blp, guint32 ssrc, gpointer user_data);
305
static void gst_rtp_session_reconfigure (RTPSession * sess, gpointer user_data);
306 307
static void gst_rtp_session_notify_early_rtcp (RTPSession * sess,
    gpointer user_data);
308 309 310 311

static RTPSessionCallbacks callbacks = {
  gst_rtp_session_process_rtp,
  gst_rtp_session_send_rtp,
312
  gst_rtp_session_sync_rtcp,
313
  gst_rtp_session_send_rtcp,
314
  gst_rtp_session_clock_rate,
315
  gst_rtp_session_reconsider,
316
  gst_rtp_session_request_key_unit,
317
  gst_rtp_session_request_time,
318
  gst_rtp_session_notify_nack,
319 320
  gst_rtp_session_reconfigure,
  gst_rtp_session_notify_early_rtcp
321 322
};

323 324 325 326 327 328 329 330 331 332 333
/* GObject vmethods */
static void gst_rtp_session_finalize (GObject * object);
static void gst_rtp_session_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec);
static void gst_rtp_session_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec);

/* GstElement vmethods */
static GstStateChangeReturn gst_rtp_session_change_state (GstElement * element,
    GstStateChange transition);
static GstPad *gst_rtp_session_request_new_pad (GstElement * element,
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
334
    GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
335 336
static void gst_rtp_session_release_pad (GstElement * element, GstPad * pad);

337 338 339 340
static gboolean gst_rtp_session_sink_setcaps (GstPad * pad,
    GstRtpSession * rtpsession, GstCaps * caps);
static gboolean gst_rtp_session_setcaps_send_rtp (GstPad * pad,
    GstRtpSession * rtpsession, GstCaps * caps);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
341

342
static void gst_rtp_session_clear_pt_map (GstRtpSession * rtpsession);
Wim Taymans's avatar
Wim Taymans committed
343

344 345
static GstStructure *gst_rtp_session_create_stats (GstRtpSession * rtpsession);

346
static guint gst_rtp_session_signals[LAST_SIGNAL] = { 0 };
347

348
static void
349
on_new_ssrc (RTPSession * session, RTPSource * src, GstRtpSession * sess)
350 351 352 353 354 355
{
  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_NEW_SSRC], 0,
      src->ssrc);
}

static void
356
on_ssrc_collision (RTPSession * session, RTPSource * src, GstRtpSession * sess)
357
{
358
  GstPad *send_rtp_sink;
359

360 361
  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_SSRC_COLLISION], 0,
      src->ssrc);
362 363

  GST_RTP_SESSION_LOCK (sess);
364 365
  if ((send_rtp_sink = sess->send_rtp_sink))
    gst_object_ref (send_rtp_sink);
366 367
  GST_RTP_SESSION_UNLOCK (sess);

368
  if (send_rtp_sink) {
369 370 371 372 373 374 375 376 377 378
    GstStructure *structure;
    GstEvent *event;
    RTPSource *internal_src;
    guint32 suggested_ssrc;

    structure = gst_structure_new ("GstRTPCollision", "ssrc", G_TYPE_UINT,
        (guint) src->ssrc, NULL);

    /* if there is no source using the suggested ssrc, most probably because
     * this ssrc has just collided, suggest upstream to use it */
379
    suggested_ssrc = rtp_session_suggest_ssrc (session, NULL);
380 381 382 383 384 385 386 387
    internal_src = rtp_session_get_source_by_ssrc (session, suggested_ssrc);
    if (!internal_src)
      gst_structure_set (structure, "suggested-ssrc", G_TYPE_UINT,
          (guint) suggested_ssrc, NULL);
    else
      g_object_unref (internal_src);

    event = gst_event_new_custom (GST_EVENT_CUSTOM_UPSTREAM, structure);
388 389 390
    gst_pad_push_event (send_rtp_sink, event);
    gst_object_unref (send_rtp_sink);
  }
391 392 393
}

static void
394
on_ssrc_validated (RTPSession * session, RTPSource * src, GstRtpSession * sess)
395 396 397 398 399
{
  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_SSRC_VALIDATED], 0,
      src->ssrc);
}

400 401 402 403 404 405 406
static void
on_ssrc_active (RTPSession * session, RTPSource * src, GstRtpSession * sess)
{
  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_SSRC_ACTIVE], 0,
      src->ssrc);
}

407 408 409
static void
on_ssrc_sdes (RTPSession * session, RTPSource * src, GstRtpSession * sess)
{
410 411 412 413 414
  GstStructure *s;
  GstMessage *m;

  /* convert the new SDES info into a message */
  RTP_SESSION_LOCK (session);
415
  g_object_get (src, "sdes", &s, NULL);
416
  RTP_SESSION_UNLOCK (session);
417

418 419 420
  m = gst_message_new_custom (GST_MESSAGE_ELEMENT, GST_OBJECT (sess), s);
  gst_element_post_message (GST_ELEMENT_CAST (sess), m);

421 422 423 424
  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_SSRC_SDES], 0,
      src->ssrc);
}

425
static void
426
on_bye_ssrc (RTPSession * session, RTPSource * src, GstRtpSession * sess)
427 428 429 430 431 432
{
  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_BYE_SSRC], 0,
      src->ssrc);
}

static void
433
on_bye_timeout (RTPSession * session, RTPSource * src, GstRtpSession * sess)
434 435 436 437 438 439
{
  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_BYE_TIMEOUT], 0,
      src->ssrc);
}

static void
440
on_timeout (RTPSession * session, RTPSource * src, GstRtpSession * sess)
441 442 443 444 445
{
  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_TIMEOUT], 0,
      src->ssrc);
}

446 447 448 449 450 451 452
static void
on_sender_timeout (RTPSession * session, RTPSource * src, GstRtpSession * sess)
{
  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_SENDER_TIMEOUT], 0,
      src->ssrc);
}

453 454 455 456 457 458 459 460 461 462 463 464 465 466 467
static void
on_new_sender_ssrc (RTPSession * session, RTPSource * src, GstRtpSession * sess)
{
  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_NEW_SENDER_SSRC], 0,
      src->ssrc);
}

static void
on_sender_ssrc_active (RTPSession * session, RTPSource * src,
    GstRtpSession * sess)
{
  g_signal_emit (sess, gst_rtp_session_signals[SIGNAL_ON_SENDER_SSRC_ACTIVE], 0,
      src->ssrc);
}

468
static void
469 470
on_notify_stats (RTPSession * session, GParamSpec * spec,
    GstRtpSession * rtpsession)
471 472 473 474
{
  g_object_notify (G_OBJECT (rtpsession), "stats");
}

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
475
#define gst_rtp_session_parent_class parent_class
476
G_DEFINE_TYPE_WITH_PRIVATE (GstRtpSession, gst_rtp_session, GST_TYPE_ELEMENT);
477 478

static void
479
gst_rtp_session_class_init (GstRtpSessionClass * klass)
480 481 482 483 484 485 486 487 488 489 490
{
  GObjectClass *gobject_class;
  GstElementClass *gstelement_class;

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

  gobject_class->finalize = gst_rtp_session_finalize;
  gobject_class->set_property = gst_rtp_session_set_property;
  gobject_class->get_property = gst_rtp_session_get_property;

491
  /**
492
   * GstRtpSession::request-pt-map:
493 494 495 496 497 498 499
   * @sess: the object which received the signal
   * @pt: the pt
   *
   * Request the payload type as #GstCaps for @pt.
   */
  gst_rtp_session_signals[SIGNAL_REQUEST_PT_MAP] =
      g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
500
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass, request_pt_map),
501
      NULL, NULL, g_cclosure_marshal_generic, GST_TYPE_CAPS, 1, G_TYPE_UINT);
Wim Taymans's avatar
Wim Taymans committed
502
  /**
503
   * GstRtpSession::clear-pt-map:
Wim Taymans's avatar
Wim Taymans committed
504 505
   * @sess: the object which received the signal
   *
506
   * Clear the cached pt-maps requested with #GstRtpSession::request-pt-map.
Wim Taymans's avatar
Wim Taymans committed
507 508 509
   */
  gst_rtp_session_signals[SIGNAL_CLEAR_PT_MAP] =
      g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
510 511 512
      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
      G_STRUCT_OFFSET (GstRtpSessionClass, clear_pt_map),
      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
513

514
  /**
515
   * GstRtpSession::on-new-ssrc:
516
   * @sess: the object which received the signal
517
   * @ssrc: the SSRC
518 519 520 521 522
   *
   * Notify of a new SSRC that entered @session.
   */
  gst_rtp_session_signals[SIGNAL_ON_NEW_SSRC] =
      g_signal_new ("on-new-ssrc", G_TYPE_FROM_CLASS (klass),
523
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass, on_new_ssrc),
524 525
      NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);
  /**
526
   * GstRtpSession::on-ssrc_collision:
527
   * @sess: the object which received the signal
528
   * @ssrc: the SSRC
529 530 531 532 533
   *
   * Notify when we have an SSRC collision
   */
  gst_rtp_session_signals[SIGNAL_ON_SSRC_COLLISION] =
      g_signal_new ("on-ssrc-collision", G_TYPE_FROM_CLASS (klass),
534
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass,
535 536 537
          on_ssrc_collision), NULL, NULL, g_cclosure_marshal_VOID__UINT,
      G_TYPE_NONE, 1, G_TYPE_UINT);
  /**
538
   * GstRtpSession::on-ssrc_validated:
539
   * @sess: the object which received the signal
540
   * @ssrc: the SSRC
541 542 543 544 545
   *
   * Notify of a new SSRC that became validated.
   */
  gst_rtp_session_signals[SIGNAL_ON_SSRC_VALIDATED] =
      g_signal_new ("on-ssrc-validated", G_TYPE_FROM_CLASS (klass),
546
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass,
547 548
          on_ssrc_validated), NULL, NULL, g_cclosure_marshal_VOID__UINT,
      G_TYPE_NONE, 1, G_TYPE_UINT);
549
  /**
550
   * GstRtpSession::on-ssrc-active:
551 552 553 554 555 556 557 558 559 560
   * @sess: the object which received the signal
   * @ssrc: the SSRC
   *
   * Notify of a SSRC that is active, i.e., sending RTCP.
   */
  gst_rtp_session_signals[SIGNAL_ON_SSRC_ACTIVE] =
      g_signal_new ("on-ssrc-active", G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass,
          on_ssrc_active), NULL, NULL, g_cclosure_marshal_VOID__UINT,
      G_TYPE_NONE, 1, G_TYPE_UINT);
561 562 563 564 565 566 567 568 569 570 571
  /**
   * GstRtpSession::on-ssrc-sdes:
   * @session: the object which received the signal
   * @src: the SSRC
   *
   * Notify that a new SDES was received for SSRC.
   */
  gst_rtp_session_signals[SIGNAL_ON_SSRC_SDES] =
      g_signal_new ("on-ssrc-sdes", G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass, on_ssrc_sdes),
      NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);
572 573

  /**
574
   * GstRtpSession::on-bye-ssrc:
575
   * @sess: the object which received the signal
576
   * @ssrc: the SSRC
577 578 579 580 581
   *
   * Notify of an SSRC that became inactive because of a BYE packet.
   */
  gst_rtp_session_signals[SIGNAL_ON_BYE_SSRC] =
      g_signal_new ("on-bye-ssrc", G_TYPE_FROM_CLASS (klass),
582
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass, on_bye_ssrc),
583 584
      NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);
  /**
585
   * GstRtpSession::on-bye-timeout:
586
   * @sess: the object which received the signal
587
   * @ssrc: the SSRC
588 589 590 591 592
   *
   * Notify of an SSRC that has timed out because of BYE
   */
  gst_rtp_session_signals[SIGNAL_ON_BYE_TIMEOUT] =
      g_signal_new ("on-bye-timeout", G_TYPE_FROM_CLASS (klass),
593
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass, on_bye_timeout),
594 595
      NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);
  /**
596
   * GstRtpSession::on-timeout:
597
   * @sess: the object which received the signal
598
   * @ssrc: the SSRC
599 600 601 602 603
   *
   * Notify of an SSRC that has timed out
   */
  gst_rtp_session_signals[SIGNAL_ON_TIMEOUT] =
      g_signal_new ("on-timeout", G_TYPE_FROM_CLASS (klass),
604
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass, on_timeout),
605
      NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);
606 607 608
  /**
   * GstRtpSession::on-sender-timeout:
   * @sess: the object which received the signal
609
   * @ssrc: the SSRC
610 611 612 613 614 615 616 617
   *
   * Notify of a sender SSRC that has timed out and became a receiver
   */
  gst_rtp_session_signals[SIGNAL_ON_SENDER_TIMEOUT] =
      g_signal_new ("on-sender-timeout", G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass,
          on_sender_timeout), NULL, NULL, g_cclosure_marshal_VOID__UINT,
      G_TYPE_NONE, 1, G_TYPE_UINT);
618

619 620 621 622 623 624
  /**
   * GstRtpSession::on-new-sender-ssrc:
   * @sess: the object which received the signal
   * @ssrc: the sender SSRC
   *
   * Notify of a new sender SSRC that entered @session.
625 626
   *
   * Since: 1.8
627 628 629 630 631 632 633 634 635 636 637 638
   */
  gst_rtp_session_signals[SIGNAL_ON_NEW_SENDER_SSRC] =
      g_signal_new ("on-new-sender-ssrc", G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass, on_new_ssrc),
      NULL, NULL, g_cclosure_marshal_VOID__UINT, G_TYPE_NONE, 1, G_TYPE_UINT);

  /**
   * GstRtpSession::on-sender-ssrc-active:
   * @sess: the object which received the signal
   * @ssrc: the sender SSRC
   *
   * Notify of a sender SSRC that is active, i.e., sending RTCP.
639 640
   *
   * Since: 1.8
641 642 643 644 645 646 647
   */
  gst_rtp_session_signals[SIGNAL_ON_SENDER_SSRC_ACTIVE] =
      g_signal_new ("on-sender-ssrc-active", G_TYPE_FROM_CLASS (klass),
      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRtpSessionClass,
          on_ssrc_active), NULL, NULL, g_cclosure_marshal_VOID__UINT,
      G_TYPE_NONE, 1, G_TYPE_UINT);

648 649
  g_object_class_install_property (gobject_class, PROP_BANDWIDTH,
      g_param_spec_double ("bandwidth", "Bandwidth",
650
          "The bandwidth of the session in bytes per second (0 for auto-discover)",
651 652
          0.0, G_MAXDOUBLE, DEFAULT_BANDWIDTH,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
653 654 655

  g_object_class_install_property (gobject_class, PROP_RTCP_FRACTION,
      g_param_spec_double ("rtcp-fraction", "RTCP Fraction",
Wim Taymans's avatar
Wim Taymans committed
656 657
          "The RTCP bandwidth of the session in bytes per second "
          "(or as a real fraction of the RTP bandwidth if < 1.0)",
658 659
          0.0, G_MAXDOUBLE, DEFAULT_RTCP_FRACTION,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
660

661 662 663
  g_object_class_install_property (gobject_class, PROP_RTCP_RR_BANDWIDTH,
      g_param_spec_int ("rtcp-rr-bandwidth", "RTCP RR bandwidth",
          "The RTCP bandwidth used for receivers in bytes per second (-1 = default)",
664 665
          -1, G_MAXINT, DEFAULT_RTCP_RR_BANDWIDTH,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
666 667 668 669

  g_object_class_install_property (gobject_class, PROP_RTCP_RS_BANDWIDTH,
      g_param_spec_int ("rtcp-rs-bandwidth", "RTCP RS bandwidth",
          "The RTCP bandwidth used for senders in bytes per second (-1 = default)",
670 671
          -1, G_MAXINT, DEFAULT_RTCP_RS_BANDWIDTH,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
672

Wim Taymans's avatar
Wim Taymans committed
673 674 675
  g_object_class_install_property (gobject_class, PROP_SDES,
      g_param_spec_boxed ("sdes", "SDES",
          "The SDES items of this session",
676
          GST_TYPE_STRUCTURE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
677 678 679 680

  g_object_class_install_property (gobject_class, PROP_NUM_SOURCES,
      g_param_spec_uint ("num-sources", "Num Sources",
          "The number of sources in the session", 0, G_MAXUINT,
681
          DEFAULT_NUM_SOURCES, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
682 683 684 685

  g_object_class_install_property (gobject_class, PROP_NUM_ACTIVE_SOURCES,
      g_param_spec_uint ("num-active-sources", "Num Active Sources",
          "The number of active sources in the session", 0, G_MAXUINT,
686 687
          DEFAULT_NUM_ACTIVE_SOURCES,
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
688

689 690 691
  g_object_class_install_property (gobject_class, PROP_INTERNAL_SESSION,
      g_param_spec_object ("internal-session", "Internal Session",
          "The internal RTPSession object", RTP_TYPE_SESSION,
692
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
693

694 695
  g_object_class_install_property (gobject_class, PROP_USE_PIPELINE_CLOCK,
      g_param_spec_boolean ("use-pipeline-clock", "Use pipeline clock",
696
          "Use the pipeline running-time to set the NTP time in the RTCP SR messages "
Hyunjun Ko's avatar
Hyunjun Ko committed
697
          "(DEPRECATED: Use ntp-time-source property)",
698
          DEFAULT_USE_PIPELINE_CLOCK,
699
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED));
700

701 702 703 704 705 706
  g_object_class_install_property (gobject_class, PROP_RTCP_MIN_INTERVAL,
      g_param_spec_uint64 ("rtcp-min-interval", "Minimum RTCP interval",
          "Minimum interval between Regular RTCP packet (in ns)",
          0, G_MAXUINT64, DEFAULT_RTCP_MIN_INTERVAL,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

707 708 709 710 711 712
  g_object_class_install_property (gobject_class, PROP_PROBATION,
      g_param_spec_uint ("probation", "Number of probations",
          "Consecutive packet sequence numbers to accept the source",
          0, G_MAXUINT, DEFAULT_PROBATION,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

713 714 715 716 717 718 719 720 721 722 723 724
  g_object_class_install_property (gobject_class, PROP_MAX_DROPOUT_TIME,
      g_param_spec_uint ("max-dropout-time", "Max dropout time",
          "The maximum time (milliseconds) of missing packets tolerated.",
          0, G_MAXUINT, DEFAULT_MAX_DROPOUT_TIME,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

  g_object_class_install_property (gobject_class, PROP_MAX_MISORDER_TIME,
      g_param_spec_uint ("max-misorder-time", "Max misorder time",
          "The maximum time (milliseconds) of misordered packets tolerated.",
          0, G_MAXUINT, DEFAULT_MAX_MISORDER_TIME,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

725 726 727 728 729 730 731 732 733 734 735 736
  /**
   * GstRtpSession::stats:
   *
   * Various session statistics. This property returns a GstStructure
   * with name application/x-rtp-session-stats with the following fields:
   *
   *  "rtx-count"       G_TYPE_UINT   The number of retransmission events
   *      received from downstream (in receiver mode)
   *  "rtx-drop-count"  G_TYPE_UINT   The number of retransmission events
   *      dropped (due to bandwidth constraints)
   *  "sent-nack-count" G_TYPE_UINT   Number of NACKs sent
   *  "recv-nack-count" G_TYPE_UINT   Number of NACKs received
737 738
   *  "source-stats"    G_TYPE_BOXED  GValueArray of #RTPSource::stats for all
   *      RTP sources (Since 1.8)
739
   *
740
   * Since: 1.4
741 742 743 744 745 746
   */
  g_object_class_install_property (gobject_class, PROP_STATS,
      g_param_spec_boxed ("stats", "Statistics",
          "Various statistics", GST_TYPE_STRUCTURE,
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));

747 748 749 750 751
  g_object_class_install_property (gobject_class, PROP_RTP_PROFILE,
      g_param_spec_enum ("rtp-profile", "RTP Profile",
          "RTP profile to use", GST_TYPE_RTP_PROFILE, DEFAULT_RTP_PROFILE,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

752 753 754 755 756 757
  g_object_class_install_property (gobject_class, PROP_NTP_TIME_SOURCE,
      g_param_spec_enum ("ntp-time-source", "NTP Time Source",
          "NTP time source for RTCP packets",
          gst_rtp_ntp_time_source_get_type (), DEFAULT_NTP_TIME_SOURCE,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

758 759 760 761 762 763 764
  g_object_class_install_property (gobject_class, PROP_RTCP_SYNC_SEND_TIME,
      g_param_spec_boolean ("rtcp-sync-send-time", "RTCP Sync Send Time",
          "Use send time or capture time for RTCP sync "
          "(TRUE = send time, FALSE = capture time)",
          DEFAULT_RTCP_SYNC_SEND_TIME,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

765 766 767 768 769 770
  gstelement_class->change_state =
      GST_DEBUG_FUNCPTR (gst_rtp_session_change_state);
  gstelement_class->request_new_pad =
      GST_DEBUG_FUNCPTR (gst_rtp_session_request_new_pad);
  gstelement_class->release_pad =
      GST_DEBUG_FUNCPTR (gst_rtp_session_release_pad);
771

Wim Taymans's avatar
Wim Taymans committed
772 773
  klass->clear_pt_map = GST_DEBUG_FUNCPTR (gst_rtp_session_clear_pt_map);

Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
774
  /* sink pads */
775 776 777 778 779 780
  gst_element_class_add_static_pad_template (gstelement_class,
      &rtpsession_recv_rtp_sink_template);
  gst_element_class_add_static_pad_template (gstelement_class,
      &rtpsession_recv_rtcp_sink_template);
  gst_element_class_add_static_pad_template (gstelement_class,
      &rtpsession_send_rtp_sink_template);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
781 782

  /* src pads */
783 784 785 786 787 788 789 790
  gst_element_class_add_static_pad_template (gstelement_class,
      &rtpsession_recv_rtp_src_template);
  gst_element_class_add_static_pad_template (gstelement_class,
      &rtpsession_sync_src_template);
  gst_element_class_add_static_pad_template (gstelement_class,
      &rtpsession_send_rtp_src_template);
  gst_element_class_add_static_pad_template (gstelement_class,
      &rtpsession_send_rtcp_src_template);
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
791

792
  gst_element_class_set_static_metadata (gstelement_class, "RTP Session",
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
793 794 795
      "Filter/Network/RTP",
      "Implement an RTP session", "Wim Taymans <wim.taymans@gmail.com>");

796 797
  GST_DEBUG_CATEGORY_INIT (gst_rtp_session_debug,
      "rtpsession", 0, "RTP Session");
798 799 800
}

static void
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
801
gst_rtp_session_init (GstRtpSession * rtpsession)
802
{
803
  rtpsession->priv = gst_rtp_session_get_instance_private (rtpsession);
Wim Taymans's avatar
Wim Taymans committed
804
  g_mutex_init (&rtpsession->priv->lock);
805
  g_cond_init (&rtpsession->priv->cond);
806
  rtpsession->priv->sysclock = gst_system_clock_obtain ();
807
  rtpsession->priv->session = rtp_session_new ();
808
  rtpsession->priv->use_pipeline_clock = DEFAULT_USE_PIPELINE_CLOCK;
809
  rtpsession->priv->rtcp_sync_send_time = DEFAULT_RTCP_SYNC_SEND_TIME;
810

811 812
  /* configure callbacks */
  rtp_session_set_callbacks (rtpsession->priv->session, &callbacks, rtpsession);
813 814 815 816 817 818 819
  /* configure signals */
  g_signal_connect (rtpsession->priv->session, "on-new-ssrc",
      (GCallback) on_new_ssrc, rtpsession);
  g_signal_connect (rtpsession->priv->session, "on-ssrc-collision",
      (GCallback) on_ssrc_collision, rtpsession);
  g_signal_connect (rtpsession->priv->session, "on-ssrc-validated",
      (GCallback) on_ssrc_validated, rtpsession);
820 821
  g_signal_connect (rtpsession->priv->session, "on-ssrc-active",
      (GCallback) on_ssrc_active, rtpsession);
822 823
  g_signal_connect (rtpsession->priv->session, "on-ssrc-sdes",
      (GCallback) on_ssrc_sdes, rtpsession);
824 825 826 827 828 829
  g_signal_connect (rtpsession->priv->session, "on-bye-ssrc",
      (GCallback) on_bye_ssrc, rtpsession);
  g_signal_connect (rtpsession->priv->session, "on-bye-timeout",
      (GCallback) on_bye_timeout, rtpsession);
  g_signal_connect (rtpsession->priv->session, "on-timeout",
      (GCallback) on_timeout, rtpsession);
830 831
  g_signal_connect (rtpsession->priv->session, "on-sender-timeout",
      (GCallback) on_sender_timeout, rtpsession);
832 833 834 835
  g_signal_connect (rtpsession->priv->session, "on-new-sender-ssrc",
      (GCallback) on_new_sender_ssrc, rtpsession);
  g_signal_connect (rtpsession->priv->session, "on-sender-ssrc-active",
      (GCallback) on_sender_ssrc_active, rtpsession);
836 837
  g_signal_connect (rtpsession->priv->session, "notify::stats",
      (GCallback) on_notify_stats, rtpsession);
838 839
  rtpsession->priv->ptmap = g_hash_table_new_full (NULL, NULL, NULL,
      (GDestroyNotify) gst_caps_unref);
840 841 842

  gst_segment_init (&rtpsession->recv_rtp_seg, GST_FORMAT_UNDEFINED);
  gst_segment_init (&rtpsession->send_rtp_seg, GST_FORMAT_UNDEFINED);
843 844

  rtpsession->priv->thread_stopped = TRUE;
845 846

  rtpsession->priv->rtx_count = 0;
847 848

  rtpsession->priv->ntp_time_source = DEFAULT_NTP_TIME_SOURCE;
849 850 851 852 853
}

static void
gst_rtp_session_finalize (GObject * object)
{
854
  GstRtpSession *rtpsession;
855 856

  rtpsession = GST_RTP_SESSION (object);
857 858

  g_hash_table_destroy (rtpsession->priv->ptmap);
Wim Taymans's avatar
Wim Taymans committed
859
  g_mutex_clear (&rtpsession->priv->lock);
860
  g_cond_clear (&rtpsession->priv->cond);
861
  g_object_unref (rtpsession->priv->sysclock);
862
  g_object_unref (rtpsession->priv->session);
863 864 865 866 867 868 869 870

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

static void
gst_rtp_session_set_property (GObject * object, guint prop_id,
    const GValue * value, GParamSpec * pspec)
{
871
  GstRtpSession *rtpsession;
872
  GstRtpSessionPrivate *priv;
873 874

  rtpsession = GST_RTP_SESSION (object);
875
  priv = rtpsession->priv;
876 877

  switch (prop_id) {
878
    case PROP_BANDWIDTH:
879
      g_object_set_property (G_OBJECT (priv->session), "bandwidth", value);
880 881
      break;
    case PROP_RTCP_FRACTION:
882 883 884 885 886 887 888 889 890
      g_object_set_property (G_OBJECT (priv->session), "rtcp-fraction", value);
      break;
    case PROP_RTCP_RR_BANDWIDTH:
      g_object_set_property (G_OBJECT (priv->session), "rtcp-rr-bandwidth",
          value);
      break;
    case PROP_RTCP_RS_BANDWIDTH:
      g_object_set_property (G_OBJECT (priv->session), "rtcp-rs-bandwidth",
          value);
891
      break;
Wim Taymans's avatar
Wim Taymans committed
892 893
    case PROP_SDES:
      rtp_session_set_sdes_struct (priv->session, g_value_get_boxed (value));
894
      break;
895 896 897
    case PROP_USE_PIPELINE_CLOCK:
      priv->use_pipeline_clock = g_value_get_boolean (value);
      break;
898 899 900 901
    case PROP_RTCP_MIN_INTERVAL:
      g_object_set_property (G_OBJECT (priv->session), "rtcp-min-interval",
          value);
      break;
902 903 904
    case PROP_PROBATION:
      g_object_set_property (G_OBJECT (priv->session), "probation", value);
      break;
905 906 907 908 909 910 911 912
    case PROP_MAX_DROPOUT_TIME:
      g_object_set_property (G_OBJECT (priv->session), "max-dropout-time",
          value);
      break;
    case PROP_MAX_MISORDER_TIME:
      g_object_set_property (G_OBJECT (priv->session), "max-misorder-time",
          value);
      break;
913 914 915
    case PROP_RTP_PROFILE:
      g_object_set_property (G_OBJECT (priv->session), "rtp-profile", value);
      break;
916 917 918
    case PROP_NTP_TIME_SOURCE:
      priv->ntp_time_source = g_value_get_enum (value);
      break;
919 920 921
    case PROP_RTCP_SYNC_SEND_TIME:
      priv->rtcp_sync_send_time = g_value_get_boolean (value);
      break;
922 923 924 925 926 927 928 929 930 931
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

static void
gst_rtp_session_get_property (GObject * object, guint prop_id,
    GValue * value, GParamSpec * pspec)
{
932
  GstRtpSession *rtpsession;
933
  GstRtpSessionPrivate *priv;
934 935

  rtpsession = GST_RTP_SESSION (object);
936
  priv = rtpsession->priv;
937 938

  switch (prop_id) {
939
    case PROP_BANDWIDTH:
940
      g_object_get_property (G_OBJECT (priv->session), "bandwidth", value);
941 942
      break;
    case PROP_RTCP_FRACTION:
943 944 945 946 947 948 949 950 951
      g_object_get_property (G_OBJECT (priv->session), "rtcp-fraction", value);
      break;
    case PROP_RTCP_RR_BANDWIDTH:
      g_object_get_property (G_OBJECT (priv->session), "rtcp-rr-bandwidth",
          value);
      break;
    case PROP_RTCP_RS_BANDWIDTH:
      g_object_get_property (G_OBJECT (priv->session), "rtcp-rs-bandwidth",
          value);
952
      break;
Wim Taymans's avatar
Wim Taymans committed
953 954
    case PROP_SDES:
      g_value_take_boxed (value, rtp_session_get_sdes_struct (priv->session));
955 956 957 958 959 960 961 962
      break;
    case PROP_NUM_SOURCES:
      g_value_set_uint (value, rtp_session_get_num_sources (priv->session));
      break;
    case PROP_NUM_ACTIVE_SOURCES:
      g_value_set_uint (value,
          rtp_session_get_num_active_sources (priv->session));
      break;
963 964 965
    case PROP_INTERNAL_SESSION:
      g_value_set_object (value, priv->session);
      break;
966 967 968
    case PROP_USE_PIPELINE_CLOCK:
      g_value_set_boolean (value, priv->use_pipeline_clock);
      break;
969 970 971 972
    case PROP_RTCP_MIN_INTERVAL:
      g_object_get_property (G_OBJECT (priv->session), "rtcp-min-interval",
          value);
      break;
973 974 975
    case PROP_PROBATION:
      g_object_get_property (G_OBJECT (priv->session), "probation", value);
      break;
976 977 978 979 980 981 982 983
    case PROP_MAX_DROPOUT_TIME:
      g_object_get_property (G_OBJECT (priv->session), "max-dropout-time",
          value);
      break;
    case PROP_MAX_MISORDER_TIME:
      g_object_get_property (G_OBJECT (priv->session), "max-misorder-time",
          value);
      break;
984 985 986
    case PROP_STATS:
      g_value_take_boxed (value, gst_rtp_session_create_stats (rtpsession));
      break;
987 988 989
    case PROP_RTP_PROFILE:
      g_object_get_property (G_OBJECT (priv->session), "rtp-profile", value);
      break;
990 991 992
    case PROP_NTP_TIME_SOURCE:
      g_value_set_enum (value, priv->ntp_time_source);
      break;
993 994 995
    case PROP_RTCP_SYNC_SEND_TIME:
      g_value_set_boolean (value, priv->rtcp_sync_send_time);
      break;
996 997 998 999 1000 1001
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
  }
}

1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013
static GstStructure *
gst_rtp_session_create_stats (GstRtpSession * rtpsession)
{
  GstStructure *s;

  g_object_get (rtpsession->priv->session, "stats", &s, NULL);
  gst_structure_set (s, "rtx-count", G_TYPE_UINT, rtpsession->priv->rtx_count,
      NULL);

  return s;
}

1014
static void
1015 1016
get_current_times (GstRtpSession * rtpsession, GstClockTime * running_time,
    guint64 * ntpnstime)
1017
{
1018
  guint64 ntpns = -1;
1019
  GstClock *clock;
Wim Taymans's avatar
Wim Taymans committed
1020
  GstClockTime base_time, rt, clock_time;
1021 1022 1023 1024 1025 1026

  GST_OBJECT_LOCK (rtpsession);
  if ((clock = GST_ELEMENT_CLOCK (rtpsession))) {
    base_time = GST_ELEMENT_CAST (rtpsession)->base_time;
    gst_object_ref (clock);
    GST_OBJECT_UNLOCK (rtpsession);
1027

Wim Taymans's avatar
Wim Taymans committed
1028
    /* get current clock time and convert to running time */
Wim Taymans's avatar
Wim Taymans committed
1029
    clock_time = gst_clock_get_time (clock);
Wim Taymans's avatar
Wim Taymans committed
1030
    rt = clock_time - base_time;
Wim Taymans's avatar
Wim Taymans committed
1031

1032
    if (rtpsession->priv->use_pipeline_clock) {
Wim Taymans's avatar
Wim Taymans committed
1033
      ntpns = rt;
1034 1035
      /* add constant to convert from 1970 based time to 1900 based time */
      ntpns += (2208988800LL * GST_SECOND);
1036
    } else {
1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057
      switch (rtpsession->priv->ntp_time_source) {
        case GST_RTP_NTP_TIME_SOURCE_NTP:
        case GST_RTP_NTP_TIME_SOURCE_UNIX:{
          GTimeVal current;

          /* get current NTP time */
          g_get_current_time (&current);
          ntpns = GST_TIMEVAL_TO_TIME (current);

          /* add constant to convert from 1970 based time to 1900 based time */
          if (rtpsession->priv->ntp_time_source == GST_RTP_NTP_TIME_SOURCE_NTP)
            ntpns += (2208988800LL * GST_SECOND);
          break;
        }
        case GST_RTP_NTP_TIME_SOURCE_RUNNING_TIME:
          ntpns = rt;
          break;
        case GST_RTP_NTP_TIME_SOURCE_CLOCK_TIME:
          ntpns = clock_time;
          break;
        default:
1058
          ntpns = -1;
1059 1060 1061
          g_assert_not_reached ();
          break;
      }
1062
    }
1063

1064 1065 1066
    gst_object_unref (clock);
  } else {
    GST_OBJECT_UNLOCK (rtpsession);
1067 1068
    rt = -1;
    ntpns = -1;
1069
  }
1070 1071 1072 1073
  if (running_time)
    *running_time = rt;
  if (ntpnstime)
    *ntpnstime = ntpns;
1074 1075
}

1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
/* must be called with GST_RTP_SESSION_LOCK */
static void
signal_waiting_rtcp_thread_unlocked (GstRtpSession * rtpsession)
{
  if (rtpsession->priv->wait_send) {
    GST_LOG_OBJECT (rtpsession, "signal RTCP thread");
    rtpsession->priv->wait_send = FALSE;
    GST_RTP_SESSION_SIGNAL (rtpsession);
  }
}

1087
static void
1088
rtcp_thread (GstRtpSession * rtpsession)
1089 1090
{
  GstClockID id;
1091
  GstClockTime current_time;
1092
  GstClockTime next_timeout;
1093
  guint64 ntpnstime;
1094
  GstClockTime running_time;
Wim Taymans's avatar
Wim Taymans committed
1095 1096
  RTPSession *session;
  GstClock *sysclock;
1097 1098 1099 1100

  GST_DEBUG_OBJECT (rtpsession, "entering RTCP thread");

  GST_RTP_SESSION_LOCK (rtpsession);
1101

1102
  while (rtpsession->priv->wait_send) {
1103
    GST_LOG_OBJECT (rtpsession, "waiting for getting started");
1104 1105 1106 1107
    GST_RTP_SESSION_WAIT (rtpsession);
    GST_LOG_OBJECT (rtpsession, "signaled...");
  }

Wim Taymans's avatar
Wim Taymans committed
1108 1109 1110 1111
  sysclock = rtpsession->priv->sysclock;
  current_time = gst_clock_get_time (sysclock);

  session = rtpsession->priv->session;
1112

1113 1114 1115 1116
  GST_DEBUG_OBJECT (rtpsession, "starting at %" GST_TIME_FORMAT,
      GST_TIME_ARGS (current_time));
  session->start_time = current_time;

1117
  while (!rtpsession->priv->stop_thread) {
1118
    GstClockReturn res;
1119

1120
    /* get initial estimate */
Wim Taymans's avatar
Wim Taymans committed
1121
    next_timeout = rtp_session_next_timeout (session, current_time);
1122

1123
    GST_DEBUG_OBJECT (rtpsession, "next check time %" GST_TIME_FORMAT,
1124 1125 1126 1127 1128
        GST_TIME_ARGS (next_timeout));

    /* leave if no more timeouts, the session ended */
    if (next_timeout == GST_CLOCK_TIME_NONE)
      break;
1129