{
GstRTSPClient *client = GST_RTSP_CLIENT (obj);
+ g_message ("finalize client %p", client);
+
gst_rtsp_connection_free (client->connection);
if (client->session_pool)
g_object_unref (client->session_pool);
static void
send_response (GstRTSPClient *client, GstRTSPMessage *response)
{
+ gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER, "GStreamer RTSP server");
+
#ifdef DEBUG
gst_rtsp_message_dump (response);
#endif
/* now keep track of the uri and the media */
client->uri = gst_rtsp_url_copy (uri);
- client->media = g_object_ref (media);
+ client->media = media;
}
else {
/* we have seen this uri before, used cached media */
- media = g_object_ref (client->media);
+ media = client->media;
g_message ("reusing cached media %p", media);
}
+ if (media)
+ g_object_ref (media);
+
return media;
/* ERRORS */
gst_rtsp_session_media_stop (media);
- gst_rtsp_session_pool_remove (client->session_pool, session);
- g_object_unref (session);
+ /* unmanage the media in the session, returns false if all media session
+ * are torn down. */
+ if (!gst_rtsp_session_release_media (session, media)) {
+ /* remove the session */
+ gst_rtsp_session_pool_remove (client->session_pool, session);
- /* remove the session id from the request, which will also remove it from the
- * response */
- gst_rtsp_message_remove_header (request, GST_RTSP_HDR_SESSION, -1);
+ /* remove the session id from the request, which will also remove it from the
+ * response */
+ gst_rtsp_message_remove_header (request, GST_RTSP_HDR_SESSION, -1);
+ }
+ g_object_unref (session);
/* construct the response now */
code = GST_RTSP_STS_OK;
not_found:
{
send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
+ g_object_unref (session);
return FALSE;
}
invalid_state:
{
send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, request);
+ g_object_unref (session);
return FALSE;
}
}
GString *rtpinfo;
guint n_streams, i;
guint timestamp, seqnum;
+ gchar *str;
if (!(session = ensure_session (client, request)))
goto no_session;
gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request);
/* add the RTP-Info header */
- gst_rtsp_message_add_header (&response, GST_RTSP_HDR_RTP_INFO, rtpinfo->str);
- g_string_free (rtpinfo, TRUE);
+ str = g_string_free (rtpinfo, FALSE);
+ gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RTP_INFO, str);
+
+ /* add the range */
+ str = gst_rtsp_range_to_string (&media->media->range);
+ gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RANGE, str);
send_response (client, &response);
not_found:
{
send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
+ g_object_unref (session);
return FALSE;
}
invalid_state:
{
send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, request);
+ g_object_unref (session);
return FALSE;
}
}
/* we had a session in the request, find it again */
if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid)))
goto session_not_found;
+
+ /* get a handle to the configuration of the media in the session, this can
+ * return NULL if this is a new url to manage in this session. */
+ media = gst_rtsp_session_get_media (session, uri);
+
need_session = FALSE;
}
else {
* something. */
if (!(session = gst_rtsp_session_pool_create (client->session_pool)))
goto service_unavailable;
+
+ /* we need a new media configuration in this session */
+ media = NULL;
+
need_session = TRUE;
}
- if (need_session) {
+ /* we have no media, find one and manage it */
+ if (media == NULL) {
GstRTSPMedia *m;
/* get a handle to the configuration of the media in the session */
media = gst_rtsp_session_manage_media (session, uri, m);
}
}
- /* get a handle to the configuration of the media in the session */
- if (!(media = gst_rtsp_session_get_media (session, uri)))
+
+ /* if we stil have no media, error */
+ if (media == NULL)
goto not_found;
/* get a handle to the stream in the media */
code = GST_RTSP_STS_OK;
gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request);
+ /* add the new session header for new session ids */
if (need_session)
gst_rtsp_message_add_header (&response, GST_RTSP_HDR_SESSION, session->sessionid);
no_stream:
{
send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
+ g_object_unref (media);
return FALSE;
}
session_not_found:
if (!(sdp = gst_rtsp_sdp_from_media (media)))
goto no_sdp;
+ g_object_unref (media);
+
gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK,
gst_rtsp_status_as_text (GST_RTSP_STS_OK), request);
media = GST_RTSP_MEDIA (obj);
+ g_message ("finalize media %p", media);
+
for (i = 0; i < media->streams->len; i++) {
GstRTSPMediaStream *stream;
return TRUE;
}
+static void
+collect_media_stats (GstRTSPMedia *media)
+{
+ GstFormat format;
+ gint64 duration;
+
+ media->range.unit = GST_RTSP_RANGE_NPT;
+ media->range.min.type = GST_RTSP_TIME_SECONDS;
+ media->range.min.seconds = 0.0;
+
+ /* get the duration */
+ format = GST_FORMAT_TIME;
+ if (!gst_element_query_duration (media->pipeline, &format, &duration))
+ duration = -1;
+
+ if (duration == -1) {
+ media->range.max.type = GST_RTSP_TIME_END;
+ media->range.max.seconds = -1;
+ }
+ else {
+ media->range.max.type = GST_RTSP_TIME_SECONDS;
+ media->range.max.seconds = ((gdouble)duration) / GST_SECOND;
+ }
+}
+
/**
* gst_rtsp_media_prepare:
* @obj: a #GstRTSPMedia
/* and back to PAUSED for live pipelines */
ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
+ /* collect stats about the media */
+ collect_media_stats (media);
+
/* unlock the udp src elements */
n_streams = gst_rtsp_media_n_streams (media);
for (i = 0; i < n_streams; i++) {
*/
#include <gst/gst.h>
+#include <gst/rtsp/gstrtsprange.h>
#include <gst/rtsp/gstrtspurl.h>
#ifndef __GST_RTSP_MEDIA_H__
/* for TCP transport */
GstElement *multifdsink;
+
+ /* the range of media */
+ GstRTSPTimeRange range;
};
struct _GstRTSPMediaClass {
{
GstSDPMessage *sdp;
guint i, n_streams;
+ gchar *rangestr;
n_streams = gst_rtsp_media_n_streams (media);
gst_sdp_message_add_time (sdp, "0", "0", NULL);
gst_sdp_message_add_attribute (sdp, "tool", "GStreamer");
gst_sdp_message_add_attribute (sdp, "type", "broadcast");
+ rangestr = gst_rtsp_range_to_string (&media->range);
+ gst_sdp_message_add_attribute (sdp, "range", rangestr);
+ g_free (rangestr);
for (i = 0; i < n_streams; i++) {
GstRTSPMediaStream *stream;
{
pool->lock = g_mutex_new ();
pool->sessions = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, g_object_unref);
+ NULL, g_object_unref);
}
static void
g_return_if_fail (GST_IS_RTSP_SESSION (sess));
g_mutex_lock (pool->lock);
- found = g_hash_table_remove (pool->sessions, sess);
+ found = g_hash_table_remove (pool->sessions, sess->sessionid);
g_mutex_unlock (pool->lock);
}
static void
gst_rtsp_session_free_stream (GstRTSPSessionStream *stream)
{
+ g_message ("free session stream %p", stream);
+
if (stream->trans.transport)
gst_rtsp_transport_free (stream->trans.transport);
size = media->streams->len;
+ g_message ("free session media %p", media);
+
for (i = 0; i < size; i++) {
GstRTSPSessionStream *stream;
session = GST_RTSP_SESSION (obj);
+ g_message ("finalize session %p", session);
+
/* free all media */
g_list_foreach (session->medias, (GFunc) gst_rtsp_session_free_media,
session);
* gst_rtsp_session_manage_media:
* @sess: a #GstRTSPSession
* @url: the url for the media
- * @obj: a #GstRTSPMediaObject
+ * @media: a #GstRTSPMediaObject
*
* Manage the media object @obj in @sess. @url will be used to retrieve this
- * media object from the session with gst_rtsp_session_get_media().
+ * media from the session with gst_rtsp_session_get_media().
+ *
+ * Ownership is taken from @media.
*
* Returns: a new @GstRTSPSessionMedia object.
*/
sess->medias = g_list_prepend (sess->medias, result);
- g_message ("manage new media %p in session %p", media, sess);
+ g_message ("manage new media %p in session %p", media, result);
return result;
}
/**
+ * gst_rtsp_session_release_media:
+ * @sess: a #GstRTSPSession
+ * @media: a #GstRTSPMediaObject
+ *
+ * Release the managed @media in @sess, freeing the memory allocated by it.
+ *
+ * Returns: %TRUE if there are more media session left in @sess.
+ */
+gboolean
+gst_rtsp_session_release_media (GstRTSPSession *sess,
+ GstRTSPSessionMedia *media)
+{
+ GList *walk, *next;
+
+ g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), FALSE);
+ g_return_val_if_fail (media != NULL, FALSE);
+
+ for (walk = sess->medias; walk;) {
+ GstRTSPSessionMedia *find;
+
+ find = (GstRTSPSessionMedia *) walk->data;
+ next = g_list_next (walk);
+
+ if (find == media) {
+ sess->medias = g_list_delete_link (sess->medias, walk);
+
+ gst_rtsp_session_free_media (find, sess);
+ break;
+ }
+ walk = next;
+ }
+ return (sess->medias != NULL);
+}
+
+/**
* gst_rtsp_session_get_media:
* @sess: a #GstRTSPSession
* @url: the url for the media
*
* Get the session media of the @url.
*
- * Returns: the configuration for @url in @sess.
+ * Returns: the configuration for @url in @sess.
*/
GstRTSPSessionMedia *
gst_rtsp_session_get_media (GstRTSPSession *sess, const GstRTSPUrl *url)
GstRTSPSessionMedia * gst_rtsp_session_manage_media (GstRTSPSession *sess,
const GstRTSPUrl *uri,
GstRTSPMedia *media);
+gboolean gst_rtsp_session_release_media (GstRTSPSession *sess,
+ GstRTSPSessionMedia *media);
/* get media in a session */
GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess,
const GstRTSPUrl *uri);
-
/* control media */
gboolean gst_rtsp_session_media_play (GstRTSPSessionMedia *media);
gboolean gst_rtsp_session_media_pause (GstRTSPSessionMedia *media);