session: improve RTP-Info
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-stream-transport.c
index 3d97db6..4020ee4 100644 (file)
  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
  * Boston, MA 02110-1301, USA.
  */
+/**
+ * SECTION:rtsp-stream-transport
+ * @short_description: A media stream transport configuration
+ * @see_also: #GstRTSPStream, #GstRTSPSessionMedia
+ *
+ * The #GstRTSPStreamTransport configures the transport used by a
+ * #GstRTSPStream. It is usually manages by a #GstRTSPSessionMedia object.
+ *
+ * With gst_rtsp_stream_transport_set_callbacks(), callbacks can be configured
+ * to handle the RTP and RTCP packets from the stream, for example when they
+ * need to be sent over TCP.
+ *
+ * With  gst_rtsp_stream_transport_set_active() the transports are added and
+ * removed from the stream.
+ *
+ * A #GstRTSPStream will call gst_rtsp_stream_transport_keep_alive() when RTCP
+ * is received from the client. It will also call
+ * gst_rtsp_stream_transport_set_timed_out() when a receiver has timed out.
+ *
+ * Last reviewed on 2013-07-16 (1.0.0)
+ */
 
 #include <string.h>
 #include <stdlib.h>
 
-#include <gst/app/gstappsrc.h>
-#include <gst/app/gstappsink.h>
-
 #include "rtsp-stream-transport.h"
 
+#define GST_RTSP_STREAM_TRANSPORT_GET_PRIVATE(obj)  \
+       (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_STREAM_TRANSPORT, GstRTSPStreamTransportPrivate))
+
+struct _GstRTSPStreamTransportPrivate
+{
+  GstRTSPStream *stream;
+
+  GstRTSPSendFunc send_rtp;
+  GstRTSPSendFunc send_rtcp;
+  gpointer user_data;
+  GDestroyNotify notify;
+
+  GstRTSPKeepAliveFunc keep_alive;
+  gpointer ka_user_data;
+  GDestroyNotify ka_notify;
+  gboolean active;
+  gboolean timed_out;
+
+  GstRTSPTransport *transport;
+  GstRTSPUrl *url;
+
+  GObject *rtpsource;
+};
+
 enum
 {
   PROP_0,
@@ -44,6 +86,8 @@ gst_rtsp_stream_transport_class_init (GstRTSPStreamTransportClass * klass)
 {
   GObjectClass *gobject_class;
 
+  g_type_class_add_private (klass, sizeof (GstRTSPStreamTransportPrivate));
+
   gobject_class = G_OBJECT_CLASS (klass);
 
   gobject_class->finalize = gst_rtsp_stream_transport_finalize;
@@ -55,26 +99,30 @@ gst_rtsp_stream_transport_class_init (GstRTSPStreamTransportClass * klass)
 static void
 gst_rtsp_stream_transport_init (GstRTSPStreamTransport * trans)
 {
+  GstRTSPStreamTransportPrivate *priv =
+      GST_RTSP_STREAM_TRANSPORT_GET_PRIVATE (trans);
+
+  trans->priv = priv;
 }
 
 static void
 gst_rtsp_stream_transport_finalize (GObject * obj)
 {
+  GstRTSPStreamTransportPrivate *priv;
   GstRTSPStreamTransport *trans;
 
   trans = GST_RTSP_STREAM_TRANSPORT (obj);
+  priv = trans->priv;
 
   /* remove callbacks now */
   gst_rtsp_stream_transport_set_callbacks (trans, NULL, NULL, NULL, NULL);
   gst_rtsp_stream_transport_set_keepalive (trans, NULL, NULL, NULL);
 
-  if (trans->transport)
-    gst_rtsp_transport_free (trans->transport);
+  if (priv->transport)
+    gst_rtsp_transport_free (priv->transport);
 
-#if 0
-  if (trans->rtpsource)
-    g_object_set_qdata (trans->rtpsource, ssrc_stream_map_key, NULL);
-#endif
+  if (priv->url)
+    gst_rtsp_url_free (priv->url);
 
   G_OBJECT_CLASS (gst_rtsp_stream_transport_parent_class)->finalize (obj);
 }
@@ -92,19 +140,37 @@ gst_rtsp_stream_transport_finalize (GObject * obj)
 GstRTSPStreamTransport *
 gst_rtsp_stream_transport_new (GstRTSPStream * stream, GstRTSPTransport * tr)
 {
+  GstRTSPStreamTransportPrivate *priv;
   GstRTSPStreamTransport *trans;
 
   g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL);
   g_return_val_if_fail (tr != NULL, NULL);
 
   trans = g_object_new (GST_TYPE_RTSP_STREAM_TRANSPORT, NULL);
-  trans->stream = stream;
-  trans->transport = tr;
+  priv = trans->priv;
+  priv->stream = stream;
+  priv->transport = tr;
 
   return trans;
 }
 
 /**
+ * gst_rtsp_stream_transport_get_stream:
+ * @trans: a #GstRTSPStreamTransport
+ *
+ * Get the #GstRTSPStream used when constructing @trans.
+ *
+ * Returns: (transfer none): the stream used when constructing @trans.
+ */
+GstRTSPStream *
+gst_rtsp_stream_transport_get_stream (GstRTSPStreamTransport * trans)
+{
+  g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), NULL);
+
+  return trans->priv->stream;
+}
+
+/**
  * gst_rtsp_stream_transport_set_callbacks:
  * @trans: a #GstRTSPStreamTransport
  * @send_rtp: (scope notified): a callback called when RTP should be sent
@@ -120,12 +186,18 @@ gst_rtsp_stream_transport_set_callbacks (GstRTSPStreamTransport * trans,
     GstRTSPSendFunc send_rtp, GstRTSPSendFunc send_rtcp,
     gpointer user_data, GDestroyNotify notify)
 {
-  trans->send_rtp = send_rtp;
-  trans->send_rtcp = send_rtcp;
-  if (trans->notify)
-    trans->notify (trans->user_data);
-  trans->user_data = user_data;
-  trans->notify = notify;
+  GstRTSPStreamTransportPrivate *priv;
+
+  g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans));
+
+  priv = trans->priv;
+
+  priv->send_rtp = send_rtp;
+  priv->send_rtcp = send_rtcp;
+  if (priv->notify)
+    priv->notify (priv->user_data);
+  priv->user_data = user_data;
+  priv->notify = notify;
 }
 
 /**
@@ -142,11 +214,17 @@ void
 gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamTransport * trans,
     GstRTSPKeepAliveFunc keep_alive, gpointer user_data, GDestroyNotify notify)
 {
-  trans->keep_alive = keep_alive;
-  if (trans->ka_notify)
-    trans->ka_notify (trans->ka_user_data);
-  trans->ka_user_data = user_data;
-  trans->ka_notify = notify;
+  GstRTSPStreamTransportPrivate *priv;
+
+  g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans));
+
+  priv = trans->priv;
+
+  priv->keep_alive = keep_alive;
+  if (priv->ka_notify)
+    priv->ka_notify (priv->ka_user_data);
+  priv->ka_user_data = user_data;
+  priv->ka_notify = notify;
 }
 
 
@@ -155,20 +233,203 @@ gst_rtsp_stream_transport_set_keepalive (GstRTSPStreamTransport * trans,
  * @trans: a #GstRTSPStreamTransport
  * @tr: (transfer full): a client #GstRTSPTransport
  *
- * Set @ct as the client transport. This function takes ownership of
- * the passed @tr.
+ * Set @tr as the client transport. This function takes ownership of the
+ * passed @tr.
  */
 void
 gst_rtsp_stream_transport_set_transport (GstRTSPStreamTransport * trans,
     GstRTSPTransport * tr)
 {
+  GstRTSPStreamTransportPrivate *priv;
+
   g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans));
   g_return_if_fail (tr != NULL);
 
+  priv = trans->priv;
+
   /* keep track of the transports in the stream. */
-  if (trans->transport)
-    gst_rtsp_transport_free (trans->transport);
-  trans->transport = tr;
+  if (priv->transport)
+    gst_rtsp_transport_free (priv->transport);
+  priv->transport = tr;
+}
+
+/**
+ * gst_rtsp_stream_transport_get_transport:
+ * @trans: a #GstRTSPStreamTransport
+ *
+ * Get the transport configured in @trans.
+ *
+ * Returns: (transfer none): the transport configured in @trans. It remains
+ *     valid for as long as @trans is valid.
+ */
+const GstRTSPTransport *
+gst_rtsp_stream_transport_get_transport (GstRTSPStreamTransport * trans)
+{
+  g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), NULL);
+
+  return trans->priv->transport;
+}
+
+/**
+ * gst_rtsp_stream_transport_set_url:
+ * @trans: a #GstRTSPStreamTransport
+ * @url: (transfer none): a client #GstRTSPUrl
+ *
+ * Set @url as the client url.
+ */
+void
+gst_rtsp_stream_transport_set_url (GstRTSPStreamTransport * trans,
+    const GstRTSPUrl * url)
+{
+  GstRTSPStreamTransportPrivate *priv;
+
+  g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans));
+
+  priv = trans->priv;
+
+  /* keep track of the transports in the stream. */
+  if (priv->url)
+    gst_rtsp_url_free (priv->url);
+  priv->url = (url ? gst_rtsp_url_copy (url) : NULL);
+}
+
+/**
+ * gst_rtsp_stream_transport_get_url:
+ * @trans: a #GstRTSPStreamTransport
+ *
+ * Get the url configured in @trans.
+ *
+ * Returns: (transfer none): the url configured in @trans. It remains
+ *     valid for as long as @trans is valid.
+ */
+const GstRTSPUrl *
+gst_rtsp_stream_transport_get_url (GstRTSPStreamTransport * trans)
+{
+  g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), NULL);
+
+  return trans->priv->url;
+}
+
+ /**
+ * gst_rtsp_stream_transport_get_rtpinfo:
+ * @trans: a #GstRTSPStreamTransport
+ * @start_time: a star time
+ *
+ * Get the RTP-Info string for @trans and @start_time.
+ *
+ * Returns: the RTPInfo string for @trans and @start_time or %NULL when
+ * the RTP-Info could not be determined. g_free() after usage.
+ */
+gchar *
+gst_rtsp_stream_transport_get_rtpinfo (GstRTSPStreamTransport * trans,
+    GstClockTime start_time)
+{
+  GstRTSPStreamTransportPrivate *priv;
+  gchar *url_str;
+  GString *rtpinfo;
+  guint rtptime, seq, clock_rate;
+  GstClockTime running_time = GST_CLOCK_TIME_NONE;
+
+  g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), NULL);
+
+  priv = trans->priv;
+
+  if (!gst_rtsp_stream_get_rtpinfo (priv->stream, &rtptime, &seq, &clock_rate,
+          &running_time))
+    return NULL;
+
+  GST_DEBUG ("RTP time %u, seq %u, rate %u, running-time %" GST_TIME_FORMAT,
+      rtptime, seq, clock_rate, GST_TIME_ARGS (running_time));
+
+  if (GST_CLOCK_TIME_IS_VALID (running_time)
+      && GST_CLOCK_TIME_IS_VALID (start_time)) {
+    if (running_time > start_time) {
+      rtptime -=
+          gst_util_uint64_scale_int (running_time - start_time, clock_rate,
+          GST_SECOND);
+    } else {
+      rtptime +=
+          gst_util_uint64_scale_int (start_time - running_time, clock_rate,
+          GST_SECOND);
+    }
+  }
+  GST_DEBUG ("RTP time %u, for start-time %" GST_TIME_FORMAT,
+      rtptime, GST_TIME_ARGS (start_time));
+
+  rtpinfo = g_string_new ("");
+
+  url_str = gst_rtsp_url_get_request_uri (trans->priv->url);
+  g_string_append_printf (rtpinfo, "url=%s;seq=%u;rtptime=%u",
+      url_str, seq, rtptime);
+  g_free (url_str);
+
+  return g_string_free (rtpinfo, FALSE);
+}
+
+/**
+ * gst_rtsp_stream_transport_set_active:
+ * @trans: a #GstRTSPStreamTransport
+ * @active: new state of @trans
+ *
+ * Activate or deactivate datatransfer configured in @trans.
+ *
+ * Returns: %TRUE when the state was changed.
+ */
+gboolean
+gst_rtsp_stream_transport_set_active (GstRTSPStreamTransport * trans,
+    gboolean active)
+{
+  GstRTSPStreamTransportPrivate *priv;
+  gboolean res;
+
+  g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE);
+
+  priv = trans->priv;
+
+  if (priv->active == active)
+    return FALSE;
+
+  if (active)
+    res = gst_rtsp_stream_add_transport (priv->stream, trans);
+  else
+    res = gst_rtsp_stream_remove_transport (priv->stream, trans);
+
+  if (res)
+    priv->active = active;
+
+  return res;
+}
+
+/**
+ * gst_rtsp_stream_transport_set_timed_out:
+ * @trans: a #GstRTSPStreamTransport
+ * @timedout: timed out value
+ *
+ * Set the timed out state of @trans to @timedout
+ */
+void
+gst_rtsp_stream_transport_set_timed_out (GstRTSPStreamTransport * trans,
+    gboolean timedout)
+{
+  g_return_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans));
+
+  trans->priv->timed_out = timedout;
+}
+
+/**
+ * gst_rtsp_stream_transport_is_timed_out:
+ * @trans: a #GstRTSPStreamTransport
+ *
+ * Check if @trans is timed out.
+ *
+ * Returns: %TRUE if @trans timed out.
+ */
+gboolean
+gst_rtsp_stream_transport_is_timed_out (GstRTSPStreamTransport * trans)
+{
+  g_return_val_if_fail (GST_IS_RTSP_STREAM_TRANSPORT (trans), FALSE);
+
+  return trans->priv->timed_out;
 }
 
 /**
@@ -184,12 +445,15 @@ gboolean
 gst_rtsp_stream_transport_send_rtp (GstRTSPStreamTransport * trans,
     GstBuffer * buffer)
 {
+  GstRTSPStreamTransportPrivate *priv;
   gboolean res = FALSE;
 
-  if (trans->send_rtp)
+  priv = trans->priv;
+
+  if (priv->send_rtp)
     res =
-        trans->send_rtp (buffer, trans->transport->interleaved.min,
-        trans->user_data);
+        priv->send_rtp (buffer, priv->transport->interleaved.min,
+        priv->user_data);
 
   return res;
 }
@@ -207,12 +471,32 @@ gboolean
 gst_rtsp_stream_transport_send_rtcp (GstRTSPStreamTransport * trans,
     GstBuffer * buffer)
 {
+  GstRTSPStreamTransportPrivate *priv;
   gboolean res = FALSE;
 
-  if (trans->send_rtcp)
+  priv = trans->priv;
+
+  if (priv->send_rtcp)
     res =
-        trans->send_rtcp (buffer, trans->transport->interleaved.max,
-        trans->user_data);
+        priv->send_rtcp (buffer, priv->transport->interleaved.max,
+        priv->user_data);
 
   return res;
 }
+
+/**
+ * gst_rtsp_stream_transport_keep_alive:
+ * @trans: a #GstRTSPStreamTransport
+ *
+ * Signal the installed keep_alive callback for @trans.
+ */
+void
+gst_rtsp_stream_transport_keep_alive (GstRTSPStreamTransport * trans)
+{
+  GstRTSPStreamTransportPrivate *priv;
+
+  priv = trans->priv;
+
+  if (priv->keep_alive)
+    priv->keep_alive (priv->ka_user_data);
+}