+
+ /* need resync, lock on to time and gstrtptime if we can, otherwise we
+ * do with the previous values */
+ if (G_UNLIKELY (jbuf->need_resync && dts != -1)) {
+ GST_INFO ("resync to time %" GST_TIME_FORMAT ", rtptime %"
+ GST_TIME_FORMAT, GST_TIME_ARGS (dts), GST_TIME_ARGS (gstrtptime));
+ rtp_jitter_buffer_resync (jbuf, dts, gstrtptime, ext_rtptime, FALSE);
+ }
+
+ GST_DEBUG ("extrtp %" G_GUINT64_FORMAT ", gstrtp %" GST_TIME_FORMAT ", base %"
+ GST_TIME_FORMAT ", send_diff %" GST_TIME_FORMAT, ext_rtptime,
+ GST_TIME_ARGS (gstrtptime), GST_TIME_ARGS (jbuf->base_rtptime),
+ GST_TIME_ARGS (gstrtptime - jbuf->base_rtptime));
+
+ rfc7273_mode = media_clock && pipeline_clock
+ && gst_clock_is_synced (media_clock);
+
+ if (rfc7273_mode && jbuf->mode == RTP_JITTER_BUFFER_MODE_SLAVE
+ && (media_clock_offset == -1 || !jbuf->rfc7273_sync)) {
+ GstClockTime internal, external;
+ GstClockTime rate_num, rate_denom;
+ GstClockTime nsrtptimediff, rtpntptime, rtpsystime;
+
+ gst_clock_get_calibration (media_clock, &internal, &external, &rate_num,
+ &rate_denom);
+
+ /* Slave to the RFC7273 media clock instead of trying to estimate it
+ * based on receive times and RTP timestamps */
+
+ if (jbuf->media_clock_base_time == -1) {
+ if (jbuf->base_time != -1) {
+ jbuf->media_clock_base_time =
+ gst_clock_unadjust_with_calibration (media_clock,
+ jbuf->base_time + base_time, internal, external, rate_num,
+ rate_denom);
+ } else {
+ if (dts != -1)
+ jbuf->media_clock_base_time =
+ gst_clock_unadjust_with_calibration (media_clock, dts + base_time,
+ internal, external, rate_num, rate_denom);
+ else
+ jbuf->media_clock_base_time =
+ gst_clock_get_internal_time (media_clock);
+ jbuf->base_rtptime = gstrtptime;
+ }
+ }
+
+ if (gstrtptime > jbuf->base_rtptime)
+ nsrtptimediff = gstrtptime - jbuf->base_rtptime;
+ else
+ nsrtptimediff = 0;
+
+ rtpntptime = nsrtptimediff + jbuf->media_clock_base_time;
+
+ rtpsystime =
+ gst_clock_adjust_with_calibration (media_clock, rtpntptime, internal,
+ external, rate_num, rate_denom);
+
+ if (rtpsystime > base_time)
+ pts = rtpsystime - base_time;
+ else
+ pts = 0;
+
+ GST_DEBUG ("RFC7273 clock time %" GST_TIME_FORMAT ", out %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (rtpsystime), GST_TIME_ARGS (pts));
+ } else if (rfc7273_mode && (jbuf->mode == RTP_JITTER_BUFFER_MODE_SLAVE
+ || jbuf->mode == RTP_JITTER_BUFFER_MODE_SYNCED)
+ && media_clock_offset != -1 && jbuf->rfc7273_sync) {
+ GstClockTime ntptime, rtptime_tmp;
+ GstClockTime ntprtptime, rtpsystime;
+ GstClockTime internal, external;
+ GstClockTime rate_num, rate_denom;
+
+ /* Don't do any of the dts related adjustments further down */
+ dts = -1;
+
+ /* Calculate the actual clock time on the sender side based on the
+ * RFC7273 clock and convert it to our pipeline clock
+ */
+
+ gst_clock_get_calibration (media_clock, &internal, &external, &rate_num,
+ &rate_denom);
+
+ ntptime = gst_clock_get_internal_time (media_clock);
+
+ ntprtptime = gst_util_uint64_scale (ntptime, jbuf->clock_rate, GST_SECOND);
+ ntprtptime += media_clock_offset;
+ ntprtptime &= 0xffffffff;
+
+ rtptime_tmp = rtptime;
+ /* Check for wraparounds, we assume that the diff between current RTP
+ * timestamp and current media clock time can't be bigger than
+ * 2**31 clock units */
+ if (ntprtptime > rtptime_tmp && ntprtptime - rtptime_tmp >= 0x80000000)
+ rtptime_tmp += G_GUINT64_CONSTANT (0x100000000);
+ else if (rtptime_tmp > ntprtptime && rtptime_tmp - ntprtptime >= 0x80000000)
+ ntprtptime += G_GUINT64_CONSTANT (0x100000000);
+
+ if (ntprtptime > rtptime_tmp)
+ ntptime -=
+ gst_util_uint64_scale (ntprtptime - rtptime_tmp, jbuf->clock_rate,
+ GST_SECOND);
+ else
+ ntptime +=
+ gst_util_uint64_scale (rtptime_tmp - ntprtptime, jbuf->clock_rate,
+ GST_SECOND);
+
+ rtpsystime =
+ gst_clock_adjust_with_calibration (media_clock, ntptime, internal,
+ external, rate_num, rate_denom);
+ /* All this assumes that the pipeline has enough additional
+ * latency to cover for the network delay */
+ if (rtpsystime > base_time)
+ pts = rtpsystime - base_time;
+ else
+ pts = 0;
+
+ GST_DEBUG ("RFC7273 clock time %" GST_TIME_FORMAT ", out %" GST_TIME_FORMAT,
+ GST_TIME_ARGS (rtpsystime), GST_TIME_ARGS (pts));
+ } else {
+ /* If we used the RFC7273 clock before and not anymore,
+ * we need to resync it later again */
+ jbuf->media_clock_base_time = -1;
+
+ /* do skew calculation by measuring the difference between rtptime and the
+ * receive dts, this function will return the skew corrected rtptime. */
+ pts = calculate_skew (jbuf, ext_rtptime, gstrtptime, dts);
+ }
+
+ /* check if timestamps are not going backwards, we can only check this if we
+ * have a previous out time and a previous send_diff */
+ if (G_LIKELY (pts != -1 && jbuf->prev_out_time != -1
+ && jbuf->prev_send_diff != -1)) {
+ /* now check for backwards timestamps */
+ if (G_UNLIKELY (
+ /* if the server timestamps went up and the out_time backwards */
+ (gstrtptime - jbuf->base_rtptime > jbuf->prev_send_diff
+ && pts < jbuf->prev_out_time) ||
+ /* if the server timestamps went backwards and the out_time forwards */
+ (gstrtptime - jbuf->base_rtptime < jbuf->prev_send_diff
+ && pts > jbuf->prev_out_time) ||
+ /* if the server timestamps did not change */
+ gstrtptime - jbuf->base_rtptime == jbuf->prev_send_diff)) {
+ GST_DEBUG ("backwards timestamps, using previous time");
+ pts = jbuf->prev_out_time;
+ }
+ }
+
+ if (dts != -1 && pts + jbuf->delay < dts) {
+ /* if we are going to produce a timestamp that is later than the input
+ * timestamp, we need to reset the jitterbuffer. Likely the server paused
+ * temporarily */
+ GST_DEBUG ("out %" GST_TIME_FORMAT " + %" G_GUINT64_FORMAT " < time %"
+ GST_TIME_FORMAT ", reset jitterbuffer", GST_TIME_ARGS (pts),
+ jbuf->delay, GST_TIME_ARGS (dts));
+ rtp_jitter_buffer_resync (jbuf, dts, gstrtptime, ext_rtptime, TRUE);
+ pts = dts;
+ }
+
+ jbuf->prev_out_time = pts;
+ jbuf->prev_send_diff = gstrtptime - jbuf->base_rtptime;
+
+ if (media_clock)
+ gst_object_unref (media_clock);
+ if (pipeline_clock)
+ gst_object_unref (pipeline_clock);
+
+ return pts;
+}
+
+
+/**
+ * rtp_jitter_buffer_insert:
+ * @jbuf: an #RTPJitterBuffer
+ * @item: an #RTPJitterBufferItem to insert
+ * @head: TRUE when the head element changed.
+ * @percent: the buffering percent after insertion
+ *
+ * Inserts @item into the packet queue of @jbuf. The sequence number of the
+ * packet will be used to sort the packets. This function takes ownerhip of
+ * @buf when the function returns %TRUE.
+ *
+ * When @head is %TRUE, the new packet was added at the head of the queue and
+ * will be available with the next call to rtp_jitter_buffer_pop() and
+ * rtp_jitter_buffer_peek().
+ *
+ * Returns: %FALSE if a packet with the same number already existed.
+ */
+gboolean
+rtp_jitter_buffer_insert (RTPJitterBuffer * jbuf, RTPJitterBufferItem * item,
+ gboolean * head, gint * percent)
+{
+ GList *list, *event = NULL;
+ guint16 seqnum;
+
+ g_return_val_if_fail (jbuf != NULL, FALSE);
+ g_return_val_if_fail (item != NULL, FALSE);
+
+ list = jbuf->packets->tail;
+
+ /* no seqnum, simply append then */
+ if (item->seqnum == -1)
+ goto append;
+
+ seqnum = item->seqnum;
+
+ /* loop the list to skip strictly larger seqnum buffers */
+ for (; list; list = g_list_previous (list)) {
+ guint16 qseq;
+ gint gap;
+ RTPJitterBufferItem *qitem = (RTPJitterBufferItem *) list;
+
+ if (qitem->seqnum == -1) {
+ /* keep a pointer to the first consecutive event if not already
+ * set. we will insert the packet after the event if we can't find
+ * a packet with lower sequence number before the event. */
+ if (event == NULL)
+ event = list;
+ continue;
+ }
+
+ qseq = qitem->seqnum;
+
+ /* compare the new seqnum to the one in the buffer */
+ gap = gst_rtp_buffer_compare_seqnum (seqnum, qseq);
+
+ /* we hit a packet with the same seqnum, notify a duplicate */
+ if (G_UNLIKELY (gap == 0))
+ goto duplicate;
+
+ /* seqnum > qseq, we can stop looking */
+ if (G_LIKELY (gap < 0))
+ break;
+
+ /* if we've found a packet with greater sequence number, cleanup the
+ * event pointer as the packet will be inserted before the event */
+ event = NULL;
+ }
+
+ /* if event is set it means that packets before the event had smaller
+ * sequence number, so we will insert our packet after the event */
+ if (event)
+ list = event;
+
+append:
+ queue_do_insert (jbuf, list, (GList *) item);