#endif
#include <stdlib.h>
+#include <stdio.h>
#include <string.h>
#include <gst/rtp/gstrtpbuffer.h>
+#include <gst/net/net.h>
#include "gstrtpjitterbuffer.h"
#include "rtpjitterbuffer.h"
static void gst_rtp_jitter_buffer_release_pad (GstElement * element,
GstPad * pad);
static GstClock *gst_rtp_jitter_buffer_provide_clock (GstElement * element);
+static gboolean gst_rtp_jitter_buffer_set_clock (GstElement * element,
+ GstClock * clock);
/* pad overrides */
static GstCaps *gst_rtp_jitter_buffer_getcaps (GstPad * pad, GstCaps * filter);
GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_release_pad);
gstelement_class->provide_clock =
GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_provide_clock);
+ gstelement_class->set_clock =
+ GST_DEBUG_FUNCPTR (gst_rtp_jitter_buffer_set_clock);
gst_element_class_add_pad_template (gstelement_class,
gst_static_pad_template_get (&gst_rtp_jitter_buffer_src_template));
return gst_system_clock_obtain ();
}
+static gboolean
+gst_rtp_jitter_buffer_set_clock (GstElement * element, GstClock * clock)
+{
+ GstRtpJitterBuffer *jitterbuffer = GST_RTP_JITTER_BUFFER (element);
+
+ rtp_jitter_buffer_set_pipeline_clock (jitterbuffer->priv->jbuf, clock);
+
+ return TRUE;
+}
+
static void
gst_rtp_jitter_buffer_clear_pt_map (GstRtpJitterBuffer * jitterbuffer)
{
GstStructure *caps_struct;
guint val;
GstClockTime tval;
+ const gchar *ts_refclk, *mediaclk;
priv = jitterbuffer->priv;
"npt start/stop: %" GST_TIME_FORMAT "-%" GST_TIME_FORMAT,
GST_TIME_ARGS (priv->npt_start), GST_TIME_ARGS (priv->npt_stop));
+ if ((ts_refclk = gst_structure_get_string (caps_struct, "a-ts-refclk"))) {
+ GstClock *clock = NULL;
+ guint64 clock_offset = -1;
+
+ GST_DEBUG_OBJECT (jitterbuffer, "Have timestamp reference clock %s",
+ ts_refclk);
+
+ if (g_str_has_prefix (ts_refclk, "ntp=")) {
+ if (g_str_has_prefix (ts_refclk, "ntp=/traceable/")) {
+ GST_FIXME_OBJECT (jitterbuffer, "Can't handle traceable NTP clocks");
+ } else {
+ const gchar *host, *portstr;
+ gchar *hostname;
+ guint port;
+
+ host = ts_refclk + sizeof ("ntp=") - 1;
+ if (host[0] == '[') {
+ /* IPv6 */
+ portstr = strchr (host, ']');
+ if (portstr && portstr[1] == ':')
+ portstr = portstr + 1;
+ else
+ portstr = NULL;
+ } else {
+ portstr = strrchr (host, ':');
+ }
+
+
+ if (!portstr || sscanf (portstr, ":%u", &port) != 1)
+ port = 123;
+
+ if (portstr)
+ hostname = g_strndup (host, (portstr - host));
+ else
+ hostname = g_strdup (host);
+
+ clock = gst_ntp_clock_new (NULL, hostname, port, 0);
+ g_free (hostname);
+ }
+ } else if (g_str_has_prefix (ts_refclk, "ptp=IEEE1588-2008:")) {
+ const gchar *domainstr =
+ ts_refclk + sizeof ("ptp=IEEE1588-2008:XX-XX-XX-XX-XX-XX-XX-XX") - 1;
+ guint domain;
+
+ if (domainstr[0] != ':' || sscanf (domainstr, ":%u", &domain) != 1)
+ domain = 0;
+
+ clock = gst_ptp_clock_new (NULL, domain);
+ } else {
+ GST_FIXME_OBJECT (jitterbuffer, "Unsupported timestamp reference clock");
+ }
+
+ if ((mediaclk = gst_structure_get_string (caps_struct, "a-mediaclk"))) {
+ GST_DEBUG_OBJECT (jitterbuffer, "Got media clock %s", mediaclk);
+
+ if (!g_str_has_prefix (mediaclk, "direct=")
+ || sscanf (mediaclk, "direct=%" G_GUINT64_FORMAT, &clock_offset) != 1)
+ GST_FIXME_OBJECT (jitterbuffer, "Unsupported media clock");
+ if (strstr (mediaclk, "rate=") != NULL) {
+ GST_FIXME_OBJECT (jitterbuffer, "Rate property not supported");
+ clock_offset = -1;
+ }
+ }
+
+ rtp_jitter_buffer_set_media_clock (priv->jbuf, clock, clock_offset);
+ } else {
+ rtp_jitter_buffer_set_media_clock (priv->jbuf, NULL, -1);
+ }
+
return TRUE;
/* ERRORS */
jbuf = RTP_JITTER_BUFFER_CAST (object);
+ if (jbuf->media_clock_synced_id)
+ g_signal_handler_disconnect (jbuf->media_clock,
+ jbuf->media_clock_synced_id);
+ if (jbuf->media_clock)
+ gst_object_unref (jbuf->media_clock);
+
+ if (jbuf->pipeline_clock)
+ gst_object_unref (jbuf->pipeline_clock);
+
g_queue_free (jbuf->packets);
G_OBJECT_CLASS (rtp_jitter_buffer_parent_class)->finalize (object);
return jbuf->clock_rate;
}
+/* FIXME: This is called from another thread than anything else
+ * and will need some locking */
+static void
+media_clock_synced_cb (GstClock * clock, gboolean synced,
+ RTPJitterBuffer * jbuf)
+{
+ GstClockTime internal, external;
+
+ if (!jbuf->pipeline_clock)
+ return;
+
+ internal = gst_clock_get_internal_time (jbuf->media_clock);
+ external = gst_clock_get_time (jbuf->pipeline_clock);
+
+ gst_clock_set_calibration (jbuf->media_clock, internal, external, 1, 1);
+}
+
+/**
+ * rtp_jitter_buffer_set_media_clock:
+ * @jbuf: an #RTPJitterBuffer
+ * @clock: (transfer full): media #GstClock
+ * @clock_offset: RTP time at clock epoch or -1
+ *
+ * Sets the media clock for the media and the clock offset
+ *
+ */
+void
+rtp_jitter_buffer_set_media_clock (RTPJitterBuffer * jbuf, GstClock * clock,
+ guint64 clock_offset)
+{
+ if (jbuf->media_clock) {
+ if (jbuf->media_clock_synced_id)
+ g_signal_handler_disconnect (jbuf->media_clock,
+ jbuf->media_clock_synced_id);
+ jbuf->media_clock_synced_id = 0;
+ gst_object_unref (jbuf->media_clock);
+ }
+ jbuf->media_clock = clock;
+ jbuf->media_clock_offset = clock_offset;
+
+ if (jbuf->pipeline_clock && jbuf->media_clock &&
+ jbuf->pipeline_clock != jbuf->media_clock) {
+ jbuf->media_clock_synced_id =
+ g_signal_connect (jbuf->media_clock, "synced",
+ G_CALLBACK (media_clock_synced_cb), jbuf);
+ if (gst_clock_is_synced (jbuf->media_clock)) {
+ GstClockTime internal, external;
+
+ internal = gst_clock_get_internal_time (jbuf->media_clock);
+ external = gst_clock_get_time (jbuf->pipeline_clock);
+
+ gst_clock_set_calibration (jbuf->media_clock, internal, external, 1, 1);
+ }
+
+ gst_clock_set_master (jbuf->media_clock, jbuf->pipeline_clock);
+ }
+}
+
+/**
+ * rtp_jitter_buffer_set_pipeline_clock:
+ * @jbuf: an #RTPJitterBuffer
+ * @clock: (transfer full): pipeline #GstClock
+ *
+ * Sets the pipeline clock
+ *
+ */
+void
+rtp_jitter_buffer_set_pipeline_clock (RTPJitterBuffer * jbuf, GstClock * clock)
+{
+ if (jbuf->pipeline_clock)
+ gst_object_unref (jbuf->pipeline_clock);
+ jbuf->pipeline_clock = clock;
+
+ if (jbuf->pipeline_clock && jbuf->media_clock &&
+ jbuf->pipeline_clock != jbuf->media_clock) {
+ if (gst_clock_is_synced (jbuf->media_clock)) {
+ GstClockTime internal, external;
+
+ internal = gst_clock_get_internal_time (jbuf->media_clock);
+ external = gst_clock_get_time (jbuf->pipeline_clock);
+
+ gst_clock_set_calibration (jbuf->media_clock, internal, external, 1, 1);
+ }
+
+ gst_clock_set_master (jbuf->media_clock, jbuf->pipeline_clock);
+ }
+}
+
/**
* rtp_jitter_buffer_reset_skew:
* @jbuf: an #RTPJitterBuffer
default:
break;
}
+
+ if (gst_clock_is_synced (jbuf->media_clock)) {
+ GstClockTime ntptime, systime;
+ GstClockTime ntprtptime, rtpsystime;
+
+ ntptime = gst_clock_get_internal_time (jbuf->media_clock);
+ systime = gst_clock_get_time (jbuf->pipeline_clock);
+ g_print ("ntp %" GST_TIME_FORMAT " sys %" GST_TIME_FORMAT "\n",
+ GST_TIME_ARGS (ntptime), GST_TIME_ARGS (systime));
+
+ ntprtptime = gst_util_uint64_scale (ntptime, jbuf->clock_rate, GST_SECOND);
+ ntprtptime += jbuf->media_clock_offset;
+ ntprtptime &= 0xffffffff;
+ g_print ("rtptime now %lu then %u\n", ntprtptime, rtptime);
+
+ if (ntprtptime > rtptime)
+ ntptime -=
+ gst_util_uint64_scale (ntprtptime - rtptime, jbuf->clock_rate,
+ GST_SECOND);
+ else
+ ntptime +=
+ gst_util_uint64_scale (rtptime - ntprtptime, jbuf->clock_rate,
+ GST_SECOND);
+
+ rtpsystime = gst_clock_adjust_unlocked (jbuf->media_clock, ntptime);
+ g_print ("rtp %" GST_TIME_FORMAT " sys %" GST_TIME_FORMAT "\n",
+ GST_TIME_ARGS (rtpsystime), GST_TIME_ARGS (systime));
+ } else {
+ g_print ("not synced yet\n");
+ }
+
/* do skew calculation by measuring the difference between rtptime and the
* receive dts, this function will return the skew corrected rtptime. */
item->pts = calculate_skew (jbuf, rtptime, dts);