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.
26 #include <sys/types.h>
27 #include <netinet/in.h>
29 #include <sys/socket.h>
32 #include <arpa/inet.h>
33 #include <sys/ioctl.h>
35 #include "rtsp-client.h"
37 #include "rtsp-params.h"
39 /* temporary multicast address until it's configurable somewhere */
40 #define MCAST_ADDRESS "224.2.0.1"
42 static GMutex *tunnels_lock;
43 static GHashTable *tunnels;
53 GST_DEBUG_CATEGORY_STATIC (rtsp_client_debug);
54 #define GST_CAT_DEFAULT rtsp_client_debug
56 static void gst_rtsp_client_get_property (GObject * object, guint propid,
57 GValue * value, GParamSpec * pspec);
58 static void gst_rtsp_client_set_property (GObject * object, guint propid,
59 const GValue * value, GParamSpec * pspec);
60 static void gst_rtsp_client_finalize (GObject * obj);
62 static void client_session_finalized (GstRTSPClient * client,
63 GstRTSPSession * session);
64 static void unlink_session_streams (GstRTSPClient * client,
65 GstRTSPSession * session, GstRTSPSessionMedia * media);
67 G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT);
70 gst_rtsp_client_class_init (GstRTSPClientClass * klass)
72 GObjectClass *gobject_class;
74 gobject_class = G_OBJECT_CLASS (klass);
76 gobject_class->get_property = gst_rtsp_client_get_property;
77 gobject_class->set_property = gst_rtsp_client_set_property;
78 gobject_class->finalize = gst_rtsp_client_finalize;
80 g_object_class_install_property (gobject_class, PROP_SESSION_POOL,
81 g_param_spec_object ("session-pool", "Session Pool",
82 "The session pool to use for client session",
83 GST_TYPE_RTSP_SESSION_POOL,
84 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
86 g_object_class_install_property (gobject_class, PROP_MEDIA_MAPPING,
87 g_param_spec_object ("media-mapping", "Media Mapping",
88 "The media mapping to use for client session",
89 GST_TYPE_RTSP_MEDIA_MAPPING,
90 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
93 g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
94 tunnels_lock = g_mutex_new ();
96 GST_DEBUG_CATEGORY_INIT (rtsp_client_debug, "rtspclient", 0, "GstRTSPClient");
100 gst_rtsp_client_init (GstRTSPClient * client)
105 client_unlink_session (GstRTSPClient * client, GstRTSPSession * session)
109 /* unlink all media managed in this session */
110 for (medias = session->medias; medias; medias = g_list_next (medias)) {
111 unlink_session_streams (client, session,
112 (GstRTSPSessionMedia *) medias->data);
117 client_cleanup_sessions (GstRTSPClient * client)
121 /* remove weak-ref from sessions */
122 for (sessions = client->sessions; sessions; sessions = g_list_next (sessions)) {
123 GstRTSPSession *session = (GstRTSPSession *) sessions->data;
124 g_object_weak_unref (G_OBJECT (session),
125 (GWeakNotify) client_session_finalized, client);
126 client_unlink_session (client, session);
128 g_list_free (client->sessions);
129 client->sessions = NULL;
132 /* A client is finalized when the connection is broken */
134 gst_rtsp_client_finalize (GObject * obj)
136 GstRTSPClient *client = GST_RTSP_CLIENT (obj);
138 GST_INFO ("finalize client %p", client);
140 client_cleanup_sessions (client);
142 gst_rtsp_connection_free (client->connection);
143 if (client->session_pool)
144 g_object_unref (client->session_pool);
145 if (client->media_mapping)
146 g_object_unref (client->media_mapping);
149 gst_rtsp_url_free (client->uri);
151 g_object_unref (client->media);
153 g_free (client->server_ip);
155 G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj);
159 gst_rtsp_client_get_property (GObject * object, guint propid,
160 GValue * value, GParamSpec * pspec)
162 GstRTSPClient *client = GST_RTSP_CLIENT (object);
165 case PROP_SESSION_POOL:
166 g_value_take_object (value, gst_rtsp_client_get_session_pool (client));
168 case PROP_MEDIA_MAPPING:
169 g_value_take_object (value, gst_rtsp_client_get_media_mapping (client));
172 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
177 gst_rtsp_client_set_property (GObject * object, guint propid,
178 const GValue * value, GParamSpec * pspec)
180 GstRTSPClient *client = GST_RTSP_CLIENT (object);
183 case PROP_SESSION_POOL:
184 gst_rtsp_client_set_session_pool (client, g_value_get_object (value));
186 case PROP_MEDIA_MAPPING:
187 gst_rtsp_client_set_media_mapping (client, g_value_get_object (value));
190 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
195 * gst_rtsp_client_new:
197 * Create a new #GstRTSPClient instance.
199 * Returns: a new #GstRTSPClient
202 gst_rtsp_client_new (void)
204 GstRTSPClient *result;
206 result = g_object_new (GST_TYPE_RTSP_CLIENT, NULL);
212 send_response (GstRTSPClient * client, GstRTSPSession * session,
213 GstRTSPMessage * response)
215 gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER,
216 "GStreamer RTSP server");
218 /* remove any previous header */
219 gst_rtsp_message_remove_header (response, GST_RTSP_HDR_SESSION, -1);
221 /* add the new session header for new session ids */
225 if (session->timeout != 60)
227 g_strdup_printf ("%s; timeout=%d", session->sessionid,
230 str = g_strdup (session->sessionid);
232 gst_rtsp_message_take_header (response, GST_RTSP_HDR_SESSION, str);
235 if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
236 gst_rtsp_message_dump (response);
239 gst_rtsp_watch_send_message (client->watch, response, NULL);
240 gst_rtsp_message_unset (response);
244 send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code,
245 GstRTSPMessage * request)
247 GstRTSPMessage response = { 0 };
249 gst_rtsp_message_init_response (&response, code,
250 gst_rtsp_status_as_text (code), request);
252 send_response (client, NULL, &response);
256 compare_uri (const GstRTSPUrl * uri1, const GstRTSPUrl * uri2)
258 if (uri1 == NULL || uri2 == NULL)
261 if (strcmp (uri1->abspath, uri2->abspath))
267 /* this function is called to initially find the media for the DESCRIBE request
268 * but is cached for when the same client (without breaking the connection) is
269 * doing a setup for the exact same url. */
270 static GstRTSPMedia *
271 find_media (GstRTSPClient * client, GstRTSPUrl * uri, GstRTSPMessage * request)
273 GstRTSPMediaFactory *factory;
276 if (!compare_uri (client->uri, uri)) {
277 /* remove any previously cached values before we try to construct a new
280 gst_rtsp_url_free (client->uri);
283 g_object_unref (client->media);
284 client->media = NULL;
286 if (!client->media_mapping)
289 /* find the factory for the uri first */
291 gst_rtsp_media_mapping_find_factory (client->media_mapping, uri)))
294 /* prepare the media and add it to the pipeline */
295 if (!(media = gst_rtsp_media_factory_construct (factory, uri)))
298 /* set ipv6 on the media before preparing */
299 media->is_ipv6 = client->is_ipv6;
301 /* prepare the media */
302 if (!(gst_rtsp_media_prepare (media)))
305 /* now keep track of the uri and the media */
306 client->uri = gst_rtsp_url_copy (uri);
307 client->media = media;
309 /* we have seen this uri before, used cached media */
310 media = client->media;
311 GST_INFO ("reusing cached media %p", media);
315 g_object_ref (media);
322 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
327 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
332 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
333 g_object_unref (factory);
338 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
339 g_object_unref (media);
340 g_object_unref (factory);
346 do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client)
348 GstRTSPMessage message = { 0 };
352 gst_rtsp_message_init_data (&message, channel);
354 data = GST_BUFFER_DATA (buffer);
355 size = GST_BUFFER_SIZE (buffer);
356 gst_rtsp_message_take_body (&message, data, size);
358 /* FIXME, client->watch could have been finalized here, we need to keep an
359 * extra refcount to the watch. */
360 gst_rtsp_watch_send_message (client->watch, &message, NULL);
362 gst_rtsp_message_steal_body (&message, &data, &size);
363 gst_rtsp_message_unset (&message);
369 do_send_data_list (GstBufferList * blist, guint8 channel,
370 GstRTSPClient * client)
372 GstBufferListIterator *it;
374 it = gst_buffer_list_iterate (blist);
375 while (gst_buffer_list_iterator_next_group (it)) {
376 GstBuffer *group = gst_buffer_list_iterator_merge_group (it);
381 do_send_data (group, channel, client);
383 gst_buffer_list_iterator_free (it);
389 link_stream (GstRTSPClient * client, GstRTSPSession * session,
390 GstRTSPSessionStream * stream)
392 GST_DEBUG ("client %p: linking stream %p", client, stream);
393 gst_rtsp_session_stream_set_callbacks (stream, (GstRTSPSendFunc) do_send_data,
394 (GstRTSPSendFunc) do_send_data, (GstRTSPSendListFunc) do_send_data_list,
395 (GstRTSPSendListFunc) do_send_data_list, client, NULL);
396 client->streams = g_list_prepend (client->streams, stream);
397 /* make sure our session can't expire */
398 gst_rtsp_session_prevent_expire (session);
402 unlink_stream (GstRTSPClient * client, GstRTSPSession * session,
403 GstRTSPSessionStream * stream)
405 GST_DEBUG ("client %p: unlinking stream %p", client, stream);
406 gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL, NULL,
408 client->streams = g_list_remove (client->streams, stream);
409 /* our session can now expire */
410 gst_rtsp_session_allow_expire (session);
414 unlink_session_streams (GstRTSPClient * client, GstRTSPSession * session,
415 GstRTSPSessionMedia * media)
419 n_streams = gst_rtsp_media_n_streams (media->media);
420 for (i = 0; i < n_streams; i++) {
421 GstRTSPSessionStream *sstream;
422 GstRTSPTransport *tr;
424 /* get the stream as configured in the session */
425 sstream = gst_rtsp_session_media_get_stream (media, i);
426 /* get the transport, if there is no transport configured, skip this stream */
427 if (!(tr = sstream->trans.transport))
430 if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
431 /* for TCP, unlink the stream from the TCP connection of the client */
432 unlink_stream (client, session, sstream);
438 close_connection (GstRTSPClient * client)
440 const gchar *tunnelid;
442 GST_DEBUG ("client %p: closing connection", client);
444 if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) {
445 g_mutex_lock (tunnels_lock);
446 /* remove from tunnelids */
447 g_hash_table_remove (tunnels, tunnelid);
448 g_mutex_unlock (tunnels_lock);
451 gst_rtsp_connection_close (client->connection);
452 if (client->watchid) {
453 g_source_destroy ((GSource *) client->watch);
455 client->watch = NULL;
460 handle_teardown_request (GstRTSPClient * client, GstRTSPUrl * uri,
461 GstRTSPSession * session, GstRTSPMessage * request)
463 GstRTSPSessionMedia *media;
464 GstRTSPMessage response = { 0 };
465 GstRTSPStatusCode code;
470 /* get a handle to the configuration of the media in the session */
471 media = gst_rtsp_session_get_media (session, uri);
475 /* unlink the all TCP callbacks */
476 unlink_session_streams (client, session, media);
478 /* remove the session from the watched sessions */
479 g_object_weak_unref (G_OBJECT (session),
480 (GWeakNotify) client_session_finalized, client);
481 client->sessions = g_list_remove (client->sessions, session);
483 gst_rtsp_session_media_set_state (media, GST_STATE_NULL);
485 /* unmanage the media in the session, returns false if all media session
487 if (!gst_rtsp_session_release_media (session, media)) {
488 /* remove the session */
489 gst_rtsp_session_pool_remove (client->session_pool, session);
491 /* construct the response now */
492 code = GST_RTSP_STS_OK;
493 gst_rtsp_message_init_response (&response, code,
494 gst_rtsp_status_as_text (code), request);
496 gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONNECTION, "close");
498 send_response (client, session, &response);
500 close_connection (client);
507 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
512 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
518 handle_get_param_request (GstRTSPClient * client, GstRTSPUrl * uri,
519 GstRTSPSession * session, GstRTSPMessage * request)
525 res = gst_rtsp_message_get_body (request, &data, &size);
526 if (res != GST_RTSP_OK)
530 /* no body, keep-alive request */
531 send_generic_response (client, GST_RTSP_STS_OK, request);
533 /* there is a body */
534 GstRTSPMessage response = { 0 };
536 /* there is a body, handle the params */
537 res = gst_rtsp_params_get (client, uri, session, request, &response);
538 if (res != GST_RTSP_OK)
541 send_response (client, session, &response);
548 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request);
554 handle_set_param_request (GstRTSPClient * client, GstRTSPUrl * uri,
555 GstRTSPSession * session, GstRTSPMessage * request)
561 res = gst_rtsp_message_get_body (request, &data, &size);
562 if (res != GST_RTSP_OK)
566 /* no body, keep-alive request */
567 send_generic_response (client, GST_RTSP_STS_OK, request);
569 GstRTSPMessage response = { 0 };
571 /* there is a body, handle the params */
572 res = gst_rtsp_params_set (client, uri, session, request, &response);
573 if (res != GST_RTSP_OK)
576 send_response (client, session, &response);
583 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request);
589 handle_pause_request (GstRTSPClient * client, GstRTSPUrl * uri,
590 GstRTSPSession * session, GstRTSPMessage * request)
592 GstRTSPSessionMedia *media;
593 GstRTSPMessage response = { 0 };
594 GstRTSPStatusCode code;
599 /* get a handle to the configuration of the media in the session */
600 media = gst_rtsp_session_get_media (session, uri);
604 /* the session state must be playing or recording */
605 if (media->state != GST_RTSP_STATE_PLAYING &&
606 media->state != GST_RTSP_STATE_RECORDING)
609 /* unlink the all TCP callbacks */
610 unlink_session_streams (client, session, media);
612 /* then pause sending */
613 gst_rtsp_session_media_set_state (media, GST_STATE_PAUSED);
615 /* construct the response now */
616 code = GST_RTSP_STS_OK;
617 gst_rtsp_message_init_response (&response, code,
618 gst_rtsp_status_as_text (code), request);
620 send_response (client, session, &response);
622 /* the state is now READY */
623 media->state = GST_RTSP_STATE_READY;
630 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
635 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
640 send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
647 handle_play_request (GstRTSPClient * client, GstRTSPUrl * uri,
648 GstRTSPSession * session, GstRTSPMessage * request)
650 GstRTSPSessionMedia *media;
651 GstRTSPMessage response = { 0 };
652 GstRTSPStatusCode code;
654 guint n_streams, i, infocount;
655 guint timestamp, seqnum;
657 GstRTSPTimeRange *range;
663 /* get a handle to the configuration of the media in the session */
664 media = gst_rtsp_session_get_media (session, uri);
668 /* the session state must be playing or ready */
669 if (media->state != GST_RTSP_STATE_PLAYING &&
670 media->state != GST_RTSP_STATE_READY)
673 /* parse the range header if we have one */
674 res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_RANGE, &str, 0);
675 if (res == GST_RTSP_OK) {
676 if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) {
677 /* we have a range, seek to the position */
678 gst_rtsp_media_seek (media->media, range);
679 gst_rtsp_range_free (range);
683 /* grab RTPInfo from the payloaders now */
684 rtpinfo = g_string_new ("");
686 n_streams = gst_rtsp_media_n_streams (media->media);
687 for (i = 0, infocount = 0; i < n_streams; i++) {
688 GstRTSPSessionStream *sstream;
689 GstRTSPMediaStream *stream;
690 GstRTSPTransport *tr;
691 GObjectClass *payobjclass;
694 /* get the stream as configured in the session */
695 sstream = gst_rtsp_session_media_get_stream (media, i);
696 /* get the transport, if there is no transport configured, skip this stream */
697 if (!(tr = sstream->trans.transport)) {
698 GST_INFO ("stream %d is not configured", i);
702 if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
703 /* for TCP, link the stream to the TCP connection of the client */
704 link_stream (client, session, sstream);
707 stream = sstream->media_stream;
709 payobjclass = G_OBJECT_GET_CLASS (stream->payloader);
711 if (g_object_class_find_property (payobjclass, "seqnum") &&
712 g_object_class_find_property (payobjclass, "timestamp")) {
715 payobj = G_OBJECT (stream->payloader);
717 /* only add RTP-Info for streams with seqnum and timestamp */
718 g_object_get (payobj, "seqnum", &seqnum, "timestamp", ×tamp, NULL);
721 g_string_append (rtpinfo, ", ");
723 uristr = gst_rtsp_url_get_request_uri (uri);
724 g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u",
725 uristr, i, seqnum, timestamp);
730 GST_WARNING ("RTP-Info cannot be determined for stream %d", i);
734 /* construct the response now */
735 code = GST_RTSP_STS_OK;
736 gst_rtsp_message_init_response (&response, code,
737 gst_rtsp_status_as_text (code), request);
739 /* add the RTP-Info header */
741 str = g_string_free (rtpinfo, FALSE);
742 gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RTP_INFO, str);
744 g_string_free (rtpinfo, TRUE);
748 str = gst_rtsp_media_get_range_string (media->media, TRUE);
749 gst_rtsp_message_take_header (&response, GST_RTSP_HDR_RANGE, str);
751 send_response (client, session, &response);
753 /* start playing after sending the request */
754 gst_rtsp_session_media_set_state (media, GST_STATE_PLAYING);
756 media->state = GST_RTSP_STATE_PLAYING;
763 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
768 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
773 send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
780 do_keepalive (GstRTSPSession * session)
782 GST_INFO ("keep session %p alive", session);
783 gst_rtsp_session_touch (session);
787 handle_setup_request (GstRTSPClient * client, GstRTSPUrl * uri,
788 GstRTSPSession * session, GstRTSPMessage * request)
793 gboolean have_transport;
794 GstRTSPTransport *ct, *st;
796 GstRTSPLowerTrans supported;
797 GstRTSPMessage response = { 0 };
798 GstRTSPStatusCode code;
799 GstRTSPSessionStream *stream;
800 gchar *trans_str, *pos;
802 GstRTSPSessionMedia *media;
805 /* the uri contains the stream number we added in the SDP config, which is
806 * always /stream=%d so we need to strip that off
807 * parse the stream we need to configure, look for the stream in the abspath
808 * first and then in the query. */
809 if (uri->abspath == NULL || !(pos = strstr (uri->abspath, "/stream="))) {
810 if (uri->query == NULL || !(pos = strstr (uri->query, "/stream=")))
814 /* we can mofify the parse uri in place */
817 pos += strlen ("/stream=");
818 if (sscanf (pos, "%u", &streamid) != 1)
821 /* parse the transport */
823 gst_rtsp_message_get_header (request, GST_RTSP_HDR_TRANSPORT, &transport,
825 if (res != GST_RTSP_OK)
828 transports = g_strsplit (transport, ",", 0);
829 gst_rtsp_transport_new (&ct);
831 /* init transports */
832 have_transport = FALSE;
833 gst_rtsp_transport_init (ct);
835 /* our supported transports */
836 supported = GST_RTSP_LOWER_TRANS_UDP |
837 GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP;
839 /* loop through the transports, try to parse */
840 for (i = 0; transports[i]; i++) {
841 res = gst_rtsp_transport_parse (transports[i], ct);
842 if (res != GST_RTSP_OK) {
843 /* no valid transport, search some more */
844 GST_WARNING ("could not parse transport %s", transports[i]);
848 /* we have a transport, see if it's RTP/AVP */
849 if (ct->trans != GST_RTSP_TRANS_RTP || ct->profile != GST_RTSP_PROFILE_AVP) {
850 GST_WARNING ("invalid transport %s", transports[i]);
854 if (!(ct->lower_transport & supported)) {
855 GST_WARNING ("unsupported transport %s", transports[i]);
859 /* we have a valid transport */
860 GST_INFO ("found valid transport %s", transports[i]);
861 have_transport = TRUE;
865 gst_rtsp_transport_init (ct);
867 g_strfreev (transports);
869 /* we have not found anything usable, error out */
871 goto unsupported_transports;
873 if (client->session_pool == NULL)
876 /* we have a valid transport now, set the destination of the client. */
877 g_free (ct->destination);
878 if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
879 ct->destination = g_strdup (MCAST_ADDRESS);
881 url = gst_rtsp_connection_get_url (client->connection);
882 ct->destination = g_strdup (url->host);
886 g_object_ref (session);
887 /* get a handle to the configuration of the media in the session, this can
888 * return NULL if this is a new url to manage in this session. */
889 media = gst_rtsp_session_get_media (session, uri);
891 /* create a session if this fails we probably reached our session limit or
893 if (!(session = gst_rtsp_session_pool_create (client->session_pool)))
894 goto service_unavailable;
896 /* we need a new media configuration in this session */
900 /* we have no media, find one and manage it */
904 /* get a handle to the configuration of the media in the session */
905 if ((m = find_media (client, uri, request))) {
906 /* manage the media in our session now */
907 media = gst_rtsp_session_manage_media (session, uri, m);
911 /* if we stil have no media, error */
915 /* fix the transports */
916 if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) {
917 /* check if the client selected channels for TCP */
918 if (ct->interleaved.min == -1 || ct->interleaved.max == -1) {
919 gst_rtsp_session_media_alloc_channels (media, &ct->interleaved);
923 /* get a handle to the stream in the media */
924 if (!(stream = gst_rtsp_session_media_get_stream (media, streamid)))
927 st = gst_rtsp_session_stream_set_transport (stream, ct);
929 /* configure keepalive for this transport */
930 gst_rtsp_session_stream_set_keepalive (stream,
931 (GstRTSPKeepAliveFunc) do_keepalive, session, NULL);
933 /* serialize the server transport */
934 trans_str = gst_rtsp_transport_as_text (st);
935 gst_rtsp_transport_free (st);
937 /* construct the response now */
938 code = GST_RTSP_STS_OK;
939 gst_rtsp_message_init_response (&response, code,
940 gst_rtsp_status_as_text (code), request);
942 gst_rtsp_message_add_header (&response, GST_RTSP_HDR_TRANSPORT, trans_str);
945 send_response (client, session, &response);
947 /* update the state */
948 switch (media->state) {
949 case GST_RTSP_STATE_PLAYING:
950 case GST_RTSP_STATE_RECORDING:
951 case GST_RTSP_STATE_READY:
952 /* no state change */
955 media->state = GST_RTSP_STATE_READY;
958 g_object_unref (session);
965 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request);
970 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
971 g_object_unref (session);
976 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
977 g_object_unref (media);
978 g_object_unref (session);
983 send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request);
986 unsupported_transports:
988 send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, request);
989 gst_rtsp_transport_free (ct);
994 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
999 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
1004 static GstSDPMessage *
1005 create_sdp (GstRTSPClient * client, GstRTSPMedia * media)
1011 gst_sdp_message_new (&sdp);
1013 /* some standard things first */
1014 gst_sdp_message_set_version (sdp, "0");
1016 if (client->is_ipv6)
1021 gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", proto,
1024 gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer");
1025 gst_sdp_message_set_information (sdp, "rtsp-server");
1026 gst_sdp_message_add_time (sdp, "0", "0", NULL);
1027 gst_sdp_message_add_attribute (sdp, "tool", "GStreamer");
1028 gst_sdp_message_add_attribute (sdp, "type", "broadcast");
1029 gst_sdp_message_add_attribute (sdp, "control", "*");
1031 info.server_proto = proto;
1032 if (media->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)
1033 info.server_ip = MCAST_ADDRESS;
1035 info.server_ip = client->server_ip;
1037 /* create an SDP for the media object */
1038 if (!gst_rtsp_sdp_from_media (sdp, &info, media))
1046 gst_sdp_message_free (sdp);
1051 /* for the describe we must generate an SDP */
1053 handle_describe_request (GstRTSPClient * client, GstRTSPUrl * uri,
1054 GstRTSPSession * session, GstRTSPMessage * request)
1056 GstRTSPMessage response = { 0 };
1060 gchar *str, *content_base;
1061 GstRTSPMedia *media;
1063 /* check what kind of format is accepted, we don't really do anything with it
1064 * and always return SDP for now. */
1069 gst_rtsp_message_get_header (request, GST_RTSP_HDR_ACCEPT, &accept, i);
1070 if (res == GST_RTSP_ENOTIMPL)
1073 if (g_ascii_strcasecmp (accept, "application/sdp") == 0)
1077 /* find the media object for the uri */
1078 if (!(media = find_media (client, uri, request)))
1081 /* create an SDP for the media object on this client */
1082 if (!(sdp = create_sdp (client, media)))
1085 g_object_unref (media);
1087 gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK,
1088 gst_rtsp_status_as_text (GST_RTSP_STS_OK), request);
1090 gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_TYPE,
1093 /* content base for some clients that might screw up creating the setup uri */
1094 str = gst_rtsp_url_get_request_uri (uri);
1095 str_len = strlen (str);
1097 /* check for trailing '/' and append one */
1098 if (str[str_len - 1] != '/') {
1099 content_base = g_malloc (str_len + 2);
1100 memcpy (content_base, str, str_len);
1101 content_base[str_len] = '/';
1102 content_base[str_len + 1] = '\0';
1108 GST_INFO ("adding content-base: %s", content_base);
1110 gst_rtsp_message_add_header (&response, GST_RTSP_HDR_CONTENT_BASE,
1112 g_free (content_base);
1114 /* add SDP to the response body */
1115 str = gst_sdp_message_as_text (sdp);
1116 gst_rtsp_message_take_body (&response, (guint8 *) str, strlen (str));
1117 gst_sdp_message_free (sdp);
1119 send_response (client, session, &response);
1126 /* error reply is already sent */
1131 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
1132 g_object_unref (media);
1138 handle_options_request (GstRTSPClient * client, GstRTSPUrl * uri,
1139 GstRTSPSession * session, GstRTSPMessage * request)
1141 GstRTSPMessage response = { 0 };
1142 GstRTSPMethod options;
1145 options = GST_RTSP_DESCRIBE |
1150 GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
1152 str = gst_rtsp_options_as_text (options);
1154 gst_rtsp_message_init_response (&response, GST_RTSP_STS_OK,
1155 gst_rtsp_status_as_text (GST_RTSP_STS_OK), request);
1157 gst_rtsp_message_add_header (&response, GST_RTSP_HDR_PUBLIC, str);
1160 send_response (client, session, &response);
1165 /* remove duplicate and trailing '/' */
1167 sanitize_uri (GstRTSPUrl * uri)
1171 gboolean have_slash, prev_slash;
1173 s = d = uri->abspath;
1174 len = strlen (uri->abspath);
1178 for (i = 0; i < len; i++) {
1179 have_slash = s[i] == '/';
1181 if (!have_slash || !prev_slash)
1183 prev_slash = have_slash;
1185 len = d - uri->abspath;
1186 /* don't remove the first slash if that's the only thing left */
1187 if (len > 1 && *(d - 1) == '/')
1193 client_session_finalized (GstRTSPClient * client, GstRTSPSession * session)
1195 GST_INFO ("client %p: session %p finished", client, session);
1197 /* unlink all media managed in this session */
1198 client_unlink_session (client, session);
1200 /* remove the session */
1201 if (!(client->sessions = g_list_remove (client->sessions, session))) {
1202 GST_INFO ("client %p: all sessions finalized, close the connection",
1204 close_connection (client);
1209 client_watch_session (GstRTSPClient * client, GstRTSPSession * session)
1213 for (walk = client->sessions; walk; walk = g_list_next (walk)) {
1214 GstRTSPSession *msession = (GstRTSPSession *) walk->data;
1216 /* we already know about this session */
1217 if (msession == session)
1221 GST_INFO ("watching session %p", session);
1223 g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized,
1225 client->sessions = g_list_prepend (client->sessions, session);
1229 handle_request (GstRTSPClient * client, GstRTSPMessage * request)
1231 GstRTSPMethod method;
1232 const gchar *uristr;
1234 GstRTSPVersion version;
1236 GstRTSPSession *session;
1239 if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
1240 gst_rtsp_message_dump (request);
1243 GST_INFO ("client %p: received a request", client);
1245 gst_rtsp_message_parse_request (request, &method, &uristr, &version);
1247 if (version != GST_RTSP_VERSION_1_0) {
1248 /* we can only handle 1.0 requests */
1249 send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
1254 /* we always try to parse the url first */
1255 if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) {
1256 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request);
1260 /* sanitize the uri */
1263 /* get the session if there is any */
1264 res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
1265 if (res == GST_RTSP_OK) {
1266 if (client->session_pool == NULL)
1269 /* we had a session in the request, find it again */
1270 if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid)))
1271 goto session_not_found;
1273 /* we add the session to the client list of watched sessions. When a session
1274 * disappears because it times out, we will be notified. If all sessions are
1275 * gone, we will close the connection */
1276 client_watch_session (client, session);
1280 /* now see what is asked and dispatch to a dedicated handler */
1282 case GST_RTSP_OPTIONS:
1283 handle_options_request (client, uri, session, request);
1285 case GST_RTSP_DESCRIBE:
1286 handle_describe_request (client, uri, session, request);
1288 case GST_RTSP_SETUP:
1289 handle_setup_request (client, uri, session, request);
1292 handle_play_request (client, uri, session, request);
1294 case GST_RTSP_PAUSE:
1295 handle_pause_request (client, uri, session, request);
1297 case GST_RTSP_TEARDOWN:
1298 handle_teardown_request (client, uri, session, request);
1300 case GST_RTSP_SET_PARAMETER:
1301 handle_set_param_request (client, uri, session, request);
1303 case GST_RTSP_GET_PARAMETER:
1304 handle_get_param_request (client, uri, session, request);
1306 case GST_RTSP_ANNOUNCE:
1307 case GST_RTSP_RECORD:
1308 case GST_RTSP_REDIRECT:
1309 send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, request);
1311 case GST_RTSP_INVALID:
1313 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, request);
1317 g_object_unref (session);
1319 gst_rtsp_url_free (uri);
1325 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, request);
1330 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, request);
1336 handle_data (GstRTSPClient * client, GstRTSPMessage * message)
1346 /* find the stream for this message */
1347 res = gst_rtsp_message_parse_data (message, &channel);
1348 if (res != GST_RTSP_OK)
1351 gst_rtsp_message_steal_body (message, &data, &size);
1353 buffer = gst_buffer_new ();
1354 GST_BUFFER_DATA (buffer) = data;
1355 GST_BUFFER_MALLOCDATA (buffer) = data;
1356 GST_BUFFER_SIZE (buffer) = size;
1359 for (walk = client->streams; walk; walk = g_list_next (walk)) {
1360 GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data;
1361 GstRTSPMediaStream *mstream;
1362 GstRTSPTransport *tr;
1364 /* get the transport, if there is no transport configured, skip this stream */
1365 if (!(tr = stream->trans.transport))
1368 /* we also need a media stream */
1369 if (!(mstream = stream->media_stream))
1372 /* check for TCP transport */
1373 if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
1374 /* dispatch to the stream based on the channel number */
1375 if (tr->interleaved.min == channel) {
1376 gst_rtsp_media_stream_rtp (mstream, buffer);
1379 } else if (tr->interleaved.max == channel) {
1380 gst_rtsp_media_stream_rtcp (mstream, buffer);
1387 gst_buffer_unref (buffer);
1391 * gst_rtsp_client_set_session_pool:
1392 * @client: a #GstRTSPClient
1393 * @pool: a #GstRTSPSessionPool
1395 * Set @pool as the sessionpool for @client which it will use to find
1396 * or allocate sessions. the sessionpool is usually inherited from the server
1397 * that created the client but can be overridden later.
1400 gst_rtsp_client_set_session_pool (GstRTSPClient * client,
1401 GstRTSPSessionPool * pool)
1403 GstRTSPSessionPool *old;
1405 old = client->session_pool;
1408 g_object_ref (pool);
1409 client->session_pool = pool;
1411 g_object_unref (old);
1416 * gst_rtsp_client_get_session_pool:
1417 * @client: a #GstRTSPClient
1419 * Get the #GstRTSPSessionPool object that @client uses to manage its sessions.
1421 * Returns: a #GstRTSPSessionPool, unref after usage.
1423 GstRTSPSessionPool *
1424 gst_rtsp_client_get_session_pool (GstRTSPClient * client)
1426 GstRTSPSessionPool *result;
1428 if ((result = client->session_pool))
1429 g_object_ref (result);
1435 * gst_rtsp_client_set_media_mapping:
1436 * @client: a #GstRTSPClient
1437 * @mapping: a #GstRTSPMediaMapping
1439 * Set @mapping as the media mapping for @client which it will use to map urls
1440 * to media streams. These mapping is usually inherited from the server that
1441 * created the client but can be overriden later.
1444 gst_rtsp_client_set_media_mapping (GstRTSPClient * client,
1445 GstRTSPMediaMapping * mapping)
1447 GstRTSPMediaMapping *old;
1449 old = client->media_mapping;
1451 if (old != mapping) {
1453 g_object_ref (mapping);
1454 client->media_mapping = mapping;
1456 g_object_unref (old);
1461 * gst_rtsp_client_get_media_mapping:
1462 * @client: a #GstRTSPClient
1464 * Get the #GstRTSPMediaMapping object that @client uses to manage its sessions.
1466 * Returns: a #GstRTSPMediaMapping, unref after usage.
1468 GstRTSPMediaMapping *
1469 gst_rtsp_client_get_media_mapping (GstRTSPClient * client)
1471 GstRTSPMediaMapping *result;
1473 if ((result = client->media_mapping))
1474 g_object_ref (result);
1479 static GstRTSPResult
1480 message_received (GstRTSPWatch * watch, GstRTSPMessage * message,
1483 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1485 switch (message->type) {
1486 case GST_RTSP_MESSAGE_REQUEST:
1487 handle_request (client, message);
1489 case GST_RTSP_MESSAGE_RESPONSE:
1491 case GST_RTSP_MESSAGE_DATA:
1492 handle_data (client, message);
1500 static GstRTSPResult
1501 message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data)
1503 GstRTSPClient *client;
1505 client = GST_RTSP_CLIENT (user_data);
1507 /* GST_INFO ("client %p: sent a message with cseq %d", client, cseq); */
1512 static GstRTSPResult
1513 closed (GstRTSPWatch * watch, gpointer user_data)
1515 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1516 const gchar *tunnelid;
1518 GST_INFO ("client %p: connection closed", client);
1520 if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) {
1521 g_mutex_lock (tunnels_lock);
1522 /* remove from tunnelids */
1523 g_hash_table_remove (tunnels, tunnelid);
1524 g_mutex_unlock (tunnels_lock);
1530 static GstRTSPResult
1531 error (GstRTSPWatch * watch, GstRTSPResult result, gpointer user_data)
1533 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1536 str = gst_rtsp_strresult (result);
1537 GST_INFO ("client %p: received an error %s", client, str);
1543 static GstRTSPResult
1544 error_full (GstRTSPWatch * watch, GstRTSPResult result,
1545 GstRTSPMessage * message, guint id, gpointer user_data)
1547 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1550 str = gst_rtsp_strresult (result);
1552 ("client %p: received an error %s when handling message %p with id %d",
1553 client, str, message, id);
1560 remember_tunnel (GstRTSPClient * client)
1562 const gchar *tunnelid;
1564 /* store client in the pending tunnels */
1565 tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
1566 if (tunnelid == NULL)
1569 GST_INFO ("client %p: inserting tunnel session %s", client, tunnelid);
1571 /* we can't have two clients connecting with the same tunnelid */
1572 g_mutex_lock (tunnels_lock);
1573 if (g_hash_table_lookup (tunnels, tunnelid))
1574 goto tunnel_existed;
1576 g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
1577 g_mutex_unlock (tunnels_lock);
1584 GST_ERROR ("client %p: no tunnelid provided", client);
1589 g_mutex_unlock (tunnels_lock);
1590 GST_ERROR ("client %p: tunnel session %s already existed", client,
1596 static GstRTSPStatusCode
1597 tunnel_start (GstRTSPWatch * watch, gpointer user_data)
1599 GstRTSPClient *client;
1601 client = GST_RTSP_CLIENT (user_data);
1603 GST_INFO ("client %p: tunnel start (connection %p)", client,
1604 client->connection);
1606 if (!remember_tunnel (client))
1609 return GST_RTSP_STS_OK;
1614 GST_ERROR ("client %p: error starting tunnel", client);
1615 return GST_RTSP_STS_SERVICE_UNAVAILABLE;
1619 static GstRTSPResult
1620 tunnel_lost (GstRTSPWatch * watch, gpointer user_data)
1622 GstRTSPClient *client;
1624 client = GST_RTSP_CLIENT (user_data);
1626 GST_INFO ("client %p: tunnel lost (connection %p)", client,
1627 client->connection);
1629 /* ignore error, it'll only be a problem when the client does a POST again */
1630 remember_tunnel (client);
1635 static GstRTSPResult
1636 tunnel_complete (GstRTSPWatch * watch, gpointer user_data)
1638 const gchar *tunnelid;
1639 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
1640 GstRTSPClient *oclient;
1642 GST_INFO ("client %p: tunnel complete", client);
1644 /* find previous tunnel */
1645 tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
1646 if (tunnelid == NULL)
1649 g_mutex_lock (tunnels_lock);
1650 if (!(oclient = g_hash_table_lookup (tunnels, tunnelid)))
1653 /* remove the old client from the table. ref before because removing it will
1654 * remove the ref to it. */
1655 g_object_ref (oclient);
1656 g_hash_table_remove (tunnels, tunnelid);
1658 if (oclient->watch == NULL)
1660 g_mutex_unlock (tunnels_lock);
1662 GST_INFO ("client %p: found tunnel %p (old %p, new %p)", client, oclient,
1663 oclient->connection, client->connection);
1665 /* merge the tunnels into the first client */
1666 gst_rtsp_connection_do_tunnel (oclient->connection, client->connection);
1667 gst_rtsp_watch_reset (oclient->watch);
1668 g_object_unref (oclient);
1670 /* we don't need this watch anymore */
1671 g_source_destroy ((GSource *) client->watch);
1672 client->watchid = 0;
1673 client->watch = NULL;
1680 GST_INFO ("client %p: no tunnelid provided", client);
1681 return GST_RTSP_STS_SERVICE_UNAVAILABLE;
1685 g_mutex_unlock (tunnels_lock);
1686 GST_INFO ("client %p: tunnel session %s not found", client, tunnelid);
1687 return GST_RTSP_STS_SERVICE_UNAVAILABLE;
1691 g_mutex_unlock (tunnels_lock);
1692 GST_INFO ("client %p: tunnel session %s was closed", client, tunnelid);
1693 g_object_unref (oclient);
1694 return GST_RTSP_STS_SERVICE_UNAVAILABLE;
1698 static GstRTSPWatchFuncs watch_funcs = {
1710 client_watch_notify (GstRTSPClient * client)
1712 GST_INFO ("client %p: watch destroyed", client);
1713 client->watchid = 0;
1714 client->watch = NULL;
1715 g_object_unref (client);
1719 * gst_rtsp_client_attach:
1720 * @client: a #GstRTSPClient
1721 * @channel: a #GIOChannel
1723 * Accept a new connection for @client on the socket in @channel.
1725 * This function should be called when the client properties and urls are fully
1726 * configured and the client is ready to start.
1728 * Returns: %TRUE if the client could be accepted.
1731 gst_rtsp_client_accept (GstRTSPClient * client, GIOChannel * channel)
1734 GstRTSPConnection *conn;
1737 GMainContext *context;
1739 struct sockaddr_storage addr;
1741 gchar ip[INET6_ADDRSTRLEN];
1743 /* a new client connected. */
1744 sock = g_io_channel_unix_get_fd (channel);
1746 GST_RTSP_CHECK (gst_rtsp_connection_accept (sock, &conn), accept_failed);
1748 fd = gst_rtsp_connection_get_readfd (conn);
1750 addrlen = sizeof (addr);
1751 if (getsockname (fd, (struct sockaddr *) &addr, &addrlen) < 0)
1752 goto getpeername_failed;
1754 client->is_ipv6 = addr.ss_family == AF_INET6;
1756 if (getnameinfo ((struct sockaddr *) &addr, addrlen, ip, sizeof (ip), NULL, 0,
1757 NI_NUMERICHOST) != 0)
1758 goto getnameinfo_failed;
1760 /* keep the original ip that the client connected to */
1761 g_free (client->server_ip);
1762 client->server_ip = g_strndup (ip, sizeof (ip));
1764 GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client,
1765 client->server_ip, client->is_ipv6);
1767 url = gst_rtsp_connection_get_url (conn);
1768 GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port);
1770 client->connection = conn;
1772 /* create watch for the connection and attach */
1773 client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs,
1774 g_object_ref (client), (GDestroyNotify) client_watch_notify);
1776 /* find the context to add the watch */
1777 if ((source = g_main_current_source ()))
1778 context = g_source_get_context (source);
1782 GST_INFO ("attaching to context %p", context);
1784 client->watchid = gst_rtsp_watch_attach (client->watch, context);
1785 gst_rtsp_watch_unref (client->watch);
1792 gchar *str = gst_rtsp_strresult (res);
1794 GST_ERROR ("Could not accept client on server socket %d: %s", sock, str);
1800 GST_ERROR ("getpeername failed: %s", g_strerror (errno));
1805 GST_ERROR ("getnameinfo failed: %s", g_strerror (errno));