2 * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
3 * Copyright (C) 2015 Centricular Ltd
4 * Author: Sebastian Dröge <sebastian@centricular.com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
23 * @short_description: A client connection state
24 * @see_also: #GstRTSPServer, #GstRTSPThreadPool
26 * The client object handles the connection with a client for as long as a TCP
29 * A #GstRTSPClient is created by #GstRTSPServer when a new connection is
30 * accepted and it inherits the #GstRTSPMountPoints, #GstRTSPSessionPool,
31 * #GstRTSPAuth and #GstRTSPThreadPool from the server.
33 * The client connection should be configured with the #GstRTSPConnection using
34 * gst_rtsp_client_set_connection() before it can be attached to a #GMainContext
35 * using gst_rtsp_client_attach(). From then on the client will handle requests
38 * Use gst_rtsp_client_session_filter() to iterate or modify all the
39 * #GstRTSPSession objects managed by the client object.
41 * Last reviewed on 2013-07-11 (1.0.0)
50 #include <gst/sdp/gstmikey.h>
51 #include <gst/rtsp/gstrtsp-enumtypes.h>
53 #include "rtsp-client.h"
55 #include "rtsp-params.h"
56 #include "rtsp-server-internal.h"
66 * send_lock, lock, tunnels_lock
69 struct _GstRTSPClientPrivate
71 GMutex lock; /* protects everything else */
74 GstRTSPConnection *connection;
76 GMainContext *watch_context;
80 /* protected by send_lock */
81 GstRTSPClientSendFunc send_func;
83 GDestroyNotify send_notify;
84 GstRTSPClientSendMessagesFunc send_messages_func;
85 gpointer send_messages_data;
86 GDestroyNotify send_messages_notify;
89 GstRTSPSessionPool *session_pool;
90 gulong session_removed_id;
91 GstRTSPMountPoints *mount_points;
93 GstRTSPThreadPool *thread_pool;
95 /* used to cache the media in the last requested DESCRIBE so that
96 * we can pick it up in the next SETUP immediately */
100 GHashTable *transports;
102 guint sessions_cookie;
104 gboolean drop_backlog;
105 gint post_session_timeout;
107 guint content_length_limit;
109 gboolean had_session;
110 GSource *rtsp_ctrl_timeout;
111 guint rtsp_ctrl_timeout_cnt;
113 /* The version currently being used */
114 GstRTSPVersion version;
116 GHashTable *pipelined_requests; /* pipelined_request_id -> session_id */
117 GstRTSPTunnelState tstate;
126 static GMutex tunnels_lock;
127 static GHashTable *tunnels; /* protected by tunnels_lock */
129 #define WATCH_BACKLOG_SIZE 100
131 #define DEFAULT_SESSION_POOL NULL
132 #define DEFAULT_MOUNT_POINTS NULL
133 #define DEFAULT_DROP_BACKLOG TRUE
134 #define DEFAULT_POST_SESSION_TIMEOUT -1
136 #define RTSP_CTRL_CB_INTERVAL 1
137 #define RTSP_CTRL_TIMEOUT_VALUE 60
145 PROP_POST_SESSION_TIMEOUT,
153 SIGNAL_PRE_OPTIONS_REQUEST,
154 SIGNAL_OPTIONS_REQUEST,
155 SIGNAL_PRE_DESCRIBE_REQUEST,
156 SIGNAL_DESCRIBE_REQUEST,
157 SIGNAL_PRE_SETUP_REQUEST,
158 SIGNAL_SETUP_REQUEST,
159 SIGNAL_PRE_PLAY_REQUEST,
161 SIGNAL_PRE_PAUSE_REQUEST,
162 SIGNAL_PAUSE_REQUEST,
163 SIGNAL_PRE_TEARDOWN_REQUEST,
164 SIGNAL_TEARDOWN_REQUEST,
165 SIGNAL_PRE_SET_PARAMETER_REQUEST,
166 SIGNAL_SET_PARAMETER_REQUEST,
167 SIGNAL_PRE_GET_PARAMETER_REQUEST,
168 SIGNAL_GET_PARAMETER_REQUEST,
169 SIGNAL_HANDLE_RESPONSE,
171 SIGNAL_PRE_ANNOUNCE_REQUEST,
172 SIGNAL_ANNOUNCE_REQUEST,
173 SIGNAL_PRE_RECORD_REQUEST,
174 SIGNAL_RECORD_REQUEST,
175 SIGNAL_CHECK_REQUIREMENTS,
179 GST_DEBUG_CATEGORY_STATIC (rtsp_client_debug);
180 #define GST_CAT_DEFAULT rtsp_client_debug
182 static guint gst_rtsp_client_signals[SIGNAL_LAST] = { 0 };
184 static void gst_rtsp_client_get_property (GObject * object, guint propid,
185 GValue * value, GParamSpec * pspec);
186 static void gst_rtsp_client_set_property (GObject * object, guint propid,
187 const GValue * value, GParamSpec * pspec);
188 static void gst_rtsp_client_finalize (GObject * obj);
190 static void rtsp_ctrl_timeout_remove (GstRTSPClient * client);
192 static GstSDPMessage *create_sdp (GstRTSPClient * client, GstRTSPMedia * media);
193 static gboolean handle_sdp (GstRTSPClient * client, GstRTSPContext * ctx,
194 GstRTSPMedia * media, GstSDPMessage * sdp);
195 static gboolean default_configure_client_media (GstRTSPClient * client,
196 GstRTSPMedia * media, GstRTSPStream * stream, GstRTSPContext * ctx);
197 static gboolean default_configure_client_transport (GstRTSPClient * client,
198 GstRTSPContext * ctx, GstRTSPTransport * ct);
199 static GstRTSPResult default_params_set (GstRTSPClient * client,
200 GstRTSPContext * ctx);
201 static GstRTSPResult default_params_get (GstRTSPClient * client,
202 GstRTSPContext * ctx);
203 static gchar *default_make_path_from_uri (GstRTSPClient * client,
204 const GstRTSPUrl * uri);
205 static gboolean default_handle_options_request (GstRTSPClient * client,
206 GstRTSPContext * ctx, GstRTSPVersion version);
207 static gboolean default_handle_set_param_request (GstRTSPClient * client,
208 GstRTSPContext * ctx);
209 static gboolean default_handle_get_param_request (GstRTSPClient * client,
210 GstRTSPContext * ctx);
211 static gboolean default_handle_play_request (GstRTSPClient * client,
212 GstRTSPContext * ctx);
214 static void client_session_removed (GstRTSPSessionPool * pool,
215 GstRTSPSession * session, GstRTSPClient * client);
216 static GstRTSPStatusCode default_pre_signal_handler (GstRTSPClient * client,
217 GstRTSPContext * ctx);
218 static gboolean pre_signal_accumulator (GSignalInvocationHint * ihint,
219 GValue * return_accu, const GValue * handler_return, gpointer data);
220 gboolean gst_rtsp_media_has_completed_sender (GstRTSPMedia * media);
222 G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT);
225 gst_rtsp_client_class_init (GstRTSPClientClass * klass)
227 GObjectClass *gobject_class;
229 gobject_class = G_OBJECT_CLASS (klass);
231 gobject_class->get_property = gst_rtsp_client_get_property;
232 gobject_class->set_property = gst_rtsp_client_set_property;
233 gobject_class->finalize = gst_rtsp_client_finalize;
235 klass->create_sdp = create_sdp;
236 klass->handle_sdp = handle_sdp;
237 klass->configure_client_media = default_configure_client_media;
238 klass->configure_client_transport = default_configure_client_transport;
239 klass->params_set = default_params_set;
240 klass->params_get = default_params_get;
241 klass->make_path_from_uri = default_make_path_from_uri;
242 klass->handle_options_request = default_handle_options_request;
243 klass->handle_set_param_request = default_handle_set_param_request;
244 klass->handle_get_param_request = default_handle_get_param_request;
245 klass->handle_play_request = default_handle_play_request;
247 klass->pre_options_request = default_pre_signal_handler;
248 klass->pre_describe_request = default_pre_signal_handler;
249 klass->pre_setup_request = default_pre_signal_handler;
250 klass->pre_play_request = default_pre_signal_handler;
251 klass->pre_pause_request = default_pre_signal_handler;
252 klass->pre_teardown_request = default_pre_signal_handler;
253 klass->pre_set_parameter_request = default_pre_signal_handler;
254 klass->pre_get_parameter_request = default_pre_signal_handler;
255 klass->pre_announce_request = default_pre_signal_handler;
256 klass->pre_record_request = default_pre_signal_handler;
258 g_object_class_install_property (gobject_class, PROP_SESSION_POOL,
259 g_param_spec_object ("session-pool", "Session Pool",
260 "The session pool to use for client session",
261 GST_TYPE_RTSP_SESSION_POOL,
262 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
264 g_object_class_install_property (gobject_class, PROP_MOUNT_POINTS,
265 g_param_spec_object ("mount-points", "Mount Points",
266 "The mount points to use for client session",
267 GST_TYPE_RTSP_MOUNT_POINTS,
268 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
270 g_object_class_install_property (gobject_class, PROP_DROP_BACKLOG,
271 g_param_spec_boolean ("drop-backlog", "Drop Backlog",
272 "Drop data when the backlog queue is full",
273 DEFAULT_DROP_BACKLOG, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
276 * GstRTSPClient::post-session-timeout:
278 * An extra tcp timeout ( > 0) after session timeout, in seconds.
279 * The tcp connection will be kept alive until this timeout happens to give
280 * the client a possibility to reuse the connection.
281 * 0 means that the connection will be closed immediately after the session
284 * Default value is -1 seconds, meaning that we let the system close
289 g_object_class_install_property (gobject_class, PROP_POST_SESSION_TIMEOUT,
290 g_param_spec_int ("post-session-timeout", "Post Session Timeout",
291 "An extra TCP connection timeout after session timeout", G_MININT,
292 G_MAXINT, DEFAULT_POST_SESSION_TIMEOUT,
293 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
295 gst_rtsp_client_signals[SIGNAL_CLOSED] =
296 g_signal_new ("closed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
297 G_STRUCT_OFFSET (GstRTSPClientClass, closed), NULL, NULL, NULL,
298 G_TYPE_NONE, 0, G_TYPE_NONE);
300 gst_rtsp_client_signals[SIGNAL_NEW_SESSION] =
301 g_signal_new ("new-session", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
302 G_STRUCT_OFFSET (GstRTSPClientClass, new_session), NULL, NULL, NULL,
303 G_TYPE_NONE, 1, GST_TYPE_RTSP_SESSION);
306 * GstRTSPClient::pre-options-request:
307 * @client: a #GstRTSPClient
308 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
310 * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
311 * otherwise an appropriate return code
315 gst_rtsp_client_signals[SIGNAL_PRE_OPTIONS_REQUEST] =
316 g_signal_new ("pre-options-request", G_TYPE_FROM_CLASS (klass),
317 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
318 pre_options_request), pre_signal_accumulator, NULL, NULL,
319 GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT);
322 * GstRTSPClient::options-request:
323 * @client: a #GstRTSPClient
324 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
326 gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST] =
327 g_signal_new ("options-request", G_TYPE_FROM_CLASS (klass),
328 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, options_request),
329 NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
332 * GstRTSPClient::pre-describe-request:
333 * @client: a #GstRTSPClient
334 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
336 * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
337 * otherwise an appropriate return code
341 gst_rtsp_client_signals[SIGNAL_PRE_DESCRIBE_REQUEST] =
342 g_signal_new ("pre-describe-request", G_TYPE_FROM_CLASS (klass),
343 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
344 pre_describe_request), pre_signal_accumulator, NULL, NULL,
345 GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT);
348 * GstRTSPClient::describe-request:
349 * @client: a #GstRTSPClient
350 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
352 gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST] =
353 g_signal_new ("describe-request", G_TYPE_FROM_CLASS (klass),
354 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, describe_request),
355 NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
358 * GstRTSPClient::pre-setup-request:
359 * @client: a #GstRTSPClient
360 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
362 * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
363 * otherwise an appropriate return code
367 gst_rtsp_client_signals[SIGNAL_PRE_SETUP_REQUEST] =
368 g_signal_new ("pre-setup-request", G_TYPE_FROM_CLASS (klass),
369 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
370 pre_setup_request), pre_signal_accumulator, NULL, NULL,
371 GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT);
374 * GstRTSPClient::setup-request:
375 * @client: a #GstRTSPClient
376 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
378 gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST] =
379 g_signal_new ("setup-request", G_TYPE_FROM_CLASS (klass),
380 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, setup_request),
381 NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
384 * GstRTSPClient::pre-play-request:
385 * @client: a #GstRTSPClient
386 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
388 * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
389 * otherwise an appropriate return code
393 gst_rtsp_client_signals[SIGNAL_PRE_PLAY_REQUEST] =
394 g_signal_new ("pre-play-request", G_TYPE_FROM_CLASS (klass),
395 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
396 pre_play_request), pre_signal_accumulator, NULL,
397 NULL, GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT);
400 * GstRTSPClient::play-request:
401 * @client: a #GstRTSPClient
402 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
404 gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST] =
405 g_signal_new ("play-request", G_TYPE_FROM_CLASS (klass),
406 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, play_request),
407 NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
410 * GstRTSPClient::pre-pause-request:
411 * @client: a #GstRTSPClient
412 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
414 * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
415 * otherwise an appropriate return code
419 gst_rtsp_client_signals[SIGNAL_PRE_PAUSE_REQUEST] =
420 g_signal_new ("pre-pause-request", G_TYPE_FROM_CLASS (klass),
421 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
422 pre_pause_request), pre_signal_accumulator, NULL, NULL,
423 GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT);
426 * GstRTSPClient::pause-request:
427 * @client: a #GstRTSPClient
428 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
430 gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST] =
431 g_signal_new ("pause-request", G_TYPE_FROM_CLASS (klass),
432 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, pause_request),
433 NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
436 * GstRTSPClient::pre-teardown-request:
437 * @client: a #GstRTSPClient
438 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
440 * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
441 * otherwise an appropriate return code
445 gst_rtsp_client_signals[SIGNAL_PRE_TEARDOWN_REQUEST] =
446 g_signal_new ("pre-teardown-request", G_TYPE_FROM_CLASS (klass),
447 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
448 pre_teardown_request), pre_signal_accumulator, NULL, NULL,
449 GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT);
452 * GstRTSPClient::teardown-request:
453 * @client: a #GstRTSPClient
454 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
456 gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST] =
457 g_signal_new ("teardown-request", G_TYPE_FROM_CLASS (klass),
458 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, teardown_request),
459 NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
462 * GstRTSPClient::pre-set-parameter-request:
463 * @client: a #GstRTSPClient
464 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
466 * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
467 * otherwise an appropriate return code
471 gst_rtsp_client_signals[SIGNAL_PRE_SET_PARAMETER_REQUEST] =
472 g_signal_new ("pre-set-parameter-request", G_TYPE_FROM_CLASS (klass),
473 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
474 pre_set_parameter_request), pre_signal_accumulator, NULL, NULL,
475 GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT);
478 * GstRTSPClient::set-parameter-request:
479 * @client: a #GstRTSPClient
480 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
482 gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST] =
483 g_signal_new ("set-parameter-request", G_TYPE_FROM_CLASS (klass),
484 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
485 set_parameter_request), NULL, NULL, NULL,
486 G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
489 * GstRTSPClient::pre-get-parameter-request:
490 * @client: a #GstRTSPClient
491 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
493 * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
494 * otherwise an appropriate return code
498 gst_rtsp_client_signals[SIGNAL_PRE_GET_PARAMETER_REQUEST] =
499 g_signal_new ("pre-get-parameter-request", G_TYPE_FROM_CLASS (klass),
500 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
501 pre_get_parameter_request), pre_signal_accumulator, NULL, NULL,
502 GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT);
505 * GstRTSPClient::get-parameter-request:
506 * @client: a #GstRTSPClient
507 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
509 gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST] =
510 g_signal_new ("get-parameter-request", G_TYPE_FROM_CLASS (klass),
511 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
512 get_parameter_request), NULL, NULL, NULL,
513 G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
516 * GstRTSPClient::handle-response:
517 * @client: a #GstRTSPClient
518 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
520 gst_rtsp_client_signals[SIGNAL_HANDLE_RESPONSE] =
521 g_signal_new ("handle-response", G_TYPE_FROM_CLASS (klass),
522 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
523 handle_response), NULL, NULL, NULL,
524 G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
527 * GstRTSPClient::send-message:
528 * @client: The RTSP client
529 * @session: (type GstRtspServer.RTSPSession): The session
530 * @message: (type GstRtsp.RTSPMessage): The message
532 gst_rtsp_client_signals[SIGNAL_SEND_MESSAGE] =
533 g_signal_new ("send-message", G_TYPE_FROM_CLASS (klass),
534 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
535 send_message), NULL, NULL, NULL,
536 G_TYPE_NONE, 2, GST_TYPE_RTSP_CONTEXT, G_TYPE_POINTER);
539 * GstRTSPClient::pre-announce-request:
540 * @client: a #GstRTSPClient
541 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
543 * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
544 * otherwise an appropriate return code
548 gst_rtsp_client_signals[SIGNAL_PRE_ANNOUNCE_REQUEST] =
549 g_signal_new ("pre-announce-request", G_TYPE_FROM_CLASS (klass),
550 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
551 pre_announce_request), pre_signal_accumulator, NULL, NULL,
552 GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT);
555 * GstRTSPClient::announce-request:
556 * @client: a #GstRTSPClient
557 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
559 gst_rtsp_client_signals[SIGNAL_ANNOUNCE_REQUEST] =
560 g_signal_new ("announce-request", G_TYPE_FROM_CLASS (klass),
561 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, announce_request),
562 NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
565 * GstRTSPClient::pre-record-request:
566 * @client: a #GstRTSPClient
567 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
569 * Returns: a #GstRTSPStatusCode, GST_RTSP_STS_OK in case of success,
570 * otherwise an appropriate return code
574 gst_rtsp_client_signals[SIGNAL_PRE_RECORD_REQUEST] =
575 g_signal_new ("pre-record-request", G_TYPE_FROM_CLASS (klass),
576 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
577 pre_record_request), pre_signal_accumulator, NULL, NULL,
578 GST_TYPE_RTSP_STATUS_CODE, 1, GST_TYPE_RTSP_CONTEXT);
581 * GstRTSPClient::record-request:
582 * @client: a #GstRTSPClient
583 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
585 gst_rtsp_client_signals[SIGNAL_RECORD_REQUEST] =
586 g_signal_new ("record-request", G_TYPE_FROM_CLASS (klass),
587 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass, record_request),
588 NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
591 * GstRTSPClient::check-requirements:
592 * @client: a #GstRTSPClient
593 * @ctx: (type GstRtspServer.RTSPContext): a #GstRTSPContext
594 * @arr: a NULL-terminated array of strings
596 * Returns: a newly allocated string with comma-separated list of
597 * unsupported options. An empty string must be returned if
598 * all options are supported.
602 gst_rtsp_client_signals[SIGNAL_CHECK_REQUIREMENTS] =
603 g_signal_new ("check-requirements", G_TYPE_FROM_CLASS (klass),
604 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPClientClass,
605 check_requirements), NULL, NULL, NULL,
606 G_TYPE_STRING, 2, GST_TYPE_RTSP_CONTEXT, G_TYPE_STRV);
609 g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
610 g_mutex_init (&tunnels_lock);
612 GST_DEBUG_CATEGORY_INIT (rtsp_client_debug, "rtspclient", 0, "GstRTSPClient");
616 gst_rtsp_client_init (GstRTSPClient * client)
618 GstRTSPClientPrivate *priv = gst_rtsp_client_get_instance_private (client);
622 g_mutex_init (&priv->lock);
623 g_mutex_init (&priv->send_lock);
624 g_mutex_init (&priv->watch_lock);
625 priv->data_seqs = g_array_new (FALSE, FALSE, sizeof (DataSeq));
626 priv->drop_backlog = DEFAULT_DROP_BACKLOG;
627 priv->post_session_timeout = DEFAULT_POST_SESSION_TIMEOUT;
629 g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
631 priv->pipelined_requests = g_hash_table_new_full (g_str_hash,
632 g_str_equal, g_free, g_free);
633 priv->tstate = TUNNEL_STATE_UNKNOWN;
634 priv->content_length_limit = G_MAXUINT;
637 static GstRTSPFilterResult
638 filter_session_media (GstRTSPSession * sess, GstRTSPSessionMedia * sessmedia,
641 gboolean *closed = user_data;
644 gboolean is_all_udp = TRUE;
646 media = gst_rtsp_session_media_get_media (sessmedia);
647 n_streams = gst_rtsp_media_n_streams (media);
649 for (i = 0; i < n_streams; i++) {
650 GstRTSPStreamTransport *transport =
651 gst_rtsp_session_media_get_transport (sessmedia, i);
652 const GstRTSPTransport *rtsp_transport;
657 rtsp_transport = gst_rtsp_stream_transport_get_transport (transport);
659 && rtsp_transport->lower_transport != GST_RTSP_LOWER_TRANS_UDP
660 && rtsp_transport->lower_transport != GST_RTSP_LOWER_TRANS_UDP_MCAST) {
666 if (!is_all_udp || gst_rtsp_media_is_stop_on_disconnect (media)) {
667 gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL);
668 return GST_RTSP_FILTER_REMOVE;
671 return GST_RTSP_FILTER_KEEP;
676 client_watch_session (GstRTSPClient * client, GstRTSPSession * session)
678 GstRTSPClientPrivate *priv = client->priv;
680 g_mutex_lock (&priv->lock);
681 /* check if we already know about this session */
682 if (g_list_find (priv->sessions, session) == NULL) {
683 GST_INFO ("watching session %p", session);
685 priv->sessions = g_list_prepend (priv->sessions, g_object_ref (session));
686 priv->sessions_cookie++;
688 /* connect removed session handler, it will be disconnected when the last
689 * session gets removed */
690 if (priv->session_removed_id == 0)
691 priv->session_removed_id = g_signal_connect_data (priv->session_pool,
692 "session-removed", G_CALLBACK (client_session_removed),
693 g_object_ref (client), (GClosureNotify) g_object_unref, 0);
695 g_mutex_unlock (&priv->lock);
700 /* should be called with lock */
702 client_unwatch_session (GstRTSPClient * client, GstRTSPSession * session,
705 GstRTSPClientPrivate *priv = client->priv;
707 GST_INFO ("client %p: unwatch session %p", client, session);
710 link = g_list_find (priv->sessions, session);
715 priv->sessions = g_list_delete_link (priv->sessions, link);
716 priv->sessions_cookie++;
718 /* if this was the last session, disconnect the handler.
719 * This will also drop the extra client ref */
720 if (!priv->sessions) {
721 g_signal_handler_disconnect (priv->session_pool, priv->session_removed_id);
722 priv->session_removed_id = 0;
725 if (!priv->drop_backlog) {
726 /* unlink all media managed in this session */
727 gst_rtsp_session_filter (session, filter_session_media, client);
730 /* remove the session */
731 g_object_unref (session);
734 static GstRTSPFilterResult
735 cleanup_session (GstRTSPClient * client, GstRTSPSession * sess,
738 gboolean *closed = user_data;
739 GstRTSPClientPrivate *priv = client->priv;
741 if (priv->drop_backlog) {
742 /* unlink all media managed in this session. This needs to happen
743 * without the client lock, so we really want to do it here. */
744 gst_rtsp_session_filter (sess, filter_session_media, user_data);
748 return GST_RTSP_FILTER_REMOVE;
750 return GST_RTSP_FILTER_KEEP;
754 clean_cached_media (GstRTSPClient * client, gboolean unprepare)
756 GstRTSPClientPrivate *priv = client->priv;
764 gst_rtsp_media_unprepare (priv->media);
765 g_object_unref (priv->media);
770 /* A client is finalized when the connection is broken */
772 gst_rtsp_client_finalize (GObject * obj)
774 GstRTSPClient *client = GST_RTSP_CLIENT (obj);
775 GstRTSPClientPrivate *priv = client->priv;
777 GST_INFO ("finalize client %p", client);
779 /* the watch and related state should be cleared before finalize
780 * as the watch actually holds a strong reference to the client */
781 g_assert (priv->watch == NULL);
782 g_assert (priv->rtsp_ctrl_timeout == NULL);
784 if (priv->watch_context) {
785 g_main_context_unref (priv->watch_context);
786 priv->watch_context = NULL;
789 gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
790 gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL);
792 /* all sessions should have been removed by now. We keep a ref to
793 * the client object for the session removed handler. The ref is
794 * dropped when the last session is removed from the list. */
795 g_assert (priv->sessions == NULL);
796 g_assert (priv->session_removed_id == 0);
798 g_array_unref (priv->data_seqs);
799 g_hash_table_unref (priv->transports);
800 g_hash_table_unref (priv->pipelined_requests);
802 if (priv->connection)
803 gst_rtsp_connection_free (priv->connection);
804 if (priv->session_pool) {
805 g_object_unref (priv->session_pool);
807 if (priv->mount_points)
808 g_object_unref (priv->mount_points);
810 g_object_unref (priv->auth);
811 if (priv->thread_pool)
812 g_object_unref (priv->thread_pool);
814 clean_cached_media (client, TRUE);
816 g_free (priv->server_ip);
817 g_mutex_clear (&priv->lock);
818 g_mutex_clear (&priv->send_lock);
819 g_mutex_clear (&priv->watch_lock);
821 G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj);
825 gst_rtsp_client_get_property (GObject * object, guint propid,
826 GValue * value, GParamSpec * pspec)
828 GstRTSPClient *client = GST_RTSP_CLIENT (object);
829 GstRTSPClientPrivate *priv = client->priv;
832 case PROP_SESSION_POOL:
833 g_value_take_object (value, gst_rtsp_client_get_session_pool (client));
835 case PROP_MOUNT_POINTS:
836 g_value_take_object (value, gst_rtsp_client_get_mount_points (client));
838 case PROP_DROP_BACKLOG:
839 g_value_set_boolean (value, priv->drop_backlog);
841 case PROP_POST_SESSION_TIMEOUT:
842 g_value_set_int (value, priv->post_session_timeout);
845 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
850 gst_rtsp_client_set_property (GObject * object, guint propid,
851 const GValue * value, GParamSpec * pspec)
853 GstRTSPClient *client = GST_RTSP_CLIENT (object);
854 GstRTSPClientPrivate *priv = client->priv;
857 case PROP_SESSION_POOL:
858 gst_rtsp_client_set_session_pool (client, g_value_get_object (value));
860 case PROP_MOUNT_POINTS:
861 gst_rtsp_client_set_mount_points (client, g_value_get_object (value));
863 case PROP_DROP_BACKLOG:
864 g_mutex_lock (&priv->lock);
865 priv->drop_backlog = g_value_get_boolean (value);
866 g_mutex_unlock (&priv->lock);
868 case PROP_POST_SESSION_TIMEOUT:
869 g_mutex_lock (&priv->lock);
870 priv->post_session_timeout = g_value_get_int (value);
871 g_mutex_unlock (&priv->lock);
874 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
879 * gst_rtsp_client_new:
881 * Create a new #GstRTSPClient instance.
883 * Returns: (transfer full): a new #GstRTSPClient
886 gst_rtsp_client_new (void)
888 GstRTSPClient *result;
890 result = g_object_new (GST_TYPE_RTSP_CLIENT, NULL);
896 send_message (GstRTSPClient * client, GstRTSPContext * ctx,
897 GstRTSPMessage * message, gboolean close)
899 GstRTSPClientPrivate *priv = client->priv;
901 gst_rtsp_message_add_header (message, GST_RTSP_HDR_SERVER,
902 "GStreamer RTSP server");
904 /* remove any previous header */
905 gst_rtsp_message_remove_header (message, GST_RTSP_HDR_SESSION, -1);
907 /* add the new session header for new session ids */
909 gst_rtsp_message_take_header (message, GST_RTSP_HDR_SESSION,
910 gst_rtsp_session_get_header (ctx->session));
913 if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
914 gst_rtsp_message_dump (message);
918 gst_rtsp_message_add_header (message, GST_RTSP_HDR_CONNECTION, "close");
921 message->type_data.response.version =
922 ctx->request->type_data.request.version;
924 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SEND_MESSAGE],
927 g_mutex_lock (&priv->send_lock);
928 if (priv->send_messages_func) {
929 priv->send_messages_func (client, message, 1, close, priv->send_data);
930 } else if (priv->send_func) {
931 priv->send_func (client, message, close, priv->send_data);
933 g_mutex_unlock (&priv->send_lock);
935 gst_rtsp_message_unset (message);
939 send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code,
940 GstRTSPContext * ctx)
942 gst_rtsp_message_init_response (ctx->response, code,
943 gst_rtsp_status_as_text (code), ctx->request);
947 send_message (client, ctx, ctx->response, FALSE);
951 send_generic_error_response (GstRTSPClient * client, GstRTSPStatusCode code,
952 GstRTSPContext * ctx)
954 GstRTSPClientClass *klass = GST_RTSP_CLIENT_GET_CLASS (client);
955 GstRTSPStatusCode adjusted_code = code;
957 if (klass->adjust_error_code != NULL) {
958 adjusted_code = klass->adjust_error_code (client, ctx, code);
959 if (adjusted_code != code) {
960 GST_DEBUG ("adjusted response error code from %d to %d", code,
964 send_generic_response (client, adjusted_code, ctx);
968 send_option_not_supported_response (GstRTSPClient * client,
969 GstRTSPContext * ctx, const gchar * unsupported_options)
971 GstRTSPStatusCode code = GST_RTSP_STS_OPTION_NOT_SUPPORTED;
973 gst_rtsp_message_init_response (ctx->response, code,
974 gst_rtsp_status_as_text (code), ctx->request);
976 if (unsupported_options != NULL) {
977 gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_UNSUPPORTED,
978 unsupported_options);
983 send_message (client, ctx, ctx->response, FALSE);
987 paths_are_equal (const gchar * path1, const gchar * path2, gint len2)
989 if (path1 == NULL || path2 == NULL)
992 if (strlen (path1) != len2)
995 if (strncmp (path1, path2, len2))
1001 /* this function is called to initially find the media for the DESCRIBE request
1002 * but is cached for when the same client (without breaking the connection) is
1003 * doing a setup for the exact same url. */
1004 static GstRTSPMedia *
1005 find_media (GstRTSPClient * client, GstRTSPContext * ctx, gchar * path,
1008 GstRTSPClientPrivate *priv = client->priv;
1009 GstRTSPMediaFactory *factory;
1010 GstRTSPMedia *media;
1014 /* find the longest matching factory for the uri first */
1015 if (!(factory = gst_rtsp_mount_points_match (priv->mount_points,
1019 ctx->factory = factory;
1021 if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_ACCESS))
1022 goto no_factory_access;
1024 if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_MEDIA_FACTORY_CONSTRUCT))
1025 goto not_authorized;
1028 path_len = *matched;
1030 path_len = strlen (path);
1032 url = gst_rtsp_url_copy (ctx->uri);
1033 /* normalize rtsp://<IP>:<PORT> to rtsp://<IP>:<PORT>/ */
1034 if (url->abspath[0] == 0) {
1035 g_free (url->abspath);
1036 url->abspath = g_strdup ("/");
1039 if (!paths_are_equal (priv->path, path, path_len)) {
1040 /* remove any previously cached values before we try to construct a new
1042 clean_cached_media (client, TRUE);
1044 /* prepare the media and add it to the pipeline */
1045 if (!(media = gst_rtsp_media_factory_construct (factory, url)))
1050 if (!(gst_rtsp_media_get_transport_mode (media) &
1051 GST_RTSP_TRANSPORT_MODE_RECORD)) {
1052 GstRTSPThread *thread;
1054 thread = gst_rtsp_thread_pool_get_thread (priv->thread_pool,
1055 GST_RTSP_THREAD_TYPE_MEDIA, ctx);
1059 /* prepare the media */
1060 if (!gst_rtsp_media_prepare (media, thread))
1064 /* now keep track of the uri and the media */
1065 priv->path = g_strndup (path, path_len);
1066 priv->media = media;
1068 /* we have seen this path before, used cached media */
1069 media = priv->media;
1071 GST_INFO ("reusing cached media %p for path %s", media, priv->path);
1074 gst_rtsp_url_free (url);
1075 g_object_unref (factory);
1076 ctx->factory = NULL;
1079 g_object_ref (media);
1086 GST_ERROR ("client %p: no factory for path %s", client, path);
1087 send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
1092 g_object_unref (factory);
1093 ctx->factory = NULL;
1094 GST_ERROR ("client %p: not authorized to see factory path %s", client,
1096 /* error reply is already sent */
1101 g_object_unref (factory);
1102 ctx->factory = NULL;
1103 GST_ERROR ("client %p: not authorized for factory path %s", client, path);
1104 /* error reply is already sent */
1109 GST_ERROR ("client %p: can't create media", client);
1110 send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1111 gst_rtsp_url_free (url);
1112 g_object_unref (factory);
1113 ctx->factory = NULL;
1118 GST_ERROR ("client %p: can't create thread", client);
1119 send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
1120 gst_rtsp_url_free (url);
1121 g_object_unref (media);
1123 g_object_unref (factory);
1124 ctx->factory = NULL;
1129 GST_ERROR ("client %p: can't prepare media", client);
1130 send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
1131 gst_rtsp_url_free (url);
1132 g_object_unref (media);
1134 g_object_unref (factory);
1135 ctx->factory = NULL;
1140 static inline DataSeq *
1141 get_data_seq_element (GstRTSPClient * client, guint8 channel)
1143 GstRTSPClientPrivate *priv = client->priv;
1144 GArray *data_seqs = priv->data_seqs;
1147 while (i < data_seqs->len) {
1148 DataSeq *data_seq = &g_array_index (data_seqs, DataSeq, i);
1149 if (data_seq->channel == channel)
1158 add_data_seq (GstRTSPClient * client, guint8 channel)
1160 GstRTSPClientPrivate *priv = client->priv;
1161 DataSeq data_seq = {.channel = channel,.seq = 0 };
1163 if (get_data_seq_element (client, channel) == NULL)
1164 g_array_append_val (priv->data_seqs, data_seq);
1168 set_data_seq (GstRTSPClient * client, guint8 channel, guint seq)
1172 data_seq = get_data_seq_element (client, channel);
1173 g_assert_nonnull (data_seq);
1174 data_seq->seq = seq;
1178 get_data_seq (GstRTSPClient * client, guint8 channel)
1182 data_seq = get_data_seq_element (client, channel);
1183 g_assert_nonnull (data_seq);
1184 return data_seq->seq;
1188 get_data_channel (GstRTSPClient * client, guint seq, guint8 * channel)
1190 GstRTSPClientPrivate *priv = client->priv;
1191 GArray *data_seqs = priv->data_seqs;
1194 while (i < data_seqs->len) {
1195 DataSeq *data_seq = &g_array_index (data_seqs, DataSeq, i);
1196 if (data_seq->seq == seq) {
1197 *channel = data_seq->channel;
1207 do_close (gpointer user_data)
1209 GstRTSPClient *client = user_data;
1211 gst_rtsp_client_close (client);
1213 return G_SOURCE_REMOVE;
1217 do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client)
1219 GstRTSPClientPrivate *priv = client->priv;
1220 GstRTSPMessage message = { 0 };
1221 gboolean ret = TRUE;
1223 gst_rtsp_message_init_data (&message, channel);
1225 gst_rtsp_message_set_body_buffer (&message, buffer);
1227 g_mutex_lock (&priv->send_lock);
1228 if (get_data_seq (client, channel) != 0) {
1229 GST_WARNING ("already a queued data message for channel %d", channel);
1230 g_mutex_unlock (&priv->send_lock);
1233 if (priv->send_messages_func) {
1235 priv->send_messages_func (client, &message, 1, FALSE, priv->send_data);
1236 } else if (priv->send_func) {
1237 ret = priv->send_func (client, &message, FALSE, priv->send_data);
1239 g_mutex_unlock (&priv->send_lock);
1241 gst_rtsp_message_unset (&message);
1246 /* close in watch context */
1247 idle_src = g_idle_source_new ();
1248 g_source_set_callback (idle_src, do_close, client, NULL);
1249 g_source_attach (idle_src, priv->watch_context);
1250 g_source_unref (idle_src);
1257 do_check_back_pressure (guint8 channel, GstRTSPClient * client)
1259 return get_data_seq (client, channel) != 0;
1263 do_send_data_list (GstBufferList * buffer_list, guint8 channel,
1264 GstRTSPClient * client)
1266 GstRTSPClientPrivate *priv = client->priv;
1267 gboolean ret = TRUE;
1268 guint i, n = gst_buffer_list_length (buffer_list);
1269 GstRTSPMessage *messages;
1271 g_mutex_lock (&priv->send_lock);
1272 if (get_data_seq (client, channel) != 0) {
1273 GST_WARNING ("already a queued data message for channel %d", channel);
1274 g_mutex_unlock (&priv->send_lock);
1278 messages = g_newa (GstRTSPMessage, n);
1279 memset (messages, 0, sizeof (GstRTSPMessage) * n);
1280 for (i = 0; i < n; i++) {
1281 GstBuffer *buffer = gst_buffer_list_get (buffer_list, i);
1282 gst_rtsp_message_init_data (&messages[i], channel);
1283 gst_rtsp_message_set_body_buffer (&messages[i], buffer);
1286 if (priv->send_messages_func) {
1288 priv->send_messages_func (client, messages, n, FALSE, priv->send_data);
1289 } else if (priv->send_func) {
1290 for (i = 0; i < n; i++) {
1291 ret = priv->send_func (client, &messages[i], FALSE, priv->send_data);
1296 g_mutex_unlock (&priv->send_lock);
1298 for (i = 0; i < n; i++) {
1299 gst_rtsp_message_unset (&messages[i]);
1305 /* close in watch context */
1306 idle_src = g_idle_source_new ();
1307 g_source_set_callback (idle_src, do_close, client, NULL);
1308 g_source_attach (idle_src, priv->watch_context);
1309 g_source_unref (idle_src);
1316 * gst_rtsp_client_close:
1317 * @client: a #GstRTSPClient
1319 * Close the connection of @client and remove all media it was managing.
1324 gst_rtsp_client_close (GstRTSPClient * client)
1326 GstRTSPClientPrivate *priv = client->priv;
1327 const gchar *tunnelid;
1329 GST_DEBUG ("client %p: closing connection", client);
1331 g_mutex_lock (&priv->watch_lock);
1333 /* Work around the lack of thread safety of gst_rtsp_connection_close */
1335 gst_rtsp_watch_set_flushing (priv->watch, TRUE);
1338 if (priv->connection) {
1339 if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) {
1340 g_mutex_lock (&tunnels_lock);
1341 /* remove from tunnelids */
1342 g_hash_table_remove (tunnels, tunnelid);
1343 g_mutex_unlock (&tunnels_lock);
1345 gst_rtsp_connection_flush (priv->connection, TRUE);
1346 gst_rtsp_connection_close (priv->connection);
1350 GST_DEBUG ("client %p: destroying watch", client);
1351 g_source_destroy ((GSource *) priv->watch);
1353 gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
1354 gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL);
1355 rtsp_ctrl_timeout_remove (client);
1358 g_mutex_unlock (&priv->watch_lock);
1362 default_make_path_from_uri (GstRTSPClient * client, const GstRTSPUrl * uri)
1367 path = g_strconcat (uri->abspath, "?", uri->query, NULL);
1369 /* normalize rtsp://<IP>:<PORT> to rtsp://<IP>:<PORT>/ */
1370 path = g_strdup (uri->abspath[0] ? uri->abspath : "/");
1376 /* Default signal handler function for all "pre-command" signals, like
1377 * pre-options-request. It just returns the RTSP return code 200.
1378 * Subclasses can override this to get another default behaviour.
1380 static GstRTSPStatusCode
1381 default_pre_signal_handler (GstRTSPClient * client, GstRTSPContext * ctx)
1383 GST_LOG_OBJECT (client, "returning GST_RTSP_STS_OK");
1384 return GST_RTSP_STS_OK;
1387 /* The pre-signal accumulator function checks the return value of the signal
1388 * handlers. If any of them returns an RTSP status code that does not start
1389 * with 2 it will return FALSE, no more signal handlers will be called, and
1390 * this last RTSP status code will be the result of the signal emission.
1393 pre_signal_accumulator (GSignalInvocationHint * ihint, GValue * return_accu,
1394 const GValue * handler_return, gpointer data)
1396 GstRTSPStatusCode handler_value = g_value_get_enum (handler_return);
1397 GstRTSPStatusCode accumulated_value = g_value_get_enum (return_accu);
1399 if (handler_value < 200 || handler_value > 299) {
1400 GST_DEBUG ("handler_value : %d, returning FALSE", handler_value);
1401 g_value_set_enum (return_accu, handler_value);
1405 /* the accumulated value is initiated to 0 by GLib. if current handler value is
1406 * bigger then use that instead
1408 * FIXME: Should we prioritize the 2xx codes in a smarter way?
1409 * Like, "201 Created" > "250 Low On Storage Space" > "200 OK"?
1411 if (handler_value > accumulated_value)
1412 g_value_set_enum (return_accu, handler_value);
1417 /* The cleanup_transports function is called from handle_teardown_request() to
1418 * remove any stream transports from the newly closed session that were added to
1419 * priv->transports in handle_setup_request(). This is done to avoid forwarding
1420 * data from the client on a channel that we just closed.
1423 cleanup_transports (GstRTSPClient * client, GPtrArray * transports)
1425 GstRTSPClientPrivate *priv = client->priv;
1426 GstRTSPStreamTransport *stream_transport;
1427 const GstRTSPTransport *rtsp_transport;
1430 GST_LOG_OBJECT (client, "potentially removing %u transports",
1433 for (i = 0; i < transports->len; i++) {
1434 stream_transport = g_ptr_array_index (transports, i);
1435 if (stream_transport == NULL) {
1436 GST_LOG_OBJECT (client, "stream transport %u is NULL, continue", i);
1440 rtsp_transport = gst_rtsp_stream_transport_get_transport (stream_transport);
1441 if (rtsp_transport == NULL) {
1442 GST_LOG_OBJECT (client, "RTSP transport %u is NULL, continue", i);
1446 /* priv->transport only stores transports where RTP is tunneled over RTSP */
1447 if (rtsp_transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
1448 if (!g_hash_table_remove (priv->transports,
1449 GINT_TO_POINTER (rtsp_transport->interleaved.min))) {
1450 GST_WARNING_OBJECT (client,
1451 "failed removing transport with key '%d' from priv->transports",
1452 rtsp_transport->interleaved.min);
1454 if (!g_hash_table_remove (priv->transports,
1455 GINT_TO_POINTER (rtsp_transport->interleaved.max))) {
1456 GST_WARNING_OBJECT (client,
1457 "failed removing transport with key '%d' from priv->transports",
1458 rtsp_transport->interleaved.max);
1461 GST_LOG_OBJECT (client, "transport %u not RTP/RTSP, skip it", i);
1467 handle_teardown_request (GstRTSPClient * client, GstRTSPContext * ctx)
1469 GstRTSPClientPrivate *priv = client->priv;
1470 GstRTSPClientClass *klass;
1471 GstRTSPSession *session;
1472 GstRTSPSessionMedia *sessmedia;
1473 GstRTSPMedia *media;
1474 GstRTSPStatusCode code;
1477 gboolean keep_session;
1478 GstRTSPStatusCode sig_result;
1479 GPtrArray *session_media_transports;
1484 session = ctx->session;
1489 klass = GST_RTSP_CLIENT_GET_CLASS (client);
1490 path = klass->make_path_from_uri (client, ctx->uri);
1492 /* get a handle to the configuration of the media in the session */
1493 sessmedia = gst_rtsp_session_dup_media (session, path, &matched);
1497 /* only aggregate control for now.. */
1498 if (path[matched] != '\0')
1503 ctx->sessmedia = sessmedia;
1505 media = gst_rtsp_session_media_get_media (sessmedia);
1506 g_object_ref (media);
1507 gst_rtsp_media_lock (media);
1509 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_TEARDOWN_REQUEST],
1510 0, ctx, &sig_result);
1511 if (sig_result != GST_RTSP_STS_OK) {
1515 /* get a reference to the transports in the session media so we can clean up
1516 * our priv->transports before returning */
1517 session_media_transports = gst_rtsp_session_media_get_transports (sessmedia);
1519 /* we emit the signal before closing the connection */
1520 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_TEARDOWN_REQUEST],
1523 gst_rtsp_session_media_set_state (sessmedia, GST_STATE_NULL);
1525 /* unmanage the media in the session, returns false if all media session
1527 keep_session = gst_rtsp_session_release_media (session, sessmedia);
1528 g_object_unref (sessmedia);
1530 /* construct the response now */
1531 code = GST_RTSP_STS_OK;
1532 gst_rtsp_message_init_response (ctx->response, code,
1533 gst_rtsp_status_as_text (code), ctx->request);
1535 send_message (client, ctx, ctx->response, TRUE);
1537 if (!keep_session) {
1538 /* remove the session */
1539 gst_rtsp_session_pool_remove (priv->session_pool, session);
1542 gst_rtsp_media_unlock (media);
1543 g_object_unref (media);
1545 /* remove all transports that were present in the session media which we just
1546 * unmanaged from the priv->transports array, so we do not try to handle data
1547 * on channels that were just closed */
1548 cleanup_transports (client, session_media_transports);
1549 g_ptr_array_unref (session_media_transports);
1556 GST_ERROR ("client %p: no session", client);
1557 send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
1562 GST_ERROR ("client %p: no uri supplied", client);
1563 send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1568 GST_ERROR ("client %p: no media for uri", client);
1569 send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
1575 GST_ERROR ("client %p: no aggregate path %s", client, path);
1576 send_generic_error_response (client,
1577 GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
1579 g_object_unref (sessmedia);
1584 GST_ERROR ("client %p: pre signal returned error: %s", client,
1585 gst_rtsp_status_as_text (sig_result));
1586 send_generic_error_response (client, sig_result, ctx);
1587 gst_rtsp_media_unlock (media);
1588 g_object_unref (media);
1589 g_object_unref (sessmedia);
1594 static GstRTSPResult
1595 default_params_set (GstRTSPClient * client, GstRTSPContext * ctx)
1599 res = gst_rtsp_params_set (client, ctx);
1604 static GstRTSPResult
1605 default_params_get (GstRTSPClient * client, GstRTSPContext * ctx)
1609 res = gst_rtsp_params_get (client, ctx);
1615 default_handle_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
1620 GstRTSPStatusCode sig_result;
1622 g_signal_emit (client,
1623 gst_rtsp_client_signals[SIGNAL_PRE_GET_PARAMETER_REQUEST], 0, ctx,
1625 if (sig_result != GST_RTSP_STS_OK) {
1629 res = gst_rtsp_message_get_body (ctx->request, &data, &size);
1630 if (res != GST_RTSP_OK)
1633 if (size == 0 || !data || strlen ((char *) data) == 0) {
1634 if (ctx->request->type_data.request.version >= GST_RTSP_VERSION_2_0) {
1635 GST_ERROR_OBJECT (client, "Using PLAY request for keep-alive is forbidden"
1640 /* no body (or only '\0'), keep-alive request */
1641 send_generic_response (client, GST_RTSP_STS_OK, ctx);
1643 /* there is a body, handle the params */
1644 res = GST_RTSP_CLIENT_GET_CLASS (client)->params_get (client, ctx);
1645 if (res != GST_RTSP_OK)
1648 send_message (client, ctx, ctx->response, FALSE);
1651 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_GET_PARAMETER_REQUEST],
1659 GST_ERROR ("client %p: pre signal returned error: %s", client,
1660 gst_rtsp_status_as_text (sig_result));
1661 send_generic_error_response (client, sig_result, ctx);
1666 GST_ERROR ("client %p: bad request", client);
1667 send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1673 default_handle_set_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
1678 GstRTSPStatusCode sig_result;
1680 g_signal_emit (client,
1681 gst_rtsp_client_signals[SIGNAL_PRE_SET_PARAMETER_REQUEST], 0, ctx,
1683 if (sig_result != GST_RTSP_STS_OK) {
1687 res = gst_rtsp_message_get_body (ctx->request, &data, &size);
1688 if (res != GST_RTSP_OK)
1691 if (size == 0 || !data || strlen ((char *) data) == 0) {
1692 /* no body (or only '\0'), keep-alive request */
1693 send_generic_response (client, GST_RTSP_STS_OK, ctx);
1695 /* there is a body, handle the params */
1696 res = GST_RTSP_CLIENT_GET_CLASS (client)->params_set (client, ctx);
1697 if (res != GST_RTSP_OK)
1700 send_message (client, ctx, ctx->response, FALSE);
1703 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SET_PARAMETER_REQUEST],
1711 GST_ERROR ("client %p: pre signal returned error: %s", client,
1712 gst_rtsp_status_as_text (sig_result));
1713 send_generic_error_response (client, sig_result, ctx);
1718 GST_ERROR ("client %p: bad request", client);
1719 send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1725 handle_pause_request (GstRTSPClient * client, GstRTSPContext * ctx)
1727 GstRTSPSession *session;
1728 GstRTSPClientClass *klass;
1729 GstRTSPSessionMedia *sessmedia;
1730 GstRTSPMedia *media;
1731 GstRTSPStatusCode code;
1732 GstRTSPState rtspstate;
1735 GstRTSPStatusCode sig_result;
1738 if (!(session = ctx->session))
1744 klass = GST_RTSP_CLIENT_GET_CLASS (client);
1745 path = klass->make_path_from_uri (client, ctx->uri);
1747 /* get a handle to the configuration of the media in the session */
1748 sessmedia = gst_rtsp_session_dup_media (session, path, &matched);
1752 if (path[matched] != '\0')
1757 media = gst_rtsp_session_media_get_media (sessmedia);
1758 g_object_ref (media);
1759 gst_rtsp_media_lock (media);
1760 n = gst_rtsp_media_n_streams (media);
1761 for (i = 0; i < n; i++) {
1762 GstRTSPStream *stream = gst_rtsp_media_get_stream (media, i);
1764 if (gst_rtsp_stream_get_publish_clock_mode (stream) ==
1765 GST_RTSP_PUBLISH_CLOCK_MODE_CLOCK_AND_OFFSET)
1769 ctx->sessmedia = sessmedia;
1771 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_PAUSE_REQUEST], 0,
1773 if (sig_result != GST_RTSP_STS_OK) {
1777 rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
1778 /* the session state must be playing or recording */
1779 if (rtspstate != GST_RTSP_STATE_PLAYING &&
1780 rtspstate != GST_RTSP_STATE_RECORDING)
1783 /* then pause sending */
1784 gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PAUSED);
1786 /* construct the response now */
1787 code = GST_RTSP_STS_OK;
1788 gst_rtsp_message_init_response (ctx->response, code,
1789 gst_rtsp_status_as_text (code), ctx->request);
1791 send_message (client, ctx, ctx->response, FALSE);
1793 /* the state is now READY */
1794 gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY);
1795 g_object_unref (sessmedia);
1797 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST], 0, ctx);
1799 gst_rtsp_media_unlock (media);
1800 g_object_unref (media);
1807 GST_ERROR ("client %p: no session", client);
1808 send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
1813 GST_ERROR ("client %p: no uri supplied", client);
1814 send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1819 GST_ERROR ("client %p: no media for uri", client);
1820 send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
1826 GST_ERROR ("client %p: no aggregate path %s", client, path);
1827 send_generic_error_response (client,
1828 GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
1829 g_object_unref (sessmedia);
1835 GST_ERROR ("client %p: pre signal returned error: %s", client,
1836 gst_rtsp_status_as_text (sig_result));
1837 send_generic_error_response (client, sig_result, ctx);
1838 gst_rtsp_media_unlock (media);
1839 g_object_unref (sessmedia);
1840 g_object_unref (media);
1845 GST_ERROR ("client %p: not PLAYING or RECORDING", client);
1846 send_generic_error_response (client,
1847 GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx);
1848 gst_rtsp_media_unlock (media);
1849 g_object_unref (sessmedia);
1850 g_object_unref (media);
1855 GST_ERROR ("client %p: pausing not supported", client);
1856 send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
1857 gst_rtsp_media_unlock (media);
1858 g_object_unref (sessmedia);
1859 g_object_unref (media);
1864 /* convert @url and @path to a URL used as a content base for the factory
1865 * located at @path */
1867 make_base_url (GstRTSPClient * client, GstRTSPUrl * url, const gchar * path)
1873 /* check for trailing '/' and append one */
1874 trail = (path[strlen (path) - 1] != '/' ? "/" : "");
1879 tmp.abspath = g_strdup_printf ("%s%s", path, trail);
1881 result = gst_rtsp_url_get_request_uri (&tmp);
1882 g_free (tmp.abspath);
1887 /* Check if the given header of type double is present and, if so,
1888 * put it's value in the supplied variable.
1890 static GstRTSPStatusCode
1891 parse_header_value_double (GstRTSPClient * client, GstRTSPContext * ctx,
1892 GstRTSPHeaderField header, gboolean * present, gdouble * value)
1898 res = gst_rtsp_message_get_header (ctx->request, header, &str, 0);
1899 if (res == GST_RTSP_OK) {
1900 *value = g_ascii_strtod (str, &end);
1902 goto parse_header_failed;
1904 GST_DEBUG ("client %p: got '%s', value %f", client,
1905 gst_rtsp_header_as_text (header), *value);
1911 return GST_RTSP_STS_OK;
1913 parse_header_failed:
1915 GST_ERROR ("client %p: failed parsing '%s' header", client,
1916 gst_rtsp_header_as_text (header));
1917 return GST_RTSP_STS_BAD_REQUEST;
1921 /* Parse scale and speed headers, if present, and set the rate to
1922 * (rate * scale * speed) */
1923 static GstRTSPStatusCode
1924 parse_scale_and_speed (GstRTSPClient * client, GstRTSPContext * ctx,
1925 gboolean * scale_present, gboolean * speed_present, gdouble * rate,
1926 GstSeekFlags * flags)
1928 gdouble scale = 1.0;
1929 gdouble speed = 1.0;
1930 GstRTSPStatusCode status;
1932 GST_DEBUG ("got rate %f", *rate);
1934 status = parse_header_value_double (client, ctx, GST_RTSP_HDR_SCALE,
1935 scale_present, &scale);
1936 if (status != GST_RTSP_STS_OK)
1939 if (*scale_present) {
1940 GST_DEBUG ("got Scale %f", scale);
1942 goto bad_scale_value;
1945 if (ABS (scale) != 1.0)
1946 *flags |= GST_SEEK_FLAG_TRICKMODE;
1949 GST_DEBUG ("rate after parsing Scale %f", *rate);
1951 status = parse_header_value_double (client, ctx, GST_RTSP_HDR_SPEED,
1952 speed_present, &speed);
1953 if (status != GST_RTSP_STS_OK)
1956 if (*speed_present) {
1957 GST_DEBUG ("got Speed %f", speed);
1959 goto bad_speed_value;
1963 GST_DEBUG ("rate after parsing Speed %f", *rate);
1969 GST_ERROR ("client %p: bad 'Scale' header value (%f)", client, scale);
1970 return GST_RTSP_STS_BAD_REQUEST;
1974 GST_ERROR ("client %p: bad 'Speed' header value (%f)", client, speed);
1975 return GST_RTSP_STS_BAD_REQUEST;
1979 static GstRTSPStatusCode
1980 setup_play_mode (GstRTSPClient * client, GstRTSPContext * ctx,
1981 GstRTSPRangeUnit * unit, gboolean * scale_present, gboolean * speed_present)
1985 GstRTSPTimeRange *range = NULL;
1987 GstSeekFlags flags = GST_SEEK_FLAG_NONE;
1988 GstRTSPClientClass *klass = GST_RTSP_CLIENT_GET_CLASS (client);
1989 GstRTSPStatusCode rtsp_status_code;
1990 GstClockTime trickmode_interval = 0;
1991 gboolean enable_rate_control = TRUE;
1993 /* parse the range header if we have one */
1994 res = gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_RANGE, &str, 0);
1995 if (res == GST_RTSP_OK) {
1996 gchar *seek_style = NULL;
1998 res = gst_rtsp_range_parse (str, &range);
1999 if (res != GST_RTSP_OK)
2000 goto parse_range_failed;
2002 *unit = range->unit;
2004 /* parse seek style header, if present */
2005 res = gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_SEEK_STYLE,
2008 if (res == GST_RTSP_OK) {
2009 if (g_strcmp0 (seek_style, "RAP") == 0)
2010 flags = GST_SEEK_FLAG_ACCURATE;
2011 else if (g_strcmp0 (seek_style, "CoRAP") == 0)
2012 flags = GST_SEEK_FLAG_KEY_UNIT;
2013 else if (g_strcmp0 (seek_style, "First-Prior") == 0)
2014 flags = GST_SEEK_FLAG_KEY_UNIT & GST_SEEK_FLAG_SNAP_BEFORE;
2015 else if (g_strcmp0 (seek_style, "Next") == 0)
2016 flags = GST_SEEK_FLAG_KEY_UNIT & GST_SEEK_FLAG_SNAP_AFTER;
2018 GST_FIXME_OBJECT (client, "Add support for seek style %s", seek_style);
2019 } else if (range->min.type == GST_RTSP_TIME_END) {
2020 flags = GST_SEEK_FLAG_ACCURATE;
2022 flags = GST_SEEK_FLAG_KEY_UNIT;
2026 gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_SEEK_STYLE,
2029 flags = GST_SEEK_FLAG_ACCURATE;
2032 /* check for scale and/or speed headers
2033 * we will set the seek rate to (speed * scale) and let the media decide
2034 * the resulting scale and speed. in the response we will use rate and applied
2035 * rate from the resulting segment as values for the speed and scale headers
2037 rtsp_status_code = parse_scale_and_speed (client, ctx, scale_present,
2038 speed_present, &rate, &flags);
2039 if (rtsp_status_code != GST_RTSP_STS_OK)
2040 goto scale_speed_failed;
2042 /* give the application a chance to tweak range, flags, or rate */
2043 if (klass->adjust_play_mode != NULL) {
2045 klass->adjust_play_mode (client, ctx, &range, &flags, &rate,
2046 &trickmode_interval, &enable_rate_control);
2047 if (rtsp_status_code != GST_RTSP_STS_OK)
2048 goto adjust_play_mode_failed;
2051 gst_rtsp_media_set_rate_control (ctx->media, enable_rate_control);
2053 /* now do the seek with the seek options */
2054 gst_rtsp_media_seek_trickmode (ctx->media, range, flags, rate,
2055 trickmode_interval);
2057 gst_rtsp_range_free (range);
2059 if (gst_rtsp_media_get_status (ctx->media) == GST_RTSP_MEDIA_STATUS_ERROR)
2062 return GST_RTSP_STS_OK;
2066 GST_ERROR ("client %p: failed parsing range header", client);
2067 return GST_RTSP_STS_BAD_REQUEST;
2072 gst_rtsp_range_free (range);
2073 GST_ERROR ("client %p: failed parsing Scale or Speed headers", client);
2074 return rtsp_status_code;
2076 adjust_play_mode_failed:
2078 GST_ERROR ("client %p: sub class returned bad code (%d)", client,
2081 gst_rtsp_range_free (range);
2082 return rtsp_status_code;
2086 GST_ERROR ("client %p: seek failed", client);
2087 return GST_RTSP_STS_SERVICE_UNAVAILABLE;
2092 default_handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx)
2094 GstRTSPSession *session;
2095 GstRTSPClientClass *klass;
2096 GstRTSPSessionMedia *sessmedia;
2097 GstRTSPMedia *media;
2098 GstRTSPStatusCode code;
2101 GstRTSPState rtspstate;
2102 GstRTSPRangeUnit unit = GST_RTSP_RANGE_NPT;
2103 gchar *path, *rtpinfo = NULL;
2105 GstRTSPStatusCode sig_result;
2106 GPtrArray *transports;
2107 gboolean scale_present;
2108 gboolean speed_present;
2110 gdouble applied_rate;
2112 if (!(session = ctx->session))
2115 if (!(uri = ctx->uri))
2118 klass = GST_RTSP_CLIENT_GET_CLASS (client);
2119 path = klass->make_path_from_uri (client, uri);
2121 /* get a handle to the configuration of the media in the session */
2122 sessmedia = gst_rtsp_session_dup_media (session, path, &matched);
2126 if (path[matched] != '\0')
2131 ctx->sessmedia = sessmedia;
2132 ctx->media = media = gst_rtsp_session_media_get_media (sessmedia);
2134 g_object_ref (media);
2135 gst_rtsp_media_lock (media);
2137 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_PLAY_REQUEST], 0,
2139 if (sig_result != GST_RTSP_STS_OK) {
2143 if (!(gst_rtsp_media_get_transport_mode (media) &
2144 GST_RTSP_TRANSPORT_MODE_PLAY))
2145 goto unsupported_mode;
2147 /* the session state must be playing or ready */
2148 rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
2149 if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_READY)
2152 /* update the pipeline */
2153 transports = gst_rtsp_session_media_get_transports (sessmedia);
2154 if (!gst_rtsp_media_complete_pipeline (media, transports)) {
2155 g_ptr_array_unref (transports);
2156 goto pipeline_error;
2158 g_ptr_array_unref (transports);
2160 /* in play we first unsuspend, media could be suspended from SDP or PAUSED */
2161 if (!gst_rtsp_media_unsuspend (media))
2162 goto unsuspend_failed;
2164 code = setup_play_mode (client, ctx, &unit, &scale_present, &speed_present);
2165 if (code != GST_RTSP_STS_OK)
2168 /* grab RTPInfo from the media now */
2169 if (gst_rtsp_media_has_completed_sender (media) &&
2170 !(rtpinfo = gst_rtsp_session_media_get_rtpinfo (sessmedia)))
2171 goto rtp_info_error;
2173 /* construct the response now */
2174 code = GST_RTSP_STS_OK;
2175 gst_rtsp_message_init_response (ctx->response, code,
2176 gst_rtsp_status_as_text (code), ctx->request);
2178 /* add the RTP-Info header */
2180 gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RTP_INFO,
2184 str = gst_rtsp_media_get_range_string (media, TRUE, unit);
2186 gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_RANGE, str);
2188 if (gst_rtsp_media_has_completed_sender (media)) {
2189 /* the scale and speed headers must always be added if they were present in
2190 * the request. however, even if they were not, we still add them if
2191 * applied_rate or rate deviate from the "normal", i.e. 1.0 */
2192 #ifdef TIZEN_PROFILE_TV
2193 /* Temporal workaround fix for TV */
2194 rate = applied_rate = 1.0;
2196 if (!gst_rtsp_media_get_rates (media, &rate, &applied_rate))
2197 goto get_rates_error;
2198 g_assert (rate != 0 && applied_rate != 0);
2200 if (scale_present || applied_rate != 1.0)
2201 gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_SCALE,
2202 g_strdup_printf ("%1.3f", applied_rate));
2204 if (speed_present || rate != 1.0)
2205 gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_SPEED,
2206 g_strdup_printf ("%1.3f", rate));
2209 if (klass->adjust_play_response) {
2210 code = klass->adjust_play_response (client, ctx);
2211 if (code != GST_RTSP_STS_OK)
2212 goto adjust_play_response_failed;
2215 send_message (client, ctx, ctx->response, FALSE);
2217 /* start playing after sending the response */
2218 gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PLAYING);
2220 gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_PLAYING);
2221 g_object_unref (sessmedia);
2223 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST], 0, ctx);
2225 gst_rtsp_media_unlock (media);
2226 g_object_unref (media);
2233 GST_ERROR ("client %p: no session", client);
2234 send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
2239 GST_ERROR ("client %p: no uri supplied", client);
2240 send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2245 GST_ERROR ("client %p: media not found", client);
2246 send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
2251 GST_ERROR ("client %p: no aggregate path %s", client, path);
2252 send_generic_error_response (client,
2253 GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
2254 g_object_unref (sessmedia);
2260 GST_ERROR ("client %p: pre signal returned error: %s", client,
2261 gst_rtsp_status_as_text (sig_result));
2262 send_generic_error_response (client, sig_result, ctx);
2263 gst_rtsp_media_unlock (media);
2264 g_object_unref (media);
2265 g_object_unref (sessmedia);
2270 GST_ERROR ("client %p: not PLAYING or READY", client);
2271 send_generic_error_response (client,
2272 GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx);
2273 gst_rtsp_media_unlock (media);
2274 g_object_unref (media);
2275 g_object_unref (sessmedia);
2280 GST_ERROR ("client %p: failed to configure the pipeline", client);
2281 send_generic_error_response (client,
2282 GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx);
2283 gst_rtsp_media_unlock (media);
2284 g_object_unref (media);
2285 g_object_unref (sessmedia);
2290 GST_ERROR ("client %p: unsuspend failed", client);
2291 send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
2292 gst_rtsp_media_unlock (media);
2293 g_object_unref (media);
2294 g_object_unref (sessmedia);
2299 GST_ERROR ("client %p: seek failed", client);
2300 send_generic_error_response (client, code, ctx);
2301 gst_rtsp_media_unlock (media);
2302 g_object_unref (media);
2303 g_object_unref (sessmedia);
2308 GST_ERROR ("client %p: media does not support PLAY", client);
2309 send_generic_error_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
2310 gst_rtsp_media_unlock (media);
2311 g_object_unref (media);
2312 g_object_unref (sessmedia);
2317 GST_ERROR ("client %p: failed obtaining rate and applied_rate", client);
2318 send_generic_error_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR,
2320 gst_rtsp_media_unlock (media);
2321 g_object_unref (media);
2322 g_object_unref (sessmedia);
2325 adjust_play_response_failed:
2327 GST_ERROR ("client %p: failed to adjust play response", client);
2328 send_generic_error_response (client, code, ctx);
2329 gst_rtsp_media_unlock (media);
2330 g_object_unref (media);
2331 g_object_unref (sessmedia);
2336 GST_ERROR ("client %p: failed to add RTP-Info", client);
2337 send_generic_error_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR,
2339 gst_rtsp_media_unlock (media);
2340 g_object_unref (media);
2341 g_object_unref (sessmedia);
2347 do_keepalive (GstRTSPSession * session)
2349 GST_INFO ("keep session %p alive", session);
2350 gst_rtsp_session_touch (session);
2353 /* parse @transport and return a valid transport in @tr. only transports
2354 * supported by @stream are returned. Returns FALSE if no valid transport
2357 parse_transport (const char *transport, GstRTSPStream * stream,
2358 GstRTSPTransport * tr)
2365 gst_rtsp_transport_init (tr);
2367 GST_DEBUG ("parsing transports %s", transport);
2369 transports = g_strsplit (transport, ",", 0);
2371 /* loop through the transports, try to parse */
2372 for (i = 0; transports[i]; i++) {
2373 g_strstrip (transports[i]);
2374 res = gst_rtsp_transport_parse (transports[i], tr);
2375 if (res != GST_RTSP_OK) {
2376 /* no valid transport, search some more */
2377 GST_WARNING ("could not parse transport %s", transports[i]);
2381 /* we have a transport, see if it's supported */
2382 if (!gst_rtsp_stream_is_transport_supported (stream, tr)) {
2383 GST_WARNING ("unsupported transport %s", transports[i]);
2387 /* we have a valid transport */
2388 GST_INFO ("found valid transport %s", transports[i]);
2393 gst_rtsp_transport_init (tr);
2395 g_strfreev (transports);
2401 default_configure_client_media (GstRTSPClient * client, GstRTSPMedia * media,
2402 GstRTSPStream * stream, GstRTSPContext * ctx)
2404 GstRTSPMessage *request = ctx->request;
2405 gchar *blocksize_str;
2407 if (!gst_rtsp_stream_is_sender (stream))
2410 if (gst_rtsp_message_get_header (request, GST_RTSP_HDR_BLOCKSIZE,
2411 &blocksize_str, 0) == GST_RTSP_OK) {
2415 blocksize = g_ascii_strtoull (blocksize_str, &end, 10);
2416 if (end == blocksize_str)
2419 /* we don't want to change the mtu when this media
2420 * can be shared because it impacts other clients */
2421 if (gst_rtsp_media_is_shared (media))
2424 if (blocksize > G_MAXUINT)
2425 blocksize = G_MAXUINT;
2427 gst_rtsp_stream_set_mtu (stream, blocksize);
2435 GST_ERROR_OBJECT (client, "failed to parse blocksize");
2436 send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
2442 default_configure_client_transport (GstRTSPClient * client,
2443 GstRTSPContext * ctx, GstRTSPTransport * ct)
2445 GstRTSPClientPrivate *priv = client->priv;
2447 /* we have a valid transport now, set the destination of the client. */
2448 if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST ||
2449 ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP) {
2450 /* allocate UDP ports */
2451 GSocketFamily family;
2452 gboolean use_client_settings = FALSE;
2454 family = priv->is_ipv6 ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_IPV4;
2456 if ((ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) &&
2457 gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_TRANSPORT_CLIENT_SETTINGS) &&
2458 (ct->destination != NULL)) {
2460 if (!gst_rtsp_stream_verify_mcast_ttl (ctx->stream, ct->ttl))
2463 use_client_settings = TRUE;
2466 /* We need to allocate the sockets for both families before starting
2467 * multiudpsink, otherwise multiudpsink won't accept new clients with
2468 * a different family.
2470 /* FIXME: could be more adequately solved by making it possible
2471 * to set a socket on multiudpsink after it has already been started */
2472 if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream,
2473 G_SOCKET_FAMILY_IPV4, ct, use_client_settings)
2474 && family == G_SOCKET_FAMILY_IPV4)
2475 goto error_allocating_ports;
2477 if (!gst_rtsp_stream_allocate_udp_sockets (ctx->stream,
2478 G_SOCKET_FAMILY_IPV6, ct, use_client_settings)
2479 && family == G_SOCKET_FAMILY_IPV6)
2480 goto error_allocating_ports;
2482 if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
2483 if (use_client_settings) {
2484 /* FIXME: the address has been successfully allocated, however, in
2485 * the use_client_settings case we need to verify that the allocated
2486 * address is the one requested by the client and if this address is
2487 * an allowed destination. Verifying this via the address pool in not
2488 * the proper way as the address pool should only be used for choosing
2489 * the server-selected address/port pairs. */
2490 GSocket *rtp_socket;
2494 gst_rtsp_stream_get_rtp_multicast_socket (ctx->stream, family);
2495 if (rtp_socket == NULL)
2497 ttl = g_socket_get_multicast_ttl (rtp_socket);
2498 g_object_unref (rtp_socket);
2499 if (ct->ttl < ttl) {
2500 /* use the maximum ttl that is requested by multicast clients */
2501 GST_DEBUG ("requested ttl %u, but keeping ttl %u", ct->ttl, ttl);
2506 GstRTSPAddress *addr = NULL;
2508 g_free (ct->destination);
2509 addr = gst_rtsp_stream_get_multicast_address (ctx->stream, family);
2512 ct->destination = g_strdup (addr->address);
2513 ct->port.min = addr->port;
2514 ct->port.max = addr->port + addr->n_ports - 1;
2515 ct->ttl = addr->ttl;
2516 gst_rtsp_address_free (addr);
2519 if (!gst_rtsp_stream_add_multicast_client_address (ctx->stream,
2520 ct->destination, ct->port.min, ct->port.max, family))
2521 goto error_mcast_transport;
2526 url = gst_rtsp_connection_get_url (priv->connection);
2527 g_free (ct->destination);
2528 ct->destination = g_strdup (url->host);
2533 url = gst_rtsp_connection_get_url (priv->connection);
2534 g_free (ct->destination);
2535 ct->destination = g_strdup (url->host);
2537 if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) {
2539 GSocketAddress *addr;
2541 sock = gst_rtsp_connection_get_read_socket (priv->connection);
2542 if ((addr = g_socket_get_remote_address (sock, NULL))) {
2543 /* our read port is the sender port of client */
2544 ct->client_port.min =
2545 g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
2546 g_object_unref (addr);
2548 if ((addr = g_socket_get_local_address (sock, NULL))) {
2549 ct->server_port.max =
2550 g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
2551 g_object_unref (addr);
2553 sock = gst_rtsp_connection_get_write_socket (priv->connection);
2554 if ((addr = g_socket_get_remote_address (sock, NULL))) {
2555 /* our write port is the receiver port of client */
2556 ct->client_port.max =
2557 g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
2558 g_object_unref (addr);
2560 if ((addr = g_socket_get_local_address (sock, NULL))) {
2561 ct->server_port.min =
2562 g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (addr));
2563 g_object_unref (addr);
2565 /* check if the client selected channels for TCP */
2566 if (ct->interleaved.min == -1 || ct->interleaved.max == -1) {
2567 gst_rtsp_session_media_alloc_channels (ctx->sessmedia,
2570 /* alloc new channels if they are already taken */
2571 while (g_hash_table_contains (priv->transports,
2572 GINT_TO_POINTER (ct->interleaved.min))
2573 || g_hash_table_contains (priv->transports,
2574 GINT_TO_POINTER (ct->interleaved.max))) {
2575 gst_rtsp_session_media_alloc_channels (ctx->sessmedia,
2577 if (ct->interleaved.max > 255)
2578 goto error_allocating_channels;
2587 GST_ERROR_OBJECT (client,
2588 "Failed to allocate UDP ports: invalid ttl value");
2591 error_allocating_ports:
2593 GST_ERROR_OBJECT (client, "Failed to allocate UDP ports");
2598 GST_ERROR_OBJECT (client, "Failed to acquire address for stream");
2603 GST_ERROR_OBJECT (client, "Failed to get UDP socket");
2606 error_mcast_transport:
2608 GST_ERROR_OBJECT (client, "Failed to add multicast client transport");
2611 error_allocating_channels:
2613 GST_ERROR_OBJECT (client, "Failed to allocate interleaved channels");
2618 static GstRTSPTransport *
2619 make_server_transport (GstRTSPClient * client, GstRTSPMedia * media,
2620 GstRTSPContext * ctx, GstRTSPTransport * ct)
2622 GstRTSPTransport *st;
2624 GSocketFamily family;
2626 /* prepare the server transport */
2627 gst_rtsp_transport_new (&st);
2629 st->trans = ct->trans;
2630 st->profile = ct->profile;
2631 st->lower_transport = ct->lower_transport;
2632 st->mode_play = ct->mode_play;
2633 st->mode_record = ct->mode_record;
2635 addr = g_inet_address_new_from_string (ct->destination);
2638 GST_ERROR ("failed to get inet addr from client destination");
2639 family = G_SOCKET_FAMILY_IPV4;
2641 family = g_inet_address_get_family (addr);
2642 g_object_unref (addr);
2646 switch (st->lower_transport) {
2647 case GST_RTSP_LOWER_TRANS_UDP:
2648 st->client_port = ct->client_port;
2649 gst_rtsp_stream_get_server_port (ctx->stream, &st->server_port, family);
2651 case GST_RTSP_LOWER_TRANS_UDP_MCAST:
2652 st->port = ct->port;
2653 st->destination = g_strdup (ct->destination);
2656 case GST_RTSP_LOWER_TRANS_TCP:
2657 st->interleaved = ct->interleaved;
2658 st->client_port = ct->client_port;
2659 st->server_port = ct->server_port;
2664 if ((gst_rtsp_media_get_transport_mode (media) &
2665 GST_RTSP_TRANSPORT_MODE_PLAY))
2666 gst_rtsp_stream_get_ssrc (ctx->stream, &st->ssrc);
2672 rtsp_ctrl_timeout_remove_unlocked (GstRTSPClientPrivate * priv)
2674 if (priv->rtsp_ctrl_timeout != NULL) {
2675 GST_DEBUG ("rtsp control session removed timeout %p.",
2676 priv->rtsp_ctrl_timeout);
2677 g_source_destroy (priv->rtsp_ctrl_timeout);
2678 g_source_unref (priv->rtsp_ctrl_timeout);
2679 priv->rtsp_ctrl_timeout = NULL;
2680 priv->rtsp_ctrl_timeout_cnt = 0;
2685 rtsp_ctrl_timeout_remove (GstRTSPClient * client)
2687 g_mutex_lock (&client->priv->lock);
2688 rtsp_ctrl_timeout_remove_unlocked (client->priv);
2689 g_mutex_unlock (&client->priv->lock);
2693 rtsp_ctrl_timeout_destroy_notify (gpointer user_data)
2695 GWeakRef *client_weak_ref = (GWeakRef *) user_data;
2697 g_weak_ref_clear (client_weak_ref);
2698 g_free (client_weak_ref);
2702 rtsp_ctrl_timeout_cb (gpointer user_data)
2704 gboolean res = G_SOURCE_CONTINUE;
2705 GstRTSPClientPrivate *priv;
2706 GWeakRef *client_weak_ref = (GWeakRef *) user_data;
2707 GstRTSPClient *client = (GstRTSPClient *) g_weak_ref_get (client_weak_ref);
2709 if (client == NULL) {
2710 return G_SOURCE_REMOVE;
2713 priv = client->priv;
2714 g_mutex_lock (&priv->lock);
2715 priv->rtsp_ctrl_timeout_cnt += RTSP_CTRL_CB_INTERVAL;
2717 if ((priv->rtsp_ctrl_timeout_cnt > RTSP_CTRL_TIMEOUT_VALUE)
2718 || (priv->had_session
2719 && priv->rtsp_ctrl_timeout_cnt > priv->post_session_timeout)) {
2720 GST_DEBUG ("rtsp control session timeout %p expired, closing client.",
2721 priv->rtsp_ctrl_timeout);
2722 rtsp_ctrl_timeout_remove_unlocked (client->priv);
2724 res = G_SOURCE_REMOVE;
2727 g_mutex_unlock (&priv->lock);
2729 if (res == G_SOURCE_REMOVE) {
2730 gst_rtsp_client_close (client);
2733 g_object_unref (client);
2739 stream_make_keymgmt (GstRTSPClient * client, const gchar * location,
2740 GstRTSPStream * stream)
2742 gchar *base64, *result = NULL;
2743 GstMIKEYMessage *mikey_msg;
2744 GstCaps *srtcpparams;
2745 GstElement *rtcp_encoder;
2746 gint srtcp_cipher, srtp_cipher;
2747 gint srtcp_auth, srtp_auth;
2749 GType ciphertype, authtype;
2750 GEnumClass *cipher_enum, *auth_enum;
2751 GEnumValue *srtcp_cipher_value, *srtp_cipher_value, *srtcp_auth_value,
2754 rtcp_encoder = gst_rtsp_stream_get_srtp_encoder (stream);
2759 ciphertype = g_type_from_name ("GstSrtpCipherType");
2760 authtype = g_type_from_name ("GstSrtpAuthType");
2762 cipher_enum = g_type_class_ref (ciphertype);
2763 auth_enum = g_type_class_ref (authtype);
2765 /* We need to bring the encoder to READY so that it generates its key */
2766 gst_element_set_state (rtcp_encoder, GST_STATE_READY);
2768 g_object_get (rtcp_encoder, "rtcp-cipher", &srtcp_cipher, "rtcp-auth",
2769 &srtcp_auth, "rtp-cipher", &srtp_cipher, "rtp-auth", &srtp_auth, "key",
2771 g_object_unref (rtcp_encoder);
2773 srtcp_cipher_value = g_enum_get_value (cipher_enum, srtcp_cipher);
2774 srtp_cipher_value = g_enum_get_value (cipher_enum, srtp_cipher);
2775 srtcp_auth_value = g_enum_get_value (auth_enum, srtcp_auth);
2776 srtp_auth_value = g_enum_get_value (auth_enum, srtp_auth);
2778 g_type_class_unref (cipher_enum);
2779 g_type_class_unref (auth_enum);
2781 srtcpparams = gst_caps_new_simple ("application/x-srtcp",
2782 "srtcp-cipher", G_TYPE_STRING, srtcp_cipher_value->value_nick,
2783 "srtcp-auth", G_TYPE_STRING, srtcp_auth_value->value_nick,
2784 "srtp-cipher", G_TYPE_STRING, srtp_cipher_value->value_nick,
2785 "srtp-auth", G_TYPE_STRING, srtp_auth_value->value_nick,
2786 "srtp-key", GST_TYPE_BUFFER, key, NULL);
2788 mikey_msg = gst_mikey_message_new_from_caps (srtcpparams);
2792 gst_rtsp_stream_get_ssrc (stream, &send_ssrc);
2793 gst_mikey_message_add_cs_srtp (mikey_msg, 0, send_ssrc, 0);
2795 base64 = gst_mikey_message_base64_encode (mikey_msg);
2796 gst_mikey_message_unref (mikey_msg);
2799 result = gst_sdp_make_keymgmt (location, base64);
2809 handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
2811 GstRTSPClientPrivate *priv = client->priv;
2814 gchar *transport, *keymgmt;
2815 GstRTSPTransport *ct, *st;
2816 GstRTSPStatusCode code;
2817 GstRTSPSession *session;
2818 GstRTSPStreamTransport *trans;
2820 GstRTSPSessionMedia *sessmedia;
2821 GstRTSPMedia *media;
2822 GstRTSPStream *stream;
2823 GstRTSPState rtspstate;
2824 GstRTSPClientClass *klass;
2825 gchar *path, *control = NULL;
2827 gboolean new_session = FALSE;
2828 GstRTSPStatusCode sig_result;
2829 gchar *pipelined_request_id = NULL, *accept_range = NULL;
2835 klass = GST_RTSP_CLIENT_GET_CLASS (client);
2836 path = klass->make_path_from_uri (client, uri);
2838 /* parse the transport */
2840 gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_TRANSPORT,
2842 if (res != GST_RTSP_OK)
2845 /* Handle Pipelined-requests if using >= 2.0 */
2846 if (ctx->request->type_data.request.version >= GST_RTSP_VERSION_2_0)
2847 gst_rtsp_message_get_header (ctx->request,
2848 GST_RTSP_HDR_PIPELINED_REQUESTS, &pipelined_request_id, 0);
2850 /* we create the session after parsing stuff so that we don't make
2851 * a session for malformed requests */
2852 if (priv->session_pool == NULL)
2855 session = ctx->session;
2858 g_object_ref (session);
2859 /* get a handle to the configuration of the media in the session, this can
2860 * return NULL if this is a new url to manage in this session. */
2861 sessmedia = gst_rtsp_session_get_media (session, path, &matched);
2863 /* we need a new media configuration in this session */
2867 /* we have no session media, find one and manage it */
2868 if (sessmedia == NULL) {
2869 /* get a handle to the configuration of the media in the session */
2870 media = find_media (client, ctx, path, &matched);
2871 /* need to suspend the media, if the protocol has changed */
2872 if (media != NULL) {
2873 gst_rtsp_media_lock (media);
2874 gst_rtsp_media_suspend (media);
2877 if ((media = gst_rtsp_session_media_get_media (sessmedia))) {
2878 g_object_ref (media);
2879 gst_rtsp_media_lock (media);
2881 goto media_not_found;
2884 /* no media, not found then */
2886 goto media_not_found_no_reply;
2888 if (path[matched] == '\0') {
2889 if (gst_rtsp_media_n_streams (media) == 1) {
2890 stream = gst_rtsp_media_get_stream (media, 0);
2892 goto control_not_found;
2895 /* path is what matched. */
2896 gchar *newpath = g_strndup (path, matched);
2897 /* control is remainder */
2898 if (matched == 1 && path[0] == '/')
2899 control = g_strdup (&path[1]);
2901 control = g_strdup (&path[matched + 1]);
2906 /* find the stream now using the control part */
2907 stream = gst_rtsp_media_find_stream (media, control);
2911 goto stream_not_found;
2913 /* now we have a uri identifying a valid media and stream */
2914 ctx->stream = stream;
2917 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_SETUP_REQUEST], 0,
2919 if (sig_result != GST_RTSP_STS_OK) {
2923 if (session == NULL) {
2924 /* create a session if this fails we probably reached our session limit or
2926 if (!(session = gst_rtsp_session_pool_create (priv->session_pool)))
2927 goto service_unavailable;
2929 /* Pipelined requests should be cleared between sessions */
2930 g_hash_table_remove_all (priv->pipelined_requests);
2932 /* make sure this client is closed when the session is closed */
2933 client_watch_session (client, session);
2936 /* signal new session */
2937 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_NEW_SESSION], 0,
2940 ctx->session = session;
2943 if (pipelined_request_id) {
2944 g_hash_table_insert (client->priv->pipelined_requests,
2945 g_strdup (pipelined_request_id),
2946 g_strdup (gst_rtsp_session_get_sessionid (session)));
2948 /* Remember that we had at least one session in the past */
2949 priv->had_session = TRUE;
2950 rtsp_ctrl_timeout_remove (client);
2952 if (!klass->configure_client_media (client, media, stream, ctx))
2953 goto configure_media_failed_no_reply;
2955 gst_rtsp_transport_new (&ct);
2957 /* parse and find a usable supported transport */
2958 if (!parse_transport (transport, stream, ct))
2959 goto unsupported_transports;
2962 && !(gst_rtsp_media_get_transport_mode (media) &
2963 GST_RTSP_TRANSPORT_MODE_PLAY)) || (ct->mode_record
2964 && !(gst_rtsp_media_get_transport_mode (media) &
2965 GST_RTSP_TRANSPORT_MODE_RECORD)))
2966 goto unsupported_mode;
2968 /* parse the keymgmt */
2969 if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_KEYMGMT,
2970 &keymgmt, 0) == GST_RTSP_OK) {
2971 if (!gst_rtsp_stream_handle_keymgmt (ctx->stream, keymgmt))
2975 if (gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_ACCEPT_RANGES,
2976 &accept_range, 0) == GST_RTSP_OK) {
2977 GEnumValue *runit = NULL;
2979 gchar **valid_ranges;
2980 GEnumClass *runit_class = g_type_class_ref (GST_TYPE_RTSP_RANGE_UNIT);
2982 gst_rtsp_message_dump (ctx->request);
2983 valid_ranges = g_strsplit (accept_range, ",", -1);
2985 for (i = 0; valid_ranges[i]; i++) {
2986 gchar *range = valid_ranges[i];
2988 while (*range == ' ')
2991 runit = g_enum_get_value_by_nick (runit_class, range);
2995 g_strfreev (valid_ranges);
2996 g_type_class_unref (runit_class);
2999 goto unsupported_range_unit;
3002 if (sessmedia == NULL) {
3003 /* manage the media in our session now, if not done already */
3005 gst_rtsp_session_manage_media (session, path, g_object_ref (media));
3006 /* if we stil have no media, error */
3007 if (sessmedia == NULL)
3008 goto sessmedia_unavailable;
3010 /* don't cache media anymore */
3011 clean_cached_media (client, FALSE);
3014 ctx->sessmedia = sessmedia;
3016 /* update the client transport */
3017 if (!klass->configure_client_transport (client, ctx, ct))
3018 goto unsupported_client_transport;
3020 /* set in the session media transport */
3021 trans = gst_rtsp_session_media_set_transport (sessmedia, stream, ct);
3025 /* configure the url used to set this transport, this we will use when
3026 * generating the response for the PLAY request */
3027 gst_rtsp_stream_transport_set_url (trans, uri);
3028 /* configure keepalive for this transport */
3029 gst_rtsp_stream_transport_set_keepalive (trans,
3030 (GstRTSPKeepAliveFunc) do_keepalive, session, NULL);
3032 if (ct->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
3033 /* our callbacks to send data on this TCP connection */
3034 gst_rtsp_stream_transport_set_callbacks (trans,
3035 (GstRTSPSendFunc) do_send_data,
3036 (GstRTSPSendFunc) do_send_data, client, NULL);
3037 gst_rtsp_stream_transport_set_list_callbacks (trans,
3038 (GstRTSPSendListFunc) do_send_data_list,
3039 (GstRTSPSendListFunc) do_send_data_list, client, NULL);
3041 gst_rtsp_stream_transport_set_back_pressure_callback (trans,
3042 (GstRTSPBackPressureFunc) do_check_back_pressure, client, NULL);
3044 g_hash_table_insert (priv->transports,
3045 GINT_TO_POINTER (ct->interleaved.min), trans);
3046 g_object_ref (trans);
3047 g_hash_table_insert (priv->transports,
3048 GINT_TO_POINTER (ct->interleaved.max), trans);
3049 g_object_ref (trans);
3050 add_data_seq (client, ct->interleaved.min);
3051 add_data_seq (client, ct->interleaved.max);
3054 /* create and serialize the server transport */
3055 st = make_server_transport (client, media, ctx, ct);
3056 trans_str = gst_rtsp_transport_as_text (st);
3058 /* FIXME-WFD : Temporarily force to set profile string */
3059 trans_str = g_strjoinv ("RTP/AVP/UDP", g_strsplit (trans_str, "RTP/AVP", -1));
3061 gst_rtsp_transport_free (st);
3063 /* construct the response now */
3064 code = GST_RTSP_STS_OK;
3065 gst_rtsp_message_init_response (ctx->response, code,
3066 gst_rtsp_status_as_text (code), ctx->request);
3068 gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_TRANSPORT,
3072 if (pipelined_request_id)
3073 gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_PIPELINED_REQUESTS,
3074 pipelined_request_id);
3076 if (ctx->request->type_data.request.version >= GST_RTSP_VERSION_2_0) {
3077 GstClockTimeDiff seekable = gst_rtsp_media_seekable (media);
3078 GString *media_properties = g_string_new (NULL);
3081 g_string_append (media_properties,
3082 "No-Seeking,Time-Progressing,Time-Duration=0.0");
3083 else if (seekable == 0)
3084 g_string_append (media_properties, "Beginning-Only");
3085 else if (seekable == G_MAXINT64)
3086 g_string_append (media_properties, "Random-Access");
3088 g_string_append_printf (media_properties,
3089 "Random-Access=%f, Unlimited, Immutable",
3090 (gdouble) seekable / GST_SECOND);
3092 gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_MEDIA_PROPERTIES,
3093 media_properties->str);
3094 g_string_free (media_properties, TRUE);
3095 /* TODO Check how Accept-Ranges should be filled */
3096 gst_rtsp_message_add_header (ctx->request, GST_RTSP_HDR_ACCEPT_RANGES,
3097 "npt, clock, smpte, clock");
3100 send_message (client, ctx, ctx->response, FALSE);
3102 /* update the state */
3103 rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
3104 switch (rtspstate) {
3105 case GST_RTSP_STATE_PLAYING:
3106 case GST_RTSP_STATE_RECORDING:
3107 case GST_RTSP_STATE_READY:
3108 /* no state change */
3111 gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY);
3115 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST], 0, ctx);
3117 gst_rtsp_media_unlock (media);
3118 g_object_unref (media);
3119 g_object_unref (session);
3128 GST_ERROR ("client %p: no uri", client);
3129 send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
3134 GST_ERROR ("client %p: no transport", client);
3135 send_generic_error_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT,
3141 GST_ERROR ("client %p: no session pool configured", client);
3142 send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
3145 media_not_found_no_reply:
3147 GST_ERROR ("client %p: media '%s' not found", client, path);
3148 /* error reply is already sent */
3149 goto cleanup_session;
3153 GST_ERROR ("client %p: media '%s' not found", client, path);
3154 send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
3155 goto cleanup_session;
3159 GST_ERROR ("client %p: no control in path '%s'", client, path);
3160 send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
3161 gst_rtsp_media_unlock (media);
3162 g_object_unref (media);
3163 goto cleanup_session;
3167 GST_ERROR ("client %p: stream '%s' not found", client,
3168 GST_STR_NULL (control));
3169 send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
3170 gst_rtsp_media_unlock (media);
3171 g_object_unref (media);
3172 goto cleanup_session;
3176 GST_ERROR ("client %p: pre signal returned error: %s", client,
3177 gst_rtsp_status_as_text (sig_result));
3178 send_generic_error_response (client, sig_result, ctx);
3179 gst_rtsp_media_unlock (media);
3180 g_object_unref (media);
3183 service_unavailable:
3185 GST_ERROR ("client %p: can't create session", client);
3186 send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
3187 gst_rtsp_media_unlock (media);
3188 g_object_unref (media);
3189 goto cleanup_session;
3191 sessmedia_unavailable:
3193 GST_ERROR ("client %p: can't create session media", client);
3194 send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
3195 goto cleanup_transport;
3197 configure_media_failed_no_reply:
3199 GST_ERROR ("client %p: configure_media failed", client);
3200 gst_rtsp_media_unlock (media);
3201 g_object_unref (media);
3202 /* error reply is already sent */
3203 goto cleanup_session;
3205 unsupported_transports:
3207 GST_ERROR ("client %p: unsupported transports", client);
3208 send_generic_error_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT,
3210 goto cleanup_transport;
3212 unsupported_client_transport:
3214 GST_ERROR ("client %p: unsupported client transport", client);
3215 send_generic_error_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT,
3217 goto cleanup_transport;
3221 GST_ERROR ("client %p: unsupported mode (media play: %d, media record: %d, "
3222 "mode play: %d, mode record: %d)", client,
3223 ! !(gst_rtsp_media_get_transport_mode (media) &
3224 GST_RTSP_TRANSPORT_MODE_PLAY),
3225 ! !(gst_rtsp_media_get_transport_mode (media) &
3226 GST_RTSP_TRANSPORT_MODE_RECORD), ct->mode_play, ct->mode_record);
3227 send_generic_error_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT,
3229 goto cleanup_transport;
3231 unsupported_range_unit:
3233 GST_ERROR ("Client %p: does not support any range format we support",
3235 send_generic_error_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx);
3236 goto cleanup_transport;
3240 GST_ERROR ("client %p: keymgmt error", client);
3241 send_generic_error_response (client, GST_RTSP_STS_KEY_MANAGEMENT_FAILURE,
3243 goto cleanup_transport;
3247 gst_rtsp_transport_free (ct);
3249 gst_rtsp_media_unlock (media);
3250 g_object_unref (media);
3254 gst_rtsp_session_pool_remove (priv->session_pool, session);
3256 g_object_unref (session);
3264 static GstSDPMessage *
3265 create_sdp (GstRTSPClient * client, GstRTSPMedia * media)
3267 GstRTSPClientPrivate *priv = client->priv;
3271 guint64 session_id_tmp;
3272 gchar session_id[21];
3274 gst_sdp_message_new (&sdp);
3276 /* some standard things first */
3277 gst_sdp_message_set_version (sdp, "0");
3284 session_id_tmp = (((guint64) g_random_int ()) << 32) | g_random_int ();
3285 g_snprintf (session_id, sizeof (session_id), "%" G_GUINT64_FORMAT,
3288 gst_sdp_message_set_origin (sdp, "-", session_id, "1", "IN", proto,
3291 gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer");
3292 gst_sdp_message_set_information (sdp, "rtsp-server");
3293 gst_sdp_message_add_time (sdp, "0", "0", NULL);
3294 gst_sdp_message_add_attribute (sdp, "tool", "GStreamer");
3295 gst_sdp_message_add_attribute (sdp, "type", "broadcast");
3296 gst_sdp_message_add_attribute (sdp, "control", "*");
3298 info.is_ipv6 = priv->is_ipv6;
3299 info.server_ip = priv->server_ip;
3301 /* create an SDP for the media object */
3302 if (!gst_rtsp_media_setup_sdp (media, sdp, &info))
3310 GST_ERROR ("client %p: could not create SDP", client);
3311 gst_sdp_message_free (sdp);
3316 /* for the describe we must generate an SDP */
3318 handle_describe_request (GstRTSPClient * client, GstRTSPContext * ctx)
3320 GstRTSPClientPrivate *priv = client->priv;
3325 GstRTSPMedia *media;
3326 GstRTSPClientClass *klass;
3327 GstRTSPStatusCode sig_result;
3329 klass = GST_RTSP_CLIENT_GET_CLASS (client);
3334 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_DESCRIBE_REQUEST],
3335 0, ctx, &sig_result);
3336 if (sig_result != GST_RTSP_STS_OK) {
3340 /* check what kind of format is accepted, we don't really do anything with it
3341 * and always return SDP for now. */
3346 gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_ACCEPT,
3348 if (res == GST_RTSP_ENOTIMPL)
3351 if (g_ascii_strcasecmp (accept, "application/sdp") == 0)
3355 if (!priv->mount_points)
3356 goto no_mount_points;
3358 if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri)))
3361 /* find the media object for the uri */
3362 if (!(media = find_media (client, ctx, path, NULL)))
3365 gst_rtsp_media_lock (media);
3367 if (!(gst_rtsp_media_get_transport_mode (media) &
3368 GST_RTSP_TRANSPORT_MODE_PLAY))
3369 goto unsupported_mode;
3371 /* create an SDP for the media object on this client */
3372 if (!(sdp = klass->create_sdp (client, media)))
3375 /* we suspend after the describe */
3376 gst_rtsp_media_suspend (media);
3378 gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
3379 gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
3381 gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_CONTENT_TYPE,
3384 /* content base for some clients that might screw up creating the setup uri */
3385 str = make_base_url (client, ctx->uri, path);
3388 GST_INFO ("adding content-base: %s", str);
3389 gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_CONTENT_BASE, str);
3391 /* add SDP to the response body */
3392 str = gst_sdp_message_as_text (sdp);
3393 gst_rtsp_message_take_body (ctx->response, (guint8 *) str, strlen (str));
3394 gst_sdp_message_free (sdp);
3396 send_message (client, ctx, ctx->response, FALSE);
3398 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST],
3401 gst_rtsp_media_unlock (media);
3402 g_object_unref (media);
3409 GST_ERROR ("client %p: pre signal returned error: %s", client,
3410 gst_rtsp_status_as_text (sig_result));
3411 send_generic_error_response (client, sig_result, ctx);
3416 GST_ERROR ("client %p: no uri", client);
3417 send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
3422 GST_ERROR ("client %p: no mount points configured", client);
3423 send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
3428 GST_ERROR ("client %p: can't find path for url", client);
3429 send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
3434 GST_ERROR ("client %p: no media", client);
3436 /* error reply is already sent */
3441 GST_ERROR ("client %p: media does not support DESCRIBE", client);
3442 send_generic_error_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
3444 gst_rtsp_media_unlock (media);
3445 g_object_unref (media);
3450 GST_ERROR ("client %p: can't create SDP", client);
3451 send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
3453 gst_rtsp_media_unlock (media);
3454 g_object_unref (media);
3460 handle_sdp (GstRTSPClient * client, GstRTSPContext * ctx, GstRTSPMedia * media,
3461 GstSDPMessage * sdp)
3463 GstRTSPClientPrivate *priv = client->priv;
3464 GstRTSPThread *thread;
3466 /* create an SDP for the media object */
3467 if (!gst_rtsp_media_handle_sdp (media, sdp))
3470 thread = gst_rtsp_thread_pool_get_thread (priv->thread_pool,
3471 GST_RTSP_THREAD_TYPE_MEDIA, ctx);
3475 /* prepare the media */
3476 if (!gst_rtsp_media_prepare (media, thread))
3484 GST_ERROR ("client %p: could not handle SDP", client);
3489 GST_ERROR ("client %p: can't create thread", client);
3494 GST_ERROR ("client %p: can't prepare media", client);
3500 handle_announce_request (GstRTSPClient * client, GstRTSPContext * ctx)
3502 GstRTSPClientPrivate *priv = client->priv;
3503 GstRTSPClientClass *klass;
3506 GstRTSPMedia *media;
3507 gchar *path, *cont = NULL;
3510 GstRTSPStatusCode sig_result;
3513 klass = GST_RTSP_CLIENT_GET_CLASS (client);
3518 if (!priv->mount_points)
3519 goto no_mount_points;
3521 /* check if reply is SDP */
3522 gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_CONTENT_TYPE, &cont,
3524 /* could not be set but since the request returned OK, we assume it
3525 * was SDP, else check it. */
3527 if (g_ascii_strcasecmp (cont, "application/sdp") != 0)
3528 goto wrong_content_type;
3531 /* get message body and parse as SDP */
3532 gst_rtsp_message_get_body (ctx->request, &data, &size);
3533 if (data == NULL || size == 0)
3536 GST_DEBUG ("client %p: parse SDP...", client);
3537 gst_sdp_message_new (&sdp);
3538 sres = gst_sdp_message_parse_buffer (data, size, sdp);
3539 if (sres != GST_SDP_OK)
3540 goto sdp_parse_failed;
3542 if (!(path = gst_rtsp_mount_points_make_path (priv->mount_points, ctx->uri)))
3545 /* find the media object for the uri */
3546 if (!(media = find_media (client, ctx, path, NULL)))
3550 gst_rtsp_media_lock (media);
3552 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_ANNOUNCE_REQUEST],
3553 0, ctx, &sig_result);
3554 if (sig_result != GST_RTSP_STS_OK) {
3558 if (!(gst_rtsp_media_get_transport_mode (media) &
3559 GST_RTSP_TRANSPORT_MODE_RECORD))
3560 goto unsupported_mode;
3562 /* Tell client subclass about the media */
3563 if (!klass->handle_sdp (client, ctx, media, sdp))
3566 gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
3567 gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
3569 n_streams = gst_rtsp_media_n_streams (media);
3570 for (i = 0; i < n_streams; i++) {
3571 GstRTSPStream *stream = gst_rtsp_media_get_stream (media, i);
3572 gchar *uri, *location, *keymgmt;
3574 uri = gst_rtsp_url_get_request_uri (ctx->uri);
3575 location = g_strdup_printf ("%s/stream=%d", uri, i);
3576 keymgmt = stream_make_keymgmt (client, location, stream);
3579 gst_rtsp_message_take_header (ctx->response, GST_RTSP_HDR_KEYMGMT,
3586 /* we suspend after the announce */
3587 gst_rtsp_media_suspend (media);
3589 send_message (client, ctx, ctx->response, FALSE);
3591 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_ANNOUNCE_REQUEST],
3594 gst_sdp_message_free (sdp);
3596 gst_rtsp_media_unlock (media);
3597 g_object_unref (media);
3603 GST_ERROR ("client %p: no uri", client);
3604 send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
3609 GST_ERROR ("client %p: no mount points configured", client);
3610 send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
3615 GST_ERROR ("client %p: can't find path for url", client);
3616 send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
3617 gst_sdp_message_free (sdp);
3622 GST_ERROR ("client %p: unknown content type", client);
3623 send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
3628 GST_ERROR ("client %p: can't find SDP message", client);
3629 send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
3634 GST_ERROR ("client %p: failed to parse SDP message", client);
3635 send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
3636 gst_sdp_message_free (sdp);
3641 GST_ERROR ("client %p: no media", client);
3643 /* error reply is already sent */
3644 gst_sdp_message_free (sdp);
3649 GST_ERROR ("client %p: pre signal returned error: %s", client,
3650 gst_rtsp_status_as_text (sig_result));
3651 send_generic_error_response (client, sig_result, ctx);
3652 gst_sdp_message_free (sdp);
3653 gst_rtsp_media_unlock (media);
3654 g_object_unref (media);
3659 GST_ERROR ("client %p: media does not support ANNOUNCE", client);
3660 send_generic_error_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
3662 gst_rtsp_media_unlock (media);
3663 g_object_unref (media);
3664 gst_sdp_message_free (sdp);
3669 GST_ERROR ("client %p: can't handle SDP", client);
3670 send_generic_error_response (client, GST_RTSP_STS_UNSUPPORTED_MEDIA_TYPE,
3673 gst_rtsp_media_unlock (media);
3674 g_object_unref (media);
3675 gst_sdp_message_free (sdp);
3681 handle_record_request (GstRTSPClient * client, GstRTSPContext * ctx)
3683 GstRTSPSession *session;
3684 GstRTSPClientClass *klass;
3685 GstRTSPSessionMedia *sessmedia;
3686 GstRTSPMedia *media;
3688 GstRTSPState rtspstate;
3691 GstRTSPStatusCode sig_result;
3692 GPtrArray *transports;
3694 if (!(session = ctx->session))
3697 if (!(uri = ctx->uri))
3700 klass = GST_RTSP_CLIENT_GET_CLASS (client);
3701 path = klass->make_path_from_uri (client, uri);
3703 /* get a handle to the configuration of the media in the session */
3704 sessmedia = gst_rtsp_session_get_media (session, path, &matched);
3708 if (path[matched] != '\0')
3713 ctx->sessmedia = sessmedia;
3714 ctx->media = media = gst_rtsp_session_media_get_media (sessmedia);
3716 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_RECORD_REQUEST], 0,
3718 if (sig_result != GST_RTSP_STS_OK) {
3722 if (!(gst_rtsp_media_get_transport_mode (media) &
3723 GST_RTSP_TRANSPORT_MODE_RECORD))
3724 goto unsupported_mode;
3726 /* the session state must be playing or ready */
3727 rtspstate = gst_rtsp_session_media_get_rtsp_state (sessmedia);
3728 if (rtspstate != GST_RTSP_STATE_PLAYING && rtspstate != GST_RTSP_STATE_READY)
3731 /* update the pipeline */
3732 transports = gst_rtsp_session_media_get_transports (sessmedia);
3733 if (!gst_rtsp_media_complete_pipeline (media, transports)) {
3734 g_ptr_array_unref (transports);
3735 goto pipeline_error;
3737 g_ptr_array_unref (transports);
3739 /* in record we first unsuspend, media could be suspended from SDP or PAUSED */
3740 if (!gst_rtsp_media_unsuspend (media))
3741 goto unsuspend_failed;
3743 gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
3744 gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
3746 send_message (client, ctx, ctx->response, FALSE);
3748 /* start playing after sending the response */
3749 gst_rtsp_session_media_set_state (sessmedia, GST_STATE_PLAYING);
3751 gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_PLAYING);
3753 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_RECORD_REQUEST], 0,
3761 GST_ERROR ("client %p: no session", client);
3762 send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
3767 GST_ERROR ("client %p: no uri supplied", client);
3768 send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
3773 GST_ERROR ("client %p: media not found", client);
3774 send_generic_error_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
3779 GST_ERROR ("client %p: no aggregate path %s", client, path);
3780 send_generic_error_response (client,
3781 GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED, ctx);
3787 GST_ERROR ("client %p: pre signal returned error: %s", client,
3788 gst_rtsp_status_as_text (sig_result));
3789 send_generic_error_response (client, sig_result, ctx);
3794 GST_ERROR ("client %p: media does not support RECORD", client);
3795 send_generic_error_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
3800 GST_ERROR ("client %p: not PLAYING or READY", client);
3801 send_generic_error_response (client,
3802 GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx);
3807 GST_ERROR ("client %p: failed to configure the pipeline", client);
3808 send_generic_error_response (client,
3809 GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, ctx);
3814 GST_ERROR ("client %p: unsuspend failed", client);
3815 send_generic_error_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
3821 default_handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx,
3822 GstRTSPVersion version)
3824 GstRTSPMethod options;
3826 GstRTSPStatusCode sig_result;
3828 options = GST_RTSP_DESCRIBE |
3833 GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
3835 if (version < GST_RTSP_VERSION_2_0) {
3836 options |= GST_RTSP_RECORD;
3837 options |= GST_RTSP_ANNOUNCE;
3840 str = gst_rtsp_options_as_text (options);
3842 gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
3843 gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
3845 gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_PUBLIC, str);
3848 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_OPTIONS_REQUEST], 0,
3850 if (sig_result != GST_RTSP_STS_OK) {
3854 send_message (client, ctx, ctx->response, FALSE);
3856 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_OPTIONS_REQUEST],
3864 GST_ERROR ("client %p: pre signal returned error: %s", client,
3865 gst_rtsp_status_as_text (sig_result));
3866 send_generic_error_response (client, sig_result, ctx);
3867 gst_rtsp_message_free (ctx->response);
3872 /* remove duplicate and trailing '/' */
3874 sanitize_uri (GstRTSPUrl * uri)
3878 gboolean have_slash, prev_slash;
3880 s = d = uri->abspath;
3881 len = strlen (uri->abspath);
3885 for (i = 0; i < len; i++) {
3886 have_slash = s[i] == '/';
3888 if (!have_slash || !prev_slash)
3890 prev_slash = have_slash;
3892 len = d - uri->abspath;
3893 /* don't remove the first slash if that's the only thing left */
3894 if (len > 1 && *(d - 1) == '/')
3899 /* is called when the session is removed from its session pool. */
3901 client_session_removed (GstRTSPSessionPool * pool, GstRTSPSession * session,
3902 GstRTSPClient * client)
3904 GstRTSPClientPrivate *priv = client->priv;
3907 GST_INFO ("client %p: session %p removed", client, session);
3909 g_mutex_lock (&priv->lock);
3910 client_unwatch_session (client, session, NULL);
3912 if (!priv->sessions && priv->rtsp_ctrl_timeout == NULL) {
3913 if (priv->post_session_timeout > 0) {
3914 GWeakRef *client_weak_ref = g_new (GWeakRef, 1);
3915 timer_src = g_timeout_source_new_seconds (RTSP_CTRL_CB_INTERVAL);
3917 g_weak_ref_init (client_weak_ref, client);
3918 g_source_set_callback (timer_src, rtsp_ctrl_timeout_cb, client_weak_ref,
3919 rtsp_ctrl_timeout_destroy_notify);
3920 priv->rtsp_ctrl_timeout_cnt = 0;
3921 g_source_attach (timer_src, priv->watch_context);
3922 priv->rtsp_ctrl_timeout = timer_src;
3923 GST_DEBUG ("rtsp control setting up connection timeout %p.",
3924 priv->rtsp_ctrl_timeout);
3925 g_mutex_unlock (&priv->lock);
3926 } else if (priv->post_session_timeout == 0) {
3927 g_mutex_unlock (&priv->lock);
3928 gst_rtsp_client_close (client);
3930 g_mutex_unlock (&priv->lock);
3933 g_mutex_unlock (&priv->lock);
3937 /* Check for Require headers. Returns TRUE if there are no Require headers,
3938 * otherwise lets the application decide which headers are supported.
3939 * By default all headers are unsupported.
3940 * If there are unsupported options, FALSE will be returned together with
3941 * a newly-allocated string of (comma-separated) unsupported options in
3942 * the unsupported_reqs variable.
3944 * There may be multiple Require headers, but we must send one single
3945 * Unsupported header with all the unsupported options as response. If
3946 * an incoming Require header contained a comma-separated list of options
3947 * GstRtspConnection will already have split that list up into multiple
3951 check_request_requirements (GstRTSPContext * ctx, gchar ** unsupported_reqs)
3954 GPtrArray *arr = NULL;
3955 GstRTSPMessage *msg = ctx->request;
3958 gchar *sig_result = NULL;
3959 gboolean result = TRUE;
3963 res = gst_rtsp_message_get_header (msg, GST_RTSP_HDR_REQUIRE, &reqs, i++);
3965 if (res == GST_RTSP_ENOTIMPL)
3969 arr = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free);
3971 g_ptr_array_add (arr, g_strdup (reqs));
3975 /* if we don't have any Require headers at all, all is fine */
3979 /* otherwise we've now processed at all the Require headers */
3980 g_ptr_array_add (arr, NULL);
3982 g_signal_emit (ctx->client,
3983 gst_rtsp_client_signals[SIGNAL_CHECK_REQUIREMENTS], 0, ctx,
3984 (gchar **) arr->pdata, &sig_result);
3986 if (sig_result == NULL) {
3987 /* no supported options, just report all of the required ones as
3989 *unsupported_reqs = g_strjoinv (", ", (gchar **) arr->pdata);
3994 if (strlen (sig_result) == 0)
3995 g_free (sig_result);
3997 *unsupported_reqs = sig_result;
4002 g_ptr_array_unref (arr);
4007 handle_request (GstRTSPClient * client, GstRTSPMessage * request)
4009 GstRTSPClientPrivate *priv = client->priv;
4010 GstRTSPMethod method;
4011 const gchar *uristr;
4012 GstRTSPUrl *uri = NULL;
4013 GstRTSPVersion version;
4015 GstRTSPSession *session = NULL;
4016 GstRTSPContext sctx = { NULL }, *ctx;
4017 GstRTSPMessage response = { 0 };
4018 gchar *unsupported_reqs = NULL;
4019 gchar *sessid = NULL, *pipelined_request_id = NULL;
4020 GstRTSPClientClass *klass;
4022 klass = GST_RTSP_CLIENT_GET_CLASS (client);
4023 if (!(ctx = gst_rtsp_context_get_current ())) {
4025 ctx->auth = priv->auth;
4026 gst_rtsp_context_push_current (ctx);
4029 ctx->conn = priv->connection;
4030 ctx->client = client;
4031 ctx->request = request;
4032 ctx->response = &response;
4034 if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
4035 gst_rtsp_message_dump (request);
4038 gst_rtsp_message_parse_request (request, &method, &uristr, &version);
4040 GST_INFO ("client %p: received a request %s %s %s", client,
4041 gst_rtsp_method_as_text (method), uristr,
4042 gst_rtsp_version_as_text (version));
4044 /* we can only handle 1.0 requests */
4045 if (version != GST_RTSP_VERSION_1_0 && version != GST_RTSP_VERSION_2_0)
4048 ctx->method = method;
4050 /* we always try to parse the url first */
4051 if (strcmp (uristr, "*") == 0) {
4052 /* special case where we have * as uri, keep uri = NULL */
4053 } else if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) {
4054 /* check if the uristr is an absolute path <=> scheme and host information
4058 scheme = g_uri_parse_scheme (uristr);
4059 if (scheme == NULL && g_str_has_prefix (uristr, "/")) {
4060 gchar *absolute_uristr = NULL;
4062 GST_WARNING_OBJECT (client, "request doesn't contain absolute url");
4063 if (priv->server_ip == NULL) {
4064 GST_WARNING_OBJECT (client, "host information missing");
4069 g_strdup_printf ("rtsp://%s%s", priv->server_ip, uristr);
4071 GST_DEBUG_OBJECT (client, "absolute url: %s", absolute_uristr);
4072 if (gst_rtsp_url_parse (absolute_uristr, &uri) != GST_RTSP_OK) {
4073 g_free (absolute_uristr);
4076 g_free (absolute_uristr);
4083 /* get the session if there is any */
4084 res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_PIPELINED_REQUESTS,
4085 &pipelined_request_id, 0);
4086 if (res == GST_RTSP_OK) {
4087 sessid = g_hash_table_lookup (client->priv->pipelined_requests,
4088 pipelined_request_id);
4091 res = GST_RTSP_ERROR;
4094 if (res != GST_RTSP_OK)
4096 gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
4098 if (res == GST_RTSP_OK) {
4099 if (priv->session_pool == NULL)
4102 /* we had a session in the request, find it again */
4103 if (!(session = gst_rtsp_session_pool_find (priv->session_pool, sessid)))
4104 goto session_not_found;
4106 /* we add the session to the client list of watched sessions. When a session
4107 * disappears because it times out, we will be notified. If all sessions are
4108 * gone, we will close the connection */
4109 client_watch_session (client, session);
4112 /* sanitize the uri */
4116 ctx->session = session;
4118 if (!gst_rtsp_auth_check (GST_RTSP_AUTH_CHECK_URL))
4119 goto not_authorized;
4121 /* handle any 'Require' headers */
4122 if (!check_request_requirements (ctx, &unsupported_reqs))
4123 goto unsupported_requirement;
4125 /* now see what is asked and dispatch to a dedicated handler */
4127 case GST_RTSP_OPTIONS:
4128 priv->version = version;
4129 klass->handle_options_request (client, ctx, version);
4131 case GST_RTSP_DESCRIBE:
4132 handle_describe_request (client, ctx);
4134 case GST_RTSP_SETUP:
4135 handle_setup_request (client, ctx);
4138 klass->handle_play_request (client, ctx);
4140 case GST_RTSP_PAUSE:
4141 handle_pause_request (client, ctx);
4143 case GST_RTSP_TEARDOWN:
4144 handle_teardown_request (client, ctx);
4146 case GST_RTSP_SET_PARAMETER:
4147 klass->handle_set_param_request (client, ctx);
4149 case GST_RTSP_GET_PARAMETER:
4150 klass->handle_get_param_request (client, ctx);
4152 case GST_RTSP_ANNOUNCE:
4153 if (version >= GST_RTSP_VERSION_2_0)
4154 goto invalid_command_for_version;
4155 handle_announce_request (client, ctx);
4157 case GST_RTSP_RECORD:
4158 if (version >= GST_RTSP_VERSION_2_0)
4159 goto invalid_command_for_version;
4160 handle_record_request (client, ctx);
4162 case GST_RTSP_REDIRECT:
4163 goto not_implemented;
4164 case GST_RTSP_INVALID:
4171 gst_rtsp_context_pop_current (ctx);
4173 g_object_unref (session);
4175 gst_rtsp_url_free (uri);
4181 GST_ERROR ("client %p: version %d not supported", client, version);
4182 send_generic_error_response (client,
4183 GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED, ctx);
4186 invalid_command_for_version:
4188 GST_ERROR ("client %p: invalid command for version", client);
4189 send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
4194 GST_ERROR ("client %p: bad request", client);
4195 send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
4200 GST_ERROR ("client %p: no pool configured", client);
4201 send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
4206 GST_ERROR ("client %p: session not found", client);
4207 send_generic_error_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, ctx);
4212 GST_ERROR ("client %p: not allowed", client);
4213 /* error reply is already sent */
4216 unsupported_requirement:
4218 GST_ERROR ("client %p: Required option is not supported (%s)", client,
4220 send_option_not_supported_response (client, ctx, unsupported_reqs);
4221 g_free (unsupported_reqs);
4226 GST_ERROR ("client %p: method %d not implemented", client, method);
4227 send_generic_error_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, ctx);
4234 handle_response (GstRTSPClient * client, GstRTSPMessage * response)
4236 GstRTSPClientPrivate *priv = client->priv;
4238 GstRTSPSession *session = NULL;
4239 GstRTSPContext sctx = { NULL }, *ctx;
4242 if (!(ctx = gst_rtsp_context_get_current ())) {
4244 ctx->auth = priv->auth;
4245 gst_rtsp_context_push_current (ctx);
4248 ctx->conn = priv->connection;
4249 ctx->client = client;
4250 ctx->request = NULL;
4252 ctx->method = GST_RTSP_INVALID;
4253 ctx->response = response;
4255 if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
4256 gst_rtsp_message_dump (response);
4259 GST_INFO ("client %p: received a response", client);
4261 /* get the session if there is any */
4263 gst_rtsp_message_get_header (response, GST_RTSP_HDR_SESSION, &sessid, 0);
4264 if (res == GST_RTSP_OK) {
4265 if (priv->session_pool == NULL)
4268 /* we had a session in the request, find it again */
4269 if (!(session = gst_rtsp_session_pool_find (priv->session_pool, sessid)))
4270 goto session_not_found;
4272 /* we add the session to the client list of watched sessions. When a session
4273 * disappears because it times out, we will be notified. If all sessions are
4274 * gone, we will close the connection */
4275 client_watch_session (client, session);
4278 ctx->session = session;
4280 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_HANDLE_RESPONSE],
4285 gst_rtsp_context_pop_current (ctx);
4287 g_object_unref (session);
4292 GST_ERROR ("client %p: no pool configured", client);
4297 GST_ERROR ("client %p: session not found", client);
4303 handle_data (GstRTSPClient * client, GstRTSPMessage * message)
4305 GstRTSPClientPrivate *priv = client->priv;
4311 GstRTSPStreamTransport *trans;
4313 /* find the stream for this message */
4314 res = gst_rtsp_message_parse_data (message, &channel);
4315 if (res != GST_RTSP_OK)
4318 gst_rtsp_message_get_body (message, &data, &size);
4320 goto invalid_length;
4322 gst_rtsp_message_steal_body (message, &data, &size);
4324 /* Strip trailing \0 (which GstRTSPConnection adds) */
4327 buffer = gst_buffer_new_wrapped (data, size);
4330 g_hash_table_lookup (priv->transports, GINT_TO_POINTER ((gint) channel));
4332 GSocketAddress *addr;
4334 /* Only create the socket address once for the transport, we don't really
4335 * want to do that for every single packet.
4337 * The netaddress meta is later used by the RTP stack to know where
4338 * packets came from and allows us to match it again to a stream transport
4340 * In theory we could use the remote socket address of the RTSP connection
4341 * here, but this would fail with a custom configure_client_transport()
4345 g_object_get_data (G_OBJECT (trans), "rtsp-client.remote-addr"))) {
4346 const GstRTSPTransport *tr;
4347 GInetAddress *iaddr;
4349 tr = gst_rtsp_stream_transport_get_transport (trans);
4350 iaddr = g_inet_address_new_from_string (tr->destination);
4352 addr = g_inet_socket_address_new (iaddr, tr->client_port.min);
4353 g_object_unref (iaddr);
4354 g_object_set_data_full (G_OBJECT (trans), "rtsp-client.remote-addr",
4355 addr, (GDestroyNotify) g_object_unref);
4360 gst_buffer_add_net_address_meta (buffer, addr);
4363 /* dispatch to the stream based on the channel number */
4364 GST_LOG_OBJECT (client, "%u bytes of data on channel %u", size, channel);
4365 gst_rtsp_stream_transport_recv_data (trans, channel, buffer);
4367 GST_DEBUG_OBJECT (client, "received %u bytes of data for "
4368 "unknown channel %u", size, channel);
4369 gst_buffer_unref (buffer);
4377 GST_DEBUG ("client %p: Short message received, ignoring", client);
4383 * gst_rtsp_client_set_session_pool:
4384 * @client: a #GstRTSPClient
4385 * @pool: (transfer none) (nullable): a #GstRTSPSessionPool
4387 * Set @pool as the sessionpool for @client which it will use to find
4388 * or allocate sessions. the sessionpool is usually inherited from the server
4389 * that created the client but can be overridden later.
4392 gst_rtsp_client_set_session_pool (GstRTSPClient * client,
4393 GstRTSPSessionPool * pool)
4395 GstRTSPSessionPool *old;
4396 GstRTSPClientPrivate *priv;
4398 g_return_if_fail (GST_IS_RTSP_CLIENT (client));
4400 priv = client->priv;
4403 g_object_ref (pool);
4405 g_mutex_lock (&priv->lock);
4406 old = priv->session_pool;
4407 priv->session_pool = pool;
4409 if (priv->session_removed_id) {
4410 g_signal_handler_disconnect (old, priv->session_removed_id);
4411 priv->session_removed_id = 0;
4413 g_mutex_unlock (&priv->lock);
4415 /* FIXME, should remove all sessions from the old pool for this client */
4417 g_object_unref (old);
4421 * gst_rtsp_client_get_session_pool:
4422 * @client: a #GstRTSPClient
4424 * Get the #GstRTSPSessionPool object that @client uses to manage its sessions.
4426 * Returns: (transfer full) (nullable): a #GstRTSPSessionPool, unref after usage.
4428 GstRTSPSessionPool *
4429 gst_rtsp_client_get_session_pool (GstRTSPClient * client)
4431 GstRTSPClientPrivate *priv;
4432 GstRTSPSessionPool *result;
4434 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
4436 priv = client->priv;
4438 g_mutex_lock (&priv->lock);
4439 if ((result = priv->session_pool))
4440 g_object_ref (result);
4441 g_mutex_unlock (&priv->lock);
4447 * gst_rtsp_client_set_mount_points:
4448 * @client: a #GstRTSPClient
4449 * @mounts: (transfer none) (nullable): a #GstRTSPMountPoints
4451 * Set @mounts as the mount points for @client which it will use to map urls
4452 * to media streams. These mount points are usually inherited from the server that
4453 * created the client but can be overriden later.
4456 gst_rtsp_client_set_mount_points (GstRTSPClient * client,
4457 GstRTSPMountPoints * mounts)
4459 GstRTSPClientPrivate *priv;
4460 GstRTSPMountPoints *old;
4462 g_return_if_fail (GST_IS_RTSP_CLIENT (client));
4464 priv = client->priv;
4467 g_object_ref (mounts);
4469 g_mutex_lock (&priv->lock);
4470 old = priv->mount_points;
4471 priv->mount_points = mounts;
4472 g_mutex_unlock (&priv->lock);
4475 g_object_unref (old);
4479 * gst_rtsp_client_get_mount_points:
4480 * @client: a #GstRTSPClient
4482 * Get the #GstRTSPMountPoints object that @client uses to manage its sessions.
4484 * Returns: (transfer full) (nullable): a #GstRTSPMountPoints, unref after usage.
4486 GstRTSPMountPoints *
4487 gst_rtsp_client_get_mount_points (GstRTSPClient * client)
4489 GstRTSPClientPrivate *priv;
4490 GstRTSPMountPoints *result;
4492 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
4494 priv = client->priv;
4496 g_mutex_lock (&priv->lock);
4497 if ((result = priv->mount_points))
4498 g_object_ref (result);
4499 g_mutex_unlock (&priv->lock);
4505 * gst_rtsp_client_set_content_length_limit:
4506 * @client: a #GstRTSPClient
4507 * @limit: Content-Length limit
4509 * Configure @client to use the specified Content-Length limit.
4511 * Define an appropriate request size limit and reject requests exceeding the
4512 * limit with response status 413 Request Entity Too Large
4517 gst_rtsp_client_set_content_length_limit (GstRTSPClient * client, guint limit)
4519 GstRTSPClientPrivate *priv;
4521 g_return_if_fail (GST_IS_RTSP_CLIENT (client));
4523 priv = client->priv;
4524 g_mutex_lock (&priv->lock);
4525 priv->content_length_limit = limit;
4526 g_mutex_unlock (&priv->lock);
4530 * gst_rtsp_client_get_content_length_limit:
4531 * @client: a #GstRTSPClient
4533 * Get the Content-Length limit of @client.
4535 * Returns: the Content-Length limit.
4540 gst_rtsp_client_get_content_length_limit (GstRTSPClient * client)
4542 GstRTSPClientPrivate *priv;
4543 glong content_length_limit;
4545 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), -1);
4546 priv = client->priv;
4548 g_mutex_lock (&priv->lock);
4549 content_length_limit = priv->content_length_limit;
4550 g_mutex_unlock (&priv->lock);
4552 return content_length_limit;
4556 * gst_rtsp_client_set_auth:
4557 * @client: a #GstRTSPClient
4558 * @auth: (transfer none) (nullable): a #GstRTSPAuth
4560 * configure @auth to be used as the authentication manager of @client.
4563 gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth)
4565 GstRTSPClientPrivate *priv;
4568 g_return_if_fail (GST_IS_RTSP_CLIENT (client));
4570 priv = client->priv;
4573 g_object_ref (auth);
4575 g_mutex_lock (&priv->lock);
4578 g_mutex_unlock (&priv->lock);
4581 g_object_unref (old);
4586 * gst_rtsp_client_get_auth:
4587 * @client: a #GstRTSPClient
4589 * Get the #GstRTSPAuth used as the authentication manager of @client.
4591 * Returns: (transfer full) (nullable): the #GstRTSPAuth of @client.
4592 * g_object_unref() after usage.
4595 gst_rtsp_client_get_auth (GstRTSPClient * client)
4597 GstRTSPClientPrivate *priv;
4598 GstRTSPAuth *result;
4600 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
4602 priv = client->priv;
4604 g_mutex_lock (&priv->lock);
4605 if ((result = priv->auth))
4606 g_object_ref (result);
4607 g_mutex_unlock (&priv->lock);
4613 * gst_rtsp_client_set_thread_pool:
4614 * @client: a #GstRTSPClient
4615 * @pool: (transfer none) (nullable): a #GstRTSPThreadPool
4617 * configure @pool to be used as the thread pool of @client.
4620 gst_rtsp_client_set_thread_pool (GstRTSPClient * client,
4621 GstRTSPThreadPool * pool)
4623 GstRTSPClientPrivate *priv;
4624 GstRTSPThreadPool *old;
4626 g_return_if_fail (GST_IS_RTSP_CLIENT (client));
4628 priv = client->priv;
4631 g_object_ref (pool);
4633 g_mutex_lock (&priv->lock);
4634 old = priv->thread_pool;
4635 priv->thread_pool = pool;
4636 g_mutex_unlock (&priv->lock);
4639 g_object_unref (old);
4643 * gst_rtsp_client_get_thread_pool:
4644 * @client: a #GstRTSPClient
4646 * Get the #GstRTSPThreadPool used as the thread pool of @client.
4648 * Returns: (transfer full) (nullable): the #GstRTSPThreadPool of @client. g_object_unref() after
4652 gst_rtsp_client_get_thread_pool (GstRTSPClient * client)
4654 GstRTSPClientPrivate *priv;
4655 GstRTSPThreadPool *result;
4657 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
4659 priv = client->priv;
4661 g_mutex_lock (&priv->lock);
4662 if ((result = priv->thread_pool))
4663 g_object_ref (result);
4664 g_mutex_unlock (&priv->lock);
4670 * gst_rtsp_client_set_connection:
4671 * @client: a #GstRTSPClient
4672 * @conn: (transfer full): a #GstRTSPConnection
4674 * Set the #GstRTSPConnection of @client. This function takes ownership of
4677 * Returns: %TRUE on success.
4680 gst_rtsp_client_set_connection (GstRTSPClient * client,
4681 GstRTSPConnection * conn)
4683 GstRTSPClientPrivate *priv;
4684 GSocket *read_socket;
4685 GSocketAddress *address;
4687 GError *error = NULL;
4689 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), FALSE);
4690 g_return_val_if_fail (conn != NULL, FALSE);
4692 priv = client->priv;
4694 gst_rtsp_connection_set_content_length_limit (conn,
4695 priv->content_length_limit);
4696 read_socket = gst_rtsp_connection_get_read_socket (conn);
4698 if (!(address = g_socket_get_local_address (read_socket, &error)))
4701 g_free (priv->server_ip);
4702 /* keep the original ip that the client connected to */
4703 if (G_IS_INET_SOCKET_ADDRESS (address)) {
4704 GInetAddress *iaddr;
4706 iaddr = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address));
4708 /* socket might be ipv6 but adress still ipv4 */
4709 priv->is_ipv6 = g_inet_address_get_family (iaddr) == G_SOCKET_FAMILY_IPV6;
4710 priv->server_ip = g_inet_address_to_string (iaddr);
4711 g_object_unref (address);
4713 priv->is_ipv6 = g_socket_get_family (read_socket) == G_SOCKET_FAMILY_IPV6;
4714 priv->server_ip = g_strdup ("unknown");
4715 g_object_unref (address);
4718 GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client,
4719 priv->server_ip, priv->is_ipv6);
4721 url = gst_rtsp_connection_get_url (conn);
4722 GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port);
4724 priv->connection = conn;
4731 GST_ERROR ("could not get local address %s", error->message);
4732 g_error_free (error);
4738 * gst_rtsp_client_get_connection:
4739 * @client: a #GstRTSPClient
4741 * Get the #GstRTSPConnection of @client.
4743 * Returns: (transfer none) (nullable): the #GstRTSPConnection of @client.
4744 * The connection object returned remains valid until the client is freed.
4747 gst_rtsp_client_get_connection (GstRTSPClient * client)
4749 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
4751 return client->priv->connection;
4755 * gst_rtsp_client_set_send_func:
4756 * @client: a #GstRTSPClient
4757 * @func: (scope notified): a #GstRTSPClientSendFunc
4758 * @user_data: (closure): user data passed to @func
4759 * @notify: (allow-none): called when @user_data is no longer in use
4761 * Set @func as the callback that will be called when a new message needs to be
4762 * sent to the client. @user_data is passed to @func and @notify is called when
4763 * @user_data is no longer in use.
4765 * By default, the client will send the messages on the #GstRTSPConnection that
4766 * was configured with gst_rtsp_client_attach() was called.
4768 * It is only allowed to set either a `send_func` or a `send_messages_func`
4769 * but not both at the same time.
4772 gst_rtsp_client_set_send_func (GstRTSPClient * client,
4773 GstRTSPClientSendFunc func, gpointer user_data, GDestroyNotify notify)
4775 GstRTSPClientPrivate *priv;
4776 GDestroyNotify old_notify;
4779 g_return_if_fail (GST_IS_RTSP_CLIENT (client));
4781 priv = client->priv;
4783 g_mutex_lock (&priv->send_lock);
4784 g_assert (func == NULL || priv->send_messages_func == NULL);
4785 priv->send_func = func;
4786 old_notify = priv->send_notify;
4787 old_data = priv->send_data;
4788 priv->send_notify = notify;
4789 priv->send_data = user_data;
4790 g_mutex_unlock (&priv->send_lock);
4793 old_notify (old_data);
4797 * gst_rtsp_client_set_send_messages_func:
4798 * @client: a #GstRTSPClient
4799 * @func: (scope notified): a #GstRTSPClientSendMessagesFunc
4800 * @user_data: (closure): user data passed to @func
4801 * @notify: (allow-none): called when @user_data is no longer in use
4803 * Set @func as the callback that will be called when new messages needs to be
4804 * sent to the client. @user_data is passed to @func and @notify is called when
4805 * @user_data is no longer in use.
4807 * By default, the client will send the messages on the #GstRTSPConnection that
4808 * was configured with gst_rtsp_client_attach() was called.
4810 * It is only allowed to set either a `send_func` or a `send_messages_func`
4811 * but not both at the same time.
4816 gst_rtsp_client_set_send_messages_func (GstRTSPClient * client,
4817 GstRTSPClientSendMessagesFunc func, gpointer user_data,
4818 GDestroyNotify notify)
4820 GstRTSPClientPrivate *priv;
4821 GDestroyNotify old_notify;
4824 g_return_if_fail (GST_IS_RTSP_CLIENT (client));
4826 priv = client->priv;
4828 g_mutex_lock (&priv->send_lock);
4829 g_assert (func == NULL || priv->send_func == NULL);
4830 priv->send_messages_func = func;
4831 old_notify = priv->send_messages_notify;
4832 old_data = priv->send_messages_data;
4833 priv->send_messages_notify = notify;
4834 priv->send_messages_data = user_data;
4835 g_mutex_unlock (&priv->send_lock);
4838 old_notify (old_data);
4842 * gst_rtsp_client_handle_message:
4843 * @client: a #GstRTSPClient
4844 * @message: (transfer none): an #GstRTSPMessage
4846 * Let the client handle @message.
4848 * Returns: a #GstRTSPResult.
4851 gst_rtsp_client_handle_message (GstRTSPClient * client,
4852 GstRTSPMessage * message)
4854 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), GST_RTSP_EINVAL);
4855 g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
4857 switch (message->type) {
4858 case GST_RTSP_MESSAGE_REQUEST:
4859 handle_request (client, message);
4861 case GST_RTSP_MESSAGE_RESPONSE:
4862 handle_response (client, message);
4864 case GST_RTSP_MESSAGE_DATA:
4865 handle_data (client, message);
4874 * gst_rtsp_client_send_message:
4875 * @client: a #GstRTSPClient
4876 * @session: (allow-none) (transfer none): a #GstRTSPSession to send
4877 * the message to or %NULL
4878 * @message: (transfer none): The #GstRTSPMessage to send
4880 * Send a message message to the remote end. @message must be a
4881 * #GST_RTSP_MESSAGE_REQUEST or a #GST_RTSP_MESSAGE_RESPONSE.
4884 gst_rtsp_client_send_message (GstRTSPClient * client, GstRTSPSession * session,
4885 GstRTSPMessage * message)
4887 GstRTSPContext sctx = { NULL }
4889 GstRTSPClientPrivate *priv;
4891 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), GST_RTSP_EINVAL);
4892 g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
4893 g_return_val_if_fail (message->type == GST_RTSP_MESSAGE_REQUEST ||
4894 message->type == GST_RTSP_MESSAGE_RESPONSE, GST_RTSP_EINVAL);
4896 priv = client->priv;
4898 if (!(ctx = gst_rtsp_context_get_current ())) {
4900 ctx->auth = priv->auth;
4901 gst_rtsp_context_push_current (ctx);
4904 ctx->conn = priv->connection;
4905 ctx->client = client;
4906 ctx->session = session;
4908 send_message (client, ctx, message, FALSE);
4911 gst_rtsp_context_pop_current (ctx);
4917 * gst_rtsp_client_get_stream_transport:
4919 * This is useful when providing a send function through
4920 * gst_rtsp_client_set_send_func() when doing RTSP over TCP:
4921 * the send function must call gst_rtsp_stream_transport_message_sent ()
4922 * on the appropriate transport when data has been received for streaming
4925 * Returns: (transfer none) (nullable): the #GstRTSPStreamTransport associated with @channel.
4929 GstRTSPStreamTransport *
4930 gst_rtsp_client_get_stream_transport (GstRTSPClient * self, guint8 channel)
4932 return g_hash_table_lookup (self->priv->transports,
4933 GINT_TO_POINTER ((gint) channel));
4937 do_send_messages (GstRTSPClient * client, GstRTSPMessage * messages,
4938 guint n_messages, gboolean close, gpointer user_data)
4940 GstRTSPClientPrivate *priv = client->priv;
4945 /* send the message */
4947 GST_INFO ("client %p: sending close message", client);
4949 ret = gst_rtsp_watch_send_messages (priv->watch, messages, n_messages, &id);
4950 if (ret != GST_RTSP_OK)
4953 for (i = 0; i < n_messages; i++) {
4954 if (gst_rtsp_message_get_type (&messages[i]) == GST_RTSP_MESSAGE_DATA) {
4958 /* We assume that all data messages in the list are for the
4960 r = gst_rtsp_message_parse_data (&messages[i], &channel);
4961 if (r != GST_RTSP_OK) {
4966 /* check if the message has been queued for transmission in watch */
4968 /* store the seq number so we can wait until it has been sent */
4969 GST_DEBUG_OBJECT (client, "wait for message %d, channel %d", id,
4971 set_data_seq (client, channel, id);
4973 GstRTSPStreamTransport *trans;
4976 g_hash_table_lookup (priv->transports,
4977 GINT_TO_POINTER ((gint) channel));
4979 GST_DEBUG_OBJECT (client, "emit 'message-sent' signal");
4980 g_mutex_unlock (&priv->send_lock);
4981 gst_rtsp_stream_transport_message_sent (trans);
4982 g_mutex_lock (&priv->send_lock);
4989 return ret == GST_RTSP_OK;
4994 GST_DEBUG_OBJECT (client, "got error %d", ret);
4999 static GstRTSPResult
5000 message_received (GstRTSPWatch * watch, GstRTSPMessage * message,
5003 return gst_rtsp_client_handle_message (GST_RTSP_CLIENT (user_data), message);
5006 static GstRTSPResult
5007 message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data)
5009 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
5010 GstRTSPClientPrivate *priv = client->priv;
5011 GstRTSPStreamTransport *trans = NULL;
5014 g_mutex_lock (&priv->send_lock);
5016 if (get_data_channel (client, cseq, &channel)) {
5017 trans = g_hash_table_lookup (priv->transports, GINT_TO_POINTER (channel));
5018 set_data_seq (client, channel, 0);
5020 g_mutex_unlock (&priv->send_lock);
5023 GST_DEBUG_OBJECT (client, "emit 'message-sent' signal");
5024 gst_rtsp_stream_transport_message_sent (trans);
5030 static GstRTSPResult
5031 closed (GstRTSPWatch * watch, gpointer user_data)
5033 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
5034 GstRTSPClientPrivate *priv = client->priv;
5035 const gchar *tunnelid;
5037 GST_INFO ("client %p: connection closed", client);
5039 if ((tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection))) {
5040 g_mutex_lock (&tunnels_lock);
5041 /* remove from tunnelids */
5042 g_hash_table_remove (tunnels, tunnelid);
5043 g_mutex_unlock (&tunnels_lock);
5046 gst_rtsp_watch_set_flushing (watch, TRUE);
5047 g_mutex_lock (&priv->watch_lock);
5048 gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
5049 gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL);
5050 g_mutex_unlock (&priv->watch_lock);
5055 static GstRTSPResult
5056 error (GstRTSPWatch * watch, GstRTSPResult result, gpointer user_data)
5058 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
5061 str = gst_rtsp_strresult (result);
5062 GST_INFO ("client %p: received an error %s", client, str);
5068 static GstRTSPResult
5069 error_full (GstRTSPWatch * watch, GstRTSPResult result,
5070 GstRTSPMessage * message, guint id, gpointer user_data)
5072 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
5074 GstRTSPContext sctx = { NULL }, *ctx;
5075 GstRTSPClientPrivate *priv;
5076 GstRTSPMessage response = { 0 };
5077 priv = client->priv;
5079 if (!(ctx = gst_rtsp_context_get_current ())) {
5081 ctx->auth = priv->auth;
5082 gst_rtsp_context_push_current (ctx);
5085 ctx->conn = priv->connection;
5086 ctx->client = client;
5087 ctx->request = message;
5088 ctx->method = GST_RTSP_INVALID;
5089 ctx->response = &response;
5091 /* only return error response if it is a request */
5092 if (!message || message->type != GST_RTSP_MESSAGE_REQUEST)
5095 if (result == GST_RTSP_ENOMEM) {
5096 send_generic_error_response (client, GST_RTSP_STS_REQUEST_ENTITY_TOO_LARGE,
5100 if (result == GST_RTSP_EPARSE) {
5101 send_generic_error_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
5107 gst_rtsp_context_pop_current (ctx);
5108 str = gst_rtsp_strresult (result);
5110 ("client %p: error when handling message %p with id %d: %s",
5111 client, message, id, str);
5118 remember_tunnel (GstRTSPClient * client)
5120 GstRTSPClientPrivate *priv = client->priv;
5121 const gchar *tunnelid;
5123 /* store client in the pending tunnels */
5124 tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection);
5125 if (tunnelid == NULL)
5128 GST_INFO ("client %p: inserting tunnel session %s", client, tunnelid);
5130 /* we can't have two clients connecting with the same tunnelid */
5131 g_mutex_lock (&tunnels_lock);
5132 if (g_hash_table_lookup (tunnels, tunnelid))
5133 goto tunnel_existed;
5135 g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
5136 g_mutex_unlock (&tunnels_lock);
5143 GST_ERROR ("client %p: no tunnelid provided", client);
5148 g_mutex_unlock (&tunnels_lock);
5149 GST_ERROR ("client %p: tunnel session %s already existed", client,
5155 static GstRTSPResult
5156 tunnel_lost (GstRTSPWatch * watch, gpointer user_data)
5158 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
5159 GstRTSPClientPrivate *priv = client->priv;
5161 GST_WARNING ("client %p: tunnel lost (connection %p)", client,
5164 /* ignore error, it'll only be a problem when the client does a POST again */
5165 remember_tunnel (client);
5170 static GstRTSPStatusCode
5171 handle_tunnel (GstRTSPClient * client)
5173 GstRTSPClientPrivate *priv = client->priv;
5174 GstRTSPClient *oclient;
5175 GstRTSPClientPrivate *opriv;
5176 const gchar *tunnelid;
5178 tunnelid = gst_rtsp_connection_get_tunnelid (priv->connection);
5179 if (tunnelid == NULL)
5182 /* check for previous tunnel */
5183 g_mutex_lock (&tunnels_lock);
5184 oclient = g_hash_table_lookup (tunnels, tunnelid);
5186 if (oclient == NULL) {
5187 /* no previous tunnel, remember tunnel */
5188 g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
5189 g_mutex_unlock (&tunnels_lock);
5191 GST_INFO ("client %p: no previous tunnel found, remembering tunnel (%p)",
5192 client, priv->connection);
5194 /* merge both tunnels into the first client */
5195 /* remove the old client from the table. ref before because removing it will
5196 * remove the ref to it. */
5197 g_object_ref (oclient);
5198 g_hash_table_remove (tunnels, tunnelid);
5199 g_mutex_unlock (&tunnels_lock);
5201 opriv = oclient->priv;
5203 g_mutex_lock (&opriv->watch_lock);
5204 if (opriv->watch == NULL)
5206 if (opriv->tstate == priv->tstate)
5207 goto tunnel_duplicate_id;
5209 GST_INFO ("client %p: found previous tunnel %p (old %p, new %p)", client,
5210 oclient, opriv->connection, priv->connection);
5212 gst_rtsp_connection_do_tunnel (opriv->connection, priv->connection);
5213 gst_rtsp_watch_reset (priv->watch);
5214 gst_rtsp_watch_reset (opriv->watch);
5215 g_mutex_unlock (&opriv->watch_lock);
5216 g_object_unref (oclient);
5218 /* the old client owns the tunnel now, the new one will be freed */
5219 g_source_destroy ((GSource *) priv->watch);
5221 gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
5222 gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL);
5223 rtsp_ctrl_timeout_remove (client);
5226 return GST_RTSP_STS_OK;
5231 GST_ERROR ("client %p: no tunnelid provided", client);
5232 return GST_RTSP_STS_SERVICE_UNAVAILABLE;
5236 GST_ERROR ("client %p: tunnel session %s was closed", client, tunnelid);
5237 g_mutex_unlock (&opriv->watch_lock);
5238 g_object_unref (oclient);
5239 return GST_RTSP_STS_SERVICE_UNAVAILABLE;
5241 tunnel_duplicate_id:
5243 GST_ERROR ("client %p: tunnel session %s was duplicate", client, tunnelid);
5244 g_mutex_unlock (&opriv->watch_lock);
5245 g_object_unref (oclient);
5246 return GST_RTSP_STS_BAD_REQUEST;
5250 static GstRTSPStatusCode
5251 tunnel_get (GstRTSPWatch * watch, gpointer user_data)
5253 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
5255 GST_INFO ("client %p: tunnel get (connection %p)", client,
5256 client->priv->connection);
5258 g_mutex_lock (&client->priv->lock);
5259 client->priv->tstate = TUNNEL_STATE_GET;
5260 g_mutex_unlock (&client->priv->lock);
5262 return handle_tunnel (client);
5265 static GstRTSPResult
5266 tunnel_post (GstRTSPWatch * watch, gpointer user_data)
5268 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
5270 GST_INFO ("client %p: tunnel post (connection %p)", client,
5271 client->priv->connection);
5273 g_mutex_lock (&client->priv->lock);
5274 client->priv->tstate = TUNNEL_STATE_POST;
5275 g_mutex_unlock (&client->priv->lock);
5277 if (handle_tunnel (client) != GST_RTSP_STS_OK)
5278 return GST_RTSP_ERROR;
5283 static GstRTSPResult
5284 tunnel_http_response (GstRTSPWatch * watch, GstRTSPMessage * request,
5285 GstRTSPMessage * response, gpointer user_data)
5287 GstRTSPClientClass *klass;
5289 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
5290 klass = GST_RTSP_CLIENT_GET_CLASS (client);
5292 if (klass->tunnel_http_response) {
5293 klass->tunnel_http_response (client, request, response);
5299 static GstRTSPWatchFuncs watch_funcs = {
5308 tunnel_http_response
5312 client_watch_notify (GstRTSPClient * client)
5314 GstRTSPClientPrivate *priv = client->priv;
5315 gboolean closed = TRUE;
5317 GST_INFO ("client %p: watch destroyed", client);
5319 /* remove all sessions if the media says so and so drop the extra client ref */
5320 gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
5321 gst_rtsp_client_set_send_messages_func (client, NULL, NULL, NULL);
5322 rtsp_ctrl_timeout_remove (client);
5323 gst_rtsp_client_session_filter (client, cleanup_session, &closed);
5326 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL);
5327 g_object_unref (client);
5331 * gst_rtsp_client_attach:
5332 * @client: a #GstRTSPClient
5333 * @context: (allow-none): a #GMainContext
5335 * Attaches @client to @context. When the mainloop for @context is run, the
5336 * client will be dispatched. When @context is %NULL, the default context will be
5339 * This function should be called when the client properties and urls are fully
5340 * configured and the client is ready to start.
5342 * Returns: the ID (greater than 0) for the source within the GMainContext.
5345 gst_rtsp_client_attach (GstRTSPClient * client, GMainContext * context)
5347 GstRTSPClientPrivate *priv;
5350 GWeakRef *client_weak_ref = g_new (GWeakRef, 1);
5352 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), 0);
5353 priv = client->priv;
5354 g_return_val_if_fail (priv->connection != NULL, 0);
5355 g_return_val_if_fail (priv->watch == NULL, 0);
5356 g_return_val_if_fail (priv->watch_context == NULL, 0);
5358 /* make sure noone will free the context before the watch is destroyed */
5359 priv->watch_context = g_main_context_ref (context);
5361 /* create watch for the connection and attach */
5362 priv->watch = gst_rtsp_watch_new (priv->connection, &watch_funcs,
5363 g_object_ref (client), (GDestroyNotify) client_watch_notify);
5364 gst_rtsp_client_set_send_func (client, NULL, NULL, NULL);
5365 gst_rtsp_client_set_send_messages_func (client, do_send_messages, priv->watch,
5366 (GDestroyNotify) gst_rtsp_watch_unref);
5368 gst_rtsp_watch_set_send_backlog (priv->watch, 0, WATCH_BACKLOG_SIZE);
5370 /* take the lock before attaching the client watch, so that the client thread
5371 * can not access the control channel timer until it's properly in place */
5372 g_mutex_lock (&priv->lock);
5374 GST_INFO ("client %p: attaching to context %p", client, context);
5375 res = gst_rtsp_watch_attach (priv->watch, context);
5377 /* Setting up a timeout for the RTSP control channel until a session
5378 * is up where it is handling timeouts. */
5380 /* remove old timeout if any */
5381 rtsp_ctrl_timeout_remove_unlocked (client->priv);
5383 timer_src = g_timeout_source_new_seconds (RTSP_CTRL_CB_INTERVAL);
5384 g_weak_ref_init (client_weak_ref, client);
5385 g_source_set_callback (timer_src, rtsp_ctrl_timeout_cb, client_weak_ref,
5386 rtsp_ctrl_timeout_destroy_notify);
5387 g_source_attach (timer_src, priv->watch_context);
5388 priv->rtsp_ctrl_timeout = timer_src;
5389 GST_DEBUG ("rtsp control setting up session timeout %p.",
5390 priv->rtsp_ctrl_timeout);
5392 g_mutex_unlock (&priv->lock);
5398 * gst_rtsp_client_session_filter:
5399 * @client: a #GstRTSPClient
5400 * @func: (scope call) (allow-none): a callback
5401 * @user_data: user data passed to @func
5403 * Call @func for each session managed by @client. The result value of @func
5404 * determines what happens to the session. @func will be called with @client
5405 * locked so no further actions on @client can be performed from @func.
5407 * If @func returns #GST_RTSP_FILTER_REMOVE, the session will be removed from
5410 * If @func returns #GST_RTSP_FILTER_KEEP, the session will remain in @client.
5412 * If @func returns #GST_RTSP_FILTER_REF, the session will remain in @client but
5413 * will also be added with an additional ref to the result #GList of this
5416 * When @func is %NULL, #GST_RTSP_FILTER_REF will be assumed for each session.
5418 * Returns: (element-type GstRTSPSession) (transfer full): a #GList with all
5419 * sessions for which @func returned #GST_RTSP_FILTER_REF. After usage, each
5420 * element in the #GList should be unreffed before the list is freed.
5423 gst_rtsp_client_session_filter (GstRTSPClient * client,
5424 GstRTSPClientSessionFilterFunc func, gpointer user_data)
5426 GstRTSPClientPrivate *priv;
5427 GList *result, *walk, *next;
5428 GHashTable *visited;
5431 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
5433 priv = client->priv;
5437 visited = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL);
5439 g_mutex_lock (&priv->lock);
5441 cookie = priv->sessions_cookie;
5442 for (walk = priv->sessions; walk; walk = next) {
5443 GstRTSPSession *sess = walk->data;
5444 GstRTSPFilterResult res;
5447 next = g_list_next (walk);
5450 /* only visit each session once */
5451 if (g_hash_table_contains (visited, sess))
5454 g_hash_table_add (visited, g_object_ref (sess));
5455 g_mutex_unlock (&priv->lock);
5457 res = func (client, sess, user_data);
5459 g_mutex_lock (&priv->lock);
5461 res = GST_RTSP_FILTER_REF;
5463 changed = (cookie != priv->sessions_cookie);
5466 case GST_RTSP_FILTER_REMOVE:
5467 /* stop watching the session and pretend it went away, if the list was
5468 * changed, we can't use the current list position, try to see if we
5469 * still have the session */
5470 client_unwatch_session (client, sess, changed ? NULL : walk);
5471 cookie = priv->sessions_cookie;
5473 case GST_RTSP_FILTER_REF:
5474 result = g_list_prepend (result, g_object_ref (sess));
5476 case GST_RTSP_FILTER_KEEP:
5483 g_mutex_unlock (&priv->lock);
5486 g_hash_table_unref (visited);
5492 * gst_rtsp_client_set_watch_flushing:
5493 * @client: a #GstRTSPClient
5494 * @val: a boolean value
5496 * sets watch flushing to @val on watch to accet/ignore new messages.
5499 gst_rtsp_client_set_watch_flushing (GstRTSPClient * client, gboolean val)
5501 GstRTSPClientPrivate *priv = NULL;
5502 g_return_if_fail (GST_IS_RTSP_CLIENT (client));
5504 priv = gst_rtsp_client_get_instance_private (client);
5506 /* make sure we unblock/block the backlog and accept/don't accept new messages on the watch */
5507 if (priv->watch != NULL) {
5508 GST_INFO ("Set watch flushing as %d", val);
5509 gst_rtsp_watch_set_flushing (priv->watch, val);