#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;
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;
};
static GMutex tunnels_lock;
-static GHashTable *tunnels;
+static GHashTable *tunnels; /* protected by tunnels_lock */
#define DEFAULT_SESSION_POOL NULL
#define DEFAULT_MOUNT_POINTS NULL
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;
}
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)
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);
}
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);
}
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);
GstRTSPTimeRange *range;
GstRTSPResult res;
GstRTSPState rtspstate;
+ GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT;
if (!(session = state->session))
goto no_session;
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);
}
}
/* 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);
/* 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);
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;
}
/**
+ * 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
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);
g_mutex_unlock (&tunnels_lock);
}
+ gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
+
return GST_RTSP_OK;
}
/* 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 */
GST_INFO ("attaching to context %p", context);
res = gst_rtsp_watch_attach (priv->watch, context);
- gst_rtsp_watch_unref (priv->watch);
return res;
}