client: expose connection
[platform/upstream/gstreamer.git] / gst / rtsp-server / rtsp-client.c
index a6510e5..af07253 100644 (file)
 #define GST_RTSP_CLIENT_GET_PRIVATE(obj)  \
    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_CLIENT, GstRTSPClientPrivate))
 
+/* locking order:
+ * send_lock, lock, tunnels_lock
+ */
+
 struct _GstRTSPClientPrivate
 {
-  GMutex lock;
+  GMutex lock;                  /* protects everything else */
+  GMutex send_lock;
   GstRTSPConnection *connection;
   GstRTSPWatch *watch;
   guint close_seq;
@@ -37,9 +42,9 @@ struct _GstRTSPClientPrivate
   gboolean is_ipv6;
   gboolean use_client_settings;
 
-  GstRTSPClientSendFunc send_func;
-  gpointer send_data;
-  GDestroyNotify send_notify;
+  GstRTSPClientSendFunc send_func;      /* protected by send_lock */
+  gpointer send_data;           /* protected by send_lock */
+  GDestroyNotify send_notify;   /* protected by send_lock */
 
   GstRTSPSessionPool *session_pool;
   GstRTSPMountPoints *mount_points;
@@ -53,7 +58,7 @@ struct _GstRTSPClientPrivate
 };
 
 static GMutex tunnels_lock;
-static GHashTable *tunnels;
+static GHashTable *tunnels;     /* protected by tunnels_lock */
 
 #define DEFAULT_SESSION_POOL            NULL
 #define DEFAULT_MOUNT_POINTS            NULL
@@ -208,6 +213,7 @@ gst_rtsp_client_init (GstRTSPClient * client)
   client->priv = priv;
 
   g_mutex_init (&priv->lock);
+  g_mutex_init (&priv->send_lock);
   priv->use_client_settings = DEFAULT_USE_CLIENT_SETTINGS;
   priv->close_seq = 0;
 }
@@ -258,12 +264,11 @@ gst_rtsp_client_finalize (GObject * obj)
 
   GST_INFO ("finalize client %p", client);
 
+  gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
+
   if (priv->watch)
     g_source_destroy ((GSource *) priv->watch);
 
-  if (priv->send_notify)
-    priv->send_notify (priv->send_data);
-
   client_cleanup_sessions (client);
 
   if (priv->connection)
@@ -284,6 +289,7 @@ gst_rtsp_client_finalize (GObject * obj)
 
   g_free (priv->server_ip);
   g_mutex_clear (&priv->lock);
+  g_mutex_clear (&priv->send_lock);
 
   G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj);
 }
@@ -374,8 +380,10 @@ send_response (GstRTSPClient * client, GstRTSPSession * session,
   if (close)
     gst_rtsp_message_add_header (response, GST_RTSP_HDR_CONNECTION, "close");
 
+  g_mutex_lock (&priv->send_lock);
   if (priv->send_func)
     priv->send_func (client, response, close, priv->send_data);
+  g_mutex_unlock (&priv->send_lock);
 
   gst_rtsp_message_unset (response);
 }
@@ -543,8 +551,10 @@ do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client)
 
   gst_rtsp_message_take_body (&message, map_info.data, map_info.size);
 
+  g_mutex_lock (&priv->send_lock);
   if (priv->send_func)
     priv->send_func (client, &message, FALSE, priv->send_data);
+  g_mutex_unlock (&priv->send_lock);
 
   gst_rtsp_message_steal_body (&message, &data, &usize);
   gst_buffer_unmap (buffer, &map_info);
@@ -849,6 +859,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state)
   GstRTSPTimeRange *range;
   GstRTSPResult res;
   GstRTSPState rtspstate;
+  GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT;
 
   if (!(session = state->session))
     goto no_session;
@@ -872,6 +883,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state)
     if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) {
       /* we have a range, seek to the position */
       gst_rtsp_media_seek (gst_rtsp_session_media_get_media (media), range);
+      unit = range->unit;
       gst_rtsp_range_free (range);
     }
   }
@@ -933,7 +945,7 @@ handle_play_request (GstRTSPClient * client, GstRTSPClientState * state)
   /* add the range */
   str =
       gst_rtsp_media_get_range_string (gst_rtsp_session_media_get_media (media),
-      TRUE);
+      TRUE, unit);
   gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RANGE, str);
 
   send_response (client, session, state->response, FALSE);
@@ -1066,7 +1078,17 @@ configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state,
 
   /* we have a valid transport now, set the destination of the client. */
   if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
-    if (ct->destination == NULL || !priv->use_client_settings) {
+    if (ct->destination && priv->use_client_settings) {
+      GstRTSPAddress *addr;
+
+      addr = gst_rtsp_stream_reserve_address (state->stream, ct->destination,
+          ct->port.min, ct->port.max - ct->port.min + 1, ct->ttl);
+
+      if (addr == NULL)
+        goto no_address;
+
+      gst_rtsp_address_free (addr);
+    } else {
       GstRTSPAddress *addr;
 
       addr = gst_rtsp_stream_get_address (state->stream);
@@ -1078,6 +1100,8 @@ configure_client_transport (GstRTSPClient * client, GstRTSPClientState * state,
       ct->port.min = addr->port;
       ct->port.max = addr->port + addr->n_ports - 1;
       ct->ttl = addr->ttl;
+
+      gst_rtsp_address_free (addr);
     }
   } else {
     GstRTSPUrl *url;
@@ -2004,6 +2028,50 @@ gst_rtsp_client_get_auth (GstRTSPClient * client)
 }
 
 /**
+ * gst_rtsp_client_get_uri:
+ * @client: a #GstRTSPClient
+ *
+ * Get the #GstRTSPUrl of @client.
+ *
+ * Returns: (transfer full): the #GstRTSPUrl of @client. Free with
+ * gst_rtsp_url_free () after usage.
+ */
+GstRTSPUrl *
+gst_rtsp_client_get_uri (GstRTSPClient * client)
+{
+  GstRTSPClientPrivate *priv;
+  GstRTSPUrl *result = NULL;
+
+  g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
+
+  priv = client->priv;
+
+  g_mutex_lock (&priv->lock);
+  if (priv->uri != NULL)
+    result = gst_rtsp_url_copy (priv->uri);
+  g_mutex_unlock (&priv->lock);
+
+  return result;
+}
+
+/**
+ * gst_rtsp_client_get_connection:
+ * @client: a #GstRTSPClient
+ *
+ * Get the #GstRTSPConnection of @client.
+ *
+ * Returns: (transfer none): the #GstRTSPConnection of @client.
+ * The connection object returned remains valid until the client is freed.
+ */
+GstRTSPConnection *
+gst_rtsp_client_get_connection (GstRTSPClient * client)
+{
+  g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
+
+  return client->priv->connection;
+}
+
+/**
  * gst_rtsp_client_set_send_func:
  * @client: a #GstRTSPClient
  * @func: a #GstRTSPClientSendFunc
@@ -2026,13 +2094,13 @@ gst_rtsp_client_set_send_func (GstRTSPClient * client,
 
   priv = client->priv;
 
-  g_mutex_lock (&priv->lock);
+  g_mutex_lock (&priv->send_lock);
   priv->send_func = func;
   old_notify = priv->send_notify;
   old_data = priv->send_data;
   priv->send_notify = notify;
   priv->send_data = user_data;
-  g_mutex_unlock (&priv->lock);
+  g_mutex_unlock (&priv->send_lock);
 
   if (old_notify)
     old_notify (old_data);
@@ -2118,6 +2186,8 @@ closed (GstRTSPWatch * watch, gpointer user_data)
     g_mutex_unlock (&tunnels_lock);
   }
 
+  gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
+
   return GST_RTSP_OK;
 }
 
@@ -2461,7 +2531,8 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context)
   /* create watch for the connection and attach */
   priv->watch = gst_rtsp_watch_new (priv->connection, &watch_funcs,
       g_object_ref (client), (GDestroyNotify) client_watch_notify);
-  gst_rtsp_client_set_send_func (client, do_send_message, NULL, NULL);
+  gst_rtsp_client_set_send_func (client, do_send_message, priv->watch,
+      (GDestroyNotify) gst_rtsp_watch_unref);
 
   /* FIXME make this configurable. We don't want to do this yet because it will
    * be superceeded by a cache object later */
@@ -2469,7 +2540,6 @@ gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context)
 
   GST_INFO ("attaching to context %p", context);
   res = gst_rtsp_watch_attach (priv->watch, context);
-  gst_rtsp_watch_unref (priv->watch);
 
   return res;
 }