mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
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:
parent
eb86865a62
commit
325dac0fc2
6 changed files with 145 additions and 8 deletions
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -139,6 +139,8 @@ struct _RTPSource {
|
|||
GstClockTime bye_time;
|
||||
GstClockTime last_activity;
|
||||
GstClockTime last_rtp_activity;
|
||||
GstClockTime last_timestamp;
|
||||
GstClockTime last_rtptime;
|
||||
|
||||
GQueue *packets;
|
||||
|
||||
|
|
Loading…
Reference in a new issue