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.
This commit is contained in:
Wim Taymans 2007-08-29 01:22:43 +00:00
parent c0a64d008a
commit 9f597336b5
7 changed files with 165 additions and 8 deletions

View file

@ -1,3 +1,23 @@
2007-08-28 Wim Taymans <wim.taymans@gmail.com>
* 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.
2007-08-28 Wim Taymans <wim.taymans@gmail.com>
* gst/rtpmanager/gstrtpbin.c: (gst_rtp_bin_clear_pt_map):

View file

@ -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.
*/

View file

@ -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;

View file

@ -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,

View file

@ -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);

View file

@ -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);

View file

@ -139,6 +139,8 @@ struct _RTPSource {
GstClockTime bye_time;
GstClockTime last_activity;
GstClockTime last_rtp_activity;
GstClockTime last_timestamp;
GstClockTime last_rtptime;
GQueue *packets;