summaryrefslogtreecommitdiffstats
path: root/gst
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@gmail.com>2007-08-29 01:22:43 +0000
committerWim Taymans <wim.taymans@gmail.com>2007-08-29 01:22:43 +0000
commit9f597336b57f7b4afc44ca2826da75eebeb7039c (patch)
tree6e28b43d055a003085f8c572a362ccd539d20499 /gst
parentc0a64d008a0b8cc4416039935e4fbc4a7da3931d (diff)
downloadgst-plugins-bad-9f597336b57f7b4afc44ca2826da75eebeb7039c.tar.gz
gst-plugins-bad-9f597336b57f7b4afc44ca2826da75eebeb7039c.tar.bz2
gst-plugins-bad-9f597336b57f7b4afc44ca2826da75eebeb7039c.zip
gst/rtpmanager/gstrtpsession.*: Distribute synchronisation parameters to the session manager so that it can generate ...
Original commit message from CVS: * gst/rtpmanager/gstrtpsession.c: (stop_rtcp_thread), (gst_rtp_session_change_state), (gst_rtp_session_event_send_rtp_sink): * gst/rtpmanager/gstrtpsession.h: Distribute synchronisation parameters to the session manager so that it can generate correct SR packets for lip-sync. * gst/rtpmanager/rtpsession.c: (rtp_session_set_base_time), (rtp_session_set_timestamp_sync), (session_start_rtcp): * gst/rtpmanager/rtpsession.h: Add methods for setting sync parameters. Set correct RTP time in SR packets using the sync params. * gst/rtpmanager/rtpsource.c: (rtp_source_send_rtp): * gst/rtpmanager/rtpsource.h: Record last RTP <-> GST timestamp so that we can use them to convert NTP to RTP timestamps in SR packets.
Diffstat (limited to 'gst')
-rw-r--r--gst/rtpmanager/gstrtpsession.c46
-rw-r--r--gst/rtpmanager/gstrtpsession.h1
-rw-r--r--gst/rtpmanager/rtpsession.c78
-rw-r--r--gst/rtpmanager/rtpsession.h7
-rw-r--r--gst/rtpmanager/rtpsource.c19
-rw-r--r--gst/rtpmanager/rtpsource.h2
6 files changed, 145 insertions, 8 deletions
diff --git a/gst/rtpmanager/gstrtpsession.c b/gst/rtpmanager/gstrtpsession.c
index 7f5782be..554422fc 100644
--- a/gst/rtpmanager/gstrtpsession.c
+++ b/gst/rtpmanager/gstrtpsession.c
@@ -648,8 +648,10 @@ gst_rtp_session_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn res;
GstRtpSession *rtpsession;
+ GstRtpSessionPrivate *priv;
rtpsession = GST_RTP_SESSION (element);
+ priv = rtpsession->priv;
switch (transition) {
case GST_STATE_CHANGE_NULL_TO_READY:
@@ -660,6 +662,7 @@ gst_rtp_session_change_state (GstElement * element, GstStateChange transition)
break;
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
stop_rtcp_thread (rtpsession);
+ break;
default:
break;
}
@@ -668,9 +671,17 @@ gst_rtp_session_change_state (GstElement * element, GstStateChange transition)
switch (transition) {
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+ {
+ GstClockTime base_time;
+
+ base_time = GST_ELEMENT_CAST (rtpsession)->base_time;
+
+ rtp_session_set_base_time (priv->session, base_time);
+
if (!start_rtcp_thread (rtpsession))
goto failed_thread;
break;
+ }
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
break;
case GST_STATE_CHANGE_PAUSED_TO_READY:
@@ -960,6 +971,40 @@ gst_rtp_session_event_send_rtp_sink (GstPad * pad, GstEvent * event)
GST_DEBUG_OBJECT (rtpsession, "received event");
switch (GST_EVENT_TYPE (event)) {
+ case GST_EVENT_NEWSEGMENT:
+ {
+ gboolean update;
+ gdouble rate, arate;
+ GstFormat format;
+ gint64 start, stop, time;
+ GstSegment *segment;
+
+ segment = &rtpsession->send_rtp_seg;
+
+ /* the newsegment event is needed to convert the RTP timestamp to
+ * running_time, which is needed to generate a mapping from RTP to NTP
+ * timestamps in SR reports */
+ gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
+ &start, &stop, &time);
+
+ GST_DEBUG_OBJECT (rtpsession,
+ "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "
+ "format GST_FORMAT_TIME, "
+ "%" GST_TIME_FORMAT " -- %" GST_TIME_FORMAT
+ ", time %" GST_TIME_FORMAT ", accum %" GST_TIME_FORMAT,
+ update, rate, arate, GST_TIME_ARGS (segment->start),
+ GST_TIME_ARGS (segment->stop), GST_TIME_ARGS (segment->time),
+ GST_TIME_ARGS (segment->accum));
+
+ gst_segment_set_newsegment_full (segment, update, rate,
+ arate, format, start, stop, time);
+
+ rtp_session_set_timestamp_sync (priv->session, start);
+
+ /* push event forward */
+ ret = gst_pad_push_event (rtpsession->send_rtp_src, event);
+ break;
+ }
default:
ret = gst_pad_push_event (rtpsession->send_rtp_src, event);
break;
@@ -991,7 +1036,6 @@ gst_rtp_session_chain_send_rtp (GstPad * pad, GstBuffer * buffer)
return ret;
}
-
/* Create sinkpad to receive RTP packets from senders. This will also create a
* srcpad for the RTP packets.
*/
diff --git a/gst/rtpmanager/gstrtpsession.h b/gst/rtpmanager/gstrtpsession.h
index 87f8ea7a..09565ac1 100644
--- a/gst/rtpmanager/gstrtpsession.h
+++ b/gst/rtpmanager/gstrtpsession.h
@@ -45,6 +45,7 @@ struct _GstRtpSession {
GstPad *recv_rtp_sink;
GstPad *recv_rtcp_sink;
GstPad *send_rtp_sink;
+ GstSegment send_rtp_seg;
GstPad *recv_rtp_src;
GstPad *sync_src;
diff --git a/gst/rtpmanager/rtpsession.c b/gst/rtpmanager/rtpsession.c
index 6fa478c8..275e7c74 100644
--- a/gst/rtpmanager/rtpsession.c
+++ b/gst/rtpmanager/rtpsession.c
@@ -1048,8 +1048,8 @@ ignore:
}
/* A Sender report contains statistics about how the sender is doing. This
- * includes timing informataion about the relation between RTP and NTP
- * timestamps is it using and the number of packets/bytes it sent to us.
+ * includes timing informataion such as the relation between RTP and NTP
+ * timestamps and the number of packets/bytes it sent to us.
*
* In this report is also included a set of report blocks related to how this
* sender is receiving data (in case we (or somebody else) is also sending stuff
@@ -1429,6 +1429,36 @@ invalid_packet:
}
}
+/**
+ * rtp_session_set_send_sync
+ * @sess: an #RTPSession
+ * @base_time: the clock base time
+ * @start_time: the timestamp start time
+ *
+ * Establish a relation between the times returned by the get_time callback and
+ * the buffer timestamps. This information is used to convert the NTP times to
+ * RTP timestamps.
+ */
+void
+rtp_session_set_base_time (RTPSession * sess, GstClockTime base_time)
+{
+ g_return_if_fail (RTP_IS_SESSION (sess));
+
+ RTP_SESSION_LOCK (sess);
+ sess->base_time = base_time;
+ RTP_SESSION_UNLOCK (sess);
+}
+
+void
+rtp_session_set_timestamp_sync (RTPSession * sess, GstClockTime start_timestamp)
+{
+ g_return_if_fail (RTP_IS_SESSION (sess));
+
+ RTP_SESSION_LOCK (sess);
+ sess->start_timestamp = start_timestamp;
+ RTP_SESSION_UNLOCK (sess);
+}
+
static GstClockTime
calculate_rtcp_interval (RTPSession * sess, gboolean deterministic,
gboolean first)
@@ -1575,16 +1605,56 @@ session_start_rtcp (RTPSession * sess, ReportData * data)
if (RTP_SOURCE_IS_SENDER (own)) {
guint64 ntptime;
guint32 rtptime;
+ GstClockTime running_time;
+ GstClockTimeDiff diff;
/* we are a sender, create SR */
GST_DEBUG ("create SR for SSRC %08x", own->ssrc);
gst_rtcp_buffer_add_packet (data->rtcp, GST_RTCP_TYPE_SR, packet);
- /* convert clock time to NTP time */
+ /* use the sync params to interpollate the date->time member to rtptime. We
+ * use the last sent timestamp and rtptime as reference points. We assume
+ * that the slope of the rtptime vs timestamp curve is 1, which is certainly
+ * sufficient for the frequency at which we report SR and the rate we send
+ * out RTP packets. */
+ rtptime = own->last_rtptime;
+ GST_DEBUG ("last_timestamp %" GST_TIME_FORMAT ", last_rtptime %"
+ G_GUINT32_FORMAT, GST_TIME_ARGS (own->last_timestamp), rtptime);
+
+ if (own->clock_rate != -1) {
+ /* Start by calculating the running_time of the timestamp, this is a result
+ * in nanoseconds. */
+ running_time =
+ (own->last_timestamp - sess->start_timestamp) + sess->base_time;
+
+ /* get the diff with the SR time */
+ diff = GST_CLOCK_DIFF (running_time, data->time);
+
+ /* now translate the diff to RTP time, handle positive and negative cases.
+ * If there is no diff, we already set rtptime correctly above. */
+ if (diff > 0) {
+ GST_DEBUG ("running_time %" GST_TIME_FORMAT ", diff %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (running_time), GST_TIME_ARGS (diff));
+ rtptime += gst_util_uint64_scale (diff, own->clock_rate, GST_SECOND);
+ } else {
+ diff = -diff;
+ GST_DEBUG ("running_time %" GST_TIME_FORMAT ", diff -%" GST_TIME_FORMAT,
+ GST_TIME_ARGS (running_time), GST_TIME_ARGS (diff));
+ rtptime -= gst_util_uint64_scale (diff, own->clock_rate, GST_SECOND);
+ }
+ } else {
+ GST_WARNING ("no clock-rate, cannot interpollate rtp time");
+ }
+
+ /* convert clock time to NTP time. upper 32 bits should contain the seconds
+ * and the lower 32 bits, the fractions of a second. */
ntptime = gst_util_uint64_scale (data->time, (1LL << 32), GST_SECOND);
+ /* conversion from unix timestamp (seconds since 1970) to NTP (seconds
+ * since 1900). FIXME nothing says that the time is in unix timestamps. */
ntptime += (2208988800LL << 32);
- rtptime = 0;
+ GST_DEBUG ("NTP %08x:%08x, RTP %" G_GUINT32_FORMAT,
+ (guint32) (ntptime >> 32), (guint32) (ntptime & 0xffffffff), rtptime);
/* fill in sender report info, FIXME RTP timestamps missing */
gst_rtcp_packet_sr_set_sender_info (packet, own->ssrc,
diff --git a/gst/rtpmanager/rtpsession.h b/gst/rtpmanager/rtpsession.h
index 9082d9d2..9380b55e 100644
--- a/gst/rtpmanager/rtpsession.h
+++ b/gst/rtpmanager/rtpsession.h
@@ -189,6 +189,10 @@ struct _RTPSession {
gpointer user_data;
RTPSessionStats stats;
+
+ /* for mapping RTP time to NTP time */
+ GstClockTime start_timestamp;
+ GstClockTime base_time;
};
/**
@@ -251,7 +255,8 @@ GstFlowReturn rtp_session_process_rtcp (RTPSession *sess, GstBuffer
/* processing packets for sending */
GstFlowReturn rtp_session_send_rtp (RTPSession *sess, GstBuffer *buffer);
-
+void rtp_session_set_base_time (RTPSession *sess, GstClockTime base_time);
+void rtp_session_set_timestamp_sync (RTPSession *sess, GstClockTime start_timestamp);
/* stopping the session */
GstFlowReturn rtp_session_send_bye (RTPSession *sess, const gchar *reason);
diff --git a/gst/rtpmanager/rtpsource.c b/gst/rtpmanager/rtpsource.c
index 1a989517..ad491bd0 100644
--- a/gst/rtpmanager/rtpsource.c
+++ b/gst/rtpmanager/rtpsource.c
@@ -456,6 +456,7 @@ rtp_source_send_rtp (RTPSource * src, GstBuffer * buffer)
{
GstFlowReturn result = GST_FLOW_OK;
guint len;
+ GstClockTime timestamp;
g_return_val_if_fail (RTP_IS_SOURCE (src), GST_FLOW_ERROR);
g_return_val_if_fail (GST_IS_BUFFER (buffer), GST_FLOW_ERROR);
@@ -469,18 +470,32 @@ rtp_source_send_rtp (RTPSource * src, GstBuffer * buffer)
src->stats.packets_sent++;
src->stats.octets_sent += len;
+ /* we keep track of the last received RTP timestamp and the corresponding
+ * GStreamer timestamp so that we can convert NTP time to RTP time when
+ * sending SR reports */
+ src->last_rtptime = gst_rtp_buffer_get_timestamp (buffer);
+
+ /* the timestamp can be undefined, in that case we use any previously
+ * received timestamp */
+ timestamp = GST_BUFFER_TIMESTAMP (buffer);
+ if (timestamp != -1)
+ src->last_timestamp = timestamp;
+
/* push packet */
if (src->callbacks.push_rtp) {
guint32 ssrc;
ssrc = gst_rtp_buffer_get_ssrc (buffer);
if (ssrc != src->ssrc) {
- GST_DEBUG ("updating SSRC from %u to %u", ssrc, src->ssrc);
+ /* the SSRC of the packet is not correct, make a writable buffer and
+ * update the SSRC. This could involve a complete copy of the packet when
+ * it is not writable. Usually the payloader will use caps negotiation to
+ * get the correct SSRC. */
buffer = gst_buffer_make_writable (buffer);
+ GST_DEBUG ("updating SSRC from %u to %u", ssrc, src->ssrc);
gst_rtp_buffer_set_ssrc (buffer, src->ssrc);
}
-
GST_DEBUG ("pushing RTP packet %" G_GUINT64_FORMAT,
src->stats.packets_sent);
result = src->callbacks.push_rtp (src, buffer, src->user_data);
diff --git a/gst/rtpmanager/rtpsource.h b/gst/rtpmanager/rtpsource.h
index 0df03f4f..7920b6f4 100644
--- a/gst/rtpmanager/rtpsource.h
+++ b/gst/rtpmanager/rtpsource.h
@@ -139,6 +139,8 @@ struct _RTPSource {
GstClockTime bye_time;
GstClockTime last_activity;
GstClockTime last_rtp_activity;
+ GstClockTime last_timestamp;
+ GstClockTime last_rtptime;
GQueue *packets;