2 * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 #include "rtsp-session.h"
24 static void gst_rtsp_session_finalize (GObject * obj);
26 G_DEFINE_TYPE (GstRTSPSession, gst_rtsp_session, G_TYPE_OBJECT);
29 gst_rtsp_session_class_init (GstRTSPSessionClass * klass)
31 GObjectClass *gobject_class;
33 gobject_class = G_OBJECT_CLASS (klass);
35 gobject_class->finalize = gst_rtsp_session_finalize;
39 gst_rtsp_session_init (GstRTSPSession * session)
44 gst_rtsp_session_free_stream (GstRTSPSessionStream *stream)
46 if (stream->client_trans)
47 gst_rtsp_transport_free (stream->client_trans);
48 g_free (stream->destination);
49 if (stream->server_trans)
50 gst_rtsp_transport_free (stream->server_trans);
52 if (stream->udpsrc[0])
53 gst_object_unref (stream->udpsrc[0]);
59 gst_rtsp_session_free_media (GstRTSPSessionMedia *media)
63 gst_element_set_state (media->pipeline, GST_STATE_NULL);
66 g_object_unref (media->factory);
68 for (walk = media->streams; walk; walk = g_list_next (walk)) {
69 GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data;
71 gst_rtsp_session_free_stream (stream);
74 gst_object_unref (media->pipeline);
75 g_list_free (media->streams);
79 gst_rtsp_session_finalize (GObject * obj)
81 GstRTSPSession *session;
84 session = GST_RTSP_SESSION (obj);
86 g_free (session->sessionid);
88 for (walk = session->medias; walk; walk = g_list_next (walk)) {
89 GstRTSPSessionMedia *media = (GstRTSPSessionMedia *) walk->data;
91 gst_rtsp_session_free_media (media);
93 g_list_free (session->medias);
95 G_OBJECT_CLASS (gst_rtsp_session_parent_class)->finalize (obj);
99 * gst_rtsp_session_get_media:
100 * @sess: a #GstRTSPSession
101 * @location: the url for the media
102 * @factory: a #GstRTSPMediaFactory
104 * Get or create the session information for @factory.
106 * Returns: the configuration for @factory in @sess.
108 GstRTSPSessionMedia *
109 gst_rtsp_session_get_media (GstRTSPSession *sess, const gchar *location, GstRTSPMediaFactory *factory)
111 GstRTSPSessionMedia *result;
116 for (walk = sess->medias; walk; walk = g_list_next (walk)) {
117 result = (GstRTSPSessionMedia *) walk->data;
119 if (result->factory == factory)
124 if (result == NULL) {
125 result = g_new0 (GstRTSPSessionMedia, 1);
126 result->factory = factory;
127 result->pipeline = gst_pipeline_new ("pipeline");
129 /* construct media and add to the pipeline */
130 result->mediabin = gst_rtsp_media_factory_construct (factory, location);
131 if (result->mediabin == NULL)
134 gst_bin_add (GST_BIN_CAST (result->pipeline), result->mediabin->element);
136 result->rtpbin = gst_element_factory_make ("gstrtpbin", "rtpbin");
138 /* add stuf to the bin */
139 gst_bin_add (GST_BIN (result->pipeline), result->rtpbin);
141 gst_element_set_state (result->pipeline, GST_STATE_READY);
143 sess->medias = g_list_prepend (sess->medias, result);
150 gst_rtsp_session_free_media (result);
156 * gst_rtsp_session_media_get_stream:
157 * @media: a #GstRTSPSessionMedia
158 * @idx: the stream index
160 * Get a previously created or create a new #GstRTSPSessionStream at @idx.
162 * Returns: a #GstRTSPSessionStream that is valid until the session of @media
165 GstRTSPSessionStream *
166 gst_rtsp_session_media_get_stream (GstRTSPSessionMedia *media, guint idx)
168 GstRTSPSessionStream *result;
173 for (walk = media->streams; walk; walk = g_list_next (walk)) {
174 result = (GstRTSPSessionStream *) walk->data;
176 if (result->idx == idx)
181 if (result == NULL) {
182 result = g_new0 (GstRTSPSessionStream, 1);
184 result->media = media;
185 result->media_stream = gst_rtsp_media_bin_get_stream (media->mediabin, idx);
187 media->streams = g_list_prepend (media->streams, result);
193 * gst_rtsp_session_new:
195 * Create a new #GstRTSPSession instance.
198 gst_rtsp_session_new (const gchar *sessionid)
200 GstRTSPSession *result;
202 result = g_object_new (GST_TYPE_RTSP_SESSION, NULL);
203 result->sessionid = g_strdup (sessionid);
209 alloc_udp_ports (GstRTSPSessionStream * stream)
211 GstStateChangeReturn ret;
212 GstElement *udpsrc0, *udpsrc1;
213 GstElement *udpsink0, *udpsink1;
214 gint tmp_rtp, tmp_rtcp;
216 gint rtpport, rtcpport, sockfd;
225 /* Start with random port */
228 /* try to allocate 2 UDP ports, the RTP port should be an even
229 * number and the RTCP port should be the next (uneven) port */
231 udpsrc0 = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL);
233 goto no_udp_protocol;
234 g_object_set (G_OBJECT (udpsrc0), "port", tmp_rtp, NULL);
236 ret = gst_element_set_state (udpsrc0, GST_STATE_PAUSED);
237 if (ret == GST_STATE_CHANGE_FAILURE) {
243 gst_element_set_state (udpsrc0, GST_STATE_NULL);
244 gst_object_unref (udpsrc0);
248 goto no_udp_protocol;
251 g_object_get (G_OBJECT (udpsrc0), "port", &tmp_rtp, NULL);
253 /* check if port is even */
254 if ((tmp_rtp & 1) != 0) {
255 /* port not even, close and allocate another */
259 gst_element_set_state (udpsrc0, GST_STATE_NULL);
260 gst_object_unref (udpsrc0);
266 /* allocate port+1 for RTCP now */
267 udpsrc1 = gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0", NULL);
269 goto no_udp_rtcp_protocol;
272 tmp_rtcp = tmp_rtp + 1;
273 g_object_set (G_OBJECT (udpsrc1), "port", tmp_rtcp, NULL);
275 ret = gst_element_set_state (udpsrc1, GST_STATE_PAUSED);
276 /* tmp_rtcp port is busy already : retry to make rtp/rtcp pair */
277 if (ret == GST_STATE_CHANGE_FAILURE) {
282 gst_element_set_state (udpsrc0, GST_STATE_NULL);
283 gst_object_unref (udpsrc0);
285 gst_element_set_state (udpsrc1, GST_STATE_NULL);
286 gst_object_unref (udpsrc1);
292 /* all fine, do port check */
293 g_object_get (G_OBJECT (udpsrc0), "port", &rtpport, NULL);
294 g_object_get (G_OBJECT (udpsrc1), "port", &rtcpport, NULL);
296 /* this should not happen... */
297 if (rtpport != tmp_rtp || rtcpport != tmp_rtcp)
300 name = g_strdup_printf ("udp://%s:%d", stream->destination, stream->client_trans->client_port.min);
301 udpsink0 = gst_element_make_from_uri (GST_URI_SINK, name, NULL);
305 goto no_udp_protocol;
307 g_object_get (G_OBJECT (udpsrc0), "sock", &sockfd, NULL);
308 g_object_set (G_OBJECT (udpsink0), "sockfd", sockfd, NULL);
309 g_object_set (G_OBJECT (udpsink0), "closefd", FALSE, NULL);
311 name = g_strdup_printf ("udp://%s:%d", stream->destination, stream->client_trans->client_port.max);
312 udpsink1 = gst_element_make_from_uri (GST_URI_SINK, name, NULL);
316 goto no_udp_protocol;
318 g_object_get (G_OBJECT (udpsrc1), "sock", &sockfd, NULL);
319 g_object_set (G_OBJECT (udpsink1), "sockfd", sockfd, NULL);
320 g_object_set (G_OBJECT (udpsink1), "closefd", FALSE, NULL);
321 g_object_set (G_OBJECT (udpsink1), "sync", FALSE, NULL);
322 g_object_set (G_OBJECT (udpsink1), "async", FALSE, NULL);
325 /* we keep these elements, we configure all in configure_transport when the
326 * server told us to really use the UDP ports. */
327 stream->udpsrc[0] = gst_object_ref (udpsrc0);
328 stream->udpsrc[1] = gst_object_ref (udpsrc1);
329 stream->udpsink[0] = gst_object_ref (udpsink0);
330 stream->udpsink[1] = gst_object_ref (udpsink1);
331 stream->server_trans->server_port.min = rtpport;
332 stream->server_trans->server_port.max = rtcpport;
334 /* they are ours now */
335 gst_object_sink (udpsrc0);
336 gst_object_sink (udpsrc1);
337 gst_object_sink (udpsink0);
338 gst_object_sink (udpsink1);
351 no_udp_rtcp_protocol:
362 gst_element_set_state (udpsrc0, GST_STATE_NULL);
363 gst_object_unref (udpsrc0);
366 gst_element_set_state (udpsrc1, GST_STATE_NULL);
367 gst_object_unref (udpsrc1);
370 gst_element_set_state (udpsink0, GST_STATE_NULL);
371 gst_object_unref (udpsink0);
374 gst_element_set_state (udpsink1, GST_STATE_NULL);
375 gst_object_unref (udpsink1);
383 * gst_rtsp_session_stream_init_udp:
384 * @stream: a #GstRTSPSessionStream
385 * @ct: a client #GstRTSPTransport
387 * Set @ct as the client transport and create and return a matching server
388 * transport. After this call the needed ports and elements will be created and
391 * Returns: a server transport or NULL if something went wrong.
394 gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream,
395 const gchar *destination, GstRTSPTransport *ct)
397 GstRTSPTransport *st;
400 GstRTSPSessionMedia *media;
402 media = stream->media;
404 /* prepare the server transport */
405 gst_rtsp_transport_new (&st);
407 st->trans = ct->trans;
408 st->profile = ct->profile;
409 st->lower_transport = ct->lower_transport;
410 st->client_port = ct->client_port;
412 /* keep track of the transports */
413 g_free (stream->destination);
414 stream->destination = g_strdup (destination);
415 if (stream->client_trans)
416 gst_rtsp_transport_free (stream->client_trans);
417 stream->client_trans = ct;
418 if (stream->server_trans)
419 gst_rtsp_transport_free (stream->server_trans);
420 stream->server_trans = st;
422 alloc_udp_ports (stream);
424 gst_bin_add (GST_BIN (media->pipeline), stream->udpsink[0]);
425 gst_bin_add (GST_BIN (media->pipeline), stream->udpsink[1]);
426 gst_bin_add (GST_BIN (media->pipeline), stream->udpsrc[1]);
428 /* hook up the stream to the RTP session elements. */
429 name = g_strdup_printf ("send_rtp_sink_%d", stream->idx);
430 stream->send_rtp_sink = gst_element_get_request_pad (media->rtpbin, name);
432 name = g_strdup_printf ("send_rtp_src_%d", stream->idx);
433 stream->send_rtp_src = gst_element_get_static_pad (media->rtpbin, name);
435 name = g_strdup_printf ("send_rtcp_src_%d", stream->idx);
436 stream->send_rtcp_src = gst_element_get_request_pad (media->rtpbin, name);
438 name = g_strdup_printf ("recv_rtcp_sink_%d", stream->idx);
439 stream->recv_rtcp_sink = gst_element_get_request_pad (media->rtpbin, name);
442 gst_pad_link (stream->media_stream->srcpad, stream->send_rtp_sink);
443 pad = gst_element_get_static_pad (stream->udpsink[0], "sink");
444 gst_pad_link (stream->send_rtp_src, pad);
445 gst_object_unref (pad);
446 pad = gst_element_get_static_pad (stream->udpsink[1], "sink");
447 gst_pad_link (stream->send_rtcp_src, pad);
448 gst_object_unref (pad);
449 pad = gst_element_get_static_pad (stream->udpsrc[1], "src");
450 gst_pad_link (pad, stream->recv_rtcp_sink);
451 gst_object_unref (pad);
457 * gst_rtsp_session_media_play:
458 * @media: a #GstRTSPSessionMedia
460 * Tell the media object @media to start playing and streaming to the client.
462 * Returns: a #GstStateChangeReturn
465 gst_rtsp_session_media_play (GstRTSPSessionMedia *media)
467 GstStateChangeReturn ret;
469 ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
475 * gst_rtsp_session_media_pause:
476 * @media: a #GstRTSPSessionMedia
478 * Tell the media object @media to pause.
480 * Returns: a #GstStateChangeReturn
483 gst_rtsp_session_media_pause (GstRTSPSessionMedia *media)
485 GstStateChangeReturn ret;
487 ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
493 * gst_rtsp_session_media_stop:
494 * @media: a #GstRTSPSessionMedia
496 * Tell the media object @media to stop playing. After this call the media
497 * cannot be played or paused anymore
499 * Returns: a #GstStateChangeReturn
502 gst_rtsp_session_media_stop (GstRTSPSessionMedia *media)
504 GstStateChangeReturn ret;
506 ret = gst_element_set_state (media->pipeline, GST_STATE_NULL);