summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian@centricular.com>2015-12-30 18:39:05 +0200
committerSebastian Dröge <sebastian@centricular.com>2016-04-03 11:22:31 +0300
commit9fab555cc598d701b8911926193f8005471e2ded (patch)
treeff15e2fc44d8c0f13c8629830ae87f2bf70a2043
parentb63a6f029f478a859ac6dc6ac1d422072fdc70a0 (diff)
rtsp-server: Implement clock signalling according to RFC7273
For NTP and PTP clocks we signal the actual clock that is used and signal the direct media clock offset. For all other clocks we at least signal that it's the local sender clock. This allows receivers to know which clock was used to generate the media and its RTP timestamps. Receivers can then implement network synchronization, either absolute or at least relative by getting the sender clock rate directly via NTP/PTP instead of estimating it from RTP timestamps and packet receive times. https://bugzilla.gnome.org/show_bug.cgi?id=760005
-rw-r--r--gst/rtsp-server/rtsp-client.c18
-rw-r--r--gst/rtsp-server/rtsp-media-factory.c51
-rw-r--r--gst/rtsp-server/rtsp-media-factory.h3
-rw-r--r--gst/rtsp-server/rtsp-media.c92
-rw-r--r--gst/rtsp-server/rtsp-media.h21
-rw-r--r--gst/rtsp-server/rtsp-sdp.c95
-rw-r--r--gst/rtsp-server/rtsp-stream.c77
-rw-r--r--gst/rtsp-server/rtsp-stream.h6
8 files changed, 363 insertions, 0 deletions
diff --git a/gst/rtsp-server/rtsp-client.c b/gst/rtsp-server/rtsp-client.c
index 7258d77..c77e359 100644
--- a/gst/rtsp-server/rtsp-client.c
+++ b/gst/rtsp-server/rtsp-client.c
@@ -1042,10 +1042,12 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx)
GstRTSPSession *session;
GstRTSPClientClass *klass;
GstRTSPSessionMedia *sessmedia;
+ GstRTSPMedia *media;
GstRTSPStatusCode code;
GstRTSPState rtspstate;
gchar *path;
gint matched;
+ guint i, n;
if (!(session = ctx->session))
goto no_session;
@@ -1066,6 +1068,16 @@ handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx)
g_free (path);
+ media = gst_rtsp_session_media_get_media (sessmedia);
+ n = gst_rtsp_media_n_streams (media);
+ for (i = 0; i < n; i++) {
+ GstRTSPStream *stream = gst_rtsp_media_get_stream (media, i);
+
+ if (gst_rtsp_stream_get_publish_clock_mode (stream) ==
+ GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET)
+ goto not_supported;
+ }
+
ctx->sessmedia = sessmedia;
rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
@@ -1126,6 +1138,12 @@ invalid_state:
ctx);
return FALSE;
}
+not_supported:
+ {
+ GST_ERROR ("client %p: pausing not supported", client);
+ send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+ return FALSE;
+ }
}
/* convert @url and @path to a URL used as a content base for the factory
diff --git a/gst/rtsp-server/rtsp-media-factory.c b/gst/rtsp-server/rtsp-media-factory.c
index 8bfc422..8665c47 100644
--- a/gst/rtsp-server/rtsp-media-factory.c
+++ b/gst/rtsp-server/rtsp-media-factory.c
@@ -72,6 +72,8 @@ struct _GstRTSPMediaFactoryPrivate
GType media_gtype;
GstClock *clock;
+
+ GstRTSPPublishClockMode publish_clock_mode;
};
#define DEFAULT_LAUNCH NULL
@@ -261,6 +263,7 @@ gst_rtsp_media_factory_init (GstRTSPMediaFactory * factory)
priv->latency = DEFAULT_LATENCY;
priv->transport_mode = DEFAULT_TRANSPORT_MODE;
priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT;
+ priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK;
g_mutex_init (&priv->lock);
g_mutex_init (&priv->medias_lock);
@@ -1335,6 +1338,51 @@ gst_rtsp_media_factory_get_clock (GstRTSPMediaFactory * factory)
return ret;
}
+/**
+ * gst_rtsp_media_factory_set_publish_clock_mode:
+ * @factory: a #GstRTSPMediaFactory
+ * @mode: the clock publish mode
+ *
+ * Sets if and how the media clock should be published according to RFC7273.
+ *
+ * Since: 1.8
+ */
+void
+gst_rtsp_media_factory_set_publish_clock_mode (GstRTSPMediaFactory * factory,
+ GstRTSPPublishClockMode mode)
+{
+ GstRTSPMediaFactoryPrivate *priv;
+
+ GST_RTSP_MEDIA_FACTORY_LOCK (factory);
+ priv = factory->priv;
+ priv->publish_clock_mode = mode;
+ GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
+}
+
+/**
+ * gst_rtsp_media_factory_get_publish_clock_mode:
+ * @factory: a #GstRTSPMediaFactory
+ *
+ * Gets if and how the media clock should be published according to RFC7273.
+ *
+ * Returns: The GstRTSPPublishClockMode
+ *
+ * Since: 1.8
+ */
+GstRTSPPublishClockMode
+gst_rtsp_media_factory_get_publish_clock_mode (GstRTSPMediaFactory * factory)
+{
+ GstRTSPMediaFactoryPrivate *priv;
+ GstRTSPPublishClockMode ret;
+
+ GST_RTSP_MEDIA_FACTORY_LOCK (factory);
+ priv = factory->priv;
+ ret = priv->publish_clock_mode;
+ GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
+
+ return ret;
+}
+
static gchar *
default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
{
@@ -1480,6 +1528,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
GstRTSPTransportMode transport_mode;
GstClock *clock;
gchar *multicast_iface;
+ GstRTSPPublishClockMode publish_clock_mode;
/* configure the sharedness */
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
@@ -1494,6 +1543,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
transport_mode = priv->transport_mode;
stop_on_disconnect = priv->stop_on_disconnect;
clock = priv->clock ? gst_object_ref (priv->clock) : NULL;
+ publish_clock_mode = priv->publish_clock_mode;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
gst_rtsp_media_set_suspend_mode (media, suspend_mode);
@@ -1506,6 +1556,7 @@ default_configure (GstRTSPMediaFactory * factory, GstRTSPMedia * media)
gst_rtsp_media_set_latency (media, latency);
gst_rtsp_media_set_transport_mode (media, transport_mode);
gst_rtsp_media_set_stop_on_disconnect (media, stop_on_disconnect);
+ gst_rtsp_media_set_publish_clock_mode (media, publish_clock_mode);
if (clock) {
gst_rtsp_media_set_clock (media, clock);
diff --git a/gst/rtsp-server/rtsp-media-factory.h b/gst/rtsp-server/rtsp-media-factory.h
index f0b6bd5..3e8adbc 100644
--- a/gst/rtsp-server/rtsp-media-factory.h
+++ b/gst/rtsp-server/rtsp-media-factory.h
@@ -168,6 +168,9 @@ void gst_rtsp_media_factory_set_clock (GstRTSPMediaFacto
GstClock * clock);
GstClock * gst_rtsp_media_factory_get_clock (GstRTSPMediaFactory *factory);
+void gst_rtsp_media_factory_set_publish_clock_mode (GstRTSPMediaFactory * factory, GstRTSPPublishClockMode mode);
+GstRTSPPublishClockMode gst_rtsp_media_factory_get_publish_clock_mode (GstRTSPMediaFactory * factory);
+
/* creating the media from the factory and a url */
GstRTSPMedia * gst_rtsp_media_factory_construct (GstRTSPMediaFactory *factory,
const GstRTSPUrl *url);
diff --git a/gst/rtsp-server/rtsp-media.c b/gst/rtsp-server/rtsp-media.c
index 4fb6d51..c08b2a9 100644
--- a/gst/rtsp-server/rtsp-media.c
+++ b/gst/rtsp-server/rtsp-media.c
@@ -141,6 +141,7 @@ struct _GstRTSPMediaPrivate
GstClockTime rtx_time; /* protected by lock */
guint latency; /* protected by lock */
GstClock *clock; /* protected by lock */
+ GstRTSPPublishClockMode publish_clock_mode;
};
#define DEFAULT_SHARED FALSE
@@ -264,6 +265,29 @@ gst_rtsp_transport_mode_get_type (void)
return (GType) id;
}
+GType
+gst_rtsp_publish_clock_mode_get_type (void)
+{
+ static gsize id = 0;
+ static const GEnumValue values[] = {
+ {C_ENUM (GST_RTSP_PUBLISH_CLOCK_MODE_NONE),
+ "GST_RTSP_PUBLISH_CLOCK_MODE_NONE", "none"},
+ {C_ENUM (GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK),
+ "GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK",
+ "clock"},
+ {C_ENUM (GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET),
+ "GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET",
+ "clock-and-offset"},
+ {0, NULL, NULL}
+ };
+
+ if (g_once_init_enter (&id)) {
+ GType tmp = g_enum_register_static ("GstRTSPPublishClockMode", values);
+ g_once_init_leave (&id, tmp);
+ }
+ return (GType) id;
+}
+
G_DEFINE_TYPE (GstRTSPMedia, gst_rtsp_media, G_TYPE_OBJECT);
static void
@@ -415,6 +439,7 @@ gst_rtsp_media_init (GstRTSPMedia * media)
priv->time_provider = DEFAULT_TIME_PROVIDER;
priv->transport_mode = DEFAULT_TRANSPORT_MODE;
priv->stop_on_disconnect = DEFAULT_STOP_ON_DISCONNECT;
+ priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK;
}
static void
@@ -1439,6 +1464,59 @@ gst_rtsp_media_set_clock (GstRTSPMedia * media, GstClock * clock)
}
/**
+ * gst_rtsp_media_set_publish_clock_mode:
+ * @media: a #GstRTSPMedia
+ * @mode: the clock publish mode
+ *
+ * Sets if and how the media clock should be published according to RFC7273.
+ *
+ * Since: 1.8
+ */
+void
+gst_rtsp_media_set_publish_clock_mode (GstRTSPMedia * media,
+ GstRTSPPublishClockMode mode)
+{
+ GstRTSPMediaPrivate *priv;
+ guint i, n;
+
+ priv = media->priv;
+ g_mutex_lock (&priv->lock);
+ priv->publish_clock_mode = mode;
+
+ n = priv->streams->len;
+ for (i = 0; i < n; i++) {
+ GstRTSPStream *stream = g_ptr_array_index (priv->streams, i);
+
+ gst_rtsp_stream_set_publish_clock_mode (stream, mode);
+ }
+ g_mutex_unlock (&priv->lock);
+}
+
+/**
+ * gst_rtsp_media_get_publish_clock_mode:
+ * @factory: a #GstRTSPMedia
+ *
+ * Gets if and how the media clock should be published according to RFC7273.
+ *
+ * Returns: The GstRTSPPublishClockMode
+ *
+ * Since: 1.8
+ */
+GstRTSPPublishClockMode
+gst_rtsp_media_get_publish_clock_mode (GstRTSPMedia * media)
+{
+ GstRTSPMediaPrivate *priv;
+ GstRTSPPublishClockMode ret;
+
+ priv = media->priv;
+ g_mutex_lock (&priv->lock);
+ ret = priv->publish_clock_mode;
+ g_mutex_unlock (&priv->lock);
+
+ return ret;
+}
+
+/**
* gst_rtsp_media_set_address_pool:
* @media: a #GstRTSPMedia
* @pool: (transfer none): a #GstRTSPAddressPool
@@ -1744,6 +1822,7 @@ gst_rtsp_media_create_stream (GstRTSPMedia * media, GstElement * payloader,
gst_rtsp_stream_set_protocols (stream, priv->protocols);
gst_rtsp_stream_set_retransmission_time (stream, priv->rtx_time);
gst_rtsp_stream_set_buffer_size (stream, priv->buffer_size);
+ gst_rtsp_stream_set_publish_clock_mode (stream, priv->publish_clock_mode);
g_ptr_array_add (priv->streams, stream);
@@ -2072,6 +2151,18 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
/* TODO: Seeking for RECORD? */
priv->seekable = FALSE;
} else {
+ guint i, n = priv->streams->len;
+
+ for (i = 0; i < n; i++) {
+ GstRTSPStream *stream = g_ptr_array_index (priv->streams, i);
+
+ if (gst_rtsp_stream_get_publish_clock_mode (stream) ==
+ GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET) {
+ priv->seekable = FALSE;
+ goto not_seekable;
+ }
+ }
+
query = gst_query_new_seeking (GST_FORMAT_TIME);
if (gst_element_query (priv->pipeline, query)) {
GstFormat format;
@@ -2081,6 +2172,7 @@ gst_rtsp_media_seek (GstRTSPMedia * media, GstRTSPTimeRange * range)
gst_query_parse_seeking (query, &format, &seekable, &start, &end);
priv->seekable = seekable;
}
+
gst_query_unref (query);
}
diff --git a/gst/rtsp-server/rtsp-media.h b/gst/rtsp-server/rtsp-media.h
index c0de06c..d004b5e 100644
--- a/gst/rtsp-server/rtsp-media.h
+++ b/gst/rtsp-server/rtsp-media.h
@@ -88,12 +88,29 @@ typedef enum {
GST_RTSP_TRANSPORT_MODE_RECORD = 2,
} GstRTSPTransportMode;
+/**
+ * GstRTSPPublishClockMode:
+ * @GST_RTSP_PUBLISH_CLOCK_MODE_NONE: Publish nothing
+ * @GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK: Publish the clock but not the offset
+ * @GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET: Publish the clock and offset
+ *
+ * Whether the clock and possibly RTP/clock offset should be published according to RFC7273.
+ */
+typedef enum {
+ GST_RTSP_PUBLISH_CLOCK_MODE_NONE,
+ GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK,
+ GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET
+} GstRTSPPublishClockMode;
+
#define GST_TYPE_RTSP_TRANSPORT_MODE (gst_rtsp_transport_mode_get_type())
GType gst_rtsp_transport_mode_get_type (void);
#define GST_TYPE_RTSP_SUSPEND_MODE (gst_rtsp_suspend_mode_get_type())
GType gst_rtsp_suspend_mode_get_type (void);
+#define GST_TYPE_RTSP_PUBLISH_CLOCK_MODE (gst_rtsp_publish_clock_mode_get_type())
+GType gst_rtsp_publish_clock_mode_get_type (void);
+
#include "rtsp-stream.h"
#include "rtsp-thread-pool.h"
#include "rtsp-permissions.h"
@@ -226,6 +243,10 @@ GstNetTimeProvider * gst_rtsp_media_get_time_provider (GstRTSPMedia *media,
void gst_rtsp_media_set_clock (GstRTSPMedia *media, GstClock * clock);
+
+void gst_rtsp_media_set_publish_clock_mode (GstRTSPMedia * media, GstRTSPPublishClockMode mode);
+GstRTSPPublishClockMode gst_rtsp_media_get_publish_clock_mode (GstRTSPMedia * media);
+
/* prepare the media for playback */
gboolean gst_rtsp_media_prepare (GstRTSPMedia *media, GstRTSPThread *thread);
gboolean gst_rtsp_media_unprepare (GstRTSPMedia *media);
diff --git a/gst/rtsp-server/rtsp-sdp.c b/gst/rtsp-server/rtsp-sdp.c
index 950a1eb..348cab3 100644
--- a/gst/rtsp-server/rtsp-sdp.c
+++ b/gst/rtsp-server/rtsp-sdp.c
@@ -26,6 +26,7 @@
#include <string.h>
+#include <gst/net/net.h>
#include <gst/sdp/gstmikey.h>
#include "rtsp-sdp.h"
@@ -169,6 +170,100 @@ make_media (GstSDPMessage * sdp, GstSDPInfo * info,
gst_mikey_message_unref (mikey_msg);
}
+ /* RFC 7273 clock signalling */
+ {
+ GstBin *joined_bin = gst_rtsp_stream_get_joined_bin (stream);
+ GstClock *clock = gst_element_get_clock (GST_ELEMENT_CAST (joined_bin));
+ gchar *ts_refclk = NULL;
+ gchar *mediaclk = NULL;
+ guint rtptime, clock_rate;
+ GstClockTime running_time, base_time, clock_time;
+ GstRTSPPublishClockMode publish_clock_mode =
+ gst_rtsp_stream_get_publish_clock_mode (stream);
+
+ gst_rtsp_stream_get_rtpinfo (stream, &rtptime, NULL, &clock_rate,
+ &running_time);
+ base_time = gst_element_get_base_time (GST_ELEMENT_CAST (joined_bin));
+ g_assert (base_time != GST_CLOCK_TIME_NONE);
+ clock_time = running_time + base_time;
+
+ if (publish_clock_mode != GST_RTSP_PUBLISH_CLOCK_MODE_NONE && clock) {
+ if (GST_IS_NTP_CLOCK (clock) || GST_IS_PTP_CLOCK (clock)) {
+ if (publish_clock_mode == GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET) {
+ guint32 mediaclk_offset;
+
+ /* Calculate RTP time at the clock's epoch. That's the direct offset */
+ clock_time =
+ gst_util_uint64_scale (clock_time, clock_rate, GST_SECOND);
+
+ clock_time &= 0xffffffff;
+ mediaclk_offset =
+ G_GUINT64_CONSTANT (0xffffffff) + rtptime - clock_time;
+ mediaclk = g_strdup_printf ("direct=%u", (guint32) mediaclk_offset);
+ }
+
+ if (GST_IS_NTP_CLOCK (clock)) {
+ gchar *ntp_address;
+ guint ntp_port;
+
+ g_object_get (clock, "address", &ntp_address, "port", &ntp_port,
+ NULL);
+
+ if (ntp_port == 123)
+ ts_refclk = g_strdup_printf ("ntp=%s", ntp_address);
+ else
+ ts_refclk = g_strdup_printf ("ntp=%s:%u", ntp_address, ntp_port);
+
+ g_free (ntp_address);
+ } else {
+ guint64 ptp_clock_id;
+ guint ptp_domain;
+
+ g_object_get (clock, "grandmaster-clock-id", &ptp_clock_id, "domain",
+ &ptp_domain, NULL);
+
+ if (ptp_domain != 0)
+ ts_refclk =
+ g_strdup_printf
+ ("ptp=IEEE1588-2008:%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X:%u",
+ (guint) (ptp_clock_id >> 56) & 0xff,
+ (guint) (ptp_clock_id >> 48) & 0xff,
+ (guint) (ptp_clock_id >> 40) & 0xff,
+ (guint) (ptp_clock_id >> 32) & 0xff,
+ (guint) (ptp_clock_id >> 24) & 0xff,
+ (guint) (ptp_clock_id >> 16) & 0xff,
+ (guint) (ptp_clock_id >> 8) & 0xff,
+ (guint) (ptp_clock_id >> 0) & 0xff, ptp_domain);
+ else
+ ts_refclk =
+ g_strdup_printf
+ ("ptp=IEEE1588-2008:%02X-%02X-%02X-%02X-%02X-%02X-%02X-%02X",
+ (guint) (ptp_clock_id >> 56) & 0xff,
+ (guint) (ptp_clock_id >> 48) & 0xff,
+ (guint) (ptp_clock_id >> 40) & 0xff,
+ (guint) (ptp_clock_id >> 32) & 0xff,
+ (guint) (ptp_clock_id >> 24) & 0xff,
+ (guint) (ptp_clock_id >> 16) & 0xff,
+ (guint) (ptp_clock_id >> 8) & 0xff,
+ (guint) (ptp_clock_id >> 0) & 0xff);
+ }
+ }
+ }
+ if (clock)
+ gst_object_unref (clock);
+
+ if (!ts_refclk)
+ ts_refclk = g_strdup ("local");
+ if (!mediaclk)
+ mediaclk = g_strdup ("sender");
+
+ gst_sdp_media_add_attribute (smedia, "ts-refclk", ts_refclk);
+ gst_sdp_media_add_attribute (smedia, "mediaclk", mediaclk);
+ g_free (ts_refclk);
+ g_free (mediaclk);
+ gst_object_unref (joined_bin);
+ }
+
update_sdp_from_tags (stream, smedia);
if ((profile == GST_RTSP_PROFILE_AVPF || profile == GST_RTSP_PROFILE_SAVPF)
diff --git a/gst/rtsp-server/rtsp-stream.c b/gst/rtsp-server/rtsp-stream.c
index 9997181..a847935 100644
--- a/gst/rtsp-server/rtsp-stream.c
+++ b/gst/rtsp-server/rtsp-stream.c
@@ -71,6 +71,7 @@ struct _GstRTSPStreamPrivate
GstElement *payloader;
guint buffer_size;
gboolean is_joined;
+ GstBin *joined_bin;
/* TRUE if this stream is running on
* the client side of an RTSP link (for RECORD) */
@@ -164,6 +165,8 @@ struct _GstRTSPStreamPrivate
/* pt->caps map for RECORD streams */
GHashTable *ptmap;
+
+ GstRTSPPublishClockMode publish_clock_mode;
};
#define DEFAULT_CONTROL NULL
@@ -259,6 +262,7 @@ gst_rtsp_stream_init (GstRTSPStream * stream)
priv->control = g_strdup (DEFAULT_CONTROL);
priv->profiles = DEFAULT_PROFILES;
priv->protocols = DEFAULT_PROTOCOLS;
+ priv->publish_clock_mode = GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK;
g_mutex_init (&priv->lock);
@@ -2281,6 +2285,51 @@ gst_rtsp_stream_set_pt_map (GstRTSPStream * stream, guint pt, GstCaps * caps)
g_mutex_unlock (&priv->lock);
}
+/**
+ * gst_rtsp_stream_set_publish_clock_mode:
+ * @stream: a #GstRTSPStream
+ * @mode: the clock publish mode
+ *
+ * Sets if and how the stream clock should be published according to RFC7273.
+ *
+ * Since: 1.8
+ */
+void
+gst_rtsp_stream_set_publish_clock_mode (GstRTSPStream * stream,
+ GstRTSPPublishClockMode mode)
+{
+ GstRTSPStreamPrivate *priv;
+
+ priv = stream->priv;
+ g_mutex_lock (&priv->lock);
+ priv->publish_clock_mode = mode;
+ g_mutex_unlock (&priv->lock);
+}
+
+/**
+ * gst_rtsp_stream_get_publish_clock_mode:
+ * @factory: a #GstRTSPStream
+ *
+ * Gets if and how the stream clock should be published according to RFC7273.
+ *
+ * Returns: The GstRTSPPublishClockMode
+ *
+ * Since: 1.8
+ */
+GstRTSPPublishClockMode
+gst_rtsp_stream_get_publish_clock_mode (GstRTSPStream * stream)
+{
+ GstRTSPStreamPrivate *priv;
+ GstRTSPPublishClockMode ret;
+
+ priv = stream->priv;
+ g_mutex_lock (&priv->lock);
+ ret = priv->publish_clock_mode;
+ g_mutex_unlock (&priv->lock);
+
+ return ret;
+}
+
static GstCaps *
request_pt_map (GstElement * rtpbin, guint session, guint pt,
GstRTSPStream * stream)
@@ -2730,6 +2779,7 @@ gst_rtsp_stream_join_bin (GstRTSPStream * stream, GstBin * bin,
(GCallback) caps_notify, stream);
}
+ priv->joined_bin = bin;
priv->is_joined = TRUE;
g_mutex_unlock (&priv->lock);
@@ -2839,6 +2889,8 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin,
if (!priv->is_joined)
goto was_not_joined;
+ priv->joined_bin = NULL;
+
/* all transports must be removed by now */
if (priv->transports != NULL)
goto transports_not_removed;
@@ -3014,6 +3066,31 @@ transports_not_removed:
}
/**
+ * gst_rtsp_stream_get_joined_bin:
+ * @stream: a #GstRTSPStream
+ *
+ * Get the previous joined bin with gst_rtsp_stream_join_bin() or NULL.
+ *
+ * Return: (transfer full): the joined bin or NULL.
+ */
+GstBin *
+gst_rtsp_stream_get_joined_bin (GstRTSPStream * stream)
+{
+ GstRTSPStreamPrivate *priv;
+ GstBin *bin = NULL;
+
+ g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
+
+ priv = stream->priv;
+
+ g_mutex_lock (&priv->lock);
+ bin = priv->joined_bin ? gst_object_ref (priv->joined_bin) : NULL;
+ g_mutex_unlock (&priv->lock);
+
+ return bin;
+}
+
+/**
* gst_rtsp_stream_get_rtpinfo:
* @stream: a #GstRTSPStream
* @rtptime: (allow-none): result RTP timestamp
diff --git a/gst/rtsp-server/rtsp-stream.h b/gst/rtsp-server/rtsp-stream.h
index c347cb8..a6ab1ff 100644
--- a/gst/rtsp-server/rtsp-stream.h
+++ b/gst/rtsp-server/rtsp-stream.h
@@ -43,6 +43,7 @@ typedef struct _GstRTSPStreamPrivate GstRTSPStreamPrivate;
#include "rtsp-stream-transport.h"
#include "rtsp-address-pool.h"
#include "rtsp-session.h"
+#include "rtsp-media.h"
/**
* GstRTSPStream:
@@ -110,6 +111,7 @@ gboolean gst_rtsp_stream_join_bin (GstRTSPStream *stream,
GstState state);
gboolean gst_rtsp_stream_leave_bin (GstRTSPStream *stream,
GstBin *bin, GstElement *rtpbin);
+GstBin * gst_rtsp_stream_get_joined_bin (GstRTSPStream *stream);
gboolean gst_rtsp_stream_set_blocked (GstRTSPStream * stream,
gboolean blocked);
@@ -174,6 +176,10 @@ GstElement * gst_rtsp_stream_request_aux_sender (GstRTSPStream * st
gboolean gst_rtsp_stream_allocate_udp_sockets (GstRTSPStream * stream, GSocketFamily family,
GstRTSPTransport *transport, gboolean use_client_setttings);
+
+void gst_rtsp_stream_set_publish_clock_mode (GstRTSPStream * stream, GstRTSPPublishClockMode mode);
+GstRTSPPublishClockMode gst_rtsp_stream_get_publish_clock_mode (GstRTSPStream * stream);
+
/**
* GstRTSPStreamTransportFilterFunc:
* @stream: a #GstRTSPStream object