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 gst_rtsp_session_media_set_state (media, GST_STATE_NULL);
378 /* unmanage the media in the session, returns false if all media session
380 if (!gst_rtsp_session_release_media (session, media)) {
381 /* remove the session */
382 gst_rtsp_session_pool_remove (client->session_pool, session);
384 /* construct the response now */
385 code = GST_RTSP_STS_OK;
386 gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request);
388 send_response (client, session, &response);
395 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
400 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
406 handle_pause_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request)
408 GstRTSPSessionMedia *media;
409 GstRTSPMessage response = { 0 };
410 GstRTSPStatusCode code;
415 /* get a handle to the configuration of the media in the session */
416 media = gst_rtsp_session_get_media (session, uri);
420 /* the session state must be playing or recording */
421 if (media->state != GST_RTSP_STATE_PLAYING &&
422 media->state != GST_RTSP_STATE_RECORDING)
425 /* unlink the all TCP callbacks */
426 unlink_session_streams (client, media);
428 /* then pause sending */
429 gst_rtsp_session_media_set_state (media, GST_STATE_PAUSED);
431 /* construct the response now */
432 code = GST_RTSP_STS_OK;
433 gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request);
435 send_response (client, session, &response);
437 /* the state is now READY */
438 media->state = GST_RTSP_STATE_READY;
445 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
450 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
455 send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, request);
461 handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request)
463 GstRTSPSessionMedia *media;
464 GstRTSPMessage response = { 0 };
465 GstRTSPStatusCode code;
468 guint timestamp, seqnum;
474 /* get a handle to the configuration of the media in the session */
475 media = gst_rtsp_session_get_media (session, uri);
479 /* the session state must be playing or ready */
480 if (media->state != GST_RTSP_STATE_PLAYING &&
481 media->state != GST_RTSP_STATE_READY)
484 /* grab RTPInfo from the payloaders now */
485 rtpinfo = g_string_new ("");
487 n_streams = gst_rtsp_media_n_streams (media->media);
488 for (i = 0; i < n_streams; i++) {
489 GstRTSPSessionStream *sstream;
490 GstRTSPMediaStream *stream;
491 GstRTSPTransport *tr;
494 /* get the stream as configured in the session */
495 sstream = gst_rtsp_session_media_get_stream (media, i);
496 /* get the transport, if there is no transport configured, skip this stream */
497 if (!(tr = sstream->trans.transport))
500 if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
501 /* for TCP, link the stream to the TCP connection of the client */
502 link_stream (client, sstream);
505 stream = sstream->media_stream;
507 g_object_get (G_OBJECT (stream->payloader), "seqnum", &seqnum, NULL);
508 g_object_get (G_OBJECT (stream->payloader), "timestamp", ×tamp, NULL);
511 g_string_append (rtpinfo, ", ");
513 uristr = gst_rtsp_url_get_request_uri (uri);
514 g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u", uristr, i, seqnum, timestamp);
518 /* construct the response now */
519 code = GST_RTSP_STS_OK;
520 gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request);
522 /* add the RTP-Info header */
523 str = g_string_free (rtpinfo, FALSE);
524 gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RTP_INFO, str);
527 str = gst_rtsp_range_to_string (&media->media->range);
528 gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RANGE, str);
530 send_response (client, session, &response);
532 /* start playing after sending the request */
533 gst_rtsp_session_media_set_state (media, GST_STATE_PLAYING);
535 media->state = GST_RTSP_STATE_PLAYING;
542 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
547 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
552 send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, request);
558 handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request)
563 gboolean have_transport;
564 GstRTSPTransport *ct, *st;
566 GstRTSPLowerTrans supported;
567 GstRTSPMessage response = { 0 };
568 GstRTSPStatusCode code;
569 GstRTSPSessionStream *stream;
570 gchar *trans_str, *pos;
572 GstRTSPSessionMedia *media;
573 gboolean need_session;
576 /* the uri contains the stream number we added in the SDP config, which is
577 * always /stream=%d so we need to strip that off
578 * parse the stream we need to configure, look for the stream in the abspath
579 * first and then in the query. */
580 if (!(pos = strstr (uri->abspath, "/stream="))) {
581 if (!(pos = strstr (uri->query, "/stream=")))
585 /* we can mofify the parse uri in place */
588 pos += strlen ("/stream=");
589 if (sscanf (pos, "%u", &streamid) != 1)
592 /* parse the transport */
593 res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_TRANSPORT, &transport, 0);
594 if (res != GST_RTSP_OK)
597 transports = g_strsplit (transport, ",", 0);
598 gst_rtsp_transport_new (&ct);
600 /* loop through the transports, try to parse */
601 have_transport = FALSE;
602 for (i = 0; transports[i]; i++) {
604 gst_rtsp_transport_init (ct);
605 res = gst_rtsp_transport_parse (transports[i], ct);
606 if (res == GST_RTSP_OK) {
607 have_transport = TRUE;
611 g_strfreev (transports);
613 /* we have not found anything usable, error out */
615 goto unsupported_transports;
617 /* we have a valid transport, check if we can handle it */
618 if (ct->trans != GST_RTSP_TRANS_RTP)
619 goto unsupported_transports;
620 if (ct->profile != GST_RTSP_PROFILE_AVP)
621 goto unsupported_transports;
623 supported = GST_RTSP_LOWER_TRANS_UDP |
624 GST_RTSP_LOWER_TRANS_UDP_MCAST |
625 GST_RTSP_LOWER_TRANS_TCP;
626 if (!(ct->lower_transport & supported))
627 goto unsupported_transports;
629 if (client->session_pool == NULL)
632 /* we have a valid transport now, set the destination of the client. */
633 g_free (ct->destination);
634 url = gst_rtsp_connection_get_url (client->connection);
635 ct->destination = g_strdup (url->host);
638 g_object_ref (session);
639 /* get a handle to the configuration of the media in the session, this can
640 * return NULL if this is a new url to manage in this session. */
641 media = gst_rtsp_session_get_media (session, uri);
643 need_session = FALSE;
646 /* create a session if this fails we probably reached our session limit or
648 if (!(session = gst_rtsp_session_pool_create (client->session_pool)))
649 goto service_unavailable;
651 /* we need a new media configuration in this session */
657 /* we have no media, find one and manage it */
661 /* get a handle to the configuration of the media in the session */
662 if ((m = find_media (client, uri, request))) {
663 /* manage the media in our session now */
664 media = gst_rtsp_session_manage_media (session, uri, m);
668 /* if we stil have no media, error */
672 /* get a handle to the stream in the media */
673 if (!(stream = gst_rtsp_session_media_get_stream (media, streamid)))
676 st = gst_rtsp_session_stream_set_transport (stream, ct);
678 /* serialize the server transport */
679 trans_str = gst_rtsp_transport_as_text (st);
680 gst_rtsp_transport_free (st);
682 /* construct the response now */
683 code = GST_RTSP_STS_OK;
684 gst_rtsp_message_init_response (&response, code, gst_rtsp_status_as_text (code), request);
686 gst_rtsp_message_add_header (&response, GST_RTSP_HDR_TRANSPORT, trans_str);
689 send_response (client, session, &response);
691 /* update the state */
692 switch (media->state) {
693 case GST_RTSP_STATE_PLAYING:
694 case GST_RTSP_STATE_RECORDING:
695 case GST_RTSP_STATE_READY:
696 /* no state change */
699 media->state = GST_RTSP_STATE_READY;
702 g_object_unref (session);
709 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request);
714 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
715 g_object_unref (session);
720 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
721 g_object_unref (media);
722 g_object_unref (session);
727 send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request);
730 unsupported_transports:
732 send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request);
733 gst_rtsp_transport_free (ct);
738 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
743 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
748 /* for the describe we must generate an SDP */
750 handle_describe_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request)
752 GstRTSPMessage response = { 0 };
759 /* check what kind of format is accepted, we don't really do anything with it
760 * and always return SDP for now. */
764 res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_ACCEPT, &accept, i);
765 if (res == GST_RTSP_ENOTIMPL)
768 if (g_ascii_strcasecmp (accept, "application/sdp") == 0)
772 /* find the media object for the uri */
773 if (!(media = find_media (client, uri, request)))
776 /* create an SDP for the media object */
777 if (!(sdp = gst_rtsp_sdp_from_media (media)))
780 g_object_unref (media);
782 gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK,
783 gst_rtsp_status_as_text (GST_RTSP_STS_OK), request);
785 gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_TYPE, "application/sdp");
787 /* content base for some clients that might screw up creating the setup uri */
788 str = g_strdup_printf ("rtsp://%s:%u%s/", uri->host, uri->port, uri->abspath);
789 gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_BASE, str);
792 /* add SDP to the response body */
793 str = gst_sdp_message_as_text (sdp);
794 gst_rtsp_message_take_body (&response, (guint8 *)str, strlen (str));
795 gst_sdp_message_free (sdp);
797 send_response (client, session, &response);
804 /* error reply is already sent */
809 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
810 g_object_unref (media);
816 handle_options_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPSession *session, GstRTSPMessage *request)
818 GstRTSPMessage response = { 0 };
819 GstRTSPMethod options;
822 options = GST_RTSP_DESCRIBE |
829 str = gst_rtsp_options_as_text (options);
831 gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK,
832 gst_rtsp_status_as_text (GST_RTSP_STS_OK), request);
834 gst_rtsp_message_add_header (&response, GST_RTSP_HDR_PUBLIC, str);
837 send_response (client, session, &response);
840 /* remove duplicate and trailing '/' */
842 santize_uri (GstRTSPUrl *uri)
846 gboolean have_slash, prev_slash;
848 s = d = uri->abspath;
849 len = strlen (uri->abspath);
853 for (i = 0; i < len; i++) {
854 have_slash = s[i] == '/';
856 if (!have_slash || !prev_slash)
858 prev_slash = have_slash;
860 len = d - uri->abspath;
861 /* don't remove the first slash if that's the only thing left */
862 if (len > 1 && *(d-1) == '/')
868 client_session_finalized (GstRTSPClient *client, GstRTSPSession *session)
870 g_message ("session %p finalized", session);
872 client->sessions = g_list_remove (client->sessions, session);
873 if (client->sessions == NULL) {
874 g_message ("all sessions finalized");
875 g_source_destroy ((GSource*)client->watch);
880 client_watch_session (GstRTSPClient *client, GstRTSPSession *session)
884 for (walk = client->sessions; walk; walk = g_list_next (walk)) {
885 GstRTSPSession *msession = (GstRTSPSession *) walk->data;
887 /* we already know about this session */
888 if (msession == session)
892 g_message ("watching session %p", session);
894 g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized, client);
895 client->sessions = g_list_prepend (client->sessions, session);
899 handle_request (GstRTSPClient *client, GstRTSPMessage *request)
901 GstRTSPMethod method;
904 GstRTSPVersion version;
906 GstRTSPSession *session;
910 gst_rtsp_message_dump (request);
913 g_message ("client %p: received a request", client);
915 gst_rtsp_message_parse_request (request, &method, &uristr, &version);
917 if (version != GST_RTSP_VERSION_1_0) {
918 /* we can only handle 1.0 requests */
919 send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, request);
923 /* we always try to parse the url first */
924 if ((res = gst_rtsp_url_parse (uristr, &uri)) != GST_RTSP_OK) {
925 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request);
929 /* sanitize the uri */
932 /* get the session if there is any */
933 res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
934 if (res == GST_RTSP_OK) {
935 if (client->session_pool == NULL)
938 /* we had a session in the request, find it again */
939 if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid)))
940 goto session_not_found;
942 client_watch_session (client, session);
947 /* now see what is asked and dispatch to a dedicated handler */
949 case GST_RTSP_OPTIONS:
950 handle_options_request (client, uri, session, request);
952 case GST_RTSP_DESCRIBE:
953 handle_describe_request (client, uri, session, request);
956 handle_setup_request (client, uri, session, request);
959 handle_play_request (client, uri, session, request);
962 handle_pause_request (client, uri, session, request);
964 case GST_RTSP_TEARDOWN:
965 handle_teardown_request (client, uri, session, request);
967 case GST_RTSP_ANNOUNCE:
968 case GST_RTSP_GET_PARAMETER:
969 case GST_RTSP_RECORD:
970 case GST_RTSP_REDIRECT:
971 case GST_RTSP_SET_PARAMETER:
972 send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, request);
974 case GST_RTSP_INVALID:
976 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request);
980 g_object_unref (session);
982 gst_rtsp_url_free (uri);
988 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
993 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
999 handle_data (GstRTSPClient *client, GstRTSPMessage *message)
1008 /* find the stream for this message */
1009 res = gst_rtsp_message_parse_data (message, &channel);
1010 if (res != GST_RTSP_OK)
1013 gst_rtsp_message_steal_body (message, &data, &size);
1015 buffer = gst_buffer_new ();
1016 GST_BUFFER_DATA (buffer) = data;
1017 GST_BUFFER_MALLOCDATA (buffer) = data;
1018 GST_BUFFER_SIZE (buffer) = size;
1020 for (walk = client->streams; walk; walk = g_list_next (walk)) {
1021 GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data;
1022 GstRTSPMediaStream *mstream;
1023 GstRTSPTransport *tr;
1025 /* get the transport, if there is no transport configured, skip this stream */
1026 if (!(tr = stream->trans.transport))
1029 /* we also need a media stream */
1030 if (!(mstream = stream->media_stream))
1033 /* check for TCP transport */
1034 if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
1035 /* dispatch to the stream based on the channel number */
1036 if (tr->interleaved.min == channel) {
1037 gst_rtsp_media_stream_rtp (mstream, buffer);
1038 } else if (tr->interleaved.max == channel) {
1039 gst_rtsp_media_stream_rtcp (mstream, buffer);
1043 gst_buffer_unref (buffer);
1047 * gst_rtsp_client_set_session_pool:
1048 * @client: a #GstRTSPClient
1049 * @pool: a #GstRTSPSessionPool
1051 * Set @pool as the sessionpool for @client which it will use to find
1052 * or allocate sessions. the sessionpool is usually inherited from the server
1053 * that created the client but can be overridden later.
1056 gst_rtsp_client_set_session_pool (GstRTSPClient *client, GstRTSPSessionPool *pool)
1058 GstRTSPSessionPool *old;
1060 old = client->session_pool;
1063 g_object_ref (pool);
1064 client->session_pool = pool;
1066 g_object_unref (old);
1071 * gst_rtsp_client_get_session_pool:
1072 * @client: a #GstRTSPClient
1074 * Get the #GstRTSPSessionPool object that @client uses to manage its sessions.
1076 * Returns: a #GstRTSPSessionPool, unref after usage.
1078 GstRTSPSessionPool *
1079 gst_rtsp_client_get_session_pool (GstRTSPClient *client)
1081 GstRTSPSessionPool *result;
1083 if ((result = client->session_pool))
1084 g_object_ref (result);
1090 * gst_rtsp_client_set_media_mapping:
1091 * @client: a #GstRTSPClient
1092 * @mapping: a #GstRTSPMediaMapping
1094 * Set @mapping as the media mapping for @client which it will use to map urls
1095 * to media streams. These mapping is usually inherited from the server that
1096 * created the client but can be overriden later.
1099 gst_rtsp_client_set_media_mapping (GstRTSPClient *client, GstRTSPMediaMapping *mapping)
1101 GstRTSPMediaMapping *old;
1103 old = client->media_mapping;
1105 if (old != mapping) {
1107 g_object_ref (mapping);
1108 client->media_mapping = mapping;
1110 g_object_unref (old);
1115 * gst_rtsp_client_get_media_mapping:
1116 * @client: a #GstRTSPClient
1118 * Get the #GstRTSPMediaMapping object that @client uses to manage its sessions.
1120 * Returns: a #GstRTSPMediaMapping, unref after usage.
1122 GstRTSPMediaMapping *
1123 gst_rtsp_client_get_media_mapping (GstRTSPClient *client)
1125 GstRTSPMediaMapping *result;
1127 if ((result = client->media_mapping))
1128 g_object_ref (result);
1133 static GstRTSPResult
1134 message_received (GstRTSPWatch *watch, GstRTSPMessage *message, gpointer user_data)
1136 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1138 switch (message->type) {
1139 case GST_RTSP_MESSAGE_REQUEST:
1140 handle_request (client, message);
1142 case GST_RTSP_MESSAGE_RESPONSE:
1144 case GST_RTSP_MESSAGE_DATA:
1145 handle_data (client, message);
1153 static GstRTSPResult
1154 message_sent (GstRTSPWatch *watch, guint cseq, gpointer user_data)
1156 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1158 g_message ("client %p: sent a message with cseq %d", client, cseq);
1163 static GstRTSPResult
1164 closed (GstRTSPWatch *watch, gpointer user_data)
1166 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1167 const gchar *tunnelid;
1169 g_message ("client %p: connection closed", client);
1171 if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) {
1172 g_mutex_lock (tunnels_lock);
1173 g_hash_table_remove (tunnels, tunnelid);
1174 g_mutex_unlock (tunnels_lock);
1177 /* remove all streams that are streaming over this client connection */
1178 unlink_streams (client);
1183 static GstRTSPResult
1184 error (GstRTSPWatch *watch, GstRTSPResult result, gpointer user_data)
1186 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1189 str = gst_rtsp_strresult (result);
1190 g_message ("client %p: received an error %s", client, str);
1196 static GstRTSPStatusCode
1197 tunnel_start (GstRTSPWatch *watch, gpointer user_data)
1199 GstRTSPClient *client;
1200 const gchar *tunnelid;
1202 client = GST_RTSP_CLIENT (user_data);
1204 g_message ("client %p: tunnel start", client);
1206 /* store client in the pending tunnels */
1207 tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
1209 g_message ("client %p: inserting %s", client, tunnelid);
1211 /* we can't have two clients connecting with the same tunnelid */
1212 g_mutex_lock (tunnels_lock);
1213 if (g_hash_table_lookup (tunnels, tunnelid))
1214 goto tunnel_existed;
1216 g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
1217 g_mutex_unlock (tunnels_lock);
1219 return GST_RTSP_STS_OK;
1224 g_mutex_unlock (tunnels_lock);
1225 g_message ("client %p: tunnel session %s existed", client, tunnelid);
1226 return GST_RTSP_STS_SERVICE_UNAVAILABLE;
1230 static GstRTSPResult
1231 tunnel_complete (GstRTSPWatch *watch, gpointer user_data)
1233 const gchar *tunnelid;
1234 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1235 GstRTSPClient *oclient;
1237 g_message ("client %p: tunnel complete", client);
1239 /* find previous tunnel */
1240 tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
1242 g_mutex_lock (tunnels_lock);
1243 if (!(oclient = g_hash_table_lookup (tunnels, tunnelid)))
1246 /* remove the old client from the table. ref before because removing it will
1247 * remove the ref to it. */
1248 g_object_ref (oclient);
1249 g_hash_table_remove (tunnels, tunnelid);
1250 g_mutex_unlock (tunnels_lock);
1252 g_message ("client %p: found tunnel %p", client, oclient);
1254 /* merge the tunnels into the first client */
1255 gst_rtsp_connection_do_tunnel (oclient->connection, client->connection);
1256 gst_rtsp_watch_reset (oclient->watch);
1257 g_object_unref (oclient);
1259 /* we don't need this watch anymore */
1260 g_source_remove (client->watchid);
1267 g_mutex_unlock (tunnels_lock);
1268 g_message ("client %p: tunnel session %s not found", client, tunnelid);
1273 static GstRTSPWatchFuncs watch_funcs = {
1283 * gst_rtsp_client_attach:
1284 * @client: a #GstRTSPClient
1285 * @channel: a #GIOChannel
1287 * Accept a new connection for @client on the socket in @source.
1289 * This function should be called when the client properties and urls are fully
1290 * configured and the client is ready to start.
1292 * Returns: %TRUE if the client could be accepted.
1295 gst_rtsp_client_accept (GstRTSPClient *client, GIOChannel *channel)
1298 GstRTSPConnection *conn;
1301 GMainContext *context;
1304 /* a new client connected. */
1305 sock = g_io_channel_unix_get_fd (channel);
1307 GST_RTSP_CHECK (gst_rtsp_connection_accept (sock, &conn), accept_failed);
1309 url = gst_rtsp_connection_get_url (conn);
1310 g_message ("added new client %p ip %s:%d", client,
1311 url->host, url->port);
1313 client->connection = conn;
1315 /* create watch for the connection and attach */
1316 client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs,
1317 g_object_ref (client), g_object_unref);
1319 /* find the context to add the watch */
1320 if ((source = g_main_current_source ()))
1321 context = g_source_get_context (source);
1325 g_message ("attaching to context %p", context);
1327 client->watchid = gst_rtsp_watch_attach (client->watch, context);
1328 gst_rtsp_watch_unref (client->watch);
1335 gchar *str = gst_rtsp_strresult (res);
1337 g_error ("Could not accept client on server socket %d: %s",