Commit 83cb1aec authored by Wim Taymans's avatar Wim Taymans Committed by Wim Taymans
Browse files

rtpbin: change how NTP time is calculated in RTCP

Don't calculate the NTP time based on the running_time of the pipeline but from
the systemclock. This allows us to generate more accurate NTP timestamps in case
the systemclock is synchronized with NTP or similar.
parent 2baa1075
......@@ -713,24 +713,29 @@ gst_rtp_session_get_property (GObject * object, guint prop_id,
}
static void
get_current_times (GstRtpSession * rtpsession,
GstClockTime * running_time, guint64 * ntpnstime)
get_current_times (GstRtpSession * rtpsession, GstClockTime * running_time,
guint64 * ntpnstime)
{
guint64 ntpns;
GstClock *clock;
GstClockTime base_time, ntpnsbase, rt;
GstClockTime base_time, rt;
GTimeVal current;
GST_OBJECT_LOCK (rtpsession);
if ((clock = GST_ELEMENT_CLOCK (rtpsession))) {
base_time = GST_ELEMENT_CAST (rtpsession)->base_time;
ntpnsbase = rtpsession->priv->ntpnsbase;
gst_object_ref (clock);
GST_OBJECT_UNLOCK (rtpsession);
/* get current NTP time */
g_get_current_time (&current);
ntpns = GST_TIMEVAL_TO_TIME (current);
/* add constant to convert from 1970 based time to 1900 based time */
ntpns += (2208988800LL * GST_SECOND);
/* get current clock time and convert to running time */
rt = gst_clock_get_time (clock) - base_time;
/* add NTP base offset to get NTP ns time */
ntpns = rt + ntpnsbase;
gst_object_unref (clock);
} else {
......@@ -751,6 +756,7 @@ rtcp_thread (GstRtpSession * rtpsession)
GstClockTime current_time;
GstClockTime next_timeout;
guint64 ntpnstime;
GstClockTime running_time;
GST_DEBUG_OBJECT (rtpsession, "entering RTCP thread");
......@@ -789,7 +795,7 @@ rtcp_thread (GstRtpSession * rtpsession)
current_time = gst_clock_get_time (rtpsession->priv->sysclock);
/* get current NTP time */
get_current_times (rtpsession, NULL, &ntpnstime);
get_current_times (rtpsession, &running_time, &ntpnstime);
/* we get unlocked because we need to perform reconsideration, don't perform
* the timeout but get a new reporting estimate. */
......@@ -798,7 +804,8 @@ rtcp_thread (GstRtpSession * rtpsession)
/* perform actions, we ignore result. Release lock because it might push. */
GST_RTP_SESSION_UNLOCK (rtpsession);
rtp_session_on_timeout (rtpsession->priv->session, current_time, ntpnstime);
rtp_session_on_timeout (rtpsession->priv->session, current_time, ntpnstime,
running_time);
GST_RTP_SESSION_LOCK (rtpsession);
}
/* mark the thread as stopped now */
......@@ -1602,9 +1609,8 @@ gst_rtp_session_chain_send_rtp_common (GstPad * pad, gpointer data,
GstRtpSession *rtpsession;
GstRtpSessionPrivate *priv;
GstFlowReturn ret;
GstClockTime timestamp;
GstClockTime timestamp, running_time;
GstClockTime current_time;
guint64 ntpnstime;
rtpsession = GST_RTP_SESSION (gst_pad_get_parent (pad));
priv = rtpsession->priv;
......@@ -1625,23 +1631,20 @@ gst_rtp_session_chain_send_rtp_common (GstPad * pad, gpointer data,
} else {
timestamp = GST_BUFFER_TIMESTAMP (GST_BUFFER_CAST (data));
}
if (GST_CLOCK_TIME_IS_VALID (timestamp)) {
/* convert to running time using the segment start value. */
ntpnstime =
running_time =
gst_segment_to_running_time (&rtpsession->send_rtp_seg, GST_FORMAT_TIME,
timestamp);
/* convert to NTP time by adding the NTP base */
ntpnstime += priv->ntpnsbase;
} else {
/* no timestamp, we could take the current running_time and convert it to
* NTP time. */
ntpnstime = -1;
/* no timestamp. */
running_time = -1;
}
current_time = gst_clock_get_time (priv->sysclock);
ret =
rtp_session_send_rtp (priv->session, data, is_list, current_time,
ntpnstime);
ret = rtp_session_send_rtp (priv->session, data, is_list, current_time,
running_time);
if (ret != GST_FLOW_OK)
goto push_error;
......
......@@ -1956,9 +1956,9 @@ ignore:
* rtp_session_send_rtp:
* @sess: an #RTPSession
* @data: pointer to either an RTP buffer or a list of RTP buffers
* @is_list: TRUE when @data is a buffer list
* @current_time: the current system time
* @ntpnstime: the NTP time in nanoseconds of when this buffer was captured.
* This is the buffer timestamp converted to NTP time.
* @running_time: the running time of @data
*
* Send the RTP buffer in the session manager. This function takes ownership of
* @buffer.
......@@ -1967,7 +1967,7 @@ ignore:
*/
GstFlowReturn
rtp_session_send_rtp (RTPSession * sess, gpointer data, gboolean is_list,
GstClockTime current_time, guint64 ntpnstime)
GstClockTime current_time, GstClockTime running_time)
{
GstFlowReturn result;
RTPSource *source;
......@@ -1997,7 +1997,7 @@ rtp_session_send_rtp (RTPSession * sess, gpointer data, gboolean is_list,
prevsender = RTP_SOURCE_IS_SENDER (source);
/* we use our own source to send */
result = rtp_source_send_rtp (source, data, is_list, ntpnstime);
result = rtp_source_send_rtp (source, data, is_list, running_time);
if (RTP_SOURCE_IS_SENDER (source) && !prevsender)
sess->stats.sender_sources++;
......@@ -2175,6 +2175,7 @@ typedef struct
GstBuffer *rtcp;
GstClockTime current_time;
guint64 ntpnstime;
GstClockTime running_time;
GstClockTime interval;
GstRTCPPacket packet;
gboolean is_bye;
......@@ -2199,8 +2200,8 @@ session_start_rtcp (RTPSession * sess, ReportData * data)
gst_rtcp_buffer_add_packet (data->rtcp, GST_RTCP_TYPE_SR, packet);
/* get latest stats */
rtp_source_get_new_sr (own, data->ntpnstime, &ntptime, &rtptime,
&packet_count, &octet_count);
rtp_source_get_new_sr (own, data->ntpnstime, data->running_time,
&ntptime, &rtptime, &packet_count, &octet_count);
/* store stats */
rtp_source_process_sr (own, data->current_time, ntptime, rtptime,
packet_count, octet_count);
......@@ -2448,6 +2449,7 @@ is_rtcp_time (RTPSession * sess, GstClockTime current_time, ReportData * data)
* @sess: an #RTPSession
* @current_time: the current system time
* @ntpnstime: the current NTP time in nanoseconds
* @running_time: the current running_time of the pipeline
*
* Perform maintenance actions after the timeout obtained with
* rtp_session_next_timeout() expired.
......@@ -2462,7 +2464,7 @@ is_rtcp_time (RTPSession * sess, GstClockTime current_time, ReportData * data)
*/
GstFlowReturn
rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
guint64 ntpnstime)
guint64 ntpnstime, GstClockTime running_time)
{
GstFlowReturn result = GST_FLOW_OK;
GList *item;
......@@ -2481,6 +2483,7 @@ rtp_session_on_timeout (RTPSession * sess, GstClockTime current_time,
data.ntpnstime = ntpnstime;
data.is_bye = FALSE;
data.has_sdes = FALSE;
data.running_time = running_time;
own = sess->source;
......
......@@ -292,7 +292,7 @@ GstFlowReturn rtp_session_process_rtcp (RTPSession *sess, GstBuffer
/* processing packets for sending */
GstFlowReturn rtp_session_send_rtp (RTPSession *sess, gpointer data, gboolean is_list,
GstClockTime current_time, guint64 ntpnstime);
GstClockTime current_time, GstClockTime running_time);
/* stopping the session */
GstFlowReturn rtp_session_schedule_bye (RTPSession *sess, const gchar *reason,
......@@ -301,6 +301,6 @@ GstFlowReturn rtp_session_schedule_bye (RTPSession *sess, const gcha
/* get interval for next RTCP interval */
GstClockTime rtp_session_next_timeout (RTPSession *sess, GstClockTime current_time);
GstFlowReturn rtp_session_on_timeout (RTPSession *sess, GstClockTime current_time,
guint64 ntpnstime);
guint64 ntpnstime, GstClockTime running_time);
#endif /* __RTP_SESSION_H__ */
......@@ -1047,8 +1047,7 @@ set_ssrc (GstBuffer ** buffer, guint group, guint idx, RTPSource * src)
* @src: an #RTPSource
* @data: an RTP buffer or a list of RTP buffers
* @is_list: if @data is a buffer or list
* @ntpnstime: the NTP time when this buffer was captured in nanoseconds. This
* is the buffer timestamp converted to NTP time.
* @running_time: the running time of @data
*
* Send @data (an RTP buffer or list of buffers) originating from @src.
* This will make @src a sender. This function takes ownership of @data and
......@@ -1058,13 +1057,13 @@ set_ssrc (GstBuffer ** buffer, guint group, guint idx, RTPSource * src)
*/
GstFlowReturn
rtp_source_send_rtp (RTPSource * src, gpointer data, gboolean is_list,
guint64 ntpnstime)
GstClockTime running_time)
{
GstFlowReturn result;
guint len;
guint32 rtptime;
guint64 ext_rtptime;
guint64 ntp_diff, rtp_diff;
guint64 rt_diff, rtp_diff;
guint64 elapsed;
GstBufferList *list = NULL;
GstBuffer *buffer = NULL;
......@@ -1104,8 +1103,8 @@ rtp_source_send_rtp (RTPSource * src, gpointer data, gboolean is_list,
src->stats.octets_sent += len;
src->bytes_sent += len;
if (src->prev_ntpnstime) {
elapsed = ntpnstime - src->prev_ntpnstime;
if (src->prev_rtime) {
elapsed = running_time - src->prev_rtime;
if (elapsed > (G_GINT64_CONSTANT (1) << 31)) {
guint64 rate;
......@@ -1122,12 +1121,12 @@ rtp_source_send_rtp (RTPSource * src, gpointer data, gboolean is_list,
else
src->bitrate = ((src->bitrate * 3) + rate) / 4;
src->prev_ntpnstime = ntpnstime;
src->prev_rtime = running_time;
src->bytes_sent = 0;
}
} else {
GST_LOG ("Reset bitrate measurement");
src->prev_ntpnstime = ntpnstime;
src->prev_rtime = running_time;
src->bitrate = 0;
}
......@@ -1139,24 +1138,24 @@ rtp_source_send_rtp (RTPSource * src, gpointer data, gboolean is_list,
ext_rtptime = src->last_rtptime;
ext_rtptime = gst_rtp_buffer_ext_timestamp (&ext_rtptime, rtptime);
GST_LOG ("SSRC %08x, RTP %" G_GUINT64_FORMAT ", NTP %" GST_TIME_FORMAT,
src->ssrc, ext_rtptime, GST_TIME_ARGS (ntpnstime));
GST_LOG ("SSRC %08x, RTP %" G_GUINT64_FORMAT ", running_time %"
GST_TIME_FORMAT, src->ssrc, ext_rtptime, GST_TIME_ARGS (running_time));
if (ext_rtptime > src->last_rtptime) {
rtp_diff = ext_rtptime - src->last_rtptime;
ntp_diff = ntpnstime - src->last_ntpnstime;
rt_diff = running_time - src->last_rtime;
/* calc the diff so we can detect drift at the sender. This can also be used
* to guestimate the clock rate if the NTP time is locked to the RTP
* timestamps (as is the case when the capture device is providing the clock). */
GST_LOG ("SSRC %08x, diff RTP %" G_GUINT64_FORMAT ", diff NTP %"
GST_TIME_FORMAT, src->ssrc, rtp_diff, GST_TIME_ARGS (ntp_diff));
GST_LOG ("SSRC %08x, diff RTP %" G_GUINT64_FORMAT ", diff running_time %"
GST_TIME_FORMAT, src->ssrc, rtp_diff, GST_TIME_ARGS (rt_diff));
}
/* we keep track of the last received RTP timestamp and the corresponding
* NTP timestamp so that we can use this info when constructing SR reports */
* buffer running_time so that we can use this info when constructing SR reports */
src->last_rtime = running_time;
src->last_rtptime = ext_rtptime;
src->last_ntpnstime = ntpnstime;
/* push packet */
if (!src->callbacks.push_rtp)
......@@ -1312,6 +1311,7 @@ rtp_source_process_rb (RTPSource * src, GstClockTime time, guint8 fractionlost,
* rtp_source_get_new_sr:
* @src: an #RTPSource
* @ntpnstime: the current time in nanoseconds since 1970
* @running_time: the current running_time of the pipeline.
* @ntptime: the NTP time in 32.32 fixed point
* @rtptime: the RTP time corresponding to @ntptime
* @packet_count: the packet count
......@@ -1319,12 +1319,19 @@ rtp_source_process_rb (RTPSource * src, GstClockTime time, guint8 fractionlost,
*
* Get new values to put into a new SR report from this source.
*
* @running_time and @ntpnstime are captured at the same time and represent the
* running time of the pipeline clock and the absolute current system time in
* nanoseconds respectively. Together with the last running_time and rtp timestamp
* we have observed in the source, we can generate @ntptime and @rtptime for an SR
* packet. @ntptime is basically the fixed point representation of @ntpnstime
* and @rtptime the associated RTP timestamp.
*
* Returns: %TRUE on success.
*/
gboolean
rtp_source_get_new_sr (RTPSource * src, guint64 ntpnstime,
guint64 * ntptime, guint32 * rtptime, guint32 * packet_count,
guint32 * octet_count)
GstClockTime running_time, guint64 * ntptime, guint32 * rtptime,
guint32 * packet_count, guint32 * octet_count)
{
guint64 t_rtp;
guint64 t_current_ntp;
......@@ -1332,30 +1339,36 @@ rtp_source_get_new_sr (RTPSource * src, guint64 ntpnstime,
g_return_val_if_fail (RTP_IS_SOURCE (src), FALSE);
/* use the sync params to interpolate 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
/* We last saw a buffer with last_rtptime at last_rtime. Given a running_time
* and an NTP time, we can scale the RTP timestamps so that they match the
* given NTP time. for scaling, we assume that the slope of the rtptime vs
* running_time vs ntptime curve is close to 1, which is certainly
* sufficient for the frequency at which we report SR and the rate we send
* out RTP packets. */
t_rtp = src->last_rtptime;
GST_DEBUG ("last_ntpnstime %" GST_TIME_FORMAT ", last_rtptime %"
G_GUINT64_FORMAT, GST_TIME_ARGS (src->last_ntpnstime), t_rtp);
GST_DEBUG ("last_rtime %" GST_TIME_FORMAT ", last_rtptime %"
G_GUINT64_FORMAT, GST_TIME_ARGS (src->last_rtime), t_rtp);
if (src->clock_rate != -1) {
/* get the diff with the SR time */
diff = GST_CLOCK_DIFF (src->last_ntpnstime, ntpnstime);
/* get the diff between the clock running_time and the buffer running_time.
* This is the elapsed time, as measured against the pipeline clock, between
* when the rtp timestamp was observed and the current running_time.
*
* We need to apply this diff to the RTP timestamp to get the RTP timestamp
* for the given ntpnstime. */
diff = GST_CLOCK_DIFF (src->last_rtime, running_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 ("ntpnstime %" GST_TIME_FORMAT ", diff %" GST_TIME_FORMAT,
GST_TIME_ARGS (ntpnstime), GST_TIME_ARGS (diff));
GST_DEBUG ("running_time %" GST_TIME_FORMAT ", diff %" GST_TIME_FORMAT,
GST_TIME_ARGS (running_time), GST_TIME_ARGS (diff));
t_rtp += gst_util_uint64_scale_int (diff, src->clock_rate, GST_SECOND);
} else {
diff = -diff;
GST_DEBUG ("ntpnstime %" GST_TIME_FORMAT ", diff -%" GST_TIME_FORMAT,
GST_TIME_ARGS (ntpnstime), GST_TIME_ARGS (diff));
GST_DEBUG ("running_time %" GST_TIME_FORMAT ", diff -%" GST_TIME_FORMAT,
GST_TIME_ARGS (running_time), GST_TIME_ARGS (diff));
t_rtp -= gst_util_uint64_scale_int (diff, src->clock_rate, GST_SECOND);
}
} else {
......
......@@ -136,12 +136,12 @@ struct _RTPSource {
GstClockTime last_activity;
GstClockTime last_rtp_activity;
GstClockTime last_rtime;
GstClockTime last_rtptime;
GstClockTime last_ntpnstime;
/* for bitrate estimation */
guint64 bitrate;
GstClockTime prev_ntpnstime;
GstClockTime prev_rtime;
guint64 bytes_sent;
GQueue *packets;
......@@ -192,8 +192,8 @@ void rtp_source_set_rtcp_from (RTPSource *src, GstNetAddress *a
/* handling RTP */
GstFlowReturn rtp_source_process_rtp (RTPSource *src, GstBuffer *buffer, RTPArrivalStats *arrival);
GstFlowReturn rtp_source_send_rtp (RTPSource *src, gpointer data, gboolean is_list, guint64 ntpnstime);
GstFlowReturn rtp_source_send_rtp (RTPSource *src, gpointer data, gboolean is_list,
GstClockTime running_time);
/* RTCP messages */
void rtp_source_process_bye (RTPSource *src, const gchar *reason);
void rtp_source_process_sr (RTPSource *src, GstClockTime time, guint64 ntptime,
......@@ -202,8 +202,8 @@ void rtp_source_process_rb (RTPSource *src, GstClockTime tim
gint32 packetslost, guint32 exthighestseq, guint32 jitter,
guint32 lsr, guint32 dlsr);
gboolean rtp_source_get_new_sr (RTPSource *src, guint64 ntpnstime, guint64 *ntptime,
guint32 *rtptime, guint32 *packet_count,
gboolean rtp_source_get_new_sr (RTPSource *src, guint64 ntpnstime, GstClockTime running_time,
guint64 *ntptime, guint32 *rtptime, guint32 *packet_count,
guint32 *octet_count);
gboolean rtp_source_get_new_rb (RTPSource *src, GstClockTime time, guint8 *fractionlost,
gint32 *packetslost, guint32 *exthighestseq, guint32 *jitter,
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment