SIGNAL_ON_FEEDBACK_RTCP,
SIGNAL_SEND_RTCP,
SIGNAL_SEND_RTCP_FULL,
+ SIGNAL_ON_RECEIVING_RTCP,
LAST_SIGNAL
};
#define DEFAULT_INTERNAL_SOURCE NULL
-#define DEFAULT_BANDWIDTH RTP_STATS_BANDWIDTH
-#define DEFAULT_RTCP_FRACTION (RTP_STATS_RTCP_FRACTION * RTP_STATS_BANDWIDTH)
+#define DEFAULT_BANDWIDTH 0.0
+#define DEFAULT_RTCP_FRACTION RTP_STATS_RTCP_FRACTION
#define DEFAULT_RTCP_RR_BANDWIDTH -1
#define DEFAULT_RTCP_RS_BANDWIDTH -1
#define DEFAULT_RTCP_MTU 1400
PROP_RTCP_FEEDBACK_RETENTION_WINDOW,
PROP_RTCP_IMMEDIATE_FEEDBACK_THRESHOLD,
PROP_PROBATION,
- PROP_STATS,
- PROP_LAST
+ PROP_STATS
};
/* update average packet size */
G_STRUCT_OFFSET (RTPSessionClass, send_rtcp), NULL, NULL,
g_cclosure_marshal_generic, G_TYPE_BOOLEAN, 1, G_TYPE_UINT64);
+ /**
+ * RTPSession::on-receiving-rtcp
+ * @session: the object which received the signal
+ * @buffer: the #GstBuffer containing the RTCP packet that was received
+ *
+ * This signal is emitted when receiving an RTCP packet before it is handled
+ * by the session. It can be used to extract custom information from RTCP packets.
+ *
+ * Since: 1.6
+ */
+ rtp_session_signals[SIGNAL_ON_RECEIVING_RTCP] =
+ g_signal_new ("on-receiving-rtcp", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (RTPSessionClass, on_receiving_rtcp),
+ NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 1,
+ GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE);
+
g_object_class_install_property (gobject_class, PROP_INTERNAL_SSRC,
g_param_spec_uint ("internal-ssrc", "Internal SSRC",
"The internal SSRC used for the session (deprecated)",
sess->mask_idx = 0;
sess->mask = 0;
- for (i = 0; i < 32; i++) {
+ /* TODO: We currently only use the first hash table but this is the
+ * beginning of an implementation for RFC2762
+ for (i = 0; i < 32; i++) {
+ */
+ for (i = 0; i < 1; i++) {
sess->ssrcs[i] =
g_hash_table_new_full (NULL, NULL, NULL,
(GDestroyNotify) g_object_unref);
sess->first_rtcp = TRUE;
sess->next_rtcp_check_time = GST_CLOCK_TIME_NONE;
+ sess->last_rtcp_send_time = GST_CLOCK_TIME_NONE;
sess->allow_early = TRUE;
sess->next_early_rtcp_time = GST_CLOCK_TIME_NONE;
g_list_free_full (sess->conflicting_addresses,
(GDestroyNotify) rtp_conflicting_address_free);
- for (i = 0; i < 32; i++)
+ /* TODO: Change this again when implementing RFC 2762
+ * for (i = 0; i < 32; i++)
+ */
+ for (i = 0; i < 1; i++)
g_hash_table_destroy (sess->ssrcs[i]);
g_mutex_clear (&sess->lock);
"RTT (%" GST_TIME_FORMAT " < %" GST_TIME_FORMAT ")",
fir ? "FIR" : "PLI",
GST_TIME_ARGS (current_time - sess->last_keyframe_request),
- GST_TIME_ARGS (round_trip_in_ns));;
+ GST_TIME_ARGS (round_trip_in_ns));
return FALSE;
}
}
return;
rtp_session_request_local_key_unit (sess, src, FALSE, current_time);
+
+ src->stats.recv_pli_count++;
}
static void
return;
rtp_session_request_local_key_unit (sess, src, TRUE, current_time);
+ src->stats.recv_fir_count++;
}
static void
GST_DEBUG ("received RTCP packet");
+ g_signal_emit (sess, rtp_session_signals[SIGNAL_ON_RECEIVING_RTCP], 0,
+ buffer);
+
RTP_SESSION_LOCK (sess);
/* update pinfo stats */
update_packet_info (sess, &pinfo, FALSE, FALSE, FALSE, buffer, current_time,
rtp_source_update_caps (source, caps);
g_object_unref (source);
}
+
+ if (gst_structure_get_uint (s, "rtx-ssrc", &ssrc)) {
+ source =
+ obtain_internal_source (sess, ssrc, &created, GST_CLOCK_TIME_NONE);
+ if (source) {
+ rtp_source_update_caps (source, caps);
+ g_object_unref (source);
+ }
+ }
RTP_SESSION_UNLOCK (sess);
}
}
g_hash_table_foreach (sess->ssrcs[sess->mask_idx],
(GHFunc) add_bitrates, &bandwidth);
- bandwidth /= 8.0;
}
- if (bandwidth < 8000)
+ if (bandwidth < RTP_STATS_BANDWIDTH)
bandwidth = RTP_STATS_BANDWIDTH;
rtp_stats_set_bandwidths (&sess->stats, bandwidth,
fci_data[1] = fci_data[2] = fci_data[3] = 0;
source->send_fir = FALSE;
+ source->stats.sent_fir_count++;
}
static void
source->send_pli = FALSE;
data->may_suppress = FALSE;
+
+ source->stats.sent_pli_count++;
}
/* construct NACK */
static gboolean
is_rtcp_time (RTPSession * sess, GstClockTime current_time, ReportData * data)
{
- GstClockTime new_send_time, elapsed;
+ GstClockTime new_send_time;
GstClockTime interval;
RTPSessionStats *stats;
}
early:
- /* get elapsed time since we last reported */
- elapsed = current_time - sess->last_rtcp_send_time;
/* take interval and add jitter */
interval = data->interval;
if (interval != GST_CLOCK_TIME_NONE)
interval = rtp_stats_add_rtcp_jitter (stats, interval);
- /* perform forward reconsideration */
- if (interval != GST_CLOCK_TIME_NONE) {
- GST_DEBUG ("forward reconsideration %" GST_TIME_FORMAT ", elapsed %"
- GST_TIME_FORMAT, GST_TIME_ARGS (interval), GST_TIME_ARGS (elapsed));
- new_send_time = interval + sess->last_rtcp_send_time;
+ if (sess->last_rtcp_send_time != GST_CLOCK_TIME_NONE) {
+ /* perform forward reconsideration */
+ if (interval != GST_CLOCK_TIME_NONE) {
+ GstClockTime elapsed;
+
+ /* get elapsed time since we last reported */
+ elapsed = current_time - sess->last_rtcp_send_time;
+
+ GST_DEBUG ("forward reconsideration %" GST_TIME_FORMAT ", elapsed %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (interval), GST_TIME_ARGS (elapsed));
+ new_send_time = interval + sess->last_rtcp_send_time;
+ } else {
+ new_send_time = sess->last_rtcp_send_time;
+ }
} else {
- new_send_time = sess->last_rtcp_send_time;
+ /* If this is the first RTCP packet, we can reconsider anything based
+ * on the last RTCP send time because there was none.
+ */
+ g_warn_if_fail (!data->is_early);
+ data->is_early = FALSE;
+ new_send_time = current_time;
}
if (!data->is_early) {
goto end;
}
+ /* RFC 4585 section 3.5.3 step 1
+ * If no regular RTCP packet has been sent before, then a regular
+ * RTCP packet has to be scheduled first and FB messages might be
+ * included there
+ */
+ if (!GST_CLOCK_TIME_IS_VALID (sess->last_rtcp_send_time)) {
+ GST_LOG_OBJECT (sess, "no RTCP sent yet");
+
+ if (current_time + max_delay > sess->next_rtcp_check_time) {
+ GST_LOG_OBJECT (sess,
+ "next scheduled time is soon %" GST_TIME_FORMAT " + %" GST_TIME_FORMAT
+ " > %" GST_TIME_FORMAT, GST_TIME_ARGS (current_time),
+ GST_TIME_ARGS (max_delay),
+ GST_TIME_ARGS (sess->next_rtcp_check_time));
+ ret = TRUE;
+ } else {
+ GST_LOG_OBJECT (sess,
+ "can't allow early feedback, next scheduled time is too late %"
+ GST_TIME_FORMAT " + %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (current_time), GST_TIME_ARGS (max_delay),
+ GST_TIME_ARGS (sess->next_rtcp_check_time));
+ ret = FALSE;
+ }
+ goto end;
+ }
+
T_rr = sess->next_rtcp_check_time - sess->last_rtcp_send_time;
/* RFC 4585 section 3.5.2 step 2b */
/* RFC 4585 section 3.5.2 step 3 */
if (current_time + T_dither_max > sess->next_rtcp_check_time) {
- GST_LOG_OBJECT (sess, "don't send because of dither");
- ret = FALSE;
+ GST_LOG_OBJECT (sess,
+ "don't send because of dither, next scheduled time is soon %"
+ GST_TIME_FORMAT " + %" GST_TIME_FORMAT " > %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (current_time), GST_TIME_ARGS (T_dither_max),
+ GST_TIME_ARGS (sess->next_rtcp_check_time));
+ ret = TRUE;
goto end;
}
GST_TIME_ARGS (sess->next_rtcp_check_time));
ret = TRUE;
} else {
- GST_LOG_OBJECT (sess, "can't allow early feedback");
+ GST_LOG_OBJECT (sess,
+ "can't allow early feedback, next scheduled time is too late %"
+ GST_TIME_FORMAT " + %" GST_TIME_FORMAT " < %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (current_time), GST_TIME_ARGS (max_delay),
+ GST_TIME_ARGS (sess->next_rtcp_check_time));
ret = FALSE;
}
goto end;
sess->next_rtcp_check_time = sess->last_rtcp_send_time + 2 * T_rr;
sess->last_rtcp_send_time += T_rr;
- GST_LOG_OBJECT (sess, "next early RTCP time %" GST_TIME_FORMAT,
- GST_TIME_ARGS (sess->next_early_rtcp_time));
+ GST_LOG_OBJECT (sess, "next early RTCP time %" GST_TIME_FORMAT
+ ", next regular RTCP time %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (sess->next_early_rtcp_time),
+ GST_TIME_ARGS (sess->next_rtcp_check_time));
RTP_SESSION_UNLOCK (sess);
/* notify app of need to send packet early