media: disconnect from signal handlers in unprepare()
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-session-media.c
index 12a01d4..c475f8f 100644 (file)
  *
  * You should have received a copy of the GNU Library General Public
  * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
  */
 #include <string.h>
 
 #include "rtsp-session.h"
 
-#undef DEBUG
+#define GST_RTSP_SESSION_MEDIA_GET_PRIVATE(obj)  \
+    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_SESSION_MEDIA, GstRTSPSessionMediaPrivate))
 
-#define DEFAULT_TIMEOUT        60
+struct _GstRTSPSessionMediaPrivate
+{
+  GMutex lock;
+  GstRTSPUrl *url;              /* unmutable */
+  GstRTSPMedia *media;          /* unmutable */
+  GstRTSPState state;           /* protected by lock */
+  guint counter;                /* protected by lock */
+
+  GPtrArray *transports;        /* protected by lock */
+};
 
 enum
 {
@@ -42,6 +52,8 @@ gst_rtsp_session_media_class_init (GstRTSPSessionMediaClass * klass)
 {
   GObjectClass *gobject_class;
 
+  g_type_class_add_private (klass, sizeof (GstRTSPSessionMediaPrivate));
+
   gobject_class = G_OBJECT_CLASS (klass);
 
   gobject_class->finalize = gst_rtsp_session_media_finalize;
@@ -53,24 +65,32 @@ gst_rtsp_session_media_class_init (GstRTSPSessionMediaClass * klass)
 static void
 gst_rtsp_session_media_init (GstRTSPSessionMedia * media)
 {
-  media->state = GST_RTSP_STATE_INIT;
+  GstRTSPSessionMediaPrivate *priv = GST_RTSP_SESSION_MEDIA_GET_PRIVATE (media);
+
+  media->priv = priv;
+
+  g_mutex_init (&priv->lock);
+  priv->state = GST_RTSP_STATE_INIT;
 }
 
 static void
 gst_rtsp_session_media_finalize (GObject * obj)
 {
   GstRTSPSessionMedia *media;
+  GstRTSPSessionMediaPrivate *priv;
 
   media = GST_RTSP_SESSION_MEDIA (obj);
+  priv = media->priv;
 
   GST_INFO ("free session media %p", media);
 
   gst_rtsp_session_media_set_state (media, GST_STATE_NULL);
 
-  g_ptr_array_unref (media->transports);
+  g_ptr_array_unref (priv->transports);
 
-  gst_rtsp_url_free (media->url);
-  g_object_unref (media->media);
+  gst_rtsp_url_free (priv->url);
+  g_object_unref (priv->media);
+  g_mutex_clear (&priv->lock);
 
   G_OBJECT_CLASS (gst_rtsp_session_media_parent_class)->finalize (obj);
 }
@@ -97,65 +117,145 @@ free_session_media (gpointer data)
 GstRTSPSessionMedia *
 gst_rtsp_session_media_new (const GstRTSPUrl * url, GstRTSPMedia * media)
 {
+  GstRTSPSessionMediaPrivate *priv;
   GstRTSPSessionMedia *result;
   guint n_streams;
 
   g_return_val_if_fail (url != NULL, NULL);
   g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
-  g_return_val_if_fail (media->status == GST_RTSP_MEDIA_STATUS_PREPARED, NULL);
+  g_return_val_if_fail (gst_rtsp_media_get_status (media) ==
+      GST_RTSP_MEDIA_STATUS_PREPARED, NULL);
 
   result = g_object_new (GST_TYPE_RTSP_SESSION_MEDIA, NULL);
-  result->url = gst_rtsp_url_copy ((GstRTSPUrl *) url);
-  result->media = media;
+  priv = result->priv;
+
+  priv->url = gst_rtsp_url_copy ((GstRTSPUrl *) url);
+  priv->media = media;
 
   /* prealloc the streams now, filled with NULL */
   n_streams = gst_rtsp_media_n_streams (media);
-  result->transports = g_ptr_array_new_full (n_streams, free_session_media);
-  g_ptr_array_set_size (result->transports, n_streams);
+  priv->transports = g_ptr_array_new_full (n_streams, free_session_media);
+  g_ptr_array_set_size (priv->transports, n_streams);
 
   return result;
 }
 
 /**
- * gst_rtsp_session_media_get_transport:
+ * gst_rtsp_session_media_matches_url:
  * @media: a #GstRTSPSessionMedia
- * @idx: the stream index
+ * @url: a #GstRTSPUrl
  *
- * Get a previously created or create a new #GstRTSPStreamTransport at @idx.
+ * Check if the url of @media matches @url.
  *
- * Returns: a #GstRTSPStreamTransport that is valid until the session of @media
- * is unreffed.
+ * Returns: %TRUE when @url matches the url of @media.
  */
-GstRTSPStreamTransport *
-gst_rtsp_session_media_get_transport (GstRTSPSessionMedia * media, guint idx)
+gboolean
+gst_rtsp_session_media_matches_url (GstRTSPSessionMedia * media,
+    const GstRTSPUrl * url)
 {
-  GstRTSPStreamTransport *result;
+  g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), FALSE);
+  g_return_val_if_fail (url != NULL, FALSE);
 
+  return g_str_equal (media->priv->url->abspath, url->abspath);
+}
+
+/**
+ * gst_rtsp_session_media_get_media:
+ * @media: a #GstRTSPSessionMedia
+ *
+ * Get the #GstRTSPMedia that was used when constructing @media
+ *
+ * Returns: (transfer none): the #GstRTSPMedia of @media. Remains valid as long
+ *         as @media is valid.
+ */
+GstRTSPMedia *
+gst_rtsp_session_media_get_media (GstRTSPSessionMedia * media)
+{
   g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL);
-  g_return_val_if_fail (media->media != NULL, NULL);
 
-  if (idx >= media->transports->len)
-    return NULL;
+  return media->priv->media;
+}
 
-  result = g_ptr_array_index (media->transports, idx);
-  if (result == NULL) {
-    GstRTSPStream *stream;
+/**
+ * gst_rtsp_session_media_get_base_time:
+ * @media: a #GstRTSPSessionMedia
+ *
+ * Get the base_time of the #GstRTSPMedia in @media
+ *
+ * Returns: the base_time of the media.
+ */
+GstClockTime
+gst_rtsp_session_media_get_base_time (GstRTSPSessionMedia * media)
+{
+  g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), GST_CLOCK_TIME_NONE);
 
-    stream = gst_rtsp_media_get_stream (media->media, idx);
-    if (stream == NULL)
-      goto no_media;
+  return gst_rtsp_media_get_base_time (media->priv->media);
+}
 
-    result = gst_rtsp_stream_transport_new (stream);
+/**
+ * gst_rtsp_session_media_set_transport:
+ * @media: a #GstRTSPSessionMedia
+ * @stream: a #GstRTSPStream
+ * @tr: a #GstRTSPTransport
+ *
+ * Configure the transport for @stream to @tr in @media.
+ *
+ * Returns: (transfer none): the new or updated #GstRTSPStreamTransport for @stream.
+ */
+GstRTSPStreamTransport *
+gst_rtsp_session_media_set_transport (GstRTSPSessionMedia * media,
+    GstRTSPStream * stream, GstRTSPTransport * tr)
+{
+  GstRTSPSessionMediaPrivate *priv;
+  GstRTSPStreamTransport *result;
+  guint idx;
 
-    g_ptr_array_index (media->transports, idx) = result;
+  g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL);
+  g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), NULL);
+  g_return_val_if_fail (tr != NULL, NULL);
+  priv = media->priv;
+  idx = gst_rtsp_stream_get_index (stream);
+  g_return_val_if_fail (idx < priv->transports->len, NULL);
+
+  g_mutex_lock (&priv->lock);
+  result = g_ptr_array_index (priv->transports, idx);
+  if (result == NULL) {
+    result = gst_rtsp_stream_transport_new (stream, tr);
+    g_ptr_array_index (priv->transports, idx) = result;
+    g_mutex_unlock (&priv->lock);
+  } else {
+    gst_rtsp_stream_transport_set_transport (result, tr);
+    g_mutex_unlock (&priv->lock);
   }
+
   return result;
+}
 
-  /* ERRORS */
-no_media:
-  {
-    return NULL;
-  }
+/**
+ * gst_rtsp_session_media_get_transport:
+ * @media: a #GstRTSPSessionMedia
+ * @idx: the stream index
+ *
+ * Get a previously created #GstRTSPStreamTransport for the stream at @idx.
+ *
+ * Returns: (transfer none): a #GstRTSPStreamTransport that is valid until the
+ * session of @media is unreffed.
+ */
+GstRTSPStreamTransport *
+gst_rtsp_session_media_get_transport (GstRTSPSessionMedia * media, guint idx)
+{
+  GstRTSPSessionMediaPrivate *priv;
+  GstRTSPStreamTransport *result;
+
+  g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), NULL);
+  priv = media->priv;
+  g_return_val_if_fail (idx < priv->transports->len, NULL);
+
+  g_mutex_lock (&priv->lock);
+  result = g_ptr_array_index (priv->transports, idx);
+  g_mutex_unlock (&priv->lock);
+
+  return result;
 }
 
 /**
@@ -172,10 +272,16 @@ gboolean
 gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia * media,
     GstRTSPRange * range)
 {
+  GstRTSPSessionMediaPrivate *priv;
+
   g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), FALSE);
 
-  range->min = media->counter++;
-  range->max = media->counter++;
+  priv = media->priv;
+
+  g_mutex_lock (&priv->lock);
+  range->min = priv->counter++;
+  range->max = priv->counter++;
+  g_mutex_unlock (&priv->lock);
 
   return TRUE;
 }
@@ -192,11 +298,64 @@ gst_rtsp_session_media_alloc_channels (GstRTSPSessionMedia * media,
 gboolean
 gst_rtsp_session_media_set_state (GstRTSPSessionMedia * media, GstState state)
 {
+  GstRTSPSessionMediaPrivate *priv;
   gboolean ret;
 
   g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media), FALSE);
 
-  ret = gst_rtsp_media_set_state (media->media, state, media->transports);
+  priv = media->priv;
+
+  g_mutex_lock (&priv->lock);
+  ret = gst_rtsp_media_set_state (priv->media, state, priv->transports);
+  g_mutex_unlock (&priv->lock);
+
+  return ret;
+}
+
+/**
+ * gst_rtsp_session_media_set_rtsp_state:
+ * @media: a #GstRTSPSessionMedia
+ * @state: a #GstRTSPState
+ *
+ * Set the RTSP state of @media to @state.
+ */
+void
+gst_rtsp_session_media_set_rtsp_state (GstRTSPSessionMedia * media,
+    GstRTSPState state)
+{
+  GstRTSPSessionMediaPrivate *priv;
+
+  g_return_if_fail (GST_IS_RTSP_SESSION_MEDIA (media));
+
+  priv = media->priv;
+
+  g_mutex_lock (&priv->lock);
+  priv->state = state;
+  g_mutex_unlock (&priv->lock);
+}
+
+/**
+ * gst_rtsp_session_media_set_rtsp_state:
+ * @media: a #GstRTSPSessionMedia
+ *
+ * Get the current RTSP state of @media.
+ *
+ * Returns: the current RTSP state of @media.
+ */
+GstRTSPState
+gst_rtsp_session_media_get_rtsp_state (GstRTSPSessionMedia * media)
+{
+  GstRTSPSessionMediaPrivate *priv;
+  GstRTSPState ret;
+
+  g_return_val_if_fail (GST_IS_RTSP_SESSION_MEDIA (media),
+      GST_RTSP_STATE_INVALID);
+
+  priv = media->priv;
+
+  g_mutex_lock (&priv->lock);
+  ret = priv->state;
+  g_mutex_unlock (&priv->lock);
 
   return ret;
 }