2 * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #include <gst/rtp/gstrtpbuffer.h>
23 #include <gst/rtp/gstrtcpbuffer.h>
24 #include <gst/netbuffer/gstnetbuffer.h>
26 #include "gstrtpbin-marshal.h"
28 #include "rtpsession.h"
30 GST_DEBUG_CATEGORY_STATIC (rtp_session_debug);
31 #define GST_CAT_DEFAULT rtp_session_debug
33 /* signals and args */
37 SIGNAL_ON_SSRC_COLLISION,
38 SIGNAL_ON_SSRC_VALIDATED,
39 SIGNAL_ON_SSRC_ACTIVE,
42 SIGNAL_ON_BYE_TIMEOUT,
47 #define DEFAULT_INTERNAL_SOURCE NULL
48 #define DEFAULT_BANDWIDTH RTP_STATS_BANDWIDTH
49 #define DEFAULT_RTCP_FRACTION RTP_STATS_RTCP_BANDWIDTH
50 #define DEFAULT_SDES_CNAME NULL
51 #define DEFAULT_SDES_NAME NULL
52 #define DEFAULT_SDES_EMAIL NULL
53 #define DEFAULT_SDES_PHONE NULL
54 #define DEFAULT_SDES_LOCATION NULL
55 #define DEFAULT_SDES_TOOL NULL
56 #define DEFAULT_SDES_NOTE NULL
57 #define DEFAULT_NUM_SOURCES 0
58 #define DEFAULT_NUM_ACTIVE_SOURCES 0
74 PROP_NUM_ACTIVE_SOURCES,
78 /* update average packet size, we keep this scaled by 16 to keep enough
80 #define UPDATE_AVG(avg, val) \
84 (avg) = ((val) + (15 * (avg))) >> 4;
86 /* GObject vmethods */
87 static void rtp_session_finalize (GObject * object);
88 static void rtp_session_set_property (GObject * object, guint prop_id,
89 const GValue * value, GParamSpec * pspec);
90 static void rtp_session_get_property (GObject * object, guint prop_id,
91 GValue * value, GParamSpec * pspec);
93 static guint rtp_session_signals[LAST_SIGNAL] = { 0 };
95 G_DEFINE_TYPE (RTPSession, rtp_session, G_TYPE_OBJECT);
97 static RTPSource *obtain_source (RTPSession * sess, guint32 ssrc,
98 gboolean * created, RTPArrivalStats * arrival, gboolean rtp);
101 rtp_session_class_init (RTPSessionClass * klass)
103 GObjectClass *gobject_class;
105 gobject_class = (GObjectClass *) klass;
107 gobject_class->finalize = rtp_session_finalize;
108 gobject_class->set_property = rtp_session_set_property;
109 gobject_class->get_property = rtp_session_get_property;
112 * RTPSession::on-new-ssrc:
113 * @session: the object which received the signal
114 * @src: the new RTPSource
116 * Notify of a new SSRC that entered @session.
118 rtp_session_signals[SIGNAL_ON_NEW_SSRC] =
119 g_signal_new ("on-new-ssrc", G_TYPE_FROM_CLASS (klass),
120 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_new_ssrc),
121 NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
124 * RTPSession::on-ssrc-collision:
125 * @session: the object which received the signal
126 * @src: the #RTPSource that caused a collision
128 * Notify when we have an SSRC collision
130 rtp_session_signals[SIGNAL_ON_SSRC_COLLISION] =
131 g_signal_new ("on-ssrc-collision", G_TYPE_FROM_CLASS (klass),
132 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_ssrc_collision),
133 NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
136 * RTPSession::on-ssrc-validated:
137 * @session: the object which received the signal
138 * @src: the new validated RTPSource
140 * Notify of a new SSRC that became validated.
142 rtp_session_signals[SIGNAL_ON_SSRC_VALIDATED] =
143 g_signal_new ("on-ssrc-validated", G_TYPE_FROM_CLASS (klass),
144 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_ssrc_validated),
145 NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
148 * RTPSession::on-ssrc-active:
149 * @session: the object which received the signal
150 * @src: the active RTPSource
152 * Notify of a SSRC that is active, i.e., sending RTCP.
154 rtp_session_signals[SIGNAL_ON_SSRC_ACTIVE] =
155 g_signal_new ("on-ssrc-active", G_TYPE_FROM_CLASS (klass),
156 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_ssrc_active),
157 NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
160 * RTPSession::on-ssrc-sdes:
161 * @session: the object which received the signal
162 * @src: the RTPSource
164 * Notify that a new SDES was received for SSRC.
166 rtp_session_signals[SIGNAL_ON_SSRC_SDES] =
167 g_signal_new ("on-ssrc-sdes", G_TYPE_FROM_CLASS (klass),
168 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_ssrc_sdes),
169 NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
172 * RTPSession::on-bye-ssrc:
173 * @session: the object which received the signal
174 * @src: the RTPSource that went away
176 * Notify of an SSRC that became inactive because of a BYE packet.
178 rtp_session_signals[SIGNAL_ON_BYE_SSRC] =
179 g_signal_new ("on-bye-ssrc", G_TYPE_FROM_CLASS (klass),
180 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_bye_ssrc),
181 NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
184 * RTPSession::on-bye-timeout:
185 * @session: the object which received the signal
186 * @src: the RTPSource that timed out
188 * Notify of an SSRC that has timed out because of BYE
190 rtp_session_signals[SIGNAL_ON_BYE_TIMEOUT] =
191 g_signal_new ("on-bye-timeout", G_TYPE_FROM_CLASS (klass),
192 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_bye_timeout),
193 NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
196 * RTPSession::on-timeout:
197 * @session: the object which received the signal
198 * @src: the RTPSource that timed out
200 * Notify of an SSRC that has timed out
202 rtp_session_signals[SIGNAL_ON_TIMEOUT] =
203 g_signal_new ("on-timeout", G_TYPE_FROM_CLASS (klass),
204 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_timeout),
205 NULL, NULL, g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1,
208 g_object_class_install_property (gobject_class, PROP_INTERNAL_SOURCE,
209 g_param_spec_object ("internal-source", "Internal Source",
210 "The internal source element of the session",
211 RTP_TYPE_SOURCE, G_PARAM_READABLE));
213 g_object_class_install_property (gobject_class, PROP_BANDWIDTH,
214 g_param_spec_double ("bandwidth", "Bandwidth",
215 "The bandwidth of the session",
216 0.0, G_MAXDOUBLE, DEFAULT_BANDWIDTH, G_PARAM_READWRITE));
218 g_object_class_install_property (gobject_class, PROP_RTCP_FRACTION,
219 g_param_spec_double ("rtcp-fraction", "RTCP Fraction",
220 "The fraction of the bandwidth used for RTCP",
221 0.0, G_MAXDOUBLE, DEFAULT_RTCP_FRACTION, G_PARAM_READWRITE));
223 g_object_class_install_property (gobject_class, PROP_SDES_CNAME,
224 g_param_spec_string ("sdes-cname", "SDES CNAME",
225 "The CNAME to put in SDES messages of this session",
226 DEFAULT_SDES_CNAME, G_PARAM_READWRITE));
228 g_object_class_install_property (gobject_class, PROP_SDES_NAME,
229 g_param_spec_string ("sdes-name", "SDES NAME",
230 "The NAME to put in SDES messages of this session",
231 DEFAULT_SDES_NAME, G_PARAM_READWRITE));
233 g_object_class_install_property (gobject_class, PROP_SDES_EMAIL,
234 g_param_spec_string ("sdes-email", "SDES EMAIL",
235 "The EMAIL to put in SDES messages of this session",
236 DEFAULT_SDES_EMAIL, G_PARAM_READWRITE));
238 g_object_class_install_property (gobject_class, PROP_SDES_PHONE,
239 g_param_spec_string ("sdes-phone", "SDES PHONE",
240 "The PHONE to put in SDES messages of this session",
241 DEFAULT_SDES_PHONE, G_PARAM_READWRITE));
243 g_object_class_install_property (gobject_class, PROP_SDES_LOCATION,
244 g_param_spec_string ("sdes-location", "SDES LOCATION",
245 "The LOCATION to put in SDES messages of this session",
246 DEFAULT_SDES_LOCATION, G_PARAM_READWRITE));
248 g_object_class_install_property (gobject_class, PROP_SDES_TOOL,
249 g_param_spec_string ("sdes-tool", "SDES TOOL",
250 "The TOOL to put in SDES messages of this session",
251 DEFAULT_SDES_TOOL, G_PARAM_READWRITE));
253 g_object_class_install_property (gobject_class, PROP_SDES_NOTE,
254 g_param_spec_string ("sdes-note", "SDES NOTE",
255 "The NOTE to put in SDES messages of this session",
256 DEFAULT_SDES_NOTE, G_PARAM_READWRITE));
258 g_object_class_install_property (gobject_class, PROP_NUM_SOURCES,
259 g_param_spec_uint ("num-sources", "Num Sources",
260 "The number of sources in the session", 0, G_MAXUINT,
261 DEFAULT_NUM_SOURCES, G_PARAM_READABLE));
263 g_object_class_install_property (gobject_class, PROP_NUM_ACTIVE_SOURCES,
264 g_param_spec_uint ("num-active-sources", "Num Active Sources",
265 "The number of active sources in the session", 0, G_MAXUINT,
266 DEFAULT_NUM_ACTIVE_SOURCES, G_PARAM_READABLE));
268 GST_DEBUG_CATEGORY_INIT (rtp_session_debug, "rtpsession", 0, "RTP Session");
272 rtp_session_init (RTPSession * sess)
277 sess->lock = g_mutex_new ();
278 sess->key = g_random_int ();
282 for (i = 0; i < 32; i++) {
284 g_hash_table_new_full (NULL, NULL, NULL,
285 (GDestroyNotify) g_object_unref);
287 sess->cnames = g_hash_table_new_full (NULL, NULL, g_free, NULL);
289 rtp_stats_init_defaults (&sess->stats);
291 /* create an active SSRC for this session manager */
292 sess->source = rtp_session_create_source (sess);
293 sess->source->validated = TRUE;
294 sess->stats.active_sources++;
296 /* default UDP header length */
297 sess->header_len = 28;
300 /* some default SDES entries */
301 str = g_strdup_printf ("%s@%s", g_get_user_name (), g_get_host_name ());
302 rtp_source_set_sdes_string (sess->source, GST_RTCP_SDES_CNAME, str);
305 rtp_source_set_sdes_string (sess->source, GST_RTCP_SDES_NAME,
307 rtp_source_set_sdes_string (sess->source, GST_RTCP_SDES_TOOL, "GStreamer");
309 sess->first_rtcp = TRUE;
311 GST_DEBUG ("%p: session using SSRC: %08x", sess, sess->source->ssrc);
315 rtp_session_finalize (GObject * object)
320 sess = RTP_SESSION_CAST (object);
322 g_mutex_free (sess->lock);
323 for (i = 0; i < 32; i++)
324 g_hash_table_destroy (sess->ssrcs[i]);
326 g_free (sess->bye_reason);
328 g_hash_table_destroy (sess->cnames);
329 g_object_unref (sess->source);
331 G_OBJECT_CLASS (rtp_session_parent_class)->finalize (object);
335 rtp_session_set_property (GObject * object, guint prop_id,
336 const GValue * value, GParamSpec * pspec)
340 sess = RTP_SESSION (object);
344 rtp_session_set_bandwidth (sess, g_value_get_double (value));
346 case PROP_RTCP_FRACTION:
347 rtp_session_set_rtcp_fraction (sess, g_value_get_double (value));
349 case PROP_SDES_CNAME:
350 rtp_session_set_sdes_string (sess, GST_RTCP_SDES_CNAME,
351 g_value_get_string (value));
354 rtp_session_set_sdes_string (sess, GST_RTCP_SDES_NAME,
355 g_value_get_string (value));
357 case PROP_SDES_EMAIL:
358 rtp_session_set_sdes_string (sess, GST_RTCP_SDES_EMAIL,
359 g_value_get_string (value));
361 case PROP_SDES_PHONE:
362 rtp_session_set_sdes_string (sess, GST_RTCP_SDES_PHONE,
363 g_value_get_string (value));
365 case PROP_SDES_LOCATION:
366 rtp_session_set_sdes_string (sess, GST_RTCP_SDES_LOC,
367 g_value_get_string (value));
370 rtp_session_set_sdes_string (sess, GST_RTCP_SDES_TOOL,
371 g_value_get_string (value));
374 rtp_session_set_sdes_string (sess, GST_RTCP_SDES_NOTE,
375 g_value_get_string (value));
378 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
384 rtp_session_get_property (GObject * object, guint prop_id,
385 GValue * value, GParamSpec * pspec)
389 sess = RTP_SESSION (object);
392 case PROP_INTERNAL_SOURCE:
393 g_value_take_object (value, rtp_session_get_internal_source (sess));
396 g_value_set_double (value, rtp_session_get_bandwidth (sess));
398 case PROP_RTCP_FRACTION:
399 g_value_set_double (value, rtp_session_get_rtcp_fraction (sess));
401 case PROP_SDES_CNAME:
402 g_value_take_string (value, rtp_session_get_sdes_string (sess,
403 GST_RTCP_SDES_CNAME));
406 g_value_take_string (value, rtp_session_get_sdes_string (sess,
407 GST_RTCP_SDES_NAME));
409 case PROP_SDES_EMAIL:
410 g_value_take_string (value, rtp_session_get_sdes_string (sess,
411 GST_RTCP_SDES_EMAIL));
413 case PROP_SDES_PHONE:
414 g_value_take_string (value, rtp_session_get_sdes_string (sess,
415 GST_RTCP_SDES_PHONE));
417 case PROP_SDES_LOCATION:
418 g_value_take_string (value, rtp_session_get_sdes_string (sess,
422 g_value_take_string (value, rtp_session_get_sdes_string (sess,
423 GST_RTCP_SDES_TOOL));
426 g_value_take_string (value, rtp_session_get_sdes_string (sess,
427 GST_RTCP_SDES_NOTE));
429 case PROP_NUM_SOURCES:
430 g_value_set_uint (value, rtp_session_get_num_sources (sess));
432 case PROP_NUM_ACTIVE_SOURCES:
433 g_value_set_uint (value, rtp_session_get_num_active_sources (sess));
436 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
442 on_new_ssrc (RTPSession * sess, RTPSource * source)
444 RTP_SESSION_UNLOCK (sess);
445 g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_NEW_SSRC], 0, source);
446 RTP_SESSION_LOCK (sess);
450 on_ssrc_collision (RTPSession * sess, RTPSource * source)
452 RTP_SESSION_UNLOCK (sess);
453 g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_SSRC_COLLISION], 0,
455 RTP_SESSION_LOCK (sess);
459 on_ssrc_validated (RTPSession * sess, RTPSource * source)
461 RTP_SESSION_UNLOCK (sess);
462 g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_SSRC_VALIDATED], 0,
464 RTP_SESSION_LOCK (sess);
468 on_ssrc_active (RTPSession * sess, RTPSource * source)
470 RTP_SESSION_UNLOCK (sess);
471 g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_SSRC_ACTIVE], 0, source);
472 RTP_SESSION_LOCK (sess);
476 on_ssrc_sdes (RTPSession * sess, RTPSource * source)
478 GST_DEBUG ("SDES changed for SSRC %08x", source->ssrc);
479 RTP_SESSION_UNLOCK (sess);
480 g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_SSRC_SDES], 0, source);
481 RTP_SESSION_LOCK (sess);
485 on_bye_ssrc (RTPSession * sess, RTPSource * source)
487 RTP_SESSION_UNLOCK (sess);
488 g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_BYE_SSRC], 0, source);
489 RTP_SESSION_LOCK (sess);
493 on_bye_timeout (RTPSession * sess, RTPSource * source)
495 RTP_SESSION_UNLOCK (sess);
496 g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_BYE_TIMEOUT], 0, source);
497 RTP_SESSION_LOCK (sess);
501 on_timeout (RTPSession * sess, RTPSource * source)
503 RTP_SESSION_UNLOCK (sess);
504 g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_TIMEOUT], 0, source);
505 RTP_SESSION_LOCK (sess);
511 * Create a new session object.
513 * Returns: a new #RTPSession. g_object_unref() after usage.
516 rtp_session_new (void)
520 sess = g_object_new (RTP_TYPE_SESSION, NULL);
526 * rtp_session_set_callbacks:
527 * @sess: an #RTPSession
528 * @callbacks: callbacks to configure
529 * @user_data: user data passed in the callbacks
531 * Configure a set of callbacks to be notified of actions.
534 rtp_session_set_callbacks (RTPSession * sess, RTPSessionCallbacks * callbacks,
537 g_return_if_fail (RTP_IS_SESSION (sess));
539 sess->callbacks.process_rtp = callbacks->process_rtp;
540 sess->callbacks.send_rtp = callbacks->send_rtp;
541 sess->callbacks.send_rtcp = callbacks->send_rtcp;
542 sess->callbacks.sync_rtcp = callbacks->sync_rtcp;
543 sess->callbacks.clock_rate = callbacks->clock_rate;
544 sess->callbacks.reconsider = callbacks->reconsider;
545 sess->user_data = user_data;
549 * rtp_session_set_bandwidth:
550 * @sess: an #RTPSession
551 * @bandwidth: the bandwidth allocated
553 * Set the session bandwidth in bytes per second.
556 rtp_session_set_bandwidth (RTPSession * sess, gdouble bandwidth)
558 g_return_if_fail (RTP_IS_SESSION (sess));
560 RTP_SESSION_LOCK (sess);
561 sess->stats.bandwidth = bandwidth;
562 RTP_SESSION_UNLOCK (sess);
566 * rtp_session_get_bandwidth:
567 * @sess: an #RTPSession
569 * Get the session bandwidth.
571 * Returns: the session bandwidth.
574 rtp_session_get_bandwidth (RTPSession * sess)
578 g_return_val_if_fail (RTP_IS_SESSION (sess), 0);
580 RTP_SESSION_LOCK (sess);
581 result = sess->stats.bandwidth;
582 RTP_SESSION_UNLOCK (sess);
588 * rtp_session_set_rtcp_fraction:
589 * @sess: an #RTPSession
590 * @bandwidth: the RTCP bandwidth
592 * Set the bandwidth that should be used for RTCP
596 rtp_session_set_rtcp_fraction (RTPSession * sess, gdouble bandwidth)
598 g_return_if_fail (RTP_IS_SESSION (sess));
600 RTP_SESSION_LOCK (sess);
601 sess->stats.rtcp_bandwidth = bandwidth;
602 RTP_SESSION_UNLOCK (sess);
606 * rtp_session_get_rtcp_fraction:
607 * @sess: an #RTPSession
609 * Get the session bandwidth used for RTCP.
611 * Returns: The bandwidth used for RTCP messages.
614 rtp_session_get_rtcp_fraction (RTPSession * sess)
618 g_return_val_if_fail (RTP_IS_SESSION (sess), 0.0);
620 RTP_SESSION_LOCK (sess);
621 result = sess->stats.rtcp_bandwidth;
622 RTP_SESSION_UNLOCK (sess);
628 * rtp_session_set_sdes_string:
629 * @sess: an #RTPSession
630 * @type: the type of the SDES item
631 * @item: a null-terminated string to set.
633 * Store an SDES item of @type in @sess.
635 * Returns: %FALSE if the data was unchanged @type is invalid.
638 rtp_session_set_sdes_string (RTPSession * sess, GstRTCPSDESType type,
643 g_return_val_if_fail (RTP_IS_SESSION (sess), FALSE);
645 RTP_SESSION_LOCK (sess);
646 result = rtp_source_set_sdes_string (sess->source, type, item);
647 RTP_SESSION_UNLOCK (sess);
653 * rtp_session_get_sdes_string:
654 * @sess: an #RTPSession
655 * @type: the type of the SDES item
657 * Get the SDES item of @type from @sess.
659 * Returns: a null-terminated copy of the SDES item or NULL when @type was not
660 * valid. g_free() after usage.
663 rtp_session_get_sdes_string (RTPSession * sess, GstRTCPSDESType type)
667 g_return_val_if_fail (RTP_IS_SESSION (sess), NULL);
669 RTP_SESSION_LOCK (sess);
670 result = rtp_source_get_sdes_string (sess->source, type);
671 RTP_SESSION_UNLOCK (sess);
677 source_push_rtp (RTPSource * source, GstBuffer * buffer, RTPSession * session)
679 GstFlowReturn result = GST_FLOW_OK;
681 if (source == session->source) {
682 GST_DEBUG ("source %08x pushed sender RTP packet", source->ssrc);
684 RTP_SESSION_UNLOCK (session);
686 if (session->callbacks.send_rtp)
688 session->callbacks.send_rtp (session, source, buffer,
691 gst_buffer_unref (buffer);
694 GST_DEBUG ("source %08x pushed receiver RTP packet", source->ssrc);
695 RTP_SESSION_UNLOCK (session);
697 if (session->callbacks.process_rtp)
699 session->callbacks.process_rtp (session, source, buffer,
702 gst_buffer_unref (buffer);
704 RTP_SESSION_LOCK (session);
710 source_clock_rate (RTPSource * source, guint8 pt, RTPSession * session)
714 if (session->callbacks.clock_rate)
715 result = session->callbacks.clock_rate (session, pt, session->user_data);
719 GST_DEBUG ("got clock-rate %d for pt %d", result, pt);
724 static RTPSourceCallbacks callbacks = {
725 (RTPSourcePushRTP) source_push_rtp,
726 (RTPSourceClockRate) source_clock_rate,
730 check_collision (RTPSession * sess, RTPSource * source,
731 RTPArrivalStats * arrival)
733 /* FIXME, do collision check */
737 /* must be called with the session lock */
739 obtain_source (RTPSession * sess, guint32 ssrc, gboolean * created,
740 RTPArrivalStats * arrival, gboolean rtp)
745 g_hash_table_lookup (sess->ssrcs[sess->mask_idx], GINT_TO_POINTER (ssrc));
746 if (source == NULL) {
747 /* make new Source in probation and insert */
748 source = rtp_source_new (ssrc);
750 /* for RTP packets we need to set the source in probation. Receiving RTCP
751 * packets of an SSRC, on the other hand, is a strong indication that we
752 * are dealing with a valid source. */
754 source->probation = RTP_DEFAULT_PROBATION;
756 source->probation = 0;
758 /* store from address, if any */
759 if (arrival->have_address) {
761 rtp_source_set_rtp_from (source, &arrival->address);
763 rtp_source_set_rtcp_from (source, &arrival->address);
766 /* configure a callback on the source */
767 rtp_source_set_callbacks (source, &callbacks, sess);
769 g_hash_table_insert (sess->ssrcs[sess->mask_idx], GINT_TO_POINTER (ssrc),
772 /* we have one more source now */
773 sess->total_sources++;
777 /* check for collision, this updates the address when not previously set */
778 if (check_collision (sess, source, arrival))
779 on_ssrc_collision (sess, source);
781 /* update last activity */
782 source->last_activity = arrival->time;
784 source->last_rtp_activity = arrival->time;
790 * rtp_session_get_internal_source:
791 * @sess: a #RTPSession
793 * Get the internal #RTPSource of @session.
795 * Returns: The internal #RTPSource. g_object_unref() after usage.
798 rtp_session_get_internal_source (RTPSession * sess)
802 g_return_val_if_fail (RTP_IS_SESSION (sess), NULL);
804 result = g_object_ref (sess->source);
810 * rtp_session_add_source:
811 * @sess: a #RTPSession
812 * @src: #RTPSource to add
814 * Add @src to @session.
816 * Returns: %TRUE on success, %FALSE if a source with the same SSRC already
817 * existed in the session.
820 rtp_session_add_source (RTPSession * sess, RTPSource * src)
822 gboolean result = FALSE;
825 g_return_val_if_fail (RTP_IS_SESSION (sess), FALSE);
826 g_return_val_if_fail (src != NULL, FALSE);
828 RTP_SESSION_LOCK (sess);
830 g_hash_table_lookup (sess->ssrcs[sess->mask_idx],
831 GINT_TO_POINTER (src->ssrc));
833 g_hash_table_insert (sess->ssrcs[sess->mask_idx],
834 GINT_TO_POINTER (src->ssrc), src);
835 /* we have one more source now */
836 sess->total_sources++;
839 RTP_SESSION_UNLOCK (sess);
845 * rtp_session_get_num_sources:
846 * @sess: an #RTPSession
848 * Get the number of sources in @sess.
850 * Returns: The number of sources in @sess.
853 rtp_session_get_num_sources (RTPSession * sess)
857 g_return_val_if_fail (RTP_IS_SESSION (sess), FALSE);
859 RTP_SESSION_LOCK (sess);
860 result = sess->total_sources;
861 RTP_SESSION_UNLOCK (sess);
867 * rtp_session_get_num_active_sources:
868 * @sess: an #RTPSession
870 * Get the number of active sources in @sess. A source is considered active when
871 * it has been validated and has not yet received a BYE RTCP message.
873 * Returns: The number of active sources in @sess.
876 rtp_session_get_num_active_sources (RTPSession * sess)
880 g_return_val_if_fail (RTP_IS_SESSION (sess), 0);
882 RTP_SESSION_LOCK (sess);
883 result = sess->stats.active_sources;
884 RTP_SESSION_UNLOCK (sess);
890 * rtp_session_get_source_by_ssrc:
891 * @sess: an #RTPSession
894 * Find the source with @ssrc in @sess.
896 * Returns: a #RTPSource with SSRC @ssrc or NULL if the source was not found.
897 * g_object_unref() after usage.
900 rtp_session_get_source_by_ssrc (RTPSession * sess, guint32 ssrc)
904 g_return_val_if_fail (RTP_IS_SESSION (sess), NULL);
906 RTP_SESSION_LOCK (sess);
908 g_hash_table_lookup (sess->ssrcs[sess->mask_idx], GINT_TO_POINTER (ssrc));
910 g_object_ref (result);
911 RTP_SESSION_UNLOCK (sess);
917 * rtp_session_get_source_by_cname:
918 * @sess: a #RTPSession
921 * Find the source with @cname in @sess.
923 * Returns: a #RTPSource with CNAME @cname or NULL if the source was not found.
924 * g_object_unref() after usage.
927 rtp_session_get_source_by_cname (RTPSession * sess, const gchar * cname)
931 g_return_val_if_fail (RTP_IS_SESSION (sess), NULL);
932 g_return_val_if_fail (cname != NULL, NULL);
934 RTP_SESSION_LOCK (sess);
935 result = g_hash_table_lookup (sess->cnames, cname);
937 g_object_ref (result);
938 RTP_SESSION_UNLOCK (sess);
944 * rtp_session_create_source:
945 * @sess: an #RTPSession
947 * Create an #RTPSource for use in @sess. This function will create a source
948 * with an ssrc that is currently not used by any participants in the session.
950 * Returns: an #RTPSource.
953 rtp_session_create_source (RTPSession * sess)
958 RTP_SESSION_LOCK (sess);
960 ssrc = g_random_int ();
962 /* see if it exists in the session, we're done if it doesn't */
963 if (g_hash_table_lookup (sess->ssrcs[sess->mask_idx],
964 GINT_TO_POINTER (ssrc)) == NULL)
967 source = rtp_source_new (ssrc);
968 g_object_ref (source);
969 rtp_source_set_callbacks (source, &callbacks, sess);
970 g_hash_table_insert (sess->ssrcs[sess->mask_idx], GINT_TO_POINTER (ssrc),
972 /* we have one more source now */
973 sess->total_sources++;
974 RTP_SESSION_UNLOCK (sess);
979 /* update the RTPArrivalStats structure with the current time and other bits
980 * about the current buffer we are handling.
981 * This function is typically called when a validated packet is received.
982 * This function should be called with the SESSION_LOCK
985 update_arrival_stats (RTPSession * sess, RTPArrivalStats * arrival,
986 gboolean rtp, GstBuffer * buffer, guint64 ntpnstime)
990 /* get time of arrival */
991 g_get_current_time (¤t);
992 arrival->time = GST_TIMEVAL_TO_TIME (current);
993 arrival->ntpnstime = ntpnstime;
995 /* get packet size including header overhead */
996 arrival->bytes = GST_BUFFER_SIZE (buffer) + sess->header_len;
999 arrival->payload_len = gst_rtp_buffer_get_payload_len (buffer);
1001 arrival->payload_len = 0;
1004 /* for netbuffer we can store the IP address to check for collisions */
1005 arrival->have_address = GST_IS_NETBUFFER (buffer);
1006 if (arrival->have_address) {
1007 GstNetBuffer *netbuf = (GstNetBuffer *) buffer;
1009 memcpy (&arrival->address, &netbuf->from, sizeof (GstNetAddress));
1014 * rtp_session_process_rtp:
1015 * @sess: and #RTPSession
1016 * @buffer: an RTP buffer
1017 * @ntpnstime: the NTP arrival time in nanoseconds
1019 * Process an RTP buffer in the session manager. This function takes ownership
1022 * Returns: a #GstFlowReturn.
1025 rtp_session_process_rtp (RTPSession * sess, GstBuffer * buffer,
1028 GstFlowReturn result;
1032 gboolean prevsender, prevactive;
1033 RTPArrivalStats arrival;
1035 g_return_val_if_fail (RTP_IS_SESSION (sess), GST_FLOW_ERROR);
1036 g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
1038 if (!gst_rtp_buffer_validate (buffer))
1039 goto invalid_packet;
1041 RTP_SESSION_LOCK (sess);
1042 /* update arrival stats */
1043 update_arrival_stats (sess, &arrival, TRUE, buffer, ntpnstime);
1045 /* ignore more RTP packets when we left the session */
1046 if (sess->source->received_bye)
1049 /* get SSRC and look up in session database */
1050 ssrc = gst_rtp_buffer_get_ssrc (buffer);
1051 source = obtain_source (sess, ssrc, &created, &arrival, TRUE);
1053 prevsender = RTP_SOURCE_IS_SENDER (source);
1054 prevactive = RTP_SOURCE_IS_ACTIVE (source);
1056 /* we need to ref so that we can process the CSRCs later */
1057 gst_buffer_ref (buffer);
1059 /* let source process the packet */
1060 result = rtp_source_process_rtp (source, buffer, &arrival);
1062 /* source became active */
1063 if (prevactive != RTP_SOURCE_IS_ACTIVE (source)) {
1064 sess->stats.active_sources++;
1065 GST_DEBUG ("source: %08x became active, %d active sources", ssrc,
1066 sess->stats.active_sources);
1067 on_ssrc_validated (sess, source);
1069 if (prevsender != RTP_SOURCE_IS_SENDER (source)) {
1070 sess->stats.sender_sources++;
1071 GST_DEBUG ("source: %08x became sender, %d sender sources", ssrc,
1072 sess->stats.sender_sources);
1076 on_new_ssrc (sess, source);
1078 if (source->validated) {
1082 /* for validated sources, we add the CSRCs as well */
1083 count = gst_rtp_buffer_get_csrc_count (buffer);
1085 for (i = 0; i < count; i++) {
1087 RTPSource *csrc_src;
1089 csrc = gst_rtp_buffer_get_csrc (buffer, i);
1092 csrc_src = obtain_source (sess, csrc, &created, &arrival, TRUE);
1095 GST_DEBUG ("created new CSRC: %08x", csrc);
1096 rtp_source_set_as_csrc (csrc_src);
1097 if (RTP_SOURCE_IS_ACTIVE (csrc_src))
1098 sess->stats.active_sources++;
1099 on_new_ssrc (sess, source);
1103 gst_buffer_unref (buffer);
1105 RTP_SESSION_UNLOCK (sess);
1112 gst_buffer_unref (buffer);
1113 GST_DEBUG ("invalid RTP packet received");
1118 gst_buffer_unref (buffer);
1119 RTP_SESSION_UNLOCK (sess);
1120 GST_DEBUG ("ignoring RTP packet because we are leaving");
1126 rtp_session_process_rb (RTPSession * sess, RTPSource * source,
1127 GstRTCPPacket * packet, RTPArrivalStats * arrival)
1131 count = gst_rtcp_packet_get_rb_count (packet);
1132 for (i = 0; i < count; i++) {
1133 guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
1134 guint8 fractionlost;
1137 gst_rtcp_packet_get_rb (packet, i, &ssrc, &fractionlost,
1138 &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
1140 GST_DEBUG ("RB %d: SSRC %08x, jitter %" G_GUINT32_FORMAT, i, ssrc, jitter);
1142 if (ssrc == sess->source->ssrc) {
1143 /* only deal with report blocks for our session, we update the stats of
1144 * the sender of the RTCP message. We could also compare our stats against
1145 * the other sender to see if we are better or worse. */
1146 rtp_source_process_rb (source, arrival->time, fractionlost, packetslost,
1147 exthighestseq, jitter, lsr, dlsr);
1149 on_ssrc_active (sess, source);
1154 /* A Sender report contains statistics about how the sender is doing. This
1155 * includes timing informataion such as the relation between RTP and NTP
1156 * timestamps and the number of packets/bytes it sent to us.
1158 * In this report is also included a set of report blocks related to how this
1159 * sender is receiving data (in case we (or somebody else) is also sending stuff
1160 * to it). This info includes the packet loss, jitter and seqnum. It also
1161 * contains information to calculate the round trip time (LSR/DLSR).
1164 rtp_session_process_sr (RTPSession * sess, GstRTCPPacket * packet,
1165 RTPArrivalStats * arrival)
1167 guint32 senderssrc, rtptime, packet_count, octet_count;
1170 gboolean created, prevsender;
1172 gst_rtcp_packet_sr_get_sender_info (packet, &senderssrc, &ntptime, &rtptime,
1173 &packet_count, &octet_count);
1175 GST_DEBUG ("got SR packet: SSRC %08x, time %" GST_TIME_FORMAT,
1176 senderssrc, GST_TIME_ARGS (arrival->time));
1178 source = obtain_source (sess, senderssrc, &created, arrival, FALSE);
1180 GST_BUFFER_OFFSET (packet->buffer) = source->clock_base;
1182 prevsender = RTP_SOURCE_IS_SENDER (source);
1184 /* first update the source */
1185 rtp_source_process_sr (source, arrival->time, ntptime, rtptime, packet_count,
1188 if (prevsender != RTP_SOURCE_IS_SENDER (source)) {
1189 sess->stats.sender_sources++;
1190 GST_DEBUG ("source: %08x became sender, %d sender sources", senderssrc,
1191 sess->stats.sender_sources);
1195 on_new_ssrc (sess, source);
1197 rtp_session_process_rb (sess, source, packet, arrival);
1200 /* A receiver report contains statistics about how a receiver is doing. It
1201 * includes stuff like packet loss, jitter and the seqnum it received last. It
1202 * also contains info to calculate the round trip time.
1204 * We are only interested in how the sender of this report is doing wrt to us.
1207 rtp_session_process_rr (RTPSession * sess, GstRTCPPacket * packet,
1208 RTPArrivalStats * arrival)
1214 senderssrc = gst_rtcp_packet_rr_get_ssrc (packet);
1216 GST_DEBUG ("got RR packet: SSRC %08x", senderssrc);
1218 source = obtain_source (sess, senderssrc, &created, arrival, FALSE);
1221 on_new_ssrc (sess, source);
1223 rtp_session_process_rb (sess, source, packet, arrival);
1226 /* Get SDES items and store them in the SSRC */
1228 rtp_session_process_sdes (RTPSession * sess, GstRTCPPacket * packet,
1229 RTPArrivalStats * arrival)
1232 gboolean more_items, more_entries;
1234 items = gst_rtcp_packet_sdes_get_item_count (packet);
1235 GST_DEBUG ("got SDES packet with %d items", items);
1237 more_items = gst_rtcp_packet_sdes_first_item (packet);
1239 while (more_items) {
1241 gboolean changed, created;
1244 ssrc = gst_rtcp_packet_sdes_get_ssrc (packet);
1246 GST_DEBUG ("item %d, SSRC %08x", i, ssrc);
1248 /* find src, no probation when dealing with RTCP */
1249 source = obtain_source (sess, ssrc, &created, arrival, FALSE);
1252 more_entries = gst_rtcp_packet_sdes_first_entry (packet);
1254 while (more_entries) {
1255 GstRTCPSDESType type;
1259 gst_rtcp_packet_sdes_get_entry (packet, &type, &len, &data);
1261 GST_DEBUG ("entry %d, type %d, len %d, data %.*s", j, type, len, len,
1264 changed |= rtp_source_set_sdes (source, type, data, len);
1266 more_entries = gst_rtcp_packet_sdes_next_entry (packet);
1271 on_new_ssrc (sess, source);
1273 on_ssrc_sdes (sess, source);
1275 more_items = gst_rtcp_packet_sdes_next_item (packet);
1280 /* BYE is sent when a client leaves the session
1283 rtp_session_process_bye (RTPSession * sess, GstRTCPPacket * packet,
1284 RTPArrivalStats * arrival)
1289 reason = gst_rtcp_packet_bye_get_reason (packet);
1290 GST_DEBUG ("got BYE packet (reason: %s)", GST_STR_NULL (reason));
1292 count = gst_rtcp_packet_bye_get_ssrc_count (packet);
1293 for (i = 0; i < count; i++) {
1296 gboolean created, prevactive, prevsender;
1297 guint pmembers, members;
1299 ssrc = gst_rtcp_packet_bye_get_nth_ssrc (packet, i);
1300 GST_DEBUG ("SSRC: %08x", ssrc);
1302 /* find src and mark bye, no probation when dealing with RTCP */
1303 source = obtain_source (sess, ssrc, &created, arrival, FALSE);
1305 /* store time for when we need to time out this source */
1306 source->bye_time = arrival->time;
1308 prevactive = RTP_SOURCE_IS_ACTIVE (source);
1309 prevsender = RTP_SOURCE_IS_SENDER (source);
1311 /* let the source handle the rest */
1312 rtp_source_process_bye (source, reason);
1314 pmembers = sess->stats.active_sources;
1316 if (prevactive && !RTP_SOURCE_IS_ACTIVE (source)) {
1317 sess->stats.active_sources--;
1318 GST_DEBUG ("source: %08x became inactive, %d active sources", ssrc,
1319 sess->stats.active_sources);
1321 if (prevsender && !RTP_SOURCE_IS_SENDER (source)) {
1322 sess->stats.sender_sources--;
1323 GST_DEBUG ("source: %08x became non sender, %d sender sources", ssrc,
1324 sess->stats.sender_sources);
1326 members = sess->stats.active_sources;
1328 if (!sess->source->received_bye && members < pmembers) {
1329 /* some members went away since the previous timeout estimate.
1330 * Perform reverse reconsideration but only when we are not scheduling a
1332 if (arrival->time < sess->next_rtcp_check_time) {
1333 GstClockTime time_remaining;
1335 time_remaining = sess->next_rtcp_check_time - arrival->time;
1336 sess->next_rtcp_check_time =
1337 gst_util_uint64_scale (time_remaining, members, pmembers);
1339 GST_DEBUG ("reverse reconsideration %" GST_TIME_FORMAT,
1340 GST_TIME_ARGS (sess->next_rtcp_check_time));
1342 sess->next_rtcp_check_time += arrival->time;
1344 /* notify app of reconsideration */
1345 if (sess->callbacks.reconsider)
1346 sess->callbacks.reconsider (sess, sess->user_data);
1351 on_new_ssrc (sess, source);
1353 on_bye_ssrc (sess, source);
1359 rtp_session_process_app (RTPSession * sess, GstRTCPPacket * packet,
1360 RTPArrivalStats * arrival)
1362 GST_DEBUG ("received APP");
1366 * rtp_session_process_rtcp:
1367 * @sess: and #RTPSession
1368 * @buffer: an RTCP buffer
1370 * Process an RTCP buffer in the session manager. This function takes ownership
1373 * Returns: a #GstFlowReturn.
1376 rtp_session_process_rtcp (RTPSession * sess, GstBuffer * buffer)
1378 GstRTCPPacket packet;
1379 gboolean more, is_bye = FALSE, is_sr = FALSE;
1380 RTPArrivalStats arrival;
1381 GstFlowReturn result = GST_FLOW_OK;
1383 g_return_val_if_fail (RTP_IS_SESSION (sess), GST_FLOW_ERROR);
1384 g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
1386 if (!gst_rtcp_buffer_validate (buffer))
1387 goto invalid_packet;
1389 GST_DEBUG ("received RTCP packet");
1391 RTP_SESSION_LOCK (sess);
1392 /* update arrival stats */
1393 update_arrival_stats (sess, &arrival, FALSE, buffer, -1);
1398 /* start processing the compound packet */
1399 more = gst_rtcp_buffer_get_first_packet (buffer, &packet);
1403 type = gst_rtcp_packet_get_type (&packet);
1405 /* when we are leaving the session, we should ignore all non-BYE messages */
1406 if (sess->source->received_bye && type != GST_RTCP_TYPE_BYE) {
1407 GST_DEBUG ("ignoring non-BYE RTCP packet because we are leaving");
1412 case GST_RTCP_TYPE_SR:
1413 rtp_session_process_sr (sess, &packet, &arrival);
1416 case GST_RTCP_TYPE_RR:
1417 rtp_session_process_rr (sess, &packet, &arrival);
1419 case GST_RTCP_TYPE_SDES:
1420 rtp_session_process_sdes (sess, &packet, &arrival);
1422 case GST_RTCP_TYPE_BYE:
1424 rtp_session_process_bye (sess, &packet, &arrival);
1426 case GST_RTCP_TYPE_APP:
1427 rtp_session_process_app (sess, &packet, &arrival);
1430 GST_WARNING ("got unknown RTCP packet");
1434 more = gst_rtcp_packet_move_to_next (&packet);
1437 /* if we are scheduling a BYE, we only want to count bye packets, else we
1438 * count everything */
1439 if (sess->source->received_bye) {
1441 sess->stats.bye_members++;
1442 UPDATE_AVG (sess->stats.avg_rtcp_packet_size, arrival.bytes);
1445 /* keep track of average packet size */
1446 UPDATE_AVG (sess->stats.avg_rtcp_packet_size, arrival.bytes);
1448 RTP_SESSION_UNLOCK (sess);
1450 /* notify caller of sr packets in the callback */
1451 if (is_sr && sess->callbacks.sync_rtcp)
1452 result = sess->callbacks.sync_rtcp (sess, sess->source, buffer,
1455 gst_buffer_unref (buffer);
1462 GST_DEBUG ("invalid RTCP packet received");
1463 gst_buffer_unref (buffer);
1468 gst_buffer_unref (buffer);
1469 RTP_SESSION_UNLOCK (sess);
1470 GST_DEBUG ("ignoring RTP packet because we left");
1476 * rtp_session_send_rtp:
1477 * @sess: an #RTPSession
1478 * @buffer: an RTP buffer
1479 * @ntpnstime: the NTP time in nanoseconds of when this buffer was captured.
1481 * Send the RTP buffer in the session manager. This function takes ownership of
1484 * Returns: a #GstFlowReturn.
1487 rtp_session_send_rtp (RTPSession * sess, GstBuffer * buffer, guint64 ntpnstime)
1489 GstFlowReturn result;
1491 gboolean prevsender;
1494 g_return_val_if_fail (RTP_IS_SESSION (sess), GST_FLOW_ERROR);
1495 g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
1497 if (!gst_rtp_buffer_validate (buffer))
1498 goto invalid_packet;
1500 GST_DEBUG ("received RTP packet for sending");
1502 RTP_SESSION_LOCK (sess);
1503 source = sess->source;
1505 /* update last activity */
1506 g_get_current_time (¤t);
1507 source->last_rtp_activity = GST_TIMEVAL_TO_TIME (current);
1509 prevsender = RTP_SOURCE_IS_SENDER (source);
1511 /* we use our own source to send */
1512 result = rtp_source_send_rtp (source, buffer, ntpnstime);
1514 if (RTP_SOURCE_IS_SENDER (source) && !prevsender)
1515 sess->stats.sender_sources++;
1516 RTP_SESSION_UNLOCK (sess);
1523 gst_buffer_unref (buffer);
1524 GST_DEBUG ("invalid RTP packet received");
1530 calculate_rtcp_interval (RTPSession * sess, gboolean deterministic,
1533 GstClockTime result;
1535 if (sess->source->received_bye) {
1536 result = rtp_stats_calculate_bye_interval (&sess->stats);
1538 result = rtp_stats_calculate_rtcp_interval (&sess->stats,
1539 RTP_SOURCE_IS_SENDER (sess->source), first);
1542 GST_DEBUG ("next deterministic interval: %" GST_TIME_FORMAT ", first %d",
1543 GST_TIME_ARGS (result), first);
1546 result = rtp_stats_add_rtcp_jitter (&sess->stats, result);
1548 GST_DEBUG ("next interval: %" GST_TIME_FORMAT, GST_TIME_ARGS (result));
1554 * rtp_session_send_bye:
1555 * @sess: an #RTPSession
1556 * @reason: a reason or NULL
1558 * Stop the current @sess and schedule a BYE message for the other members.
1560 * Returns: a #GstFlowReturn.
1563 rtp_session_send_bye (RTPSession * sess, const gchar * reason)
1565 GstFlowReturn result = GST_FLOW_OK;
1567 GstClockTime current, interval;
1570 g_return_val_if_fail (RTP_IS_SESSION (sess), GST_FLOW_ERROR);
1572 RTP_SESSION_LOCK (sess);
1573 source = sess->source;
1575 /* ignore more BYEs */
1576 if (source->received_bye)
1579 /* we have BYE now */
1580 source->received_bye = TRUE;
1581 /* at least one member wants to send a BYE */
1582 g_free (sess->bye_reason);
1583 sess->bye_reason = g_strdup (reason);
1584 sess->stats.avg_rtcp_packet_size = 100;
1585 sess->stats.bye_members = 1;
1586 sess->first_rtcp = TRUE;
1587 sess->sent_bye = FALSE;
1589 /* get current time */
1590 g_get_current_time (&curtv);
1591 current = GST_TIMEVAL_TO_TIME (curtv);
1593 /* reschedule transmission */
1594 sess->last_rtcp_send_time = current;
1595 interval = calculate_rtcp_interval (sess, FALSE, TRUE);
1596 sess->next_rtcp_check_time = current + interval;
1598 GST_DEBUG ("Schedule BYE for %" GST_TIME_FORMAT ", %" GST_TIME_FORMAT,
1599 GST_TIME_ARGS (interval), GST_TIME_ARGS (sess->next_rtcp_check_time));
1601 /* notify app of reconsideration */
1602 if (sess->callbacks.reconsider)
1603 sess->callbacks.reconsider (sess, sess->user_data);
1605 RTP_SESSION_UNLOCK (sess);
1611 * rtp_session_next_timeout:
1612 * @sess: an #RTPSession
1613 * @time: the current system time
1615 * Get the next time we should perform session maintenance tasks.
1617 * Returns: a time when rtp_session_on_timeout() should be called with the
1618 * current system time.
1621 rtp_session_next_timeout (RTPSession * sess, GstClockTime time)
1623 GstClockTime result;
1625 g_return_val_if_fail (RTP_IS_SESSION (sess), GST_FLOW_ERROR);
1627 RTP_SESSION_LOCK (sess);
1629 result = sess->next_rtcp_check_time;
1631 GST_DEBUG ("current time: %" GST_TIME_FORMAT ", next :%" GST_TIME_FORMAT,
1632 GST_TIME_ARGS (time), GST_TIME_ARGS (result));
1634 if (result < time) {
1635 GST_DEBUG ("take current time as base");
1636 /* our previous check time expired, start counting from the current time
1641 if (sess->source->received_bye) {
1642 if (sess->sent_bye) {
1643 GST_DEBUG ("we sent BYE already");
1644 result = GST_CLOCK_TIME_NONE;
1645 } else if (sess->stats.active_sources >= 50) {
1646 GST_DEBUG ("reconsider BYE, more than 50 sources");
1647 /* reconsider BYE if members >= 50 */
1648 result += calculate_rtcp_interval (sess, FALSE, TRUE);
1651 if (sess->first_rtcp) {
1652 GST_DEBUG ("first RTCP packet");
1653 /* we are called for the first time */
1654 result += calculate_rtcp_interval (sess, FALSE, TRUE);
1655 } else if (sess->next_rtcp_check_time < time) {
1656 GST_DEBUG ("old check time expired, getting new timeout");
1657 /* get a new timeout when we need to */
1658 result += calculate_rtcp_interval (sess, FALSE, FALSE);
1661 sess->next_rtcp_check_time = result;
1663 GST_DEBUG ("next timeout: %" GST_TIME_FORMAT, GST_TIME_ARGS (result));
1664 RTP_SESSION_UNLOCK (sess);
1675 GstClockTime interval;
1676 GstRTCPPacket packet;
1682 session_start_rtcp (RTPSession * sess, ReportData * data)
1684 GstRTCPPacket *packet = &data->packet;
1685 RTPSource *own = sess->source;
1687 data->rtcp = gst_rtcp_buffer_new (sess->mtu);
1689 if (RTP_SOURCE_IS_SENDER (own)) {
1692 guint32 packet_count, octet_count;
1694 /* we are a sender, create SR */
1695 GST_DEBUG ("create SR for SSRC %08x", own->ssrc);
1696 gst_rtcp_buffer_add_packet (data->rtcp, GST_RTCP_TYPE_SR, packet);
1698 /* get latest stats */
1699 rtp_source_get_new_sr (own, data->ntpnstime, &ntptime, &rtptime,
1700 &packet_count, &octet_count);
1702 rtp_source_process_sr (own, data->ntpnstime, ntptime, rtptime, packet_count,
1705 /* fill in sender report info */
1706 gst_rtcp_packet_sr_set_sender_info (packet, own->ssrc,
1707 ntptime, rtptime, packet_count, octet_count);
1709 /* we are only receiver, create RR */
1710 GST_DEBUG ("create RR for SSRC %08x", own->ssrc);
1711 gst_rtcp_buffer_add_packet (data->rtcp, GST_RTCP_TYPE_RR, packet);
1712 gst_rtcp_packet_rr_set_ssrc (packet, own->ssrc);
1716 /* construct a Sender or Receiver Report */
1718 session_report_blocks (const gchar * key, RTPSource * source, ReportData * data)
1720 RTPSession *sess = data->sess;
1721 GstRTCPPacket *packet = &data->packet;
1723 /* create a new buffer if needed */
1724 if (data->rtcp == NULL) {
1725 session_start_rtcp (sess, data);
1727 if (gst_rtcp_packet_get_rb_count (packet) < GST_RTCP_MAX_RB_COUNT) {
1728 /* only report about other sender sources */
1729 if (source != sess->source && RTP_SOURCE_IS_SENDER (source)) {
1730 guint8 fractionlost;
1732 guint32 exthighestseq, jitter;
1736 rtp_source_get_new_rb (source, data->time, &fractionlost, &packetslost,
1737 &exthighestseq, &jitter, &lsr, &dlsr);
1739 /* packet is not yet filled, add report block for this source. */
1740 gst_rtcp_packet_add_rb (packet, source->ssrc, fractionlost, packetslost,
1741 exthighestseq, jitter, lsr, dlsr);
1746 /* perform cleanup of sources that timed out */
1748 session_cleanup (const gchar * key, RTPSource * source, ReportData * data)
1750 gboolean remove = FALSE;
1751 gboolean byetimeout = FALSE;
1752 gboolean is_sender, is_active;
1753 RTPSession *sess = data->sess;
1754 GstClockTime interval;
1756 is_sender = RTP_SOURCE_IS_SENDER (source);
1757 is_active = RTP_SOURCE_IS_ACTIVE (source);
1759 /* check for our own source, we don't want to delete our own source. */
1760 if (!(source == sess->source)) {
1761 if (source->received_bye) {
1762 /* if we received a BYE from the source, remove the source after some
1764 if (data->time > source->bye_time &&
1765 data->time - source->bye_time > sess->stats.bye_timeout) {
1766 GST_DEBUG ("removing BYE source %08x", source->ssrc);
1771 /* sources that were inactive for more than 5 times the deterministic reporting
1772 * interval get timed out. the min timeout is 5 seconds. */
1773 if (data->time > source->last_activity) {
1774 interval = MAX (data->interval * 5, 5 * GST_SECOND);
1775 if (data->time - source->last_activity > interval) {
1776 GST_DEBUG ("removing timeout source %08x, last %" GST_TIME_FORMAT,
1777 source->ssrc, GST_TIME_ARGS (source->last_activity));
1783 /* senders that did not send for a long time become a receiver, this also
1784 * holds for our own source. */
1786 if (data->time > source->last_rtp_activity) {
1787 interval = MAX (data->interval * 2, 5 * GST_SECOND);
1788 if (data->time - source->last_rtp_activity > interval) {
1789 GST_DEBUG ("sender source %08x timed out and became receiver, last %"
1790 GST_TIME_FORMAT, source->ssrc,
1791 GST_TIME_ARGS (source->last_rtp_activity));
1792 source->is_sender = FALSE;
1793 sess->stats.sender_sources--;
1799 sess->total_sources--;
1801 sess->stats.sender_sources--;
1803 sess->stats.active_sources--;
1806 on_bye_timeout (sess, source);
1808 on_timeout (sess, source);
1814 session_sdes (RTPSession * sess, ReportData * data)
1816 GstRTCPPacket *packet = &data->packet;
1820 /* add SDES packet */
1821 gst_rtcp_buffer_add_packet (data->rtcp, GST_RTCP_TYPE_SDES, packet);
1823 gst_rtcp_packet_sdes_add_item (packet, sess->source->ssrc);
1825 rtp_source_get_sdes (sess->source, GST_RTCP_SDES_CNAME, &sdes_data,
1827 gst_rtcp_packet_sdes_add_entry (packet, GST_RTCP_SDES_CNAME, sdes_len,
1830 /* other SDES items must only be added at regular intervals and only when the
1831 * user requests to since it might be a privacy problem */
1833 gst_rtcp_packet_sdes_add_entry (&packet, GST_RTCP_SDES_NAME,
1834 strlen (sess->name), (guint8 *) sess->name);
1835 gst_rtcp_packet_sdes_add_entry (&packet, GST_RTCP_SDES_TOOL,
1836 strlen (sess->tool), (guint8 *) sess->tool);
1839 data->has_sdes = TRUE;
1842 /* schedule a BYE packet */
1844 session_bye (RTPSession * sess, ReportData * data)
1846 GstRTCPPacket *packet = &data->packet;
1849 session_start_rtcp (sess, data);
1852 session_sdes (sess, data);
1854 /* add a BYE packet */
1855 gst_rtcp_buffer_add_packet (data->rtcp, GST_RTCP_TYPE_BYE, packet);
1856 gst_rtcp_packet_bye_add_ssrc (packet, sess->source->ssrc);
1857 if (sess->bye_reason)
1858 gst_rtcp_packet_bye_set_reason (packet, sess->bye_reason);
1860 /* we have a BYE packet now */
1861 data->is_bye = TRUE;
1865 is_rtcp_time (RTPSession * sess, GstClockTime time, ReportData * data)
1867 GstClockTime new_send_time, elapsed;
1870 /* no need to check yet */
1871 if (sess->next_rtcp_check_time > time) {
1872 GST_DEBUG ("no check time yet, next %" GST_TIME_FORMAT " > now %"
1873 GST_TIME_FORMAT, GST_TIME_ARGS (sess->next_rtcp_check_time),
1874 GST_TIME_ARGS (time));
1878 /* get elapsed time since we last reported */
1879 elapsed = time - sess->last_rtcp_send_time;
1881 /* perform forward reconsideration */
1882 new_send_time = rtp_stats_add_rtcp_jitter (&sess->stats, data->interval);
1884 GST_DEBUG ("forward reconsideration %" GST_TIME_FORMAT ", elapsed %"
1885 GST_TIME_FORMAT, GST_TIME_ARGS (new_send_time), GST_TIME_ARGS (elapsed));
1887 new_send_time += sess->last_rtcp_send_time;
1889 /* check if reconsideration */
1890 if (time < new_send_time) {
1891 GST_DEBUG ("reconsider RTCP for %" GST_TIME_FORMAT,
1892 GST_TIME_ARGS (new_send_time));
1894 /* store new check time */
1895 sess->next_rtcp_check_time = new_send_time;
1898 new_send_time = calculate_rtcp_interval (sess, FALSE, FALSE);
1900 GST_DEBUG ("can send RTCP now, next interval %" GST_TIME_FORMAT,
1901 GST_TIME_ARGS (new_send_time));
1902 sess->next_rtcp_check_time = time + new_send_time;
1908 * rtp_session_on_timeout:
1909 * @sess: an #RTPSession
1910 * @time: the current system time
1911 * @ntpnstime: the current NTP time in nanoseconds
1913 * Perform maintenance actions after the timeout obtained with
1914 * rtp_session_next_timeout() expired.
1916 * This function will perform timeouts of receivers and senders, send a BYE
1917 * packet or generate RTCP packets with current session stats.
1919 * This function can call the #RTPSessionSendRTCP callback, possibly multiple
1920 * times, for each packet that should be processed.
1922 * Returns: a #GstFlowReturn.
1925 rtp_session_on_timeout (RTPSession * sess, GstClockTime time, guint64 ntpnstime)
1927 GstFlowReturn result = GST_FLOW_OK;
1930 g_return_val_if_fail (RTP_IS_SESSION (sess), GST_FLOW_ERROR);
1932 GST_DEBUG ("reporting at %" GST_TIME_FORMAT ", NTP time %" GST_TIME_FORMAT,
1933 GST_TIME_ARGS (time), GST_TIME_ARGS (ntpnstime));
1938 data.ntpnstime = ntpnstime;
1939 data.is_bye = FALSE;
1940 data.has_sdes = FALSE;
1942 RTP_SESSION_LOCK (sess);
1943 /* get a new interval, we need this for various cleanups etc */
1944 data.interval = calculate_rtcp_interval (sess, TRUE, sess->first_rtcp);
1946 /* first perform cleanups */
1947 g_hash_table_foreach_remove (sess->ssrcs[sess->mask_idx],
1948 (GHRFunc) session_cleanup, &data);
1950 /* see if we need to generate SR or RR packets */
1951 if (is_rtcp_time (sess, time, &data)) {
1952 if (sess->source->received_bye) {
1953 /* generate BYE instead */
1954 session_bye (sess, &data);
1955 sess->sent_bye = TRUE;
1957 /* loop over all known sources and do something */
1958 g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
1959 (GHFunc) session_report_blocks, &data);
1966 /* we keep track of the last report time in order to timeout inactive
1967 * receivers or senders */
1968 sess->last_rtcp_send_time = data.time;
1969 sess->first_rtcp = FALSE;
1971 /* add SDES for this source when not already added */
1973 session_sdes (sess, &data);
1975 /* update average RTCP size before sending */
1976 size = GST_BUFFER_SIZE (data.rtcp) + sess->header_len;
1977 UPDATE_AVG (sess->stats.avg_rtcp_packet_size, size);
1979 RTP_SESSION_UNLOCK (sess);
1981 /* push out the RTCP packet */
1983 /* close the RTCP packet */
1984 gst_rtcp_buffer_end (data.rtcp);
1986 if (sess->callbacks.send_rtcp)
1987 result = sess->callbacks.send_rtcp (sess, sess->source, data.rtcp,
1990 gst_buffer_unref (data.rtcp);