stream: release some locks in error cases
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-stream.c
index 3380bd0..fb20090 100644 (file)
@@ -68,6 +68,7 @@ struct _GstRTSPStreamPrivate
   gboolean is_joined;
   gchar *control;
 
+  GstRTSPProfile profiles;
   GstRTSPLowerTrans protocols;
 
   /* pads on the rtpbin */
@@ -127,6 +128,7 @@ struct _GstRTSPStreamPrivate
 };
 
 #define DEFAULT_CONTROL         NULL
+#define DEFAULT_PROFILES        GST_RTSP_PROFILE_AVP
 #define DEFAULT_PROTOCOLS       GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \
                                         GST_RTSP_LOWER_TRANS_TCP
 
@@ -134,6 +136,7 @@ enum
 {
   PROP_0,
   PROP_CONTROL,
+  PROP_PROFILES,
   PROP_PROTOCOLS,
   PROP_LAST
 };
@@ -170,6 +173,11 @@ gst_rtsp_stream_class_init (GstRTSPStreamClass * klass)
           "The control string for this stream", DEFAULT_CONTROL,
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  g_object_class_install_property (gobject_class, PROP_PROFILES,
+      g_param_spec_flags ("profiles", "Profiles",
+          "Allowed transfer profiles", GST_TYPE_RTSP_PROFILE,
+          DEFAULT_PROFILES, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   g_object_class_install_property (gobject_class, PROP_PROTOCOLS,
       g_param_spec_flags ("protocols", "Protocols",
           "Allowed lower transport protocols", GST_TYPE_RTSP_LOWER_TRANS,
@@ -191,6 +199,7 @@ gst_rtsp_stream_init (GstRTSPStream * stream)
 
   priv->dscp_qos = -1;
   priv->control = g_strdup (DEFAULT_CONTROL);
+  priv->profiles = DEFAULT_PROFILES;
   priv->protocols = DEFAULT_PROTOCOLS;
 
   g_mutex_init (&priv->lock);
@@ -238,6 +247,9 @@ gst_rtsp_stream_get_property (GObject * object, guint propid,
     case PROP_CONTROL:
       g_value_take_string (value, gst_rtsp_stream_get_control (stream));
       break;
+    case PROP_PROFILES:
+      g_value_set_flags (value, gst_rtsp_stream_get_profiles (stream));
+      break;
     case PROP_PROTOCOLS:
       g_value_set_flags (value, gst_rtsp_stream_get_protocols (stream));
       break;
@@ -256,6 +268,9 @@ gst_rtsp_stream_set_property (GObject * object, guint propid,
     case PROP_CONTROL:
       gst_rtsp_stream_set_control (stream, g_value_get_string (value));
       break;
+    case PROP_PROFILES:
+      gst_rtsp_stream_set_profiles (stream, g_value_get_flags (value));
+      break;
     case PROP_PROTOCOLS:
       gst_rtsp_stream_set_protocols (stream, g_value_get_flags (value));
       break;
@@ -546,6 +561,106 @@ gst_rtsp_stream_get_dscp_qos (GstRTSPStream * stream)
 }
 
 /**
+ * gst_rtsp_stream_is_transport_supported:
+ * @stream: a #GstRTSPStream
+ * @transport: a #GstRTSPTransport
+ *
+ * Check if @transport can be handled by stream
+ *
+ * Returns: %TRUE if @transport can be handled by @stream.
+ */
+gboolean
+gst_rtsp_stream_is_transport_supported (GstRTSPStream * stream,
+    GstRTSPTransport * transport)
+{
+  GstRTSPStreamPrivate *priv;
+
+  g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
+
+  priv = stream->priv;
+
+  g_mutex_lock (&priv->lock);
+  if (transport->trans != GST_RTSP_TRANS_RTP)
+    goto unsupported_transmode;
+
+  if (!(transport->profile & priv->profiles))
+    goto unsupported_profile;
+
+  if (!(transport->lower_transport & priv->protocols))
+    goto unsupported_ltrans;
+
+  g_mutex_unlock (&priv->lock);
+
+  return TRUE;
+
+  /* ERRORS */
+unsupported_transmode:
+  {
+    GST_DEBUG ("unsupported transport mode %d", transport->trans);
+    g_mutex_unlock (&priv->lock);
+    return FALSE;
+  }
+unsupported_profile:
+  {
+    GST_DEBUG ("unsupported profile %d", transport->profile);
+    g_mutex_unlock (&priv->lock);
+    return FALSE;
+  }
+unsupported_ltrans:
+  {
+    GST_DEBUG ("unsupported lower transport %d", transport->lower_transport);
+    g_mutex_unlock (&priv->lock);
+    return FALSE;
+  }
+}
+
+/**
+ * gst_rtsp_stream_set_profiles:
+ * @stream: a #GstRTSPStream
+ * @profiles: the new profiles
+ *
+ * Configure the allowed profiles for @stream.
+ */
+void
+gst_rtsp_stream_set_profiles (GstRTSPStream * stream, GstRTSPProfile profiles)
+{
+  GstRTSPStreamPrivate *priv;
+
+  g_return_if_fail (GST_IS_RTSP_STREAM (stream));
+
+  priv = stream->priv;
+
+  g_mutex_lock (&priv->lock);
+  priv->profiles = profiles;
+  g_mutex_unlock (&priv->lock);
+}
+
+/**
+ * gst_rtsp_stream_get_profiles:
+ * @stream: a #GstRTSPStream
+ *
+ * Get the allowed profiles of @stream.
+ *
+ * Returns: a #GstRTSPProfile
+ */
+GstRTSPProfile
+gst_rtsp_stream_get_profiles (GstRTSPStream * stream)
+{
+  GstRTSPStreamPrivate *priv;
+  GstRTSPProfile res;
+
+  g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), GST_RTSP_PROFILE_UNKNOWN);
+
+  priv = stream->priv;
+
+  g_mutex_lock (&priv->lock);
+  res = priv->profiles;
+  g_mutex_unlock (&priv->lock);
+
+  return res;
+}
+
+/**
  * gst_rtsp_stream_set_protocols:
  * @stream: a #GstRTSPStream
  * @protocols: the new flags
@@ -1742,6 +1857,7 @@ gst_rtsp_stream_leave_bin (GstRTSPStream * stream, GstBin * bin,
 
 was_not_joined:
   {
+    g_mutex_unlock (&priv->lock);
     return TRUE;
   }
 }
@@ -1751,6 +1867,7 @@ was_not_joined:
  * @stream: a #GstRTSPStream
  * @rtptime: (allow-none): result RTP timestamp
  * @seq: (allow-none): result RTP seqnum
+ * @clock_rate: the clock rate
  * @running_time: (allow-none): result running-time
  *
  * Retrieve the current rtptime, seq and running-time. This is used to
@@ -1760,9 +1877,11 @@ was_not_joined:
  */
 gboolean
 gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream,
-    guint * rtptime, guint * seq, GstClockTime * running_time)
+    guint * rtptime, guint * seq, guint * clock_rate,
+    GstClockTime * running_time)
 {
   GstRTSPStreamPrivate *priv;
+  GstStructure *stats;
   GObjectClass *payobjclass;
 
   g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), FALSE);
@@ -1771,17 +1890,53 @@ gst_rtsp_stream_get_rtpinfo (GstRTSPStream * stream,
 
   payobjclass = G_OBJECT_GET_CLASS (priv->payloader);
 
-  if (seq && g_object_class_find_property (payobjclass, "seqnum"))
-    g_object_get (priv->payloader, "seqnum", seq, NULL);
+  g_mutex_lock (&priv->lock);
 
-  if (rtptime && g_object_class_find_property (payobjclass, "timestamp"))
-    g_object_get (priv->payloader, "timestamp", rtptime, NULL);
+  if (g_object_class_find_property (payobjclass, "stats")) {
+    g_object_get (priv->payloader, "stats", &stats, NULL);
+    if (stats == NULL)
+      goto no_stats;
 
-  if (running_time
-      && g_object_class_find_property (payobjclass, "running-time"))
-    g_object_get (priv->payloader, "running-time", running_time, NULL);
+    if (seq)
+      gst_structure_get_uint (stats, "seqnum", seq);
+
+    if (rtptime)
+      gst_structure_get_uint (stats, "timestamp", rtptime);
+
+    if (running_time)
+      gst_structure_get_clock_time (stats, "running-time", running_time);
+
+    if (clock_rate) {
+      gst_structure_get_uint (stats, "clock-rate", clock_rate);
+      if (*clock_rate == 0 && running_time)
+        *running_time = GST_CLOCK_TIME_NONE;
+    }
+    gst_structure_free (stats);
+  } else {
+    if (!g_object_class_find_property (payobjclass, "seqnum") ||
+        !g_object_class_find_property (payobjclass, "timestamp"))
+      goto no_stats;
+
+    if (seq)
+      g_object_get (priv->payloader, "seqnum", seq, NULL);
+
+    if (rtptime)
+      g_object_get (priv->payloader, "timestamp", rtptime, NULL);
+
+    if (running_time)
+      *running_time = GST_CLOCK_TIME_NONE;
+  }
+  g_mutex_unlock (&priv->lock);
 
   return TRUE;
+
+  /* ERRORS */
+no_stats:
+  {
+    GST_WARNING ("Could not get payloader stats");
+    g_mutex_unlock (&priv->lock);
+    return FALSE;
+  }
 }
 
 /**
@@ -1920,14 +2075,14 @@ update_transport (GstRTSPStream * stream, GstRTSPStreamTransport * trans,
       }
 
       if (add) {
-        GST_INFO ("adding %s:%d-%d", dest, min, max);
-        g_signal_emit_by_name (priv->udpsink[0], "add", dest, min, NULL);
-        g_signal_emit_by_name (priv->udpsink[1], "add", dest, max, NULL);
         if (ttl > 0) {
           GST_INFO ("setting ttl-mc %d", ttl);
           g_object_set (G_OBJECT (priv->udpsink[0]), "ttl-mc", ttl, NULL);
           g_object_set (G_OBJECT (priv->udpsink[1]), "ttl-mc", ttl, NULL);
         }
+        GST_INFO ("adding %s:%d-%d", dest, min, max);
+        g_signal_emit_by_name (priv->udpsink[0], "add", dest, min, NULL);
+        g_signal_emit_by_name (priv->udpsink[1], "add", dest, max, NULL);
         priv->transports = g_list_prepend (priv->transports, trans);
       } else {
         GST_INFO ("removing %s:%d-%d", dest, min, max);
@@ -2035,15 +2190,15 @@ gst_rtsp_stream_remove_transport (GstRTSPStream * stream,
  *
  * @stream must be joined to a bin.
  *
- * Returns: the RTP socket or %NULL if no socket could be allocated for @family.
- *     Unref after usage
+ * Returns: (transfer full): the RTP socket or %NULL if no socket could be
+ *     allocated for @family. Unref after usage
  */
 GSocket *
 gst_rtsp_stream_get_rtp_socket (GstRTSPStream * stream, GSocketFamily family)
 {
   GstRTSPStreamPrivate *priv = GST_RTSP_STREAM_GET_PRIVATE (stream);
   GSocket *socket;
-  gchar *name;
+  const gchar *name;
 
   g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL);
   g_return_val_if_fail (family == G_SOCKET_FAMILY_IPV4 ||
@@ -2069,15 +2224,15 @@ gst_rtsp_stream_get_rtp_socket (GstRTSPStream * stream, GSocketFamily family)
  *
  * @stream must be joined to a bin.
  *
- * Returns: the RTCP socket or %NULL if no socket could be allocated for
- *     @family. Unref after usage
+ * Returns: (transfer full): the RTCP socket or %NULL if no socket could be
+ *     allocated for @family. Unref after usage
  */
 GSocket *
 gst_rtsp_stream_get_rtcp_socket (GstRTSPStream * stream, GSocketFamily family)
 {
   GstRTSPStreamPrivate *priv = GST_RTSP_STREAM_GET_PRIVATE (stream);
   GSocket *socket;
-  gchar *name;
+  const gchar *name;
 
   g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL);
   g_return_val_if_fail (family == G_SOCKET_FAMILY_IPV4 ||