2 * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 #include <sys/ioctl.h>
22 #include "rtsp-client.h"
27 static GMutex *tunnels_lock;
28 static GHashTable *tunnels;
38 static void gst_rtsp_client_get_property (GObject *object, guint propid,
39 GValue *value, GParamSpec *pspec);
40 static void gst_rtsp_client_set_property (GObject *object, guint propid,
41 const GValue *value, GParamSpec *pspec);
42 static void gst_rtsp_client_finalize (GObject * obj);
44 static void client_session_finalized (GstRTSPClient *client, GstRTSPSession *session);
46 G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT);
49 gst_rtsp_client_class_init (GstRTSPClientClass * klass)
51 GObjectClass *gobject_class;
53 gobject_class = G_OBJECT_CLASS (klass);
55 gobject_class->get_property = gst_rtsp_client_get_property;
56 gobject_class->set_property = gst_rtsp_client_set_property;
57 gobject_class->finalize = gst_rtsp_client_finalize;
59 g_object_class_install_property (gobject_class, PROP_SESSION_POOL,
60 g_param_spec_object ("session-pool", "Session Pool",
61 "The session pool to use for client session",
62 GST_TYPE_RTSP_SESSION_POOL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
64 g_object_class_install_property (gobject_class, PROP_MEDIA_MAPPING,
65 g_param_spec_object ("media-mapping", "Media Mapping",
66 "The media mapping to use for client session",
67 GST_TYPE_RTSP_MEDIA_MAPPING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
69 tunnels = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
70 tunnels_lock = g_mutex_new ();
74 gst_rtsp_client_init (GstRTSPClient * client)
78 /* A client is finalized when the connection is broken */
80 gst_rtsp_client_finalize (GObject * obj)
82 GstRTSPClient *client = GST_RTSP_CLIENT (obj);
85 g_message ("finalize client %p", client);
87 for (walk = client->sessions; walk; walk = g_list_next (walk))
88 g_object_weak_unref (G_OBJECT (walk->data), (GWeakNotify) client_session_finalized, client);
89 g_list_free (client->sessions);
91 gst_rtsp_connection_free (client->connection);
92 if (client->session_pool)
93 g_object_unref (client->session_pool);
94 if (client->media_mapping)
95 g_object_unref (client->media_mapping);
98 gst_rtsp_url_free (client->uri);
100 g_object_unref (client->media);
102 G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj);
106 gst_rtsp_client_get_property (GObject *object, guint propid,
107 GValue *value, GParamSpec *pspec)
109 GstRTSPClient *client = GST_RTSP_CLIENT (object);
112 case PROP_SESSION_POOL:
113 g_value_take_object (value, gst_rtsp_client_get_session_pool (client));
115 case PROP_MEDIA_MAPPING:
116 g_value_take_object (value, gst_rtsp_client_get_media_mapping (client));
119 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
124 gst_rtsp_client_set_property (GObject *object, guint propid,
125 const GValue *value, GParamSpec *pspec)
127 GstRTSPClient *client = GST_RTSP_CLIENT (object);
130 case PROP_SESSION_POOL:
131 gst_rtsp_client_set_session_pool (client, g_value_get_object (value));
133 case PROP_MEDIA_MAPPING:
134 gst_rtsp_client_set_media_mapping (client, g_value_get_object (value));
137 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
142 * gst_rtsp_client_new:
144 * Create a new #GstRTSPClient instance.
147 gst_rtsp_client_new (void)
149 GstRTSPClient *result;
151 result = g_object_new (GST_TYPE_RTSP_CLIENT, NULL);
157 send_response (GstRTSPClient *client, GstRTSPSession *session, GstRTSPMessage *response)
159 gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER, "GStreamer RTSP server");
161 /* remove any previous header */
162 gst_rtsp_message_remove_header (response, GST_RTSP_HDR_SESSION, -1);
164 /* add the new session header for new session ids */
168 if (session->timeout != 60)
169 str = g_strdup_printf ("%s; timeout=%d", session->sessionid, session->timeout);
171 str = g_strdup (session->sessionid);
173 gst_rtsp_message_take_header (response, GST_RTSP_HDR_SESSION, str);
177 gst_rtsp_message_dump (response);
180 gst_rtsp_watch_queue_message (client->watch, response);
181 gst_rtsp_message_unset (response);
185 send_generic_response (GstRTSPClient *client, GstRTSPStatusCode code,
186 GstRTSPMessage *request)
188 GstRTSPMessage response = { 0 };
190 gst_rtsp_message_init_response (&response, code,
191 gst_rtsp_status_as_text (code), request);
193 send_response (client, NULL, &response);
197 compare_uri (const GstRTSPUrl *uri1, const GstRTSPUrl *uri2)
199 if (uri1 == NULL || uri2 == NULL)
202 if (strcmp (uri1->abspath, uri2->abspath))
208 /* this function is called to initially find the media for the DESCRIBE request
209 * but is cached for when the same client (without breaking the connection) is
210 * doing a setup for the exact same url. */
211 static GstRTSPMedia *
212 find_media (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *request)
214 GstRTSPMediaFactory *factory;
217 if (!compare_uri (client->uri, uri)) {
218 /* remove any previously cached values before we try to construct a new
221 gst_rtsp_url_free (client->uri);
224 g_object_unref (client->media);
225 client->media = NULL;
227 if (!client->media_mapping)
230 /* find the factory for the uri first */
231 if (!(factory = gst_rtsp_media_mapping_find_factory (client->media_mapping, uri)))
234 /* prepare the media and add it to the pipeline */
235 if (!(media = gst_rtsp_media_factory_construct (factory, uri)))
238 /* prepare the media */
239 if (!(gst_rtsp_media_prepare (media)))
242 /* now keep track of the uri and the media */
243 client->uri = gst_rtsp_url_copy (uri);
244 client->media = media;
247 /* we have seen this uri before, used cached media */
248 media = client->media;
249 g_message ("reusing cached media %p", media);
253 g_object_ref (media);
260 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
265 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
270 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
271 g_object_unref (factory);
276 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
277 g_object_unref (media);
278 g_object_unref (factory);
284 do_send_data (GstBuffer *buffer, guint8 channel, GstRTSPClient *client)
286 GstRTSPMessage message = { 0 };
290 gst_rtsp_message_init_data (&message, channel);
292 data = GST_BUFFER_DATA (buffer);
293 size = GST_BUFFER_SIZE (buffer);
294 gst_rtsp_message_take_body (&message, data, size);
296 gst_rtsp_watch_queue_message (client->watch, &message);
298 gst_rtsp_message_steal_body (&message, &data, &size);
299 gst_rtsp_message_unset (&message);
305 link_stream (GstRTSPClient *client, GstRTSPSessionStream *stream)
307 gst_rtsp_session_stream_set_callbacks (stream, (GstRTSPSendFunc) do_send_data,
308 (GstRTSPSendFunc) do_send_data, client, NULL);
309 client->streams = g_list_prepend (client->streams, stream);
313 unlink_stream (GstRTSPClient *client, GstRTSPSessionStream *stream)
315 gst_rtsp_session_stream_set_callbacks (stream, NULL,
316 NULL, client, g_object_unref);
317 client->streams = g_list_remove (client->streams, stream);
321 unlink_streams (GstRTSPClient *client)
325 for (walk = client->streams; walk; walk = g_list_next (walk)) {
326 GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data;
328 gst_rtsp_session_stream_set_callbacks (stream, NULL,
331 g_list_free (client->streams);
332 client->streams = NULL;
336 unlink_session_streams (GstRTSPClient *client, GstRTSPSessionMedia *media)
340 n_streams = gst_rtsp_media_n_streams (media->media);
341 for (i = 0; i < n_streams; i++) {
342 GstRTSPSessionStream *sstream;
343 GstRTSPTransport *tr;
345 /* get the stream as configured in the session */
346 sstream = gst_rtsp_session_media_get_stream (media, i);
347 /* get the transport, if there is no transport configured, skip this stream */
348 if (!(tr = sstream->trans.transport))
351 if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
352 /* for TCP, unlink the stream from the TCP connection of the client */
353 unlink_stream (client, sstream);
359 handle_teardown_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request)
361 GstRTSPSessionMedia *media;
362 GstRTSPMessage response = { 0 };
363 GstRTSPStatusCode code;
368 /* get a handle to the configuration of the media in the session */
369 media = gst_rtsp_session_get_media (session, uri);
373 /* unlink the all TCP callbacks */
374 unlink_session_streams (client, media);
376 /* remove the session from the watched sessions */
377 g_object_weak_unref (G_OBJECT (session), (GWeakNotify) client_session_finalized, client);
378 client->sessions = g_list_remove (client->sessions, session);
380 gst_rtsp_session_media_set_state (media, GST_STATE_NULL);
382 /* unmanage the media in the session, returns false if all media session
384 if (!gst_rtsp_session_release_media (session, media)) {
385 /* remove the session */
386 gst_rtsp_session_pool_remove (client->session_pool, session);
388 /* construct the response now */
389 code = GST_RTSP_STS_OK;
390 gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request);
392 send_response (client, session, &response);
399 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
404 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
410 handle_pause_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request)
412 GstRTSPSessionMedia *media;
413 GstRTSPMessage response = { 0 };
414 GstRTSPStatusCode code;
419 /* get a handle to the configuration of the media in the session */
420 media = gst_rtsp_session_get_media (session, uri);
424 /* the session state must be playing or recording */
425 if (media->state != GST_RTSP_STATE_PLAYING &&
426 media->state != GST_RTSP_STATE_RECORDING)
429 /* unlink the all TCP callbacks */
430 unlink_session_streams (client, media);
432 /* then pause sending */
433 gst_rtsp_session_media_set_state (media, GST_STATE_PAUSED);
435 /* construct the response now */
436 code = GST_RTSP_STS_OK;
437 gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request);
439 send_response (client, session, &response);
441 /* the state is now READY */
442 media->state = GST_RTSP_STATE_READY;
449 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
454 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
459 send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, request);
465 handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request)
467 GstRTSPSessionMedia *media;
468 GstRTSPMessage response = { 0 };
469 GstRTSPStatusCode code;
472 guint timestamp, seqnum;
478 /* get a handle to the configuration of the media in the session */
479 media = gst_rtsp_session_get_media (session, uri);
483 /* the session state must be playing or ready */
484 if (media->state != GST_RTSP_STATE_PLAYING &&
485 media->state != GST_RTSP_STATE_READY)
488 /* grab RTPInfo from the payloaders now */
489 rtpinfo = g_string_new ("");
491 n_streams = gst_rtsp_media_n_streams (media->media);
492 for (i = 0; i < n_streams; i++) {
493 GstRTSPSessionStream *sstream;
494 GstRTSPMediaStream *stream;
495 GstRTSPTransport *tr;
498 /* get the stream as configured in the session */
499 sstream = gst_rtsp_session_media_get_stream (media, i);
500 /* get the transport, if there is no transport configured, skip this stream */
501 if (!(tr = sstream->trans.transport))
504 if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
505 /* for TCP, link the stream to the TCP connection of the client */
506 link_stream (client, sstream);
509 stream = sstream->media_stream;
511 g_object_get (G_OBJECT (stream->payloader), "seqnum", &seqnum, NULL);
512 g_object_get (G_OBJECT (stream->payloader), "timestamp", ×tamp, NULL);
515 g_string_append (rtpinfo, ", ");
517 uristr = gst_rtsp_url_get_request_uri (uri);
518 g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u", uristr, i, seqnum, timestamp);
522 /* construct the response now */
523 code = GST_RTSP_STS_OK;
524 gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request);
526 /* add the RTP-Info header */
527 str = g_string_free (rtpinfo, FALSE);
528 gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RTP_INFO, str);
531 str = gst_rtsp_range_to_string (&media->media->range);
532 gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RANGE, str);
534 send_response (client, session, &response);
536 /* start playing after sending the request */
537 gst_rtsp_session_media_set_state (media, GST_STATE_PLAYING);
539 media->state = GST_RTSP_STATE_PLAYING;
546 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
551 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
556 send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, request);
562 handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request)
567 gboolean have_transport;
568 GstRTSPTransport *ct, *st;
570 GstRTSPLowerTrans supported;
571 GstRTSPMessage response = { 0 };
572 GstRTSPStatusCode code;
573 GstRTSPSessionStream *stream;
574 gchar *trans_str, *pos;
576 GstRTSPSessionMedia *media;
577 gboolean need_session;
580 /* the uri contains the stream number we added in the SDP config, which is
581 * always /stream=%d so we need to strip that off
582 * parse the stream we need to configure, look for the stream in the abspath
583 * first and then in the query. */
584 if (!(pos = strstr (uri->abspath, "/stream="))) {
585 if (!(pos = strstr (uri->query, "/stream=")))
589 /* we can mofify the parse uri in place */
592 pos += strlen ("/stream=");
593 if (sscanf (pos, "%u", &streamid) != 1)
596 /* parse the transport */
597 res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_TRANSPORT, &transport, 0);
598 if (res != GST_RTSP_OK)
601 transports = g_strsplit (transport, ",", 0);
602 gst_rtsp_transport_new (&ct);
604 /* loop through the transports, try to parse */
605 have_transport = FALSE;
606 for (i = 0; transports[i]; i++) {
608 gst_rtsp_transport_init (ct);
609 res = gst_rtsp_transport_parse (transports[i], ct);
610 if (res == GST_RTSP_OK) {
611 have_transport = TRUE;
615 g_strfreev (transports);
617 /* we have not found anything usable, error out */
619 goto unsupported_transports;
621 /* we have a valid transport, check if we can handle it */
622 if (ct->trans != GST_RTSP_TRANS_RTP)
623 goto unsupported_transports;
624 if (ct->profile != GST_RTSP_PROFILE_AVP)
625 goto unsupported_transports;
627 supported = GST_RTSP_LOWER_TRANS_UDP |
628 GST_RTSP_LOWER_TRANS_UDP_MCAST |
629 GST_RTSP_LOWER_TRANS_TCP;
630 if (!(ct->lower_transport & supported))
631 goto unsupported_transports;
633 if (client->session_pool == NULL)
636 /* we have a valid transport now, set the destination of the client. */
637 g_free (ct->destination);
638 url = gst_rtsp_connection_get_url (client->connection);
639 ct->destination = g_strdup (url->host);
642 g_object_ref (session);
643 /* get a handle to the configuration of the media in the session, this can
644 * return NULL if this is a new url to manage in this session. */
645 media = gst_rtsp_session_get_media (session, uri);
647 need_session = FALSE;
650 /* create a session if this fails we probably reached our session limit or
652 if (!(session = gst_rtsp_session_pool_create (client->session_pool)))
653 goto service_unavailable;
655 /* we need a new media configuration in this session */
661 /* we have no media, find one and manage it */
665 /* get a handle to the configuration of the media in the session */
666 if ((m = find_media (client, uri, request))) {
667 /* manage the media in our session now */
668 media = gst_rtsp_session_manage_media (session, uri, m);
672 /* if we stil have no media, error */
676 /* get a handle to the stream in the media */
677 if (!(stream = gst_rtsp_session_media_get_stream (media, streamid)))
680 st = gst_rtsp_session_stream_set_transport (stream, ct);
682 /* serialize the server transport */
683 trans_str = gst_rtsp_transport_as_text (st);
684 gst_rtsp_transport_free (st);
686 /* construct the response now */
687 code = GST_RTSP_STS_OK;
688 gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request);
690 gst_rtsp_message_add_header (&response, GST_RTSP_HDR_TRANSPORT, trans_str);
693 send_response (client, session, &response);
695 /* update the state */
696 switch (media->state) {
697 case GST_RTSP_STATE_PLAYING:
698 case GST_RTSP_STATE_RECORDING:
699 case GST_RTSP_STATE_READY:
700 /* no state change */
703 media->state = GST_RTSP_STATE_READY;
706 g_object_unref (session);
713 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request);
718 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
719 g_object_unref (session);
724 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
725 g_object_unref (media);
726 g_object_unref (session);
731 send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request);
734 unsupported_transports:
736 send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request);
737 gst_rtsp_transport_free (ct);
742 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
747 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
752 /* for the describe we must generate an SDP */
754 handle_describe_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request)
756 GstRTSPMessage response = { 0 };
763 /* check what kind of format is accepted, we don't really do anything with it
764 * and always return SDP for now. */
768 res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_ACCEPT, &accept, i);
769 if (res == GST_RTSP_ENOTIMPL)
772 if (g_ascii_strcasecmp (accept, "application/sdp") == 0)
776 /* find the media object for the uri */
777 if (!(media = find_media (client, uri, request)))
780 /* create an SDP for the media object */
781 if (!(sdp = gst_rtsp_sdp_from_media (media)))
784 g_object_unref (media);
786 gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK,
787 gst_rtsp_status_as_text (GST_RTSP_STS_OK), request);
789 gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_TYPE, "application/sdp");
791 /* content base for some clients that might screw up creating the setup uri */
792 str = g_strdup_printf ("rtsp://%s:%u%s/", uri->host, uri->port, uri->abspath);
793 gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_BASE, str);
796 /* add SDP to the response body */
797 str = gst_sdp_message_as_text (sdp);
798 gst_rtsp_message_take_body (&response, (guint8 *)str, strlen (str));
799 gst_sdp_message_free (sdp);
801 send_response (client, session, &response);
808 /* error reply is already sent */
813 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
814 g_object_unref (media);
820 handle_options_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request)
822 GstRTSPMessage response = { 0 };
823 GstRTSPMethod options;
826 options = GST_RTSP_DESCRIBE |
833 str = gst_rtsp_options_as_text (options);
835 gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK,
836 gst_rtsp_status_as_text (GST_RTSP_STS_OK), request);
838 gst_rtsp_message_add_header (&response, GST_RTSP_HDR_PUBLIC, str);
841 send_response (client, session, &response);
844 /* remove duplicate and trailing '/' */
846 santize_uri (GstRTSPUrl *uri)
850 gboolean have_slash, prev_slash;
852 s = d = uri->abspath;
853 len = strlen (uri->abspath);
857 for (i = 0; i < len; i++) {
858 have_slash = s[i] == '/';
860 if (!have_slash || !prev_slash)
862 prev_slash = have_slash;
864 len = d - uri->abspath;
865 /* don't remove the first slash if that's the only thing left */
866 if (len > 1 && *(d-1) == '/')
872 client_session_finalized (GstRTSPClient *client, GstRTSPSession *session)
874 if (!(client->sessions = g_list_remove (client->sessions, session))) {
875 g_message ("all sessions finalized, close the connection");
876 g_source_destroy ((GSource*)client->watch);
881 client_watch_session (GstRTSPClient *client, GstRTSPSession *session)
885 for (walk = client->sessions; walk; walk = g_list_next (walk)) {
886 GstRTSPSession *msession = (GstRTSPSession *) walk->data;
888 /* we already know about this session */
889 if (msession == session)
893 g_message ("watching session %p", session);
895 g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized, client);
896 client->sessions = g_list_prepend (client->sessions, session);
900 handle_request (GstRTSPClient *client, GstRTSPMessage *request)
902 GstRTSPMethod method;
905 GstRTSPVersion version;
907 GstRTSPSession *session;
911 gst_rtsp_message_dump (request);
914 g_message ("client %p: received a request", client);
916 gst_rtsp_message_parse_request (request, &method, &uristr, &version);
918 if (version != GST_RTSP_VERSION_1_0) {
919 /* we can only handle 1.0 requests */
920 send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, request);
924 /* we always try to parse the url first */
925 if ((res = gst_rtsp_url_parse (uristr, &uri)) != GST_RTSP_OK) {
926 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request);
930 /* sanitize the uri */
933 /* get the session if there is any */
934 res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
935 if (res == GST_RTSP_OK) {
936 if (client->session_pool == NULL)
939 /* we had a session in the request, find it again */
940 if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid)))
941 goto session_not_found;
943 /* we add the session to the client list of watched sessions. When a session
944 * disappears because it times out, we will be notified. If all sessions are
945 * gone, we will close the connection */
946 client_watch_session (client, session);
951 /* now see what is asked and dispatch to a dedicated handler */
953 case GST_RTSP_OPTIONS:
954 handle_options_request (client, uri, session, request);
956 case GST_RTSP_DESCRIBE:
957 handle_describe_request (client, uri, session, request);
960 handle_setup_request (client, uri, session, request);
963 handle_play_request (client, uri, session, request);
966 handle_pause_request (client, uri, session, request);
968 case GST_RTSP_TEARDOWN:
969 handle_teardown_request (client, uri, session, request);
971 case GST_RTSP_ANNOUNCE:
972 case GST_RTSP_GET_PARAMETER:
973 case GST_RTSP_RECORD:
974 case GST_RTSP_REDIRECT:
975 case GST_RTSP_SET_PARAMETER:
976 send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, request);
978 case GST_RTSP_INVALID:
980 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request);
984 g_object_unref (session);
986 gst_rtsp_url_free (uri);
992 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
997 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
1003 handle_data (GstRTSPClient *client, GstRTSPMessage *message)
1012 /* find the stream for this message */
1013 res = gst_rtsp_message_parse_data (message, &channel);
1014 if (res != GST_RTSP_OK)
1017 gst_rtsp_message_steal_body (message, &data, &size);
1019 buffer = gst_buffer_new ();
1020 GST_BUFFER_DATA (buffer) = data;
1021 GST_BUFFER_MALLOCDATA (buffer) = data;
1022 GST_BUFFER_SIZE (buffer) = size;
1024 for (walk = client->streams; walk; walk = g_list_next (walk)) {
1025 GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data;
1026 GstRTSPMediaStream *mstream;
1027 GstRTSPTransport *tr;
1029 /* get the transport, if there is no transport configured, skip this stream */
1030 if (!(tr = stream->trans.transport))
1033 /* we also need a media stream */
1034 if (!(mstream = stream->media_stream))
1037 /* check for TCP transport */
1038 if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
1039 /* dispatch to the stream based on the channel number */
1040 if (tr->interleaved.min == channel) {
1041 gst_rtsp_media_stream_rtp (mstream, buffer);
1042 } else if (tr->interleaved.max == channel) {
1043 gst_rtsp_media_stream_rtcp (mstream, buffer);
1047 gst_buffer_unref (buffer);
1051 * gst_rtsp_client_set_session_pool:
1052 * @client: a #GstRTSPClient
1053 * @pool: a #GstRTSPSessionPool
1055 * Set @pool as the sessionpool for @client which it will use to find
1056 * or allocate sessions. the sessionpool is usually inherited from the server
1057 * that created the client but can be overridden later.
1060 gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *pool)
1062 GstRTSPSessionPool *old;
1064 old = client->session_pool;
1067 g_object_ref (pool);
1068 client->session_pool = pool;
1070 g_object_unref (old);
1075 * gst_rtsp_client_get_session_pool:
1076 * @client: a #GstRTSPClient
1078 * Get the #GstRTSPSessionPool object that @client uses to manage its sessions.
1080 * Returns: a #GstRTSPSessionPool, unref after usage.
1082 GstRTSPSessionPool *
1083 gst_rtsp_client_get_session_pool (GstRTSPClient *client)
1085 GstRTSPSessionPool *result;
1087 if ((result = client->session_pool))
1088 g_object_ref (result);
1094 * gst_rtsp_client_set_media_mapping:
1095 * @client: a #GstRTSPClient
1096 * @mapping: a #GstRTSPMediaMapping
1098 * Set @mapping as the media mapping for @client which it will use to map urls
1099 * to media streams. These mapping is usually inherited from the server that
1100 * created the client but can be overriden later.
1103 gst_rtsp_client_set_media_mapping (GstRTSPClient *client, GstRTSPMediaMapping *mapping)
1105 GstRTSPMediaMapping *old;
1107 old = client->media_mapping;
1109 if (old != mapping) {
1111 g_object_ref (mapping);
1112 client->media_mapping = mapping;
1114 g_object_unref (old);
1119 * gst_rtsp_client_get_media_mapping:
1120 * @client: a #GstRTSPClient
1122 * Get the #GstRTSPMediaMapping object that @client uses to manage its sessions.
1124 * Returns: a #GstRTSPMediaMapping, unref after usage.
1126 GstRTSPMediaMapping *
1127 gst_rtsp_client_get_media_mapping (GstRTSPClient *client)
1129 GstRTSPMediaMapping *result;
1131 if ((result = client->media_mapping))
1132 g_object_ref (result);
1137 static GstRTSPResult
1138 message_received (GstRTSPWatch *watch, GstRTSPMessage *message, gpointer user_data)
1140 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1142 switch (message->type) {
1143 case GST_RTSP_MESSAGE_REQUEST:
1144 handle_request (client, message);
1146 case GST_RTSP_MESSAGE_RESPONSE:
1148 case GST_RTSP_MESSAGE_DATA:
1149 handle_data (client, message);
1157 static GstRTSPResult
1158 message_sent (GstRTSPWatch *watch, guint cseq, gpointer user_data)
1160 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1162 g_message ("client %p: sent a message with cseq %d", client, cseq);
1167 static GstRTSPResult
1168 closed (GstRTSPWatch *watch, gpointer user_data)
1170 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1171 const gchar *tunnelid;
1173 g_message ("client %p: connection closed", client);
1175 if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) {
1176 g_mutex_lock (tunnels_lock);
1177 g_hash_table_remove (tunnels, tunnelid);
1178 g_mutex_unlock (tunnels_lock);
1181 /* remove all streams that are streaming over this client connection */
1182 unlink_streams (client);
1187 static GstRTSPResult
1188 error (GstRTSPWatch *watch, GstRTSPResult result, gpointer user_data)
1190 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1193 str = gst_rtsp_strresult (result);
1194 g_message ("client %p: received an error %s", client, str);
1200 static GstRTSPStatusCode
1201 tunnel_start (GstRTSPWatch *watch, gpointer user_data)
1203 GstRTSPClient *client;
1204 const gchar *tunnelid;
1206 client = GST_RTSP_CLIENT (user_data);
1208 g_message ("client %p: tunnel start", client);
1210 /* store client in the pending tunnels */
1211 tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
1213 g_message ("client %p: inserting %s", client, tunnelid);
1215 /* we can't have two clients connecting with the same tunnelid */
1216 g_mutex_lock (tunnels_lock);
1217 if (g_hash_table_lookup (tunnels, tunnelid))
1218 goto tunnel_existed;
1220 g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
1221 g_mutex_unlock (tunnels_lock);
1223 return GST_RTSP_STS_OK;
1228 g_mutex_unlock (tunnels_lock);
1229 g_message ("client %p: tunnel session %s existed", client, tunnelid);
1230 return GST_RTSP_STS_SERVICE_UNAVAILABLE;
1234 static GstRTSPResult
1235 tunnel_complete (GstRTSPWatch *watch, gpointer user_data)
1237 const gchar *tunnelid;
1238 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1239 GstRTSPClient *oclient;
1241 g_message ("client %p: tunnel complete", client);
1243 /* find previous tunnel */
1244 tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
1246 g_mutex_lock (tunnels_lock);
1247 if (!(oclient = g_hash_table_lookup (tunnels, tunnelid)))
1250 /* remove the old client from the table. ref before because removing it will
1251 * remove the ref to it. */
1252 g_object_ref (oclient);
1253 g_hash_table_remove (tunnels, tunnelid);
1254 g_mutex_unlock (tunnels_lock);
1256 g_message ("client %p: found tunnel %p", client, oclient);
1258 /* merge the tunnels into the first client */
1259 gst_rtsp_connection_do_tunnel (oclient->connection, client->connection);
1260 gst_rtsp_watch_reset (oclient->watch);
1261 g_object_unref (oclient);
1263 /* we don't need this watch anymore */
1264 g_source_remove (client->watchid);
1271 g_mutex_unlock (tunnels_lock);
1272 g_message ("client %p: tunnel session %s not found", client, tunnelid);
1277 static GstRTSPWatchFuncs watch_funcs = {
1287 * gst_rtsp_client_attach:
1288 * @client: a #GstRTSPClient
1289 * @channel: a #GIOChannel
1291 * Accept a new connection for @client on the socket in @source.
1293 * This function should be called when the client properties and urls are fully
1294 * configured and the client is ready to start.
1296 * Returns: %TRUE if the client could be accepted.
1299 gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel)
1302 GstRTSPConnection *conn;
1305 GMainContext *context;
1308 /* a new client connected. */
1309 sock = g_io_channel_unix_get_fd (channel);
1311 GST_RTSP_CHECK (gst_rtsp_connection_accept (sock, &conn), accept_failed);
1313 url = gst_rtsp_connection_get_url (conn);
1314 g_message ("added new client %p ip %s:%d", client,
1315 url->host, url->port);
1317 client->connection = conn;
1319 /* create watch for the connection and attach */
1320 client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs,
1321 g_object_ref (client), g_object_unref);
1323 /* find the context to add the watch */
1324 if ((source = g_main_current_source ()))
1325 context = g_source_get_context (source);
1329 g_message ("attaching to context %p", context);
1331 client->watchid = gst_rtsp_watch_attach (client->watch, context);
1332 gst_rtsp_watch_unref (client->watch);
1339 gchar *str = gst_rtsp_strresult (res);
1341 g_error ("Could not accept client on server socket %d: %s",