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., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
23 #include "rtsp-client.h"
25 #include "rtsp-params.h"
27 #define GST_RTSP_CLIENT_GET_PRIVATE(obj) \
28 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_CLIENT, GstRTSPClientPrivate))
31 * send_lock, lock, tunnels_lock
34 struct _GstRTSPClientPrivate
36 GMutex lock; /* protects everything else */
38 GstRTSPConnection *connection;
43 gboolean use_client_settings;
45 GstRTSPClientSendFunc send_func; /* protected by send_lock */
46 gpointer send_data; /* protected by send_lock */
47 GDestroyNotify send_notify; /* protected by send_lock */
49 GstRTSPSessionPool *session_pool;
50 GstRTSPMountPoints *mount_points;
60 static GMutex tunnels_lock;
61 static GHashTable *tunnels; /* protected by tunnels_lock */
63 #define DEFAULT_SESSION_POOL NULL
64 #define DEFAULT_MOUNT_POINTS NULL
65 #define DEFAULT_USE_CLIENT_SETTINGS FALSE
72 PROP_USE_CLIENT_SETTINGS,
80 SIGNAL_OPTIONS_REQUEST,
81 SIGNAL_DESCRIBE_REQUEST,
85 SIGNAL_TEARDOWN_REQUEST,
86 SIGNAL_SET_PARAMETER_REQUEST,
87 SIGNAL_GET_PARAMETER_REQUEST,
91 GST_DEBUG_CATEGORY_STATIC (rtsp_client_debug);
92 #define GST_CAT_DEFAULT rtsp_client_debug
94 static guint gst_rtsp_client_signals[SIGNAL_LAST] = { 0 };
96 static void gst_rtsp_client_get_property (GObject * object, guint propid,
97 GValue * value, GParamSpec * pspec);
98 static void gst_rtsp_client_set_property (GObject * object, guint propid,
99 const GValue * value, GParamSpec * pspec);
100 static void gst_rtsp_client_finalize (GObject * obj);
102 static GstSDPMessage *create_sdp (GstRTSPClient * client, GstRTSPMedia * media);
103 static void client_session_finalized (GstRTSPClient * client,
104 GstRTSPSession * session);
105 static void unlink_session_transports (GstRTSPClient * client,
106 GstRTSPSession * session, GstRTSPSessionMedia * media);
107 static gboolean default_configure_client_transport (GstRTSPClient * client,
108 GstRTSPClientState * state, GstRTSPTransport * ct);
109 static GstRTSPResult default_params_set (GstRTSPClient * client,
110 GstRTSPClientState * state);
111 static GstRTSPResult default_params_get (GstRTSPClient * client,
112 GstRTSPClientState * state);
114 G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT);
117 gst_rtsp_client_class_init (GstRTSPClientClass * klass)
119 GObjectClass *gobject_class;
121 g_type_class_add_private (klass, sizeof (GstRTSPClientPrivate));
123 gobject_class = G_OBJECT_CLASS (klass);
125 gobject_class->get_property = gst_rtsp_client_get_property;
126 gobject_class->set_property = gst_rtsp_client_set_property;
127 gobject_class->finalize = gst_rtsp_client_finalize;
129 klass->create_sdp = create_sdp;
130 klass->configure_client_transport = default_configure_client_transport;
131 klass->params_set = default_params_set;
132 klass->params_get = default_params_get;
134 g_object_class_install_property (gobject_class, PROP_SESSION_POOL,
135 g_param_spec_object ("session-pool", "Session Pool",
136 "The session pool to use for client session",
137 GST_TYPE_RTSP_SESSION_POOL,
138 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
140 g_object_class_install_property (gobject_class, PROP_MOUNT_POINTS,
141 g_param_spec_object ("mount-points", "Mount Points",
142 "The mount points to use for client session",
143 GST_TYPE_RTSP_MOUNT_POINTS,
144 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
146 g_object_class_install_property (gobject_class, PROP_USE_CLIENT_SETTINGS,
147 g_param_spec_boolean ("use-client-settings", "Use Client Settings",
148 "Use client settings for ttl and destination in multicast",
149 DEFAULT_USE_CLIENT_SETTINGS,
150 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
152 gst_rtsp_client_signals[SIGNAL_CLOSED] =
153 g_signal_new ("closed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
154 G_STRUCT_OFFSET (GstRTSPClientClass, closed), NULL, NULL,
155 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
157 gst_rtsp_client_signals[SIGNAL_NEW_SESSION] =
158 g_signal_new ("new-session", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
159 G_STRUCT_OFFSET (GstRTSPClientClass, new_session), NULL, NULL,
160 g_cclosure_marshal_VOID__OBJECT, G_TYPE_NONE, 1, GST_TYPE_RTSP_SESSION);
162 gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST] =
163 g_signal_new ("options-request", G_TYPE_FROM_CLASS (klass),
164 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, options_request),
165 NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
168 gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST] =
169 g_signal_new ("describe-request", G_TYPE_FROM_CLASS (klass),
170 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, describe_request),
171 NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
174 gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST] =
175 g_signal_new ("setup-request", G_TYPE_FROM_CLASS (klass),
176 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, setup_request),
177 NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
180 gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST] =
181 g_signal_new ("play-request", G_TYPE_FROM_CLASS (klass),
182 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, play_request),
183 NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
186 gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST] =
187 g_signal_new ("pause-request", G_TYPE_FROM_CLASS (klass),
188 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, pause_request),
189 NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
192 gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST] =
193 g_signal_new ("teardown-request", G_TYPE_FROM_CLASS (klass),
194 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, teardown_request),
195 NULL, NULL, g_cclosure_marshal_VOID__POINTER, G_TYPE_NONE, 1,
198 gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST] =
199 g_signal_new ("set-parameter-request", G_TYPE_FROM_CLASS (klass),
200 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
201 set_parameter_request), NULL, NULL, g_cclosure_marshal_VOID__POINTER,
202 G_TYPE_NONE, 1, G_TYPE_POINTER);
204 gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST] =
205 g_signal_new ("get-parameter-request", G_TYPE_FROM_CLASS (klass),
206 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
207 get_parameter_request), NULL, NULL, g_cclosure_marshal_VOID__POINTER,
208 G_TYPE_NONE, 1, G_TYPE_POINTER);
211 g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
212 g_mutex_init (&tunnels_lock);
214 GST_DEBUG_CATEGORY_INIT (rtsp_client_debug, "rtspclient", 0, "GstRTSPClient");
218 gst_rtsp_client_init (GstRTSPClient * client)
220 GstRTSPClientPrivate *priv = GST_RTSP_CLIENT_GET_PRIVATE (client);
224 g_mutex_init (&priv->lock);
225 g_mutex_init (&priv->send_lock);
226 priv->use_client_settings = DEFAULT_USE_CLIENT_SETTINGS;
230 static GstRTSPFilterResult
231 filter_session (GstRTSPSession * sess, GstRTSPSessionMedia * media,
234 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
236 gst_rtsp_session_media_set_state (media, GST_STATE_NULL);
237 unlink_session_transports (client, sess, media);
239 /* unmanage the media in the session */
240 return GST_RTSP_FILTER_REMOVE;
244 client_unlink_session (GstRTSPClient * client, GstRTSPSession * session)
246 /* unlink all media managed in this session */
247 gst_rtsp_session_filter (session, filter_session, client);
251 client_cleanup_sessions (GstRTSPClient * client)
253 GstRTSPClientPrivate *priv = client->priv;
256 /* remove weak-ref from sessions */
257 for (sessions = priv->sessions; sessions; sessions = g_list_next (sessions)) {
258 GstRTSPSession *session = (GstRTSPSession *) sessions->data;
259 g_object_weak_unref (G_OBJECT (session),
260 (GWeakNotify) client_session_finalized, client);
261 client_unlink_session (client, session);
263 g_list_free (priv->sessions);
264 priv->sessions = NULL;
267 /* A client is finalized when the connection is broken */
269 gst_rtsp_client_finalize (GObject * obj)
271 GstRTSPClient *client = GST_RTSP_CLIENT (obj);
272 GstRTSPClientPrivate *priv = client->priv;
274 GST_INFO ("finalize client %p", client);
276 gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
279 g_source_destroy ((GSource *) priv->watch);
281 client_cleanup_sessions (client);
283 if (priv->connection)
284 gst_rtsp_connection_free (priv->connection);
285 if (priv->session_pool)
286 g_object_unref (priv->session_pool);
287 if (priv->mount_points)
288 g_object_unref (priv->mount_points);
290 g_object_unref (priv->auth);
293 gst_rtsp_url_free (priv->uri);
295 gst_rtsp_media_unprepare (priv->media);
296 g_object_unref (priv->media);
299 g_free (priv->server_ip);
300 g_mutex_clear (&priv->lock);
301 g_mutex_clear (&priv->send_lock);
303 G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj);
307 gst_rtsp_client_get_property (GObject * object, guint propid,
308 GValue * value, GParamSpec * pspec)
310 GstRTSPClient *client = GST_RTSP_CLIENT (object);
313 case PROP_SESSION_POOL:
314 g_value_take_object (value, gst_rtsp_client_get_session_pool (client));
316 case PROP_MOUNT_POINTS:
317 g_value_take_object (value, gst_rtsp_client_get_mount_points (client));
319 case PROP_USE_CLIENT_SETTINGS:
320 g_value_set_boolean (value,
321 gst_rtsp_client_get_use_client_settings (client));
324 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
329 gst_rtsp_client_set_property (GObject * object, guint propid,
330 const GValue * value, GParamSpec * pspec)
332 GstRTSPClient *client = GST_RTSP_CLIENT (object);
335 case PROP_SESSION_POOL:
336 gst_rtsp_client_set_session_pool (client, g_value_get_object (value));
338 case PROP_MOUNT_POINTS:
339 gst_rtsp_client_set_mount_points (client, g_value_get_object (value));
341 case PROP_USE_CLIENT_SETTINGS:
342 gst_rtsp_client_set_use_client_settings (client,
343 g_value_get_boolean (value));
346 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
351 * gst_rtsp_client_new:
353 * Create a new #GstRTSPClient instance.
355 * Returns: a new #GstRTSPClient
358 gst_rtsp_client_new (void)
360 GstRTSPClient *result;
362 result = g_object_new (GST_TYPE_RTSP_CLIENT, NULL);
368 send_response (GstRTSPClient * client, GstRTSPSession * session,
369 GstRTSPMessage * response, gboolean close)
371 GstRTSPClientPrivate *priv = client->priv;
373 gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER,
374 "GStreamer RTSP server");
376 /* remove any previous header */
377 gst_rtsp_message_remove_header (response, GST_RTSP_HDR_SESSION, -1);
379 /* add the new session header for new session ids */
381 gst_rtsp_message_take_header (response, GST_RTSP_HDR_SESSION,
382 gst_rtsp_session_get_header (session));
385 if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
386 gst_rtsp_message_dump (response);
390 gst_rtsp_message_add_header (response, GST_RTSP_HDR_CONNECTION, "close");
392 g_mutex_lock (&priv->send_lock);
394 priv->send_func (client, response, close, priv->send_data);
395 g_mutex_unlock (&priv->send_lock);
397 gst_rtsp_message_unset (response);
401 send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code,
402 GstRTSPClientState * state)
404 gst_rtsp_message_init_response (state->response, code,
405 gst_rtsp_status_as_text (code), state->request);
407 send_response (client, NULL, state->response, FALSE);
411 handle_unauthorized_request (GstRTSPClient * client, GstRTSPAuth * auth,
412 GstRTSPClientState * state)
414 gst_rtsp_message_init_response (state->response, GST_RTSP_STS_UNAUTHORIZED,
415 gst_rtsp_status_as_text (GST_RTSP_STS_UNAUTHORIZED), state->request);
418 /* and let the authentication manager setup the auth tokens */
419 gst_rtsp_auth_setup_auth (auth, client, 0, state);
422 send_response (client, state->session, state->response, FALSE);
427 compare_uri (const GstRTSPUrl * uri1, const GstRTSPUrl * uri2)
429 if (uri1 == NULL || uri2 == NULL)
432 if (strcmp (uri1->abspath, uri2->abspath))
438 /* this function is called to initially find the media for the DESCRIBE request
439 * but is cached for when the same client (without breaking the connection) is
440 * doing a setup for the exact same url. */
441 static GstRTSPMedia *
442 find_media (GstRTSPClient * client, GstRTSPClientState * state)
444 GstRTSPClientPrivate *priv = client->priv;
445 GstRTSPMediaFactory *factory;
449 if (!compare_uri (priv->uri, state->uri)) {
450 /* remove any previously cached values before we try to construct a new
453 gst_rtsp_url_free (priv->uri);
456 gst_rtsp_media_unprepare (priv->media);
457 g_object_unref (priv->media);
461 if (!priv->mount_points)
462 goto no_mount_points;
464 /* find the factory for the uri first */
466 gst_rtsp_mount_points_find_factory (priv->mount_points,
470 /* check if we have access to the factory */
471 if ((auth = gst_rtsp_media_factory_get_auth (factory))) {
472 state->factory = factory;
474 if (!gst_rtsp_auth_check (auth, client, 0, state))
477 state->factory = NULL;
478 g_object_unref (auth);
481 /* prepare the media and add it to the pipeline */
482 if (!(media = gst_rtsp_media_factory_construct (factory, state->uri)))
485 g_object_unref (factory);
488 /* prepare the media */
489 if (!(gst_rtsp_media_prepare (media)))
492 /* now keep track of the uri and the media */
493 priv->uri = gst_rtsp_url_copy (state->uri);
495 state->media = media;
497 /* we have seen this uri before, used cached media */
499 state->media = media;
500 GST_INFO ("reusing cached media %p", media);
504 g_object_ref (media);
511 GST_ERROR ("client %p: no mount points configured", client);
512 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
517 GST_ERROR ("client %p: no factory for uri", client);
518 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
523 GST_ERROR ("client %p: unauthorized request", client);
524 handle_unauthorized_request (client, auth, state);
525 g_object_unref (factory);
526 state->factory = NULL;
527 g_object_unref (auth);
532 GST_ERROR ("client %p: can't create media", client);
533 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
534 g_object_unref (factory);
539 GST_ERROR ("client %p: can't prepare media", client);
540 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
541 g_object_unref (media);
547 do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client)
549 GstRTSPClientPrivate *priv = client->priv;
550 GstRTSPMessage message = { 0 };
555 gst_rtsp_message_init_data (&message, channel);
557 /* FIXME, need some sort of iovec RTSPMessage here */
558 if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ))
561 gst_rtsp_message_take_body (&message, map_info.data, map_info.size);
563 g_mutex_lock (&priv->send_lock);
565 priv->send_func (client, &message, FALSE, priv->send_data);
566 g_mutex_unlock (&priv->send_lock);
568 gst_rtsp_message_steal_body (&message, &data, &usize);
569 gst_buffer_unmap (buffer, &map_info);
571 gst_rtsp_message_unset (&message);
577 link_transport (GstRTSPClient * client, GstRTSPSession * session,
578 GstRTSPStreamTransport * trans)
580 GstRTSPClientPrivate *priv = client->priv;
582 GST_DEBUG ("client %p: linking transport %p", client, trans);
584 gst_rtsp_stream_transport_set_callbacks (trans,
585 (GstRTSPSendFunc) do_send_data,
586 (GstRTSPSendFunc) do_send_data, client, NULL);
588 priv->transports = g_list_prepend (priv->transports, trans);
590 /* make sure our session can't expire */
591 gst_rtsp_session_prevent_expire (session);
595 unlink_transport (GstRTSPClient * client, GstRTSPSession * session,
596 GstRTSPStreamTransport * trans)
598 GstRTSPClientPrivate *priv = client->priv;
600 GST_DEBUG ("client %p: unlinking transport %p", client, trans);
602 gst_rtsp_stream_transport_set_callbacks (trans, NULL, NULL, NULL, NULL);
604 priv->transports = g_list_remove (priv->transports, trans);
606 /* our session can now expire */
607 gst_rtsp_session_allow_expire (session);
611 unlink_session_transports (GstRTSPClient * client, GstRTSPSession * session,
612 GstRTSPSessionMedia * media)
617 gst_rtsp_media_n_streams (gst_rtsp_session_media_get_media (media));
618 for (i = 0; i < n_streams; i++) {
619 GstRTSPStreamTransport *trans;
620 const GstRTSPTransport *tr;
622 /* get the transport, if there is no transport configured, skip this stream */
623 trans = gst_rtsp_session_media_get_transport (media, i);
627 tr = gst_rtsp_stream_transport_get_transport (trans);
629 if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
630 /* for TCP, unlink the stream from the TCP connection of the client */
631 unlink_transport (client, session, trans);
637 close_connection (GstRTSPClient * client)
639 GstRTSPClientPrivate *priv = client->priv;
640 const gchar *tunnelid;
642 GST_DEBUG ("client %p: closing connection", client);
644 if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) {
645 g_mutex_lock (&tunnels_lock);
646 /* remove from tunnelids */
647 g_hash_table_remove (tunnels, tunnelid);
648 g_mutex_unlock (&tunnels_lock);
651 gst_rtsp_connection_close (priv->connection);
655 handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state)
657 GstRTSPClientPrivate *priv = client->priv;
658 GstRTSPSession *session;
659 GstRTSPSessionMedia *media;
660 GstRTSPStatusCode code;
665 session = state->session;
667 /* get a handle to the configuration of the media in the session */
668 media = gst_rtsp_session_get_media (session, state->uri);
672 state->sessmedia = media;
674 /* we emit the signal before closing the connection */
675 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST],
678 /* unlink the all TCP callbacks */
679 unlink_session_transports (client, session, media);
681 /* remove the session from the watched sessions */
682 g_object_weak_unref (G_OBJECT (session),
683 (GWeakNotify) client_session_finalized, client);
684 priv->sessions = g_list_remove (priv->sessions, session);
686 gst_rtsp_session_media_set_state (media, GST_STATE_NULL);
688 /* unmanage the media in the session, returns false if all media session
690 if (!gst_rtsp_session_release_media (session, media)) {
691 /* remove the session */
692 gst_rtsp_session_pool_remove (priv->session_pool, session);
694 /* construct the response now */
695 code = GST_RTSP_STS_OK;
696 gst_rtsp_message_init_response (state->response, code,
697 gst_rtsp_status_as_text (code), state->request);
699 send_response (client, session, state->response, TRUE);
706 GST_ERROR ("client %p: no session", client);
707 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state);
712 GST_ERROR ("client %p: no media for uri", client);
713 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
719 default_params_set (GstRTSPClient * client, GstRTSPClientState * state)
723 res = gst_rtsp_params_set (client, state);
729 default_params_get (GstRTSPClient * client, GstRTSPClientState * state)
733 res = gst_rtsp_params_get (client, state);
739 handle_get_param_request (GstRTSPClient * client, GstRTSPClientState * state)
745 res = gst_rtsp_message_get_body (state->request, &data, &size);
746 if (res != GST_RTSP_OK)
750 /* no body, keep-alive request */
751 send_generic_response (client, GST_RTSP_STS_OK, state);
753 /* there is a body, handle the params */
754 res = GST_RTSP_CLIENT_GET_CLASS (client)->params_get (client, state);
755 if (res != GST_RTSP_OK)
758 send_response (client, state->session, state->response, FALSE);
761 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST],
769 GST_ERROR ("client %p: bad request", client);
770 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state);
776 handle_set_param_request (GstRTSPClient * client, GstRTSPClientState * state)
782 res = gst_rtsp_message_get_body (state->request, &data, &size);
783 if (res != GST_RTSP_OK)
787 /* no body, keep-alive request */
788 send_generic_response (client, GST_RTSP_STS_OK, state);
790 /* there is a body, handle the params */
791 res = GST_RTSP_CLIENT_GET_CLASS (client)->params_set (client, state);
792 if (res != GST_RTSP_OK)
795 send_response (client, state->session, state->response, FALSE);
798 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST],
806 GST_ERROR ("client %p: bad request", client);
807 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state);
813 handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state)
815 GstRTSPSession *session;
816 GstRTSPSessionMedia *media;
817 GstRTSPStatusCode code;
818 GstRTSPState rtspstate;
820 if (!(session = state->session))
823 /* get a handle to the configuration of the media in the session */
824 media = gst_rtsp_session_get_media (session, state->uri);
828 state->sessmedia = media;
830 rtspstate = gst_rtsp_session_media_get_rtsp_state (media);
831 /* the session state must be playing or recording */
832 if (rtspstate != GST_RTSP_STATE_PLAYING &&
833 rtspstate != GST_RTSP_STATE_RECORDING)
836 /* unlink the all TCP callbacks */
837 unlink_session_transports (client, session, media);
839 /* then pause sending */
840 gst_rtsp_session_media_set_state (media, GST_STATE_PAUSED);
842 /* construct the response now */
843 code = GST_RTSP_STS_OK;
844 gst_rtsp_message_init_response (state->response, code,
845 gst_rtsp_status_as_text (code), state->request);
847 send_response (client, session, state->response, FALSE);
849 /* the state is now READY */
850 gst_rtsp_session_media_set_rtsp_state (media, GST_RTSP_STATE_READY);
852 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST],
860 GST_ERROR ("client %p: no seesion", client);
861 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state);
866 GST_ERROR ("client %p: no media for uri", client);
867 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
872 GST_ERROR ("client %p: not PLAYING or RECORDING", client);
873 send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
880 handle_play_request (GstRTSPClient * client, GstRTSPClientState * state)
882 GstRTSPSession *session;
883 GstRTSPSessionMedia *media;
884 GstRTSPStatusCode code;
886 guint n_streams, i, infocount;
888 GstRTSPTimeRange *range;
890 GstRTSPState rtspstate;
891 GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT;
893 if (!(session = state->session))
896 /* get a handle to the configuration of the media in the session */
897 media = gst_rtsp_session_get_media (session, state->uri);
901 state->sessmedia = media;
903 /* the session state must be playing or ready */
904 rtspstate = gst_rtsp_session_media_get_rtsp_state (media);
905 if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_READY)
908 /* parse the range header if we have one */
910 gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_RANGE, &str, 0);
911 if (res == GST_RTSP_OK) {
912 if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) {
913 /* we have a range, seek to the position */
915 gst_rtsp_media_seek (gst_rtsp_session_media_get_media (media), range);
916 gst_rtsp_range_free (range);
920 /* grab RTPInfo from the payloaders now */
921 rtpinfo = g_string_new ("");
924 gst_rtsp_media_n_streams (gst_rtsp_session_media_get_media (media));
925 for (i = 0, infocount = 0; i < n_streams; i++) {
926 GstRTSPStreamTransport *trans;
927 GstRTSPStream *stream;
928 const GstRTSPTransport *tr;
932 /* get the transport, if there is no transport configured, skip this stream */
933 trans = gst_rtsp_session_media_get_transport (media, i);
935 GST_INFO ("stream %d is not configured", i);
938 tr = gst_rtsp_stream_transport_get_transport (trans);
940 if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
941 /* for TCP, link the stream to the TCP connection of the client */
942 link_transport (client, session, trans);
945 stream = gst_rtsp_stream_transport_get_stream (trans);
946 if (gst_rtsp_stream_get_rtpinfo (stream, &rtptime, &seq)) {
948 g_string_append (rtpinfo, ", ");
950 uristr = gst_rtsp_url_get_request_uri (state->uri);
951 g_string_append_printf (rtpinfo, "url=%s/stream=%d;seq=%u;rtptime=%u",
952 uristr, i, seq, rtptime);
957 GST_WARNING ("RTP-Info cannot be determined for stream %d", i);
961 /* construct the response now */
962 code = GST_RTSP_STS_OK;
963 gst_rtsp_message_init_response (state->response, code,
964 gst_rtsp_status_as_text (code), state->request);
966 /* add the RTP-Info header */
968 str = g_string_free (rtpinfo, FALSE);
969 gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RTP_INFO, str);
971 g_string_free (rtpinfo, TRUE);
976 gst_rtsp_media_get_range_string (gst_rtsp_session_media_get_media (media),
978 gst_rtsp_message_take_header (state->response, GST_RTSP_HDR_RANGE, str);
980 send_response (client, session, state->response, FALSE);
982 /* start playing after sending the request */
983 gst_rtsp_session_media_set_state (media, GST_STATE_PLAYING);
985 gst_rtsp_session_media_set_rtsp_state (media, GST_RTSP_STATE_PLAYING);
987 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST],
995 GST_ERROR ("client %p: no session", client);
996 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state);
1001 GST_ERROR ("client %p: media not found", client);
1002 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
1007 GST_ERROR ("client %p: not PLAYING or READY", client);
1008 send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
1015 do_keepalive (GstRTSPSession * session)
1017 GST_INFO ("keep session %p alive", session);
1018 gst_rtsp_session_touch (session);
1021 /* parse @transport and return a valid transport in @tr. only transports
1022 * from @supported are returned. Returns FALSE if no valid transport
1025 parse_transport (const char *transport, GstRTSPLowerTrans supported,
1026 GstRTSPTransport * tr)
1033 gst_rtsp_transport_init (tr);
1035 GST_DEBUG ("parsing transports %s", transport);
1037 transports = g_strsplit (transport, ",", 0);
1039 /* loop through the transports, try to parse */
1040 for (i = 0; transports[i]; i++) {
1041 res = gst_rtsp_transport_parse (transports[i], tr);
1042 if (res != GST_RTSP_OK) {
1043 /* no valid transport, search some more */
1044 GST_WARNING ("could not parse transport %s", transports[i]);
1048 /* we have a transport, see if it's RTP/AVP */
1049 if (tr->trans != GST_RTSP_TRANS_RTP || tr->profile != GST_RTSP_PROFILE_AVP) {
1050 GST_WARNING ("invalid transport %s", transports[i]);
1054 if (!(tr->lower_transport & supported)) {
1055 GST_WARNING ("unsupported transport %s", transports[i]);
1059 /* we have a valid transport */
1060 GST_INFO ("found valid transport %s", transports[i]);
1065 gst_rtsp_transport_init (tr);
1067 g_strfreev (transports);
1073 handle_blocksize (GstRTSPMedia * media, GstRTSPStream * stream,
1074 GstRTSPMessage * request)
1076 gchar *blocksize_str;
1077 gboolean ret = TRUE;
1079 if (gst_rtsp_message_get_header (request, GST_RTSP_HDR_BLOCKSIZE,
1080 &blocksize_str, 0) == GST_RTSP_OK) {
1084 blocksize = g_ascii_strtoull (blocksize_str, &end, 10);
1085 if (end == blocksize_str) {
1086 GST_ERROR ("failed to parse blocksize");
1089 /* we don't want to change the mtu when this media
1090 * can be shared because it impacts other clients */
1091 if (gst_rtsp_media_is_shared (media))
1094 if (blocksize > G_MAXUINT)
1095 blocksize = G_MAXUINT;
1096 gst_rtsp_stream_set_mtu (stream, blocksize);
1103 default_configure_client_transport (GstRTSPClient * client,
1104 GstRTSPClientState * state, GstRTSPTransport * ct)
1106 GstRTSPClientPrivate *priv = client->priv;
1108 /* we have a valid transport now, set the destination of the client. */
1109 if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
1110 if (ct->destination && priv->use_client_settings) {
1111 GstRTSPAddress *addr;
1113 addr = gst_rtsp_stream_reserve_address (state->stream, ct->destination,
1114 ct->port.min, ct->port.max - ct->port.min + 1, ct->ttl);
1119 gst_rtsp_address_free (addr);
1121 GstRTSPAddress *addr;
1123 addr = gst_rtsp_stream_get_address (state->stream);
1127 g_free (ct->destination);
1128 ct->destination = g_strdup (addr->address);
1129 ct->port.min = addr->port;
1130 ct->port.max = addr->port + addr->n_ports - 1;
1131 ct->ttl = addr->ttl;
1133 gst_rtsp_address_free (addr);
1138 url = gst_rtsp_connection_get_url (priv->connection);
1139 g_free (ct->destination);
1140 ct->destination = g_strdup (url->host);
1142 if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) {
1143 /* check if the client selected channels for TCP */
1144 if (ct->interleaved.min == -1 || ct->interleaved.max == -1) {
1145 gst_rtsp_session_media_alloc_channels (state->sessmedia,
1155 GST_ERROR_OBJECT (client, "failed to acquire address for stream");
1160 static GstRTSPTransport *
1161 make_server_transport (GstRTSPClient * client, GstRTSPClientState * state,
1162 GstRTSPTransport * ct)
1164 GstRTSPTransport *st;
1166 GSocketFamily family;
1168 /* prepare the server transport */
1169 gst_rtsp_transport_new (&st);
1171 st->trans = ct->trans;
1172 st->profile = ct->profile;
1173 st->lower_transport = ct->lower_transport;
1175 addr = g_inet_address_new_from_string (ct->destination);
1178 GST_ERROR ("failed to get inet addr from client destination");
1179 family = G_SOCKET_FAMILY_IPV4;
1181 family = g_inet_address_get_family (addr);
1182 g_object_unref (addr);
1186 switch (st->lower_transport) {
1187 case GST_RTSP_LOWER_TRANS_UDP:
1188 st->client_port = ct->client_port;
1189 gst_rtsp_stream_get_server_port (state->stream, &st->server_port, family);
1191 case GST_RTSP_LOWER_TRANS_UDP_MCAST:
1192 st->port = ct->port;
1193 st->destination = g_strdup (ct->destination);
1196 case GST_RTSP_LOWER_TRANS_TCP:
1197 st->interleaved = ct->interleaved;
1202 gst_rtsp_stream_get_ssrc (state->stream, &st->ssrc);
1208 handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state)
1210 GstRTSPClientPrivate *priv = client->priv;
1214 GstRTSPTransport *ct, *st;
1215 GstRTSPLowerTrans supported;
1216 GstRTSPStatusCode code;
1217 GstRTSPSession *session;
1218 GstRTSPStreamTransport *trans;
1219 gchar *trans_str, *pos;
1221 GstRTSPSessionMedia *sessmedia;
1222 GstRTSPMedia *media;
1223 GstRTSPStream *stream;
1224 GstRTSPState rtspstate;
1225 GstRTSPClientClass *klass;
1229 /* the uri contains the stream number we added in the SDP config, which is
1230 * always /stream=%d so we need to strip that off
1231 * parse the stream we need to configure, look for the stream in the abspath
1232 * first and then in the query. */
1233 if (uri->abspath == NULL || !(pos = strstr (uri->abspath, "/stream="))) {
1234 if (uri->query == NULL || !(pos = strstr (uri->query, "/stream=")))
1238 /* we can mofify the parsed uri in place */
1241 pos += strlen ("/stream=");
1242 if (sscanf (pos, "%u", &streamid) != 1)
1245 /* parse the transport */
1247 gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_TRANSPORT,
1249 if (res != GST_RTSP_OK)
1252 gst_rtsp_transport_new (&ct);
1254 /* our supported transports */
1255 supported = GST_RTSP_LOWER_TRANS_UDP |
1256 GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP;
1258 /* parse and find a usable supported transport */
1259 if (!parse_transport (transport, supported, ct))
1260 goto unsupported_transports;
1262 /* we create the session after parsing stuff so that we don't make
1263 * a session for malformed requests */
1264 if (priv->session_pool == NULL)
1267 session = state->session;
1270 g_object_ref (session);
1271 /* get a handle to the configuration of the media in the session, this can
1272 * return NULL if this is a new url to manage in this session. */
1273 sessmedia = gst_rtsp_session_get_media (session, uri);
1275 /* create a session if this fails we probably reached our session limit or
1277 if (!(session = gst_rtsp_session_pool_create (priv->session_pool)))
1278 goto service_unavailable;
1280 state->session = session;
1282 /* we need a new media configuration in this session */
1286 /* we have no media, find one and manage it */
1287 if (sessmedia == NULL) {
1288 /* get a handle to the configuration of the media in the session */
1289 if ((media = find_media (client, state))) {
1290 /* manage the media in our session now */
1291 sessmedia = gst_rtsp_session_manage_media (session, uri, media);
1295 /* if we stil have no media, error */
1296 if (sessmedia == NULL)
1299 state->sessmedia = sessmedia;
1300 state->media = media = gst_rtsp_session_media_get_media (sessmedia);
1302 /* now get the stream */
1303 stream = gst_rtsp_media_get_stream (media, streamid);
1307 state->stream = stream;
1309 /* set blocksize on this stream */
1310 if (!handle_blocksize (media, stream, state->request))
1311 goto invalid_blocksize;
1313 /* update the client transport */
1314 klass = GST_RTSP_CLIENT_GET_CLASS (client);
1315 if (!klass->configure_client_transport (client, state, ct))
1316 goto unsupported_client_transport;
1318 /* set in the session media transport */
1319 trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct);
1321 /* configure keepalive for this transport */
1322 gst_rtsp_stream_transport_set_keepalive (trans,
1323 (GstRTSPKeepAliveFunc) do_keepalive, session, NULL);
1325 /* create and serialize the server transport */
1326 st = make_server_transport (client, state, ct);
1327 trans_str = gst_rtsp_transport_as_text (st);
1328 gst_rtsp_transport_free (st);
1330 /* construct the response now */
1331 code = GST_RTSP_STS_OK;
1332 gst_rtsp_message_init_response (state->response, code,
1333 gst_rtsp_status_as_text (code), state->request);
1335 gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_TRANSPORT,
1339 send_response (client, session, state->response, FALSE);
1341 /* update the state */
1342 rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
1343 switch (rtspstate) {
1344 case GST_RTSP_STATE_PLAYING:
1345 case GST_RTSP_STATE_RECORDING:
1346 case GST_RTSP_STATE_READY:
1347 /* no state change */
1350 gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY);
1353 g_object_unref (session);
1355 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST],
1363 GST_ERROR ("client %p: bad request", client);
1364 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state);
1369 GST_ERROR ("client %p: media not found", client);
1370 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
1371 g_object_unref (session);
1372 gst_rtsp_transport_free (ct);
1377 GST_ERROR ("client %p: invalid blocksize", client);
1378 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state);
1379 g_object_unref (session);
1380 gst_rtsp_transport_free (ct);
1383 unsupported_client_transport:
1385 GST_ERROR ("client %p: unsupported client transport", client);
1386 send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state);
1387 g_object_unref (session);
1388 gst_rtsp_transport_free (ct);
1393 GST_ERROR ("client %p: no transport", client);
1394 send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state);
1397 unsupported_transports:
1399 GST_ERROR ("client %p: unsupported transports", client);
1400 send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state);
1401 gst_rtsp_transport_free (ct);
1406 GST_ERROR ("client %p: no session pool configured", client);
1407 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state);
1408 gst_rtsp_transport_free (ct);
1411 service_unavailable:
1413 GST_ERROR ("client %p: can't create session", client);
1414 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
1415 gst_rtsp_transport_free (ct);
1420 static GstSDPMessage *
1421 create_sdp (GstRTSPClient * client, GstRTSPMedia * media)
1423 GstRTSPClientPrivate *priv = client->priv;
1428 gst_sdp_message_new (&sdp);
1430 /* some standard things first */
1431 gst_sdp_message_set_version (sdp, "0");
1438 gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", proto,
1441 gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer");
1442 gst_sdp_message_set_information (sdp, "rtsp-server");
1443 gst_sdp_message_add_time (sdp, "0", "0", NULL);
1444 gst_sdp_message_add_attribute (sdp, "tool", "GStreamer");
1445 gst_sdp_message_add_attribute (sdp, "type", "broadcast");
1446 gst_sdp_message_add_attribute (sdp, "control", "*");
1448 info.is_ipv6 = priv->is_ipv6;
1449 info.server_ip = priv->server_ip;
1451 /* create an SDP for the media object */
1452 if (!gst_rtsp_sdp_from_media (sdp, &info, media))
1460 GST_ERROR ("client %p: could not create SDP", client);
1461 gst_sdp_message_free (sdp);
1466 /* for the describe we must generate an SDP */
1468 handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state)
1473 gchar *str, *content_base;
1474 GstRTSPMedia *media;
1475 GstRTSPClientClass *klass;
1477 klass = GST_RTSP_CLIENT_GET_CLASS (client);
1479 /* check what kind of format is accepted, we don't really do anything with it
1480 * and always return SDP for now. */
1485 gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_ACCEPT,
1487 if (res == GST_RTSP_ENOTIMPL)
1490 if (g_ascii_strcasecmp (accept, "application/sdp") == 0)
1494 /* find the media object for the uri */
1495 if (!(media = find_media (client, state)))
1498 /* create an SDP for the media object on this client */
1499 if (!(sdp = klass->create_sdp (client, media)))
1502 g_object_unref (media);
1504 gst_rtsp_message_init_response (state->response, GST_RTSP_STS_OK,
1505 gst_rtsp_status_as_text (GST_RTSP_STS_OK), state->request);
1507 gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONTENT_TYPE,
1510 /* content base for some clients that might screw up creating the setup uri */
1511 str = gst_rtsp_url_get_request_uri (state->uri);
1512 str_len = strlen (str);
1514 /* check for trailing '/' and append one */
1515 if (str[str_len - 1] != '/') {
1516 content_base = g_malloc (str_len + 2);
1517 memcpy (content_base, str, str_len);
1518 content_base[str_len] = '/';
1519 content_base[str_len + 1] = '\0';
1525 GST_INFO ("adding content-base: %s", content_base);
1527 gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONTENT_BASE,
1529 g_free (content_base);
1531 /* add SDP to the response body */
1532 str = gst_sdp_message_as_text (sdp);
1533 gst_rtsp_message_take_body (state->response, (guint8 *) str, strlen (str));
1534 gst_sdp_message_free (sdp);
1536 send_response (client, state->session, state->response, FALSE);
1538 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST],
1546 GST_ERROR ("client %p: no media", client);
1547 /* error reply is already sent */
1552 GST_ERROR ("client %p: can't create SDP", client);
1553 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
1554 g_object_unref (media);
1560 handle_options_request (GstRTSPClient * client, GstRTSPClientState * state)
1562 GstRTSPMethod options;
1565 options = GST_RTSP_DESCRIBE |
1570 GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
1572 str = gst_rtsp_options_as_text (options);
1574 gst_rtsp_message_init_response (state->response, GST_RTSP_STS_OK,
1575 gst_rtsp_status_as_text (GST_RTSP_STS_OK), state->request);
1577 gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_PUBLIC, str);
1580 send_response (client, state->session, state->response, FALSE);
1582 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST],
1588 /* remove duplicate and trailing '/' */
1590 sanitize_uri (GstRTSPUrl * uri)
1594 gboolean have_slash, prev_slash;
1596 s = d = uri->abspath;
1597 len = strlen (uri->abspath);
1601 for (i = 0; i < len; i++) {
1602 have_slash = s[i] == '/';
1604 if (!have_slash || !prev_slash)
1606 prev_slash = have_slash;
1608 len = d - uri->abspath;
1609 /* don't remove the first slash if that's the only thing left */
1610 if (len > 1 && *(d - 1) == '/')
1616 client_session_finalized (GstRTSPClient * client, GstRTSPSession * session)
1618 GstRTSPClientPrivate *priv = client->priv;
1620 GST_INFO ("client %p: session %p finished", client, session);
1622 /* unlink all media managed in this session */
1623 client_unlink_session (client, session);
1625 /* remove the session */
1626 if (!(priv->sessions = g_list_remove (priv->sessions, session))) {
1627 GST_INFO ("client %p: all sessions finalized, close the connection",
1629 close_connection (client);
1634 client_watch_session (GstRTSPClient * client, GstRTSPSession * session)
1636 GstRTSPClientPrivate *priv = client->priv;
1639 for (walk = priv->sessions; walk; walk = g_list_next (walk)) {
1640 GstRTSPSession *msession = (GstRTSPSession *) walk->data;
1642 /* we already know about this session */
1643 if (msession == session)
1647 GST_INFO ("watching session %p", session);
1649 g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized,
1651 priv->sessions = g_list_prepend (priv->sessions, session);
1653 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_NEW_SESSION], 0,
1658 handle_request (GstRTSPClient * client, GstRTSPMessage * request)
1660 GstRTSPClientPrivate *priv = client->priv;
1661 GstRTSPMethod method;
1662 const gchar *uristr;
1663 GstRTSPUrl *uri = NULL;
1664 GstRTSPVersion version;
1666 GstRTSPSession *session = NULL;
1667 GstRTSPClientState state = { NULL };
1668 GstRTSPMessage response = { 0 };
1671 state.request = request;
1672 state.response = &response;
1674 if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
1675 gst_rtsp_message_dump (request);
1678 GST_INFO ("client %p: received a request", client);
1680 gst_rtsp_message_parse_request (request, &method, &uristr, &version);
1682 /* we can only handle 1.0 requests */
1683 if (version != GST_RTSP_VERSION_1_0)
1686 state.method = method;
1688 /* we always try to parse the url first */
1689 if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK)
1692 /* get the session if there is any */
1693 res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
1694 if (res == GST_RTSP_OK) {
1695 if (priv->session_pool == NULL)
1698 /* we had a session in the request, find it again */
1699 if (!(session = gst_rtsp_session_pool_find (priv->session_pool, sessid)))
1700 goto session_not_found;
1702 /* we add the session to the client list of watched sessions. When a session
1703 * disappears because it times out, we will be notified. If all sessions are
1704 * gone, we will close the connection */
1705 client_watch_session (client, session);
1708 /* sanitize the uri */
1711 state.session = session;
1714 if (!gst_rtsp_auth_check (priv->auth, client, 0, &state))
1715 goto not_authorized;
1718 /* now see what is asked and dispatch to a dedicated handler */
1720 case GST_RTSP_OPTIONS:
1721 handle_options_request (client, &state);
1723 case GST_RTSP_DESCRIBE:
1724 handle_describe_request (client, &state);
1726 case GST_RTSP_SETUP:
1727 handle_setup_request (client, &state);
1730 handle_play_request (client, &state);
1732 case GST_RTSP_PAUSE:
1733 handle_pause_request (client, &state);
1735 case GST_RTSP_TEARDOWN:
1736 handle_teardown_request (client, &state);
1738 case GST_RTSP_SET_PARAMETER:
1739 handle_set_param_request (client, &state);
1741 case GST_RTSP_GET_PARAMETER:
1742 handle_get_param_request (client, &state);
1744 case GST_RTSP_ANNOUNCE:
1745 case GST_RTSP_RECORD:
1746 case GST_RTSP_REDIRECT:
1747 goto not_implemented;
1748 case GST_RTSP_INVALID:
1755 g_object_unref (session);
1757 gst_rtsp_url_free (uri);
1763 GST_ERROR ("client %p: version %d not supported", client, version);
1764 send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
1770 GST_ERROR ("client %p: bad request", client);
1771 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &state);
1776 GST_ERROR ("client %p: no pool configured", client);
1777 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, &state);
1782 GST_ERROR ("client %p: session not found", client);
1783 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, &state);
1788 GST_ERROR ("client %p: not allowed", client);
1789 handle_unauthorized_request (client, priv->auth, &state);
1794 GST_ERROR ("client %p: method %d not implemented", client, method);
1795 send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, &state);
1801 handle_data (GstRTSPClient * client, GstRTSPMessage * message)
1803 GstRTSPClientPrivate *priv = client->priv;
1812 /* find the stream for this message */
1813 res = gst_rtsp_message_parse_data (message, &channel);
1814 if (res != GST_RTSP_OK)
1817 gst_rtsp_message_steal_body (message, &data, &size);
1819 buffer = gst_buffer_new_wrapped (data, size);
1822 for (walk = priv->transports; walk; walk = g_list_next (walk)) {
1823 GstRTSPStreamTransport *trans;
1824 GstRTSPStream *stream;
1825 const GstRTSPTransport *tr;
1829 tr = gst_rtsp_stream_transport_get_transport (trans);
1830 stream = gst_rtsp_stream_transport_get_stream (trans);
1832 /* check for TCP transport */
1833 if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
1834 /* dispatch to the stream based on the channel number */
1835 if (tr->interleaved.min == channel) {
1836 gst_rtsp_stream_recv_rtp (stream, buffer);
1839 } else if (tr->interleaved.max == channel) {
1840 gst_rtsp_stream_recv_rtcp (stream, buffer);
1847 gst_buffer_unref (buffer);
1851 * gst_rtsp_client_set_session_pool:
1852 * @client: a #GstRTSPClient
1853 * @pool: a #GstRTSPSessionPool
1855 * Set @pool as the sessionpool for @client which it will use to find
1856 * or allocate sessions. the sessionpool is usually inherited from the server
1857 * that created the client but can be overridden later.
1860 gst_rtsp_client_set_session_pool (GstRTSPClient * client,
1861 GstRTSPSessionPool * pool)
1863 GstRTSPSessionPool *old;
1864 GstRTSPClientPrivate *priv;
1866 g_return_if_fail (GST_IS_RTSP_CLIENT (client));
1868 priv = client->priv;
1871 g_object_ref (pool);
1873 g_mutex_lock (&priv->lock);
1874 old = priv->session_pool;
1875 priv->session_pool = pool;
1876 g_mutex_unlock (&priv->lock);
1879 g_object_unref (old);
1883 * gst_rtsp_client_get_session_pool:
1884 * @client: a #GstRTSPClient
1886 * Get the #GstRTSPSessionPool object that @client uses to manage its sessions.
1888 * Returns: (transfer full): a #GstRTSPSessionPool, unref after usage.
1890 GstRTSPSessionPool *
1891 gst_rtsp_client_get_session_pool (GstRTSPClient * client)
1893 GstRTSPClientPrivate *priv;
1894 GstRTSPSessionPool *result;
1896 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
1898 priv = client->priv;
1900 g_mutex_lock (&priv->lock);
1901 if ((result = priv->session_pool))
1902 g_object_ref (result);
1903 g_mutex_unlock (&priv->lock);
1909 * gst_rtsp_client_set_mount_points:
1910 * @client: a #GstRTSPClient
1911 * @mounts: a #GstRTSPMountPoints
1913 * Set @mounts as the mount points for @client which it will use to map urls
1914 * to media streams. These mount points are usually inherited from the server that
1915 * created the client but can be overriden later.
1918 gst_rtsp_client_set_mount_points (GstRTSPClient * client,
1919 GstRTSPMountPoints * mounts)
1921 GstRTSPClientPrivate *priv;
1922 GstRTSPMountPoints *old;
1924 g_return_if_fail (GST_IS_RTSP_CLIENT (client));
1926 priv = client->priv;
1929 g_object_ref (mounts);
1931 g_mutex_lock (&priv->lock);
1932 old = priv->mount_points;
1933 priv->mount_points = mounts;
1934 g_mutex_unlock (&priv->lock);
1937 g_object_unref (old);
1941 * gst_rtsp_client_get_mount_points:
1942 * @client: a #GstRTSPClient
1944 * Get the #GstRTSPMountPoints object that @client uses to manage its sessions.
1946 * Returns: (transfer full): a #GstRTSPMountPoints, unref after usage.
1948 GstRTSPMountPoints *
1949 gst_rtsp_client_get_mount_points (GstRTSPClient * client)
1951 GstRTSPClientPrivate *priv;
1952 GstRTSPMountPoints *result;
1954 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
1956 priv = client->priv;
1958 g_mutex_lock (&priv->lock);
1959 if ((result = priv->mount_points))
1960 g_object_ref (result);
1961 g_mutex_unlock (&priv->lock);
1967 * gst_rtsp_client_set_use_client_settings:
1968 * @client: a #GstRTSPClient
1969 * @use_client_settings: whether to use client settings for multicast
1971 * Use client transport settings (destination and ttl) for multicast.
1972 * When @use_client_settings is %FALSE, the server settings will be
1976 gst_rtsp_client_set_use_client_settings (GstRTSPClient * client,
1977 gboolean use_client_settings)
1979 GstRTSPClientPrivate *priv;
1981 g_return_if_fail (GST_IS_RTSP_CLIENT (client));
1983 priv = client->priv;
1985 g_mutex_lock (&priv->lock);
1986 priv->use_client_settings = use_client_settings;
1987 g_mutex_unlock (&priv->lock);
1991 * gst_rtsp_client_get_use_client_settings:
1992 * @client: a #GstRTSPClient
1994 * Check if client transport settings (destination and ttl) for multicast
1998 gst_rtsp_client_get_use_client_settings (GstRTSPClient * client)
2000 GstRTSPClientPrivate *priv;
2003 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE);
2005 priv = client->priv;
2007 g_mutex_lock (&priv->lock);
2008 res = priv->use_client_settings;
2009 g_mutex_unlock (&priv->lock);
2015 * gst_rtsp_client_set_auth:
2016 * @client: a #GstRTSPClient
2017 * @auth: a #GstRTSPAuth
2019 * configure @auth to be used as the authentication manager of @client.
2022 gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth)
2024 GstRTSPClientPrivate *priv;
2027 g_return_if_fail (GST_IS_RTSP_CLIENT (client));
2029 priv = client->priv;
2032 g_object_ref (auth);
2034 g_mutex_lock (&priv->lock);
2037 g_mutex_unlock (&priv->lock);
2040 g_object_unref (old);
2045 * gst_rtsp_client_get_auth:
2046 * @client: a #GstRTSPClient
2048 * Get the #GstRTSPAuth used as the authentication manager of @client.
2050 * Returns: (transfer full): the #GstRTSPAuth of @client. g_object_unref() after
2054 gst_rtsp_client_get_auth (GstRTSPClient * client)
2056 GstRTSPClientPrivate *priv;
2057 GstRTSPAuth *result;
2059 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
2061 priv = client->priv;
2063 g_mutex_lock (&priv->lock);
2064 if ((result = priv->auth))
2065 g_object_ref (result);
2066 g_mutex_unlock (&priv->lock);
2072 * gst_rtsp_client_get_uri:
2073 * @client: a #GstRTSPClient
2075 * Get the #GstRTSPUrl of @client.
2077 * Returns: (transfer full): the #GstRTSPUrl of @client. Free with
2078 * gst_rtsp_url_free () after usage.
2081 gst_rtsp_client_get_uri (GstRTSPClient * client)
2083 GstRTSPClientPrivate *priv;
2084 GstRTSPUrl *result = NULL;
2086 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
2088 priv = client->priv;
2090 g_mutex_lock (&priv->lock);
2091 if (priv->uri != NULL)
2092 result = gst_rtsp_url_copy (priv->uri);
2093 g_mutex_unlock (&priv->lock);
2099 * gst_rtsp_client_set_connection:
2100 * @client: a #GstRTSPClient
2101 * @conn: (transfer full): a #GstRTSPConnection
2103 * Set the #GstRTSPConnection of @client. This function takes ownership of
2106 * Returns: %TRUE on success.
2109 gst_rtsp_client_set_connection (GstRTSPClient * client,
2110 GstRTSPConnection * conn)
2112 GstRTSPClientPrivate *priv;
2113 GSocket *read_socket;
2114 GSocketAddress *address;
2116 GError *error = NULL;
2118 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE);
2119 g_return_val_if_fail (conn != NULL, FALSE);
2121 priv = client->priv;
2123 read_socket = gst_rtsp_connection_get_read_socket (conn);
2125 if (!(address = g_socket_get_local_address (read_socket, &error)))
2128 g_free (priv->server_ip);
2129 /* keep the original ip that the client connected to */
2130 if (G_IS_INET_SOCKET_ADDRESS (address)) {
2131 GInetAddress *iaddr;
2133 iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address));
2135 /* socket might be ipv6 but adress still ipv4 */
2136 priv->is_ipv6 = g_inet_address_get_family (iaddr) == G_SOCKET_FAMILY_IPV6;
2137 priv->server_ip = g_inet_address_to_string (iaddr);
2138 g_object_unref (address);
2140 priv->is_ipv6 = g_socket_get_family (read_socket) == G_SOCKET_FAMILY_IPV6;
2141 priv->server_ip = g_strdup ("unknown");
2144 GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client,
2145 priv->server_ip, priv->is_ipv6);
2147 url = gst_rtsp_connection_get_url (conn);
2148 GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port);
2150 priv->connection = conn;
2157 GST_ERROR ("could not get remote address %s", error->message);
2158 g_error_free (error);
2164 * gst_rtsp_client_get_connection:
2165 * @client: a #GstRTSPClient
2167 * Get the #GstRTSPConnection of @client.
2169 * Returns: (transfer none): the #GstRTSPConnection of @client.
2170 * The connection object returned remains valid until the client is freed.
2173 gst_rtsp_client_get_connection (GstRTSPClient * client)
2175 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
2177 return client->priv->connection;
2181 * gst_rtsp_client_set_send_func:
2182 * @client: a #GstRTSPClient
2183 * @func: a #GstRTSPClientSendFunc
2184 * @user_data: user data passed to @func
2185 * @notify: called when @user_data is no longer in use
2187 * Set @func as the callback that will be called when a new message needs to be
2188 * sent to the client. @user_data is passed to @func and @notify is called when
2189 * @user_data is no longer in use.
2192 gst_rtsp_client_set_send_func (GstRTSPClient * client,
2193 GstRTSPClientSendFunc func, gpointer user_data, GDestroyNotify notify)
2195 GstRTSPClientPrivate *priv;
2196 GDestroyNotify old_notify;
2199 g_return_if_fail (GST_IS_RTSP_CLIENT (client));
2201 priv = client->priv;
2203 g_mutex_lock (&priv->send_lock);
2204 priv->send_func = func;
2205 old_notify = priv->send_notify;
2206 old_data = priv->send_data;
2207 priv->send_notify = notify;
2208 priv->send_data = user_data;
2209 g_mutex_unlock (&priv->send_lock);
2212 old_notify (old_data);
2216 * gst_rtsp_client_handle_message:
2217 * @client: a #GstRTSPClient
2218 * @message: an #GstRTSPMessage
2220 * Let the client handle @message.
2222 * Returns: a #GstRTSPResult.
2225 gst_rtsp_client_handle_message (GstRTSPClient * client,
2226 GstRTSPMessage * message)
2228 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), GST_RTSP_EINVAL);
2229 g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
2231 switch (message->type) {
2232 case GST_RTSP_MESSAGE_REQUEST:
2233 handle_request (client, message);
2235 case GST_RTSP_MESSAGE_RESPONSE:
2237 case GST_RTSP_MESSAGE_DATA:
2238 handle_data (client, message);
2246 static GstRTSPResult
2247 do_send_message (GstRTSPClient * client, GstRTSPMessage * message,
2248 gboolean close, gpointer user_data)
2250 GstRTSPClientPrivate *priv = client->priv;
2252 /* send the response and store the seq number so we can wait until it's
2253 * written to the client to close the connection */
2254 return gst_rtsp_watch_send_message (priv->watch, message, close ?
2255 &priv->close_seq : NULL);
2258 static GstRTSPResult
2259 message_received (GstRTSPWatch * watch, GstRTSPMessage * message,
2262 return gst_rtsp_client_handle_message (GST_RTSP_CLIENT (user_data), message);
2265 static GstRTSPResult
2266 message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data)
2268 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2269 GstRTSPClientPrivate *priv = client->priv;
2271 if (priv->close_seq && priv->close_seq == cseq) {
2272 priv->close_seq = 0;
2273 close_connection (client);
2279 static GstRTSPResult
2280 closed (GstRTSPWatch * watch, gpointer user_data)
2282 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2283 GstRTSPClientPrivate *priv = client->priv;
2284 const gchar *tunnelid;
2286 GST_INFO ("client %p: connection closed", client);
2288 if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) {
2289 g_mutex_lock (&tunnels_lock);
2290 /* remove from tunnelids */
2291 g_hash_table_remove (tunnels, tunnelid);
2292 g_mutex_unlock (&tunnels_lock);
2295 gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
2300 static GstRTSPResult
2301 error (GstRTSPWatch * watch, GstRTSPResult result, gpointer user_data)
2303 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2306 str = gst_rtsp_strresult (result);
2307 GST_INFO ("client %p: received an error %s", client, str);
2313 static GstRTSPResult
2314 error_full (GstRTSPWatch * watch, GstRTSPResult result,
2315 GstRTSPMessage * message, guint id, gpointer user_data)
2317 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2320 str = gst_rtsp_strresult (result);
2322 ("client %p: error when handling message %p with id %d: %s",
2323 client, message, id, str);
2330 remember_tunnel (GstRTSPClient * client)
2332 GstRTSPClientPrivate *priv = client->priv;
2333 const gchar *tunnelid;
2335 /* store client in the pending tunnels */
2336 tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection);
2337 if (tunnelid == NULL)
2340 GST_INFO ("client %p: inserting tunnel session %s", client, tunnelid);
2342 /* we can't have two clients connecting with the same tunnelid */
2343 g_mutex_lock (&tunnels_lock);
2344 if (g_hash_table_lookup (tunnels, tunnelid))
2345 goto tunnel_existed;
2347 g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
2348 g_mutex_unlock (&tunnels_lock);
2355 GST_ERROR ("client %p: no tunnelid provided", client);
2360 g_mutex_unlock (&tunnels_lock);
2361 GST_ERROR ("client %p: tunnel session %s already existed", client,
2367 static GstRTSPStatusCode
2368 tunnel_start (GstRTSPWatch * watch, gpointer user_data)
2370 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2371 GstRTSPClientPrivate *priv = client->priv;
2373 GST_INFO ("client %p: tunnel start (connection %p)", client,
2376 if (!remember_tunnel (client))
2379 return GST_RTSP_STS_OK;
2384 GST_ERROR ("client %p: error starting tunnel", client);
2385 return GST_RTSP_STS_SERVICE_UNAVAILABLE;
2389 static GstRTSPResult
2390 tunnel_lost (GstRTSPWatch * watch, gpointer user_data)
2392 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2393 GstRTSPClientPrivate *priv = client->priv;
2395 GST_WARNING ("client %p: tunnel lost (connection %p)", client,
2398 /* ignore error, it'll only be a problem when the client does a POST again */
2399 remember_tunnel (client);
2404 static GstRTSPResult
2405 tunnel_complete (GstRTSPWatch * watch, gpointer user_data)
2407 const gchar *tunnelid;
2408 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2409 GstRTSPClientPrivate *priv = client->priv;
2410 GstRTSPClient *oclient;
2411 GstRTSPClientPrivate *opriv;
2413 GST_INFO ("client %p: tunnel complete", client);
2415 /* find previous tunnel */
2416 tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection);
2417 if (tunnelid == NULL)
2420 g_mutex_lock (&tunnels_lock);
2421 if (!(oclient = g_hash_table_lookup (tunnels, tunnelid)))
2424 /* remove the old client from the table. ref before because removing it will
2425 * remove the ref to it. */
2426 g_object_ref (oclient);
2427 g_hash_table_remove (tunnels, tunnelid);
2429 opriv = oclient->priv;
2431 if (opriv->watch == NULL)
2433 g_mutex_unlock (&tunnels_lock);
2435 GST_INFO ("client %p: found tunnel %p (old %p, new %p)", client, oclient,
2436 opriv->connection, priv->connection);
2438 /* merge the tunnels into the first client */
2439 gst_rtsp_connection_do_tunnel (opriv->connection, priv->connection);
2440 gst_rtsp_watch_reset (opriv->watch);
2441 g_object_unref (oclient);
2448 GST_ERROR ("client %p: no tunnelid provided", client);
2449 return GST_RTSP_ERROR;
2453 g_mutex_unlock (&tunnels_lock);
2454 GST_ERROR ("client %p: tunnel session %s not found", client, tunnelid);
2455 return GST_RTSP_ERROR;
2459 g_mutex_unlock (&tunnels_lock);
2460 GST_ERROR ("client %p: tunnel session %s was closed", client, tunnelid);
2461 g_object_unref (oclient);
2462 return GST_RTSP_ERROR;
2466 static GstRTSPWatchFuncs watch_funcs = {
2478 client_watch_notify (GstRTSPClient * client)
2480 GstRTSPClientPrivate *priv = client->priv;
2482 GST_INFO ("client %p: watch destroyed", client);
2484 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL);
2485 g_object_unref (client);
2489 * gst_rtsp_client_attach:
2490 * @client: a #GstRTSPClient
2491 * @context: (allow-none): a #GMainContext
2493 * Attaches @client to @context. When the mainloop for @context is run, the
2494 * client will be dispatched. When @context is NULL, the default context will be
2497 * This function should be called when the client properties and urls are fully
2498 * configured and the client is ready to start.
2500 * Returns: the ID (greater than 0) for the source within the GMainContext.
2503 gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context)
2505 GstRTSPClientPrivate *priv;
2508 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), 0);
2509 priv = client->priv;
2510 g_return_val_if_fail (priv->watch == NULL, 0);
2512 /* create watch for the connection and attach */
2513 priv->watch = gst_rtsp_watch_new (priv->connection, &watch_funcs,
2514 g_object_ref (client), (GDestroyNotify) client_watch_notify);
2515 gst_rtsp_client_set_send_func (client, do_send_message, priv->watch,
2516 (GDestroyNotify) gst_rtsp_watch_unref);
2518 /* FIXME make this configurable. We don't want to do this yet because it will
2519 * be superceeded by a cache object later */
2520 gst_rtsp_watch_set_send_backlog (priv->watch, 0, 100);
2522 GST_INFO ("attaching to context %p", context);
2523 res = gst_rtsp_watch_attach (priv->watch, context);