2 * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
4 * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
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., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
22 * * Modifications by Samsung Electronics Co., Ltd.
24 * 1. Applied Miracast WFD Server function
33 #include <sys/types.h>
34 #include <netinet/in.h>
36 #include <sys/socket.h>
39 #include <arpa/inet.h>
40 #include <sys/ioctl.h>
42 #include "rtsp-client.h"
44 #include "rtsp-params.h"
46 #include <exynos/exynos_drm.h>
50 #include <X11/Xutil.h>
56 #define DEFAULT_RTSP_TIMEOUT 60
57 #define DRM_EXYNOS_VIDI_ON 1
58 #define DRM_EXYNOS_VIDI_OFF 0
60 //#define WFD_PAD_PROBE
63 gulong ahs_appsrc_cb_probe_id = 0;
67 /* temporary multicast address until it's configurable somewhere */
68 #define MCAST_ADDRESS "224.2.0.1"
70 #define DEFAULT_WFD_MTU_SIZE 1400
72 static GMutex *tunnels_lock;
73 static GHashTable *tunnels;
90 GST_DEBUG_CATEGORY_STATIC (rtsp_client_debug);
91 #define GST_CAT_DEFAULT rtsp_client_debug
93 static guint gst_rtsp_client_signals[SIGNAL_LAST] = { 0 };
95 static void gst_rtsp_client_get_property (GObject * object, guint propid,
96 GValue * value, GParamSpec * pspec);
97 static void gst_rtsp_client_set_property (GObject * object, guint propid,
98 const GValue * value, GParamSpec * pspec);
99 static void gst_rtsp_client_finalize (GObject * obj);
101 static void client_session_finalized (GstRTSPClient * client,
102 GstRTSPSession * session);
103 static void unlink_session_streams (GstRTSPClient * client,
104 GstRTSPSession * session, GstRTSPSessionMedia * media);
106 set_edid_info(gchar *edid_info, gboolean plug);
109 gst_rtsp_client_parse_methods (GstRTSPClient * client, GstRTSPMessage * response);
111 keep_alive_condition(gpointer userdata);
113 gst_rtsp_client_sending_m16_message (GstRTSPClient * client);
117 gst_dump_data (GstPad * pad, GstMiniObject * obj, gpointer u_data);
119 static void gst_rtsp_client_create_srcbin (GstRTSPClient * client);
121 G_DEFINE_TYPE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT);
123 static const char fake_edid_info[] = {
124 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x4c, 0x2d, 0x05, 0x05,
125 0x00, 0x00, 0x00, 0x00, 0x30, 0x12, 0x01, 0x03, 0x80, 0x10, 0x09, 0x78,
126 0x0a, 0xee, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54, 0xbd,
127 0xee, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
128 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x66, 0x21, 0x50, 0xb0, 0x51, 0x00,
129 0x1b, 0x30, 0x40, 0x70, 0x36, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e,
130 0x01, 0x1d, 0x00, 0x72, 0x51, 0xd0, 0x1e, 0x20, 0x6e, 0x28, 0x55, 0x00,
131 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x18,
132 0x4b, 0x1a, 0x44, 0x17, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
133 0x00, 0x00, 0x00, 0xfc, 0x00, 0x53, 0x41, 0x4d, 0x53, 0x55, 0x4e, 0x47,
134 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20, 0x01, 0xbc, 0x02, 0x03, 0x1e, 0xf1,
135 0x46, 0x84, 0x05, 0x03, 0x10, 0x20, 0x22, 0x23, 0x09, 0x07, 0x07, 0x83,
136 0x01, 0x00, 0x00, 0xe2, 0x00, 0x0f, 0x67, 0x03, 0x0c, 0x00, 0x10, 0x00,
137 0xb8, 0x2d, 0x01, 0x1d, 0x80, 0x18, 0x71, 0x1c, 0x16, 0x20, 0x58, 0x2c,
138 0x25, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x9e, 0x8c, 0x0a, 0xd0, 0x8a,
139 0x20, 0xe0, 0x2d, 0x10, 0x10, 0x3e, 0x96, 0x00, 0xa0, 0x5a, 0x00, 0x00,
140 0x00, 0x18, 0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40, 0x58, 0x2c,
141 0x45, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00,
142 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
143 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
144 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
145 0x00, 0x00, 0x00, 0x06
149 gst_rtsp_client_class_init (GstRTSPClientClass * klass)
151 GObjectClass *gobject_class;
153 gobject_class = G_OBJECT_CLASS (klass);
155 gobject_class->get_property = gst_rtsp_client_get_property;
156 gobject_class->set_property = gst_rtsp_client_set_property;
157 gobject_class->finalize = gst_rtsp_client_finalize;
159 g_object_class_install_property (gobject_class, PROP_SESSION_POOL,
160 g_param_spec_object ("session-pool", "Session Pool",
161 "The session pool to use for client session",
162 GST_TYPE_RTSP_SESSION_POOL,
163 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
165 g_object_class_install_property (gobject_class, PROP_MEDIA_MAPPING,
166 g_param_spec_object ("media-mapping", "Media Mapping",
167 "The media mapping to use for client session",
168 GST_TYPE_RTSP_MEDIA_MAPPING,
169 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
171 gst_rtsp_client_signals[SIGNAL_CLOSED] =
172 g_signal_new ("closed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
173 G_STRUCT_OFFSET (GstRTSPClientClass, closed), NULL, NULL,
174 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
176 gst_rtsp_client_signals[SIGNAL_ERROR] =
177 g_signal_new ("error_noti", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
178 G_STRUCT_OFFSET (GstRTSPClientClass, on_error), NULL, NULL,
179 g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
182 g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
183 tunnels_lock = g_mutex_new ();
185 GST_DEBUG_CATEGORY_INIT (rtsp_client_debug, "rtspclient", 0, "GstRTSPClient");
189 gst_rtsp_client_init (GstRTSPClient * client)
191 client->state_lock = g_mutex_new ();
192 client->keep_alive_lock = g_mutex_new();
193 client->keep_alive_flag = TRUE;
194 client->state_wait = g_cond_new ();
195 client->client_state = CLIENT_STATE_UNKNOWN;
196 client->videosrc_type = WFD_INI_VSRC_XVIMAGESRC;
197 client->session_mode = 0;
198 client->infile = NULL;
199 client->MTUsize = DEFAULT_WFD_MTU_SIZE;
203 client_unlink_session (GstRTSPClient * client, GstRTSPSession * session)
207 /* unlink all media managed in this session */
208 for (medias = session->medias; medias; medias = g_list_next (medias)) {
209 unlink_session_streams (client, session,
210 (GstRTSPSessionMedia *) medias->data);
215 client_cleanup_sessions (GstRTSPClient * client)
219 /* remove weak-ref from sessions */
220 for (sessions = client->sessions; sessions; sessions = g_list_next (sessions)) {
221 GstRTSPSession *session = (GstRTSPSession *) sessions->data;
222 g_object_weak_unref (G_OBJECT (session),
223 (GWeakNotify) client_session_finalized, client);
224 client_unlink_session (client, session);
226 g_list_free (client->sessions);
227 client->sessions = NULL;
230 /* A client is finalized when the connection is broken */
232 gst_rtsp_client_finalize (GObject * obj)
234 GstRTSPClient *client = GST_RTSP_CLIENT (obj);
236 GST_INFO ("finalize client %p", client);
238 client_cleanup_sessions (client);
240 if(client->connection)
242 gst_rtsp_connection_close (client->connection);
243 gst_rtsp_connection_free(client->connection);
245 g_source_destroy ((GSource *) client->watch);
247 client->watch = NULL;
249 if (client->session_pool)
250 g_object_unref (client->session_pool);
251 if (client->media_mapping)
252 g_object_unref (client->media_mapping);
254 g_object_unref (client->auth);
257 gst_rtsp_url_free (client->uri);
259 g_object_unref (client->media);
260 g_free (client->server_ip);
261 set_edid_info(NULL, FALSE);
262 if(client->keep_alive_lock)
263 g_mutex_free (client->keep_alive_lock);
264 client->keep_alive_lock = NULL;
265 g_cond_signal (client->state_wait);
267 g_object_unref (client->server);
269 close(client->tcpsock);
270 G_OBJECT_CLASS (gst_rtsp_client_parent_class)->finalize (obj);
274 set_edid_info(gchar *edid_info, gboolean plug)
280 int eventBase, errorBase;
281 int dri2Major, dri2Minor;
282 char *driverName, *deviceName;
283 struct drm_exynos_vidi_connection vidi;
284 GST_INFO("set_edid_info");
286 dpy = XOpenDisplay(NULL);
288 GST_ERROR(" Error: fail to open display");
290 screen = DefaultScreen(dpy);
293 if (!DRI2QueryExtension (dpy, &eventBase, &errorBase)) {
294 GST_ERROR(" Error : DRI2QueryExtension");
297 if (!DRI2QueryVersion (dpy, &dri2Major, &dri2Minor)) {
298 GST_ERROR("!!Error : DRI2QueryVersion !!");
302 if (!DRI2Connect (dpy, RootWindow(dpy, screen), &driverName, &deviceName)) {
303 GST_ERROR( "!!Error : DRI2Connect !!\n");
307 GST_INFO("Open drm device : %s\n", deviceName);
309 /* get the drm_fd though opening the deviceName */
310 drm_fd = open (deviceName, O_RDWR);
312 GST_ERROR("!!Error : cannot open drm device (%s)", deviceName);
315 /* get the drm magic */
316 drmGetMagic(drm_fd, &magic);
317 GST_INFO(">>> drm magic=%d", magic);
319 if (!DRI2Authenticate(dpy, RootWindow(dpy, screen), magic)) {
320 GST_ERROR("!!Error : DRI2Authenticate !!");
325 vidi.connection = DRM_EXYNOS_VIDI_ON;
326 vidi.extensions = DRM_EXYNOS_VIDI_ON;
327 vidi.edid = (uint64_t *)fake_edid_info;
328 GST_ERROR(">>>>>>>>>>>>>>>>>>>>set\n");
330 vidi.connection = DRM_EXYNOS_VIDI_OFF;
331 vidi.extensions = DRM_EXYNOS_VIDI_OFF;
333 GST_ERROR(">>>>>>>>>>>>>>>>>>>>unset\n");
336 ioctl (drm_fd, DRM_IOCTL_EXYNOS_VIDI_CONNECTION, &vidi);
344 gst_rtsp_client_get_property (GObject * object, guint propid,
345 GValue * value, GParamSpec * pspec)
347 GstRTSPClient *client = GST_RTSP_CLIENT (object);
350 case PROP_SESSION_POOL:
351 g_value_take_object (value, gst_rtsp_client_get_session_pool (client));
353 case PROP_MEDIA_MAPPING:
354 g_value_take_object (value, gst_rtsp_client_get_media_mapping (client));
357 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
362 gst_rtsp_client_set_property (GObject * object, guint propid,
363 const GValue * value, GParamSpec * pspec)
365 GstRTSPClient *client = GST_RTSP_CLIENT (object);
368 case PROP_SESSION_POOL:
369 gst_rtsp_client_set_session_pool (client, g_value_get_object (value));
371 case PROP_MEDIA_MAPPING:
372 gst_rtsp_client_set_media_mapping (client, g_value_get_object (value));
375 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
380 * gst_rtsp_client_new:
382 * Create a new #GstRTSPClient instance.
384 * Returns: a new #GstRTSPClient
387 gst_rtsp_client_new (void)
389 GstRTSPClient *result;
391 result = g_object_new (GST_TYPE_RTSP_CLIENT, NULL);
397 send_response (GstRTSPClient * client, GstRTSPSession * session,
398 GstRTSPMessage * response)
400 #if 0 //Changes for testing with dongle
401 gst_rtsp_message_add_header (response, GST_RTSP_HDR_SERVER,
402 "GStreamer RTSP server");
404 /* remove any previous header */
405 gst_rtsp_message_remove_header (response, GST_RTSP_HDR_SESSION, -1);
407 /* add the new session header for new session ids */
411 GST_DEBUG ("session is not NULL - %p", session);
413 if (session->timeout > 30)
414 str = g_strdup_printf ("%s; timeout=%d", session->sessionid, session->timeout);
417 str = g_strdup_printf ("%s;timeout=%d", session->sessionid, 30);
420 gst_rtsp_message_take_header (response, GST_RTSP_HDR_SESSION, str);
423 if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
424 gst_rtsp_message_dump (response);
427 gst_rtsp_watch_send_message (client->watch, response, NULL);
428 gst_rtsp_message_unset (response);
433 send_request (GstRTSPClient * client, GstRTSPSession * session, GstRTSPMessage * request)
435 /* remove any previous header */
436 gst_rtsp_message_remove_header (request, GST_RTSP_HDR_SESSION, -1);
438 /* add the new session header for new session ids */
442 GST_DEBUG ("session is not NULL - %p", session);
444 if (session->timeout != DEFAULT_RTSP_TIMEOUT)
446 g_strdup_printf ("%s; timeout=%d", session->sessionid,
449 str = g_strdup (session->sessionid);
451 gst_rtsp_message_take_header (request, GST_RTSP_HDR_SESSION, str);
454 if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
455 gst_rtsp_message_dump (request);
458 gst_rtsp_watch_send_message (client->watch, request, NULL);
459 gst_rtsp_message_unset (request);
463 send_generic_response (GstRTSPClient * client, GstRTSPStatusCode code,
464 GstRTSPClientState * state)
466 gst_rtsp_message_init_response (state->response, code,
467 gst_rtsp_status_as_text (code), state->request);
469 send_response (client, NULL, state->response);
473 handle_unauthorized_request (GstRTSPClient * client, GstRTSPAuth * auth,
474 GstRTSPClientState * state)
476 gst_rtsp_message_init_response (state->response, GST_RTSP_STS_UNAUTHORIZED,
477 gst_rtsp_status_as_text (GST_RTSP_STS_UNAUTHORIZED), state->request);
480 /* and let the authentication manager setup the auth tokens */
481 gst_rtsp_auth_setup_auth (auth, client, 0, state);
484 send_response (client, state->session, state->response);
489 compare_uri (const GstRTSPUrl * uri1, const GstRTSPUrl * uri2)
491 if (uri1 == NULL || uri2 == NULL)
494 if (strcmp (uri1->abspath, uri2->abspath))
500 /* this function is called to initially find the media for the DESCRIBE request
501 * but is cached for when the same client (without breaking the connection) is
502 * doing a setup for the exact same url. */
503 static GstRTSPMedia *
504 find_media (GstRTSPClient * client, GstRTSPClientState * state)
506 GstRTSPMediaFactory *factory;
510 GST_INFO_OBJECT (client, "client->uri = %s & state->uri = %s",
511 client->uri->abspath, state->uri->abspath);
513 if (!compare_uri (client->uri, state->uri)) {
514 /* remove any previously cached values before we try to construct a new
517 gst_rtsp_url_free (client->uri);
520 g_object_unref (client->media);
521 client->media = NULL;
523 if (!client->media_mapping)
526 GST_DEBUG ("Going to find factory for media mapping...");
528 /* find the factory for the uri first */
530 gst_rtsp_media_mapping_find_factory (client->media_mapping,
534 state->factory = factory;
536 GST_DEBUG ("Going to get media factory auth...");
538 /* check if we have access to the factory */
539 if ((auth = gst_rtsp_media_factory_get_auth (factory))) {
540 if (!gst_rtsp_auth_check (auth, client, 0, state))
543 g_object_unref (auth);
546 GST_DEBUG ("Going to do media factory construct...");
548 GST_DEBUG ("Setting source bin...");
549 gst_rtsp_media_factory_set_srcbin (factory, GST_ELEMENT(client->srcbin->srcbin));
551 /* prepare the media and add it to the pipeline */
552 if (!(media = gst_rtsp_media_factory_construct (factory, state->uri)))
555 g_object_unref (factory);
557 /* set ipv6 on the media before preparing */
558 media->is_ipv6 = client->is_ipv6;
559 state->media = media;
561 GST_DEBUG ("Going to do prepare media...");
563 /* prepare the media */
564 if (!(gst_rtsp_media_prepare (media)))
567 GST_DEBUG ("prepare media done...");
569 /* now keep track of the uri and the media */
570 client->uri = gst_rtsp_url_copy (state->uri);
571 client->media = media;
573 /* we have seen this uri before, used cached media */
574 media = client->media;
575 state->media = media;
576 GST_INFO ("reusing cached media %p", media);
580 g_object_ref (media);
587 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
592 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
597 handle_unauthorized_request (client, auth, state);
598 g_object_unref (factory);
599 g_object_unref (auth);
604 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
605 g_object_unref (factory);
610 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
611 g_object_unref (media);
612 g_object_unref (factory);
618 do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client)
620 GstRTSPMessage message = { 0 };
625 gst_rtsp_message_init_data (&message, channel);
627 gst_buffer_map(buffer, &mapinfo, GST_MAP_READ);
630 gst_rtsp_message_take_body (&message, data, size);
632 /* FIXME, client->watch could have been finalized here, we need to keep an
633 * extra refcount to the watch. */
634 gst_rtsp_watch_send_message (client->watch, &message, NULL);
636 gst_rtsp_message_steal_body (&message, &data, &size);
637 gst_rtsp_message_unset (&message);
639 gst_buffer_unmap(buffer, &mapinfo);
645 do_send_data_list (GstBufferList * blist, guint8 channel,
646 GstRTSPClient * client)
649 guint length = gst_buffer_list_length(blist);
651 for(; i < length; ++i)
653 buffer = gst_buffer_list_get(blist, i);
655 do_send_data (buffer, channel, client);
662 link_stream (GstRTSPClient * client, GstRTSPSession * session,
663 GstRTSPSessionStream * stream)
665 GST_DEBUG ("client %p: linking stream %p", client, stream);
666 gst_rtsp_session_stream_set_callbacks (stream, (GstRTSPSendFunc) do_send_data,
667 (GstRTSPSendFunc) do_send_data, (GstRTSPSendListFunc) do_send_data_list,
668 (GstRTSPSendListFunc) do_send_data_list, client, NULL);
669 client->streams = g_list_prepend (client->streams, stream);
670 /* make sure our session can't expire */
671 gst_rtsp_session_prevent_expire (session);
675 unlink_stream (GstRTSPClient * client, GstRTSPSession * session,
676 GstRTSPSessionStream * stream)
678 GST_DEBUG ("client %p: unlinking stream %p", client, stream);
679 gst_rtsp_session_stream_set_callbacks (stream, NULL, NULL, NULL, NULL, NULL,
681 client->streams = g_list_remove (client->streams, stream);
682 /* our session can now expire */
683 gst_rtsp_session_allow_expire (session);
687 unlink_session_streams (GstRTSPClient * client, GstRTSPSession * session,
688 GstRTSPSessionMedia * media)
692 n_streams = gst_rtsp_media_n_streams (media->media);
693 for (i = 0; i < n_streams; i++) {
694 GstRTSPSessionStream *sstream;
695 GstRTSPTransport *tr;
697 /* get the stream as configured in the session */
698 sstream = gst_rtsp_session_media_get_stream (media, i);
699 /* get the transport, if there is no transport configured, skip this stream */
700 if (!(tr = sstream->trans.transport))
703 if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
704 /* for TCP, unlink the stream from the TCP connection of the client */
705 unlink_stream (client, session, sstream);
711 close_connection (GstRTSPClient * client)
713 const gchar *tunnelid;
715 GST_DEBUG ("client %p: closing connection", client);
717 if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) {
718 g_mutex_lock (tunnels_lock);
719 /* remove from tunnelids */
720 g_hash_table_remove (tunnels, tunnelid);
721 g_mutex_unlock (tunnels_lock);
724 gst_rtsp_connection_close (client->connection);
725 if (client->watchid) {
726 g_source_destroy ((GSource *) client->watch);
728 client->watch = NULL;
733 handle_teardown_request (GstRTSPClient * client, GstRTSPClientState * state)
735 GstRTSPSession *session;
736 GstRTSPSessionMedia *media;
737 GstRTSPStatusCode code;
742 session = state->session;
744 /* get a handle to the configuration of the media in the session */
745 media = gst_rtsp_session_get_media (session, state->uri);
749 state->sessmedia = media;
751 /* unlink the all TCP callbacks */
752 unlink_session_streams (client, session, media);
754 /* remove the session from the watched sessions */
755 g_object_weak_unref (G_OBJECT (session),
756 (GWeakNotify) client_session_finalized, client);
757 client->sessions = g_list_remove (client->sessions, session);
759 gst_rtsp_session_media_set_state (media, GST_STATE_PAUSED);
760 gst_rtsp_session_media_set_state (media, GST_STATE_NULL);
762 /* unmanage the media in the session, returns false if all media session
764 if (!gst_rtsp_session_release_media (session, media)) {
765 /* remove the session */
766 gst_rtsp_session_pool_remove (client->session_pool, session);
768 /* construct the response now */
769 code = GST_RTSP_STS_OK;
770 gst_rtsp_message_init_response (state->response, code,
771 gst_rtsp_status_as_text (code), state->request);
773 gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONNECTION,
776 send_response (client, session, state->response);
778 close_connection (client);
785 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state);
790 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
795 prepare_src_response (GstRTSPClient *client, GstRTSPMessage *response, GstRTSPMessage *request, GstRTSPMethod method, WFDMessageType message_type)
797 if(method == GST_RTSP_GET_PARAMETER) {
798 //gst_rtsp_message_init_response (response, GST_RTSP_STS_OK, gst_rtsp_status_as_text (GST_RTSP_STS_OK), request);
799 return GST_RTSP_EINVAL;
800 } else if(method == GST_RTSP_SET_PARAMETER) {
801 switch(message_type) {
808 gst_rtsp_message_init_response (response, GST_RTSP_STS_OK, gst_rtsp_status_as_text (GST_RTSP_STS_OK), request);
810 default: return GST_RTSP_EINVAL;
813 return GST_RTSP_EINVAL;
816 WFDMessageType get_rtsp_source_config_message_type(WFDMessage *msg, GstRTSPMethod message_type)
818 if(message_type == GST_RTSP_GET_PARAMETER) {
819 return WFD_MESSAGE_UNKNOWN;
820 } else if(message_type == GST_RTSP_SET_PARAMETER) {
821 if (msg->route) return WFD_MESSAGE_10;
822 else if (msg->connector_type) return WFD_MESSAGE_11;
823 else if (msg->standby) return WFD_MESSAGE_12;
824 else if (msg->idr_request) return WFD_MESSAGE_13;
825 else if (msg->uibc_capability) return WFD_MESSAGE_14;
826 else if (msg->uibc_setting) return WFD_MESSAGE_15;
827 else return WFD_MESSAGE_UNKNOWN;
829 return WFD_MESSAGE_UNKNOWN;
833 handle_get_param_request (GstRTSPClient * client, GstRTSPClientState * state)
838 WFDMessageType message_type;
840 res = gst_rtsp_message_get_body (state->request, &data, &size);
841 if (res != GST_RTSP_OK)
845 /* no body, keep-alive request */
846 send_generic_response (client, GST_RTSP_STS_OK, state);
849 wfdconfig_message_new(&msg);
850 wfdconfig_message_init(msg);
851 wfdconfig_message_parse_buffer(data,size,msg);
852 //GST_DEBUG("\nM3 response server side message body: %s\n\n\n", wfdconfig_message_as_text(msg));
853 message_type = get_rtsp_source_config_message_type (msg, GST_RTSP_GET_PARAMETER);
855 res = prepare_src_response(client, state->response, state->request, GST_RTSP_GET_PARAMETER, message_type);
856 if (res != GST_RTSP_OK) {
857 /* there is a body, handle the params */
858 res = gst_rtsp_params_get (client, state);
859 if (res != GST_RTSP_OK)
862 send_response (client, state->session, state->response);
869 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state);
874 static guint32 gIDRReqcount = 0;
876 handle_set_param_request (GstRTSPClient * client, GstRTSPClientState * state)
881 WFDMessageType message_type;
884 res = gst_rtsp_message_get_body (state->request, &data, &size);
885 if (res != GST_RTSP_OK)
889 /* no body, keep-alive request */
890 send_generic_response (client, GST_RTSP_STS_OK, state);
893 wfdconfig_message_new(&msg);
894 wfdconfig_message_init(msg);
895 wfdconfig_message_parse_buffer(data,size,msg);
896 //GST_DEBUG("\nM3 response server side message body: %s\n\n\n", wfdconfig_message_as_text(msg));
897 message_type = get_rtsp_source_config_message_type (msg, GST_RTSP_SET_PARAMETER);
898 switch (message_type) {
901 WFDSinkType sinktype;
902 confret = wfdconfig_get_audio_sink_type(msg, &sinktype);
903 if(confret == WFD_OK)
904 GST_DEBUG("M10 server set param request route to %s sink", sinktype?"SECONDARY":"PRIMARY");
909 WFDConnector connector;
910 confret = wfdconfig_get_connector_type(msg, &connector);
911 if(confret == WFD_OK)
912 GST_DEBUG("M11 server set param request connector type to %d", connector);
917 gboolean standby_enable;
918 confret = wfdconfig_get_standby(msg, &standby_enable);
919 if(confret == WFD_OK)
920 GST_DEBUG("M12 server set param request STANDBY %s", standby_enable?"ENABLE":"DISABLE");
925 GST_DEBUG("M13 server set param request for IDR frame");
926 g_object_set (client->srcbin->venc, "force-i-frame", 1, NULL);
932 guint32 input_category;
934 WFDHIDCTypePathPair *inp_pair;
935 guint32 inp_type_path_count = 0;
938 confret = wfdconfig_get_uibc_capability(msg, &input_category, &inp_type, inp_pair, &inp_type_path_count, &tcp_port);
939 if(confret == WFD_OK) {
940 GST_DEBUG("M14 server set param UIBC input category: %s %s", input_category&WFD_UIBC_INPUT_CAT_GENERIC?"GENERIC":"", input_category&WFD_UIBC_INPUT_CAT_HIDC?"HIDC":"");
941 GST_DEBUG("UIBC input type: %s %s %s %s %s %s %s %s", inp_type&WFD_UIBC_INPUT_TYPE_KEYBOARD?"KEYBOARD":"", inp_type&WFD_UIBC_INPUT_TYPE_MOUSE?"MOUSE":"",
942 inp_type&WFD_UIBC_INPUT_TYPE_SINGLETOUCH?"SINGLETOUCH":"", inp_type&WFD_UIBC_INPUT_TYPE_MULTITOUCH?"MULTITOUCH":"",
943 inp_type&WFD_UIBC_INPUT_TYPE_JOYSTICK?"JOYSTICK":"", inp_type&WFD_UIBC_INPUT_TYPE_CAMERA?"CAMERA":"",
944 inp_type&WFD_UIBC_INPUT_TYPE_GESTURE?"GESTURE":"", inp_type&WFD_UIBC_INPUT_TYPE_REMOTECONTROL?"REMOTECONTROL":"");
945 for(;i<inp_type_path_count;i++) {
946 GST_DEBUG("UIBC %d: %s%s%s%s%s%s%s%s %s%s%s%s%s%s", i, inp_pair[i].inp_type&WFD_UIBC_INPUT_TYPE_KEYBOARD?"KEYBOARD":"", inp_pair[i].inp_type&WFD_UIBC_INPUT_TYPE_MOUSE?"MOUSE":"",
947 inp_pair[i].inp_type&WFD_UIBC_INPUT_TYPE_SINGLETOUCH?"SINGLETOUCH":"", inp_pair[i].inp_type&WFD_UIBC_INPUT_TYPE_MULTITOUCH?"MULTITOUCH":"",
948 inp_pair[i].inp_type&WFD_UIBC_INPUT_TYPE_JOYSTICK?"JOYSTICK":"", inp_pair[i].inp_type&WFD_UIBC_INPUT_TYPE_CAMERA?"CAMERA":"",
949 inp_pair[i].inp_type&WFD_UIBC_INPUT_TYPE_GESTURE?"GESTURE":"", inp_pair[i].inp_type&WFD_UIBC_INPUT_TYPE_REMOTECONTROL?"REMOTECONTROL":"",
950 inp_pair[i].inp_path&WFD_UIBC_INPUT_PATH_INFRARED?"INFRARED":"", inp_pair[i].inp_path&WFD_UIBC_INPUT_PATH_USB?"USB":"",
951 inp_pair[i].inp_path&WFD_UIBC_INPUT_PATH_BT?"BT":"", inp_pair[i].inp_path&WFD_UIBC_INPUT_PATH_ZIGBEE?"ZIGBEE":"",
952 inp_pair[i].inp_path&WFD_UIBC_INPUT_PATH_WIFI?"WIFI":"", inp_pair[i].inp_path&WFD_UIBC_INPUT_PATH_NOSP?"NOSP":"");
959 gboolean uibc_enable;
960 confret = wfdconfig_get_uibc_status(msg, &uibc_enable);
961 if(confret == WFD_OK)
962 GST_DEBUG("M15 server set param request for UIBC %s", uibc_enable?"ENABLE":"DISABLE");
967 GST_ERROR_OBJECT (client, "Not handling message num - %d", message_type);
972 res = prepare_src_response(client, state->response, state->request, GST_RTSP_SET_PARAMETER, message_type);
973 if (res != GST_RTSP_OK) {
974 /* there is a body, handle the params */
975 res = gst_rtsp_params_set (client, state);
976 if (res != GST_RTSP_OK)
979 send_response (client, state->session, state->response);
987 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state);
993 handle_pause_request (GstRTSPClient * client, GstRTSPClientState * state)
995 GstRTSPSession *session;
996 GstRTSPSessionMedia *media;
997 GstRTSPStatusCode code;
999 if (!(session = state->session))
1002 /* get a handle to the configuration of the media in the session */
1003 media = gst_rtsp_session_get_media (session, state->uri);
1007 state->sessmedia = media;
1009 /* the session state must be playing or recording */
1010 if (media->state != GST_RTSP_STATE_PLAYING &&
1011 media->state != GST_RTSP_STATE_RECORDING)
1014 /* unlink the all TCP callbacks */
1015 unlink_session_streams (client, session, media);
1017 /* then pause sending */
1018 gst_rtsp_session_media_set_state (media, GST_STATE_PAUSED);
1020 /* construct the response now */
1021 code = GST_RTSP_STS_OK;
1022 gst_rtsp_message_init_response (state->response, code,
1023 gst_rtsp_status_as_text (code), state->request);
1025 send_response (client, session, state->response);
1027 /* the state is now READY */
1028 media->state = GST_RTSP_STATE_READY;
1035 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state);
1040 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
1045 send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
1052 handle_play_request (GstRTSPClient * client, GstRTSPClientState * state)
1054 GstRTSPSession *session;
1055 GstRTSPSessionMedia *media;
1056 GstRTSPStatusCode code;
1058 guint n_streams, i, infocount;
1059 guint timestamp, seqnum;
1061 GstRTSPTimeRange *range;
1064 if (!(session = state->session))
1067 /* get a handle to the configuration of the media in the session */
1068 media = gst_rtsp_session_get_media (session, state->uri);
1072 state->sessmedia = media;
1074 /* the session state must be playing or ready */
1075 if (media->state != GST_RTSP_STATE_PLAYING &&
1076 media->state != GST_RTSP_STATE_READY)
1079 /* parse the range header if we have one */
1081 gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_RANGE, &str, 0);
1082 if (res == GST_RTSP_OK) {
1083 if (gst_rtsp_range_parse (str, &range) == GST_RTSP_OK) {
1084 /* we have a range, seek to the position */
1085 gst_rtsp_media_seek (media->media, range);
1086 gst_rtsp_range_free (range);
1090 /* grab RTPInfo from the payloaders now */
1091 rtpinfo = g_string_new ("");
1093 n_streams = gst_rtsp_media_n_streams (media->media);
1094 for (i = 0, infocount = 0; i < n_streams; i++) {
1095 GstRTSPSessionStream *sstream;
1096 GstRTSPMediaStream *stream;
1097 GstRTSPTransport *tr;
1098 GObjectClass *payobjclass;
1101 /* get the stream as configured in the session */
1102 sstream = gst_rtsp_session_media_get_stream (media, i);
1103 /* get the transport, if there is no transport configured, skip this stream */
1104 if (!(tr = sstream->trans.transport)) {
1105 GST_INFO ("stream %d is not configured", i);
1109 if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
1110 /* for TCP, link the stream to the TCP connection of the client */
1111 link_stream (client, session, sstream);
1114 stream = sstream->media_stream;
1116 payobjclass = G_OBJECT_GET_CLASS (stream->payloader);
1118 if (g_object_class_find_property (payobjclass, "seqnum") &&
1119 g_object_class_find_property (payobjclass, "timestamp")) {
1122 payobj = G_OBJECT (stream->payloader);
1124 /* only add RTP-Info for streams with seqnum and timestamp */
1125 g_object_get (payobj, "seqnum", &seqnum, "timestamp", ×tamp, NULL);
1128 g_string_append (rtpinfo, ", ");
1130 uristr = gst_rtsp_url_get_request_uri (state->uri);
1131 g_string_append_printf (rtpinfo, "url=%s;seq=%u;rtptime=%u",
1132 uristr,seqnum, timestamp);
1137 GST_WARNING ("RTP-Info cannot be determined for stream %d", i);
1141 /* construct the response now */
1142 code = GST_RTSP_STS_OK;
1143 gst_rtsp_message_init_response (state->response, code,
1144 gst_rtsp_status_as_text (code), state->request);
1145 send_response (client, NULL, state->response);
1147 /* start playing after sending the request */
1148 GST_INFO("set media to GST_STATE_PLAYING");
1149 gst_rtsp_session_media_set_state (media, GST_STATE_PLAYING);
1151 media->state = GST_RTSP_STATE_PLAYING;
1158 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, state);
1163 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
1168 send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
1175 do_keepalive (GstRTSPSession * session)
1177 GST_INFO ("keep session %p alive", session);
1178 gst_rtsp_session_touch (session);
1182 handle_setup_request (GstRTSPClient * client, GstRTSPClientState * state)
1187 gchar *user_agent; //Changes for testing with dongle
1189 gboolean have_transport;
1190 GstRTSPTransport *ct, *st;
1192 GstRTSPLowerTrans supported;
1193 GstRTSPStatusCode code;
1194 GstRTSPSession *session;
1195 GstRTSPSessionStream *stream;
1196 gchar *trans_str, *pos;
1198 GstRTSPSessionMedia *media;
1203 /* the uri contains the stream number we added in the SDP config, which is
1204 * always /stream=%d so we need to strip that off
1205 * parse the stream we need to configure, look for the stream in the abspath
1206 * first and then in the query. */
1207 if (uri->abspath == NULL || !(pos = strstr (uri->abspath, "/streamid="))) {
1208 if (uri->query == NULL || !(pos = strstr (uri->query, "/streamid=")))
1210 GST_ERROR ("bad request...");
1215 /* we can mofify the parse uri in place */
1218 pos += strlen ("/streamid=");
1219 if (sscanf (pos, "%u", &streamid) != 1)
1222 res = gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_USER_AGENT,
1223 &user_agent, 0); //Changes for testing with dongle
1225 /* parse the transport */
1227 gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_TRANSPORT,
1229 if (res != GST_RTSP_OK)
1232 transports = g_strsplit (transport, ",", 0);
1233 gst_rtsp_transport_new (&ct);
1235 /* init transports */
1236 have_transport = FALSE;
1237 gst_rtsp_transport_init (ct);
1239 /* our supported transports */
1240 supported = GST_RTSP_LOWER_TRANS_UDP |
1241 GST_RTSP_LOWER_TRANS_UDP_MCAST | GST_RTSP_LOWER_TRANS_TCP;
1243 /* loop through the transports, try to parse */
1244 for (i = 0; transports[i]; i++) {
1245 res = gst_rtsp_transport_parse (transports[i], ct);
1246 if (res != GST_RTSP_OK) {
1247 /* no valid transport, search some more */
1248 GST_WARNING ("could not parse transport %s", transports[i]);
1252 /* we have a transport, see if it's RTP/AVP */
1253 if (ct->trans != GST_RTSP_TRANS_RTP || ct->profile != GST_RTSP_PROFILE_AVP) {
1254 GST_WARNING ("invalid transport %s", transports[i]);
1258 if (!(ct->lower_transport & supported)) {
1259 GST_WARNING ("unsupported transport %s", transports[i]);
1263 /* we have a valid transport */
1264 GST_INFO ("found valid transport %s", transports[i]);
1265 have_transport = TRUE;
1269 gst_rtsp_transport_init (ct);
1271 g_strfreev (transports);
1273 /* we have not found anything usable, error out */
1274 if (!have_transport)
1275 goto unsupported_transports;
1277 if (client->session_pool == NULL)
1280 /* we have a valid transport now, set the destination of the client. */
1281 g_free (ct->destination);
1282 if (ct->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST) {
1283 ct->destination = g_strdup (MCAST_ADDRESS);
1284 ct->port.min = client->crtp_port0; //Changes for testing with dongle
1285 ct->port.max = -1; //Changes for testing with dongle
1287 url = gst_rtsp_connection_get_url (client->connection);
1288 ct->destination = g_strdup (url->host);
1289 ct->client_port.min = client->crtp_port0; //Changes for testing with dongle
1290 ct->client_port.max = -1; //Changes for testing with dongle
1293 session = state->session;
1296 g_object_ref (session);
1297 /* get a handle to the configuration of the media in the session, this can
1298 * return NULL if this is a new url to manage in this session. */
1299 media = gst_rtsp_session_get_media (session, uri);
1301 /* create a session if this fails we probably reached our session limit or
1303 if (!(session = gst_rtsp_session_pool_create (client->session_pool)))
1304 goto service_unavailable;
1305 session->timeout = DEFAULT_RTSP_TIMEOUT;
1306 state->session = session;
1307 client->sessionid = g_strdup(session->sessionid);
1308 /* we need a new media configuration in this session */
1312 /* we have no media, find one and manage it */
1313 if (media == NULL) {
1316 // TODO: need to decide on arguments...
1317 gst_rtsp_client_create_srcbin (client);
1318 if (NULL == client->srcbin) {
1319 GST_ERROR_OBJECT (client, "Failed to create src bin...");
1323 /* get a handle to the configuration of the media in the session */
1324 if ((m = find_media (client, state))) {
1325 /* manage the media in our session now */
1326 media = gst_rtsp_session_manage_media (session, uri, m);
1330 /* if we stil have no media, error */
1334 state->sessmedia = media;
1336 /* fix the transports */
1337 if (ct->lower_transport & GST_RTSP_LOWER_TRANS_TCP) {
1338 /* check if the client selected channels for TCP */
1339 if (ct->interleaved.min == -1 || ct->interleaved.max == -1) {
1340 gst_rtsp_session_media_alloc_channels (media, &ct->interleaved);
1344 /* get a handle to the stream in the media */
1345 if (!(stream = gst_rtsp_session_media_get_stream (media, streamid)))
1348 st = gst_rtsp_session_stream_set_transport (stream, ct);
1350 /* configure keepalive for this transport */
1351 gst_rtsp_session_stream_set_keepalive (stream,
1352 (GstRTSPKeepAliveFunc) do_keepalive, session, NULL);
1354 /* serialize the server transport */
1355 trans_str = gst_rtsp_transport_as_text (st);
1356 gst_rtsp_transport_free (st);
1358 /* construct the response now */
1359 code = GST_RTSP_STS_OK;
1360 gst_rtsp_message_init_response (state->response, code,
1361 gst_rtsp_status_as_text (code), state->request);
1363 gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_TRANSPORT,
1367 GST_ERROR ("user agent %s", user_agent);
1369 gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_USER_AGENT, user_agent);
1370 g_free (user_agent);
1371 }*/ //Changes for testing with dongle
1372 //gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONTENT_TYPE, "text/parameters");
1373 //textparam = g_strdup ("wfd_presentation_URL: rtsp://192.168.16.1/wfd1.0/streamid=0 none");
1374 //gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONTENT_LENGTH, g_strdup_printf ("%d",strlen(textparam)));
1375 /* adding data field */
1376 //gst_rtsp_message_set_body (state->response, textparam, strlen(textparam));
1378 send_response (client, session, state->response);
1380 /* update the state */
1381 switch (media->state) {
1382 case GST_RTSP_STATE_PLAYING:
1383 case GST_RTSP_STATE_RECORDING:
1384 case GST_RTSP_STATE_READY:
1385 /* no state change */
1388 media->state = GST_RTSP_STATE_READY;
1391 g_object_unref (session);
1398 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, state);
1403 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
1404 g_object_unref (session);
1409 send_generic_response (client, GST_RTSP_STS_NOT_FOUND, state);
1410 g_object_unref (media);
1411 g_object_unref (session);
1416 send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state);
1419 unsupported_transports:
1421 send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_TRANSPORT, state);
1422 gst_rtsp_transport_free (ct);
1427 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
1430 service_unavailable:
1432 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
1437 static GstSDPMessage *
1438 create_sdp (GstRTSPClient * client, GstRTSPMedia * media)
1444 gst_sdp_message_new (&sdp);
1446 /* some standard things first */
1447 gst_sdp_message_set_version (sdp, "0");
1449 if (client->is_ipv6)
1454 gst_sdp_message_set_origin (sdp, "-", "1188340656180883", "1", "IN", proto,
1457 gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer");
1458 gst_sdp_message_set_information (sdp, "rtsp-server");
1459 gst_sdp_message_add_time (sdp, "0", "0", NULL);
1460 gst_sdp_message_add_attribute (sdp, "tool", "GStreamer");
1461 gst_sdp_message_add_attribute (sdp, "type", "broadcast");
1462 gst_sdp_message_add_attribute (sdp, "control", "*");
1464 info.server_proto = proto;
1465 if (media->protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST)
1466 info.server_ip = MCAST_ADDRESS;
1468 info.server_ip = client->server_ip;
1470 /* create an SDP for the media object */
1471 if (!gst_rtsp_sdp_from_media (sdp, &info, media))
1479 gst_sdp_message_free (sdp);
1484 /* for the describe we must generate an SDP */
1486 handle_describe_request (GstRTSPClient * client, GstRTSPClientState * state)
1491 gchar *str, *content_base;
1492 GstRTSPMedia *media;
1494 /* check what kind of format is accepted, we don't really do anything with it
1495 * and always return SDP for now. */
1499 gst_rtsp_message_get_header (state->request, GST_RTSP_HDR_ACCEPT,
1501 if (res == GST_RTSP_ENOTIMPL)
1504 if (g_ascii_strcasecmp (accept, "application/sdp") == 0)
1508 /* find the media object for the uri */
1509 if (!(media = find_media (client, state)))
1512 /* create an SDP for the media object on this client */
1513 if (!(sdp = create_sdp (client, media)))
1516 g_object_unref (media);
1518 gst_rtsp_message_init_response (state->response, GST_RTSP_STS_OK,
1519 gst_rtsp_status_as_text (GST_RTSP_STS_OK), state->request);
1521 gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONTENT_TYPE,
1524 /* content base for some clients that might screw up creating the setup uri */
1525 str = gst_rtsp_url_get_request_uri (state->uri);
1526 str_len = strlen (str);
1528 /* check for trailing '/' and append one */
1529 if (str[str_len - 1] != '/') {
1530 content_base = g_malloc (str_len + 2);
1531 memcpy (content_base, str, str_len);
1532 content_base[str_len] = '/';
1533 content_base[str_len + 1] = '\0';
1539 GST_INFO ("adding content-base: %s", content_base);
1541 gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_CONTENT_BASE,
1543 g_free (content_base);
1545 /* add SDP to the response body */
1546 str = gst_sdp_message_as_text (sdp);
1547 gst_rtsp_message_take_body (state->response, (guint8 *) str, strlen (str));
1548 gst_sdp_message_free (sdp);
1550 send_response (client, state->session, state->response);
1557 /* error reply is already sent */
1562 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, state);
1563 g_object_unref (media);
1569 handle_options_request (GstRTSPClient * client, GstRTSPClientState * state)
1571 GstRTSPMethod options;
1573 GstRTSPMessage request = { 0 };
1574 GstRTSPMessage response = { 0 };
1575 GstRTSPResult res = GST_RTSP_OK;
1576 GstRTSPUrl *url = NULL;
1577 gchar *url_str = NULL;
1578 WFDMessage *msg3res;
1579 WFDAudioFormats caCodec = WFD_AUDIO_UNKNOWN;
1580 WFDAudioFreq cFreq = WFD_FREQ_UNKNOWN;
1581 WFDAudioChannels cChanels = WFD_CHANNEL_UNKNOWN;
1582 guint cBitwidth = 0;
1583 guint caLatency = 0;
1584 WFDVideoCodecs cvCodec = WFD_VIDEO_UNKNOWN;
1585 WFDVideoNativeResolution cNative = WFD_VIDEO_CEA_RESOLUTION;
1586 guint64 cNativeResolution = 0;
1587 WFDVideoCEAResolution cCEAResolution = WFD_CEA_UNKNOWN;
1588 WFDVideoVESAResolution cVESAResolution = WFD_VESA_UNKNOWN;
1589 WFDVideoHHResolution cHHResolution = WFD_HH_UNKNOWN;
1590 WFDVideoH264Profile cProfile = WFD_H264_UNKNOWN_PROFILE;
1591 WFDVideoH264Level cLevel = WFD_H264_LEVEL_UNKNOWN;
1592 guint32 cMaxHeight = 0;
1593 guint32 cMaxWidth = 0;
1594 guint32 cmin_slice_size = 0;
1595 guint32 cslice_enc_params = 0;
1596 guint cframe_rate_control = 0;
1597 guint cvLatency = 0;
1598 WFDRTSPTransMode ctrans = WFD_RTSP_TRANS_UNKNOWN;
1599 WFDRTSPProfile cprofile = WFD_RTSP_PROFILE_UNKNOWN;
1600 WFDRTSPLowerTrans clowertrans = WFD_RTSP_LOWER_TRANS_UNKNOWN;
1601 guint32 crtp_port0 = 0;
1602 guint32 crtp_port1 = 0;
1605 options = GST_RTSP_OPTIONS |
1609 GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
1611 str = gst_rtsp_options_as_text (options);
1613 /*append WFD specific method */
1614 //g_string_append (str, "org.wfa.wfd1.0, ");
1615 tmp = g_strdup (", org.wfa.wfd1.0");
1616 g_strlcat (str, tmp, strlen (tmp) + strlen (str) + 1);
1618 gst_rtsp_message_init_response (state->response, GST_RTSP_STS_OK,
1619 gst_rtsp_status_as_text (GST_RTSP_STS_OK), state->request);
1621 gst_rtsp_message_add_header (state->response, GST_RTSP_HDR_PUBLIC, str);
1624 send_response (client, state->session, state->response);
1626 GST_DEBUG_OBJECT (client, "Sent OPTIONS Response...");
1628 ////////////////////////////////////
1629 //// GET_PARAMETER Msg (M3) /////
1630 ///////////////////////////////////
1632 url = gst_rtsp_connection_get_url (client->connection);
1633 url_str = gst_rtsp_url_get_request_uri (url);
1635 res = gst_rtsp_message_init_request (&request, GST_RTSP_GET_PARAMETER, url_str);
1637 goto create_request_failed;
1639 /* add content type */
1640 gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CONTENT_TYPE, "text/parameters");
1647 wfdconfig_message_new(&msg3);
1648 wfdconfig_message_init(msg3);
1649 wfdconfig_set_supported_audio_format(msg3, WFD_AUDIO_UNKNOWN, WFD_FREQ_UNKNOWN,WFD_CHANNEL_UNKNOWN, 0, 0);
1650 wfdconfig_set_supported_video_format(msg3, WFD_VIDEO_UNKNOWN, WFD_VIDEO_CEA_RESOLUTION, WFD_CEA_UNKNOWN,
1651 WFD_CEA_UNKNOWN, WFD_VESA_UNKNOWN,WFD_HH_UNKNOWN, WFD_H264_UNKNOWN_PROFILE,
1652 WFD_H264_LEVEL_UNKNOWN,0,0, 0, 0, 0, 0);
1653 wfdconfig_set_prefered_RTP_ports(msg3, WFD_RTSP_TRANS_UNKNOWN, WFD_RTSP_PROFILE_UNKNOWN,
1654 WFD_RTSP_LOWER_TRANS_UNKNOWN, 0, 0);
1656 g_print("===================================M3 Message server side============================\n");
1657 wfdconfig_message_dump(msg3);
1658 g_print("=====================================================================================\n");
1659 msg = wfdconfig_message_as_text(msg3);
1660 msglen = strlen(msg);
1661 msglength = g_string_new ("");
1662 g_string_append_printf (msglength,"%d",msglen);
1663 GST_DEBUG("M3 server side message body: %s\n\n\n", msg);
1664 /* add content-length type */
1665 gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CONTENT_LENGTH, g_string_free (msglength, FALSE));
1666 /* adding data field */
1667 gst_rtsp_message_set_body (&request, (guint8*)msg, msglen);
1669 wfdconfig_message_free(msg3);
1672 GST_DEBUG ("send GET_PARAM (M3)...");
1674 // TODO: need to add session i.e. 2nd variable
1675 send_request (client, NULL, &request);
1677 res = gst_rtsp_connection_receive (client->connection, &response, NULL);
1678 if (GST_RTSP_OK != res) {
1682 if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
1683 gst_rtsp_message_dump (&response);
1689 gst_rtsp_message_get_body (&response, (guint8**)&data, &size);
1691 wfdconfig_message_new(&msg3res);
1692 wfdconfig_message_init(msg3res);
1693 wfdconfig_message_parse_buffer((guint8*)data,size,msg3res);
1694 GST_DEBUG("\nM3 response server side message body: %s\n\n\n", wfdconfig_message_as_text(msg3res));
1696 wfdconfig_get_supported_audio_format(msg3res, &caCodec, &cFreq, &cChanels, &cBitwidth, &caLatency);
1697 wfdconfig_get_supported_video_format(msg3res, &cvCodec, &cNative, &cNativeResolution,
1698 (guint64 *)&cCEAResolution, (guint64 *)&cVESAResolution, (guint64 *)&cHHResolution,
1699 &cProfile, &cLevel, &cvLatency, &cMaxHeight,
1700 &cMaxWidth, &cmin_slice_size, &cslice_enc_params, &cframe_rate_control);
1701 wfdconfig_get_prefered_RTP_ports(msg3res, &ctrans, &cprofile, &clowertrans, &crtp_port0, &crtp_port1);
1702 g_print("==============================M3 response Message server side========================\n");
1703 wfdconfig_message_dump(msg3res);
1704 g_print("=====================================================================================\n");
1707 ////////////////////////////////////
1708 //// SET_PARAMETER Msg (M4) /////
1709 ///////////////////////////////////
1711 memset (&request, 0x00, sizeof (GstRTSPMessage));
1712 memset (&response, 0x00, sizeof (GstRTSPMessage));
1714 res = gst_rtsp_message_init_request (&request, GST_RTSP_SET_PARAMETER, url_str);
1716 goto create_request_failed;
1717 GST_DEBUG("\nM4 message body server side url : %s\n\n\n", url_str);
1718 /* add content type */
1719 gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CONTENT_TYPE, "text/parameters");
1727 wfdconfig_message_new(&msg4);
1728 wfdconfig_message_init(msg4);
1729 wfdconfig_set_prefered_audio_format(msg4, WFD_AUDIO_AAC, WFD_FREQ_48000, WFD_CHANNEL_2, cBitwidth, caLatency);
1730 wfdconfig_set_prefered_video_format(msg4, WFD_VIDEO_H264,WFD_VIDEO_CEA_RESOLUTION, WFD_CEA_1280x720P30,
1731 WFD_CEA_1280x720P30, WFD_VESA_1280x768P30,WFD_HH_960x540P30, WFD_H264_BASE_PROFILE,
1732 WFD_H264_LEVEL_4, cvLatency, cMaxHeight,cMaxWidth, cmin_slice_size, cslice_enc_params, cframe_rate_control);
1733 wfdconfig_set_prefered_RTP_ports(msg4, WFD_RTSP_TRANS_RTP, WFD_RTSP_PROFILE_AVP, WFD_RTSP_LOWER_TRANS_UDP, crtp_port0, crtp_port1);
1734 g_print("==================================M4 Message server side=============================\n");
1735 wfdconfig_message_dump(msg4);
1736 g_print("=====================================================================================\n");
1737 msg = wfdconfig_message_as_text(msg4);
1738 msglen = strlen(msg);
1739 msglength = g_string_new ("");
1740 g_string_append_printf (msglength,"%d",msglen);
1741 GST_DEBUG("\nM4 message body server side : %s\n\n\n", msg);
1742 /* add content-length type */
1743 gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CONTENT_LENGTH, g_string_free (msglength, FALSE));
1744 /* adding data field */
1745 gst_rtsp_message_set_body (&request, (guint8*)msg, msglen);
1747 wfdconfig_message_free(msg4);
1750 GST_DEBUG ("send SET_PARAM (M4)...");
1752 // TODO: need to add session i.e. 2nd variable
1753 send_request (client, NULL, &request);
1755 res = gst_rtsp_connection_receive (client->connection, &response, NULL);
1756 if (GST_RTSP_OK != res) {
1760 if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
1761 gst_rtsp_message_dump (&response);
1766 create_request_failed:
1767 GST_ERROR_OBJECT (client, "Failed to create server request...reason : %d", res);
1771 GST_ERROR_OBJECT (client, "Failed to receive response .....reason: %d", res);
1775 /* remove duplicate and trailing '/' */
1777 sanitize_uri (GstRTSPUrl * uri)
1781 gboolean have_slash, prev_slash;
1783 s = d = uri->abspath;
1784 len = strlen (uri->abspath);
1788 for (i = 0; i < len; i++) {
1789 have_slash = s[i] == '/';
1791 if (!have_slash || !prev_slash)
1793 prev_slash = have_slash;
1795 len = d - uri->abspath;
1796 /* don't remove the first slash if that's the only thing left */
1797 if (len > 1 && *(d - 1) == '/')
1803 client_session_finalized (GstRTSPClient * client, GstRTSPSession * session)
1805 GST_INFO ("client %p: session %p finished", client, session);
1807 /* unlink all media managed in this session */
1808 client_unlink_session (client, session);
1810 /* remove the session */
1811 if (!(client->sessions = g_list_remove (client->sessions, session))) {
1812 GST_INFO ("client %p: all sessions finalized, close the connection",
1814 close_connection (client);
1819 client_watch_session (GstRTSPClient * client, GstRTSPSession * session)
1823 for (walk = client->sessions; walk; walk = g_list_next (walk)) {
1824 GstRTSPSession *msession = (GstRTSPSession *) walk->data;
1826 /* we already know about this session */
1827 if (msession == session)
1831 GST_INFO ("watching session %p", session);
1833 g_object_weak_ref (G_OBJECT (session), (GWeakNotify) client_session_finalized,
1835 client->sessions = g_list_prepend (client->sessions, session);
1839 handle_request (GstRTSPClient * client, GstRTSPMessage * request)
1841 GstRTSPMethod method;
1842 const gchar *uristr;
1844 GstRTSPVersion version;
1846 GstRTSPSession *session;
1847 GstRTSPClientState state = { NULL };
1848 GstRTSPMessage response = { 0 };
1851 state.request = request;
1852 state.response = &response;
1854 if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
1855 gst_rtsp_message_dump (request);
1858 GST_INFO ("client %p: received a request", client);
1860 gst_rtsp_message_parse_request (request, &method, &uristr, &version);
1862 if (version != GST_RTSP_VERSION_1_0) {
1863 /* we can only handle 1.0 requests */
1864 send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
1868 state.method = method;
1870 /* we always try to parse the url first */
1871 if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) {
1872 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &state);
1876 /* sanitize the uri */
1880 GST_DEBUG ("state -> URI = %s", uri->abspath);
1882 /* get the session if there is any */
1883 res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &sessid, 0);
1884 if (res == GST_RTSP_OK) {
1885 if (client->session_pool == NULL)
1888 /* we had a session in the request, find it again */
1889 if (!(session = gst_rtsp_session_pool_find (client->session_pool, sessid)))
1890 goto session_not_found;
1892 GST_DEBUG ("sessid = %s", sessid);
1894 /* we add the session to the client list of watched sessions. When a session
1895 * disappears because it times out, we will be notified. If all sessions are
1896 * gone, we will close the connection */
1897 client_watch_session (client, session);
1898 if(client->sessionID) g_free(client->sessionID);
1899 client->sessionID = g_strdup(sessid);
1900 } else if(method == GST_RTSP_SET_PARAMETER){
1901 if (client->session_pool == NULL)
1903 if (!(session = gst_rtsp_session_pool_find (client->session_pool, client->sessionID)))
1904 goto session_not_found;
1905 GST_DEBUG ("sessid = %s", client->sessionID);
1906 client_watch_session (client, session);
1908 else session = NULL;
1910 GST_DEBUG ("session = %p", session);
1911 state.session = session;
1915 GstRTSPSessionMedia *temp = session->medias->data;
1916 temp->url->abspath = g_strdup(uri->abspath);
1920 if (!gst_rtsp_auth_check (client->auth, client, 0, &state))
1921 goto not_authorized;
1924 GST_INFO ("Method = %d", method);
1926 /* now see what is asked and dispatch to a dedicated handler */
1928 case GST_RTSP_OPTIONS:
1929 //handle_options_request (client, &state);
1931 case GST_RTSP_DESCRIBE:
1932 handle_describe_request (client, &state);
1934 case GST_RTSP_SETUP:
1935 handle_setup_request (client, &state);
1938 handle_play_request (client, &state);
1939 g_timeout_add((DEFAULT_RTSP_TIMEOUT - 5)*1000, keep_alive_condition, client);
1941 case GST_RTSP_PAUSE:
1942 handle_pause_request (client, &state);
1944 case GST_RTSP_TEARDOWN:
1945 handle_teardown_request (client, &state);
1947 case GST_RTSP_SET_PARAMETER:
1948 handle_set_param_request (client, &state);
1950 case GST_RTSP_GET_PARAMETER:
1951 handle_get_param_request (client, &state);
1953 case GST_RTSP_ANNOUNCE:
1954 case GST_RTSP_RECORD:
1955 case GST_RTSP_REDIRECT:
1956 send_generic_response (client, GST_RTSP_STS_NOT_IMPLEMENTED, &state);
1958 case GST_RTSP_INVALID:
1960 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &state);
1964 g_object_unref (session);
1966 gst_rtsp_url_free (uri);
1972 send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, &state);
1977 send_generic_response (client, GST_RTSP_STS_SESSION_NOT_FOUND, &state);
1982 handle_unauthorized_request (client, client->auth, &state);
1988 handle_data (GstRTSPClient * client, GstRTSPMessage * message)
1998 /* find the stream for this message */
1999 res = gst_rtsp_message_parse_data (message, &channel);
2000 if (res != GST_RTSP_OK)
2003 gst_rtsp_message_steal_body (message, &data, &size);
2005 buffer = gst_buffer_new ();
2006 gst_buffer_insert_memory(buffer, -1, gst_memory_new_wrapped(0, data, size, 0, size, data, g_free));
2009 for (walk = client->streams; walk; walk = g_list_next (walk)) {
2010 GstRTSPSessionStream *stream = (GstRTSPSessionStream *) walk->data;
2011 GstRTSPMediaStream *mstream;
2012 GstRTSPTransport *tr;
2014 /* get the transport, if there is no transport configured, skip this stream */
2015 if (!(tr = stream->trans.transport))
2018 /* we also need a media stream */
2019 if (!(mstream = stream->media_stream))
2022 /* check for TCP transport */
2023 if (tr->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
2024 GST_INFO ("Transport is GST_RTSP_LOWER_TRANS_TCP");
2025 /* dispatch to the stream based on the port number */
2026 if (client->crtp_port0) {
2027 gst_rtsp_media_stream_rtp (mstream, buffer);
2030 } else if (client->crtp_port1) {
2031 gst_rtsp_media_stream_rtcp (mstream, buffer);
2038 gst_buffer_unref (buffer);
2042 * gst_rtsp_client_set_session_pool:
2043 * @client: a #GstRTSPClient
2044 * @pool: a #GstRTSPSessionPool
2046 * Set @pool as the sessionpool for @client which it will use to find
2047 * or allocate sessions. the sessionpool is usually inherited from the server
2048 * that created the client but can be overridden later.
2051 gst_rtsp_client_set_session_pool (GstRTSPClient * client,
2052 GstRTSPSessionPool * pool)
2054 GstRTSPSessionPool *old;
2056 old = client->session_pool;
2059 g_object_ref (pool);
2060 client->session_pool = pool;
2062 g_object_unref (old);
2067 * gst_rtsp_client_get_session_pool:
2068 * @client: a #GstRTSPClient
2070 * Get the #GstRTSPSessionPool object that @client uses to manage its sessions.
2072 * Returns: a #GstRTSPSessionPool, unref after usage.
2074 GstRTSPSessionPool *
2075 gst_rtsp_client_get_session_pool (GstRTSPClient * client)
2077 GstRTSPSessionPool *result;
2079 if ((result = client->session_pool))
2080 g_object_ref (result);
2086 * gst_rtsp_client_set_server:
2087 * @client: a #GstRTSPClient
2088 * @server: a #GstRTSPServer
2090 * Set @server as the server that created @client.
2093 gst_rtsp_client_set_server (GstRTSPClient * client, GstRTSPServer * server)
2097 old = client->server;
2098 if (old != server) {
2100 g_object_ref (server);
2101 client->server = server;
2103 g_object_unref (old);
2108 * gst_rtsp_client_get_server:
2109 * @client: a #GstRTSPClient
2111 * Get the #GstRTSPServer object that @client was created from.
2113 * Returns: a #GstRTSPServer, unref after usage.
2116 gst_rtsp_client_get_server (GstRTSPClient * client)
2118 GstRTSPServer *result;
2120 if ((result = client->server))
2121 g_object_ref (result);
2127 * gst_rtsp_client_set_media_mapping:
2128 * @client: a #GstRTSPClient
2129 * @mapping: a #GstRTSPMediaMapping
2131 * Set @mapping as the media mapping for @client which it will use to map urls
2132 * to media streams. These mapping is usually inherited from the server that
2133 * created the client but can be overriden later.
2136 gst_rtsp_client_set_media_mapping (GstRTSPClient * client,
2137 GstRTSPMediaMapping * mapping)
2139 GstRTSPMediaMapping *old;
2141 old = client->media_mapping;
2143 if (old != mapping) {
2145 g_object_ref (mapping);
2146 client->media_mapping = mapping;
2148 g_object_unref (old);
2153 * gst_rtsp_client_get_media_mapping:
2154 * @client: a #GstRTSPClient
2156 * Get the #GstRTSPMediaMapping object that @client uses to manage its sessions.
2158 * Returns: a #GstRTSPMediaMapping, unref after usage.
2160 GstRTSPMediaMapping *
2161 gst_rtsp_client_get_media_mapping (GstRTSPClient * client)
2163 GstRTSPMediaMapping *result;
2165 if ((result = client->media_mapping))
2166 g_object_ref (result);
2172 * gst_rtsp_client_set_auth:
2173 * @client: a #GstRTSPClient
2174 * @auth: a #GstRTSPAuth
2176 * configure @auth to be used as the authentication manager of @client.
2179 gst_rtsp_client_set_auth (GstRTSPClient * client, GstRTSPAuth * auth)
2183 g_return_if_fail (GST_IS_RTSP_CLIENT (client));
2189 g_object_ref (auth);
2190 client->auth = auth;
2192 g_object_unref (old);
2198 * gst_rtsp_client_get_auth:
2199 * @client: a #GstRTSPClient
2201 * Get the #GstRTSPAuth used as the authentication manager of @client.
2203 * Returns: the #GstRTSPAuth of @client. g_object_unref() after
2207 gst_rtsp_client_get_auth (GstRTSPClient * client)
2209 GstRTSPAuth *result;
2211 g_return_val_if_fail (GST_IS_RTSP_CLIENT (client), NULL);
2213 if ((result = client->auth))
2214 g_object_ref (result);
2219 static GstRTSPResult
2220 message_received (GstRTSPWatch * watch, GstRTSPMessage * message,
2223 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2225 GST_INFO_OBJECT (client, "revd message method = %s",
2226 message->type == GST_RTSP_MESSAGE_REQUEST ? "request" :
2227 message->type == GST_RTSP_MESSAGE_RESPONSE ? "reponse" : "data/unknown");
2228 switch (message->type) {
2229 case GST_RTSP_MESSAGE_REQUEST:
2230 handle_request (client, message);
2232 case GST_RTSP_MESSAGE_RESPONSE:
2234 GstRTSPStatusCode code;
2235 const gchar *uristr;
2236 GstRTSPVersion version;
2238 gst_rtsp_message_parse_response (message, &code, &uristr, &version);
2239 GST_INFO_OBJECT (client, "revd message method = %d", code);
2240 g_mutex_lock(client->keep_alive_lock);
2241 client->keep_alive_flag = TRUE;
2242 g_mutex_unlock(client->keep_alive_lock);
2245 case GST_RTSP_MESSAGE_DATA:
2246 handle_data (client, message);
2254 static GstRTSPResult
2255 message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data)
2257 GstRTSPClient *client;
2259 client = GST_RTSP_CLIENT (user_data);
2264 static GstRTSPResult
2265 closed (GstRTSPWatch * watch, gpointer user_data)
2267 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2268 const gchar *tunnelid;
2270 GST_INFO ("client %p: connection closed", client);
2272 if ((tunnelid = gst_rtsp_connection_get_tunnelid (client->connection))) {
2273 g_mutex_lock (tunnels_lock);
2274 /* remove from tunnelids */
2275 g_hash_table_remove (tunnels, tunnelid);
2276 g_mutex_unlock (tunnels_lock);
2282 static GstRTSPResult
2283 error (GstRTSPWatch * watch, GstRTSPResult result, gpointer user_data)
2285 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2288 str = gst_rtsp_strresult (result);
2289 GST_INFO ("client %p: received an error %s", client, str);
2295 static GstRTSPResult
2296 error_full (GstRTSPWatch * watch, GstRTSPResult result,
2297 GstRTSPMessage * message, guint id, gpointer user_data)
2299 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2302 str = gst_rtsp_strresult (result);
2304 ("client %p: received an error %s when handling message %p with id %d",
2305 client, str, message, id);
2312 remember_tunnel (GstRTSPClient * client)
2314 const gchar *tunnelid;
2316 /* store client in the pending tunnels */
2317 tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
2318 if (tunnelid == NULL)
2321 GST_INFO ("client %p: inserting tunnel session %s", client, tunnelid);
2323 /* we can't have two clients connecting with the same tunnelid */
2324 g_mutex_lock (tunnels_lock);
2325 if (g_hash_table_lookup (tunnels, tunnelid))
2326 goto tunnel_existed;
2328 g_hash_table_insert (tunnels, g_strdup (tunnelid), g_object_ref (client));
2329 g_mutex_unlock (tunnels_lock);
2336 GST_ERROR ("client %p: no tunnelid provided", client);
2341 g_mutex_unlock (tunnels_lock);
2342 GST_ERROR ("client %p: tunnel session %s already existed", client,
2348 static GstRTSPStatusCode
2349 tunnel_start (GstRTSPWatch * watch, gpointer user_data)
2351 GstRTSPClient *client;
2353 client = GST_RTSP_CLIENT (user_data);
2355 GST_INFO ("client %p: tunnel start (connection %p)", client,
2356 client->connection);
2358 if (!remember_tunnel (client))
2361 return GST_RTSP_STS_OK;
2366 GST_ERROR ("client %p: error starting tunnel", client);
2367 return GST_RTSP_STS_SERVICE_UNAVAILABLE;
2371 static GstRTSPResult
2372 tunnel_lost (GstRTSPWatch * watch, gpointer user_data)
2374 GstRTSPClient *client;
2376 client = GST_RTSP_CLIENT (user_data);
2378 GST_INFO ("client %p: tunnel lost (connection %p)", client,
2379 client->connection);
2381 /* ignore error, it'll only be a problem when the client does a POST again */
2382 remember_tunnel (client);
2387 static GstRTSPResult
2388 tunnel_complete (GstRTSPWatch * watch, gpointer user_data)
2390 const gchar *tunnelid;
2391 GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
2392 GstRTSPClient *oclient;
2394 GST_INFO ("client %p: tunnel complete", client);
2396 /* find previous tunnel */
2397 tunnelid = gst_rtsp_connection_get_tunnelid (client->connection);
2398 if (tunnelid == NULL)
2401 g_mutex_lock (tunnels_lock);
2402 if (!(oclient = g_hash_table_lookup (tunnels, tunnelid)))
2405 /* remove the old client from the table. ref before because removing it will
2406 * remove the ref to it. */
2407 g_object_ref (oclient);
2408 g_hash_table_remove (tunnels, tunnelid);
2410 if (oclient->watch == NULL)
2412 g_mutex_unlock (tunnels_lock);
2414 GST_INFO ("client %p: found tunnel %p (old %p, new %p)", client, oclient,
2415 oclient->connection, client->connection);
2417 /* merge the tunnels into the first client */
2418 gst_rtsp_connection_do_tunnel (oclient->connection, client->connection);
2419 gst_rtsp_watch_reset (oclient->watch);
2420 g_object_unref (oclient);
2422 /* we don't need this watch anymore */
2423 g_source_destroy ((GSource *) client->watch);
2424 client->watchid = 0;
2425 client->watch = NULL;
2432 GST_INFO ("client %p: no tunnelid provided", client);
2433 return GST_RTSP_STS_SERVICE_UNAVAILABLE;
2437 g_mutex_unlock (tunnels_lock);
2438 GST_INFO ("client %p: tunnel session %s not found", client, tunnelid);
2439 return GST_RTSP_STS_SERVICE_UNAVAILABLE;
2443 g_mutex_unlock (tunnels_lock);
2444 GST_INFO ("client %p: tunnel session %s was closed", client, tunnelid);
2445 g_object_unref (oclient);
2446 return GST_RTSP_STS_SERVICE_UNAVAILABLE;
2450 static GstRTSPWatchFuncs watch_funcs = {
2462 client_watch_notify (GstRTSPClient * client)
2464 GST_INFO ("client %p: watch destroyed", client);
2465 client->watchid = 0;
2466 client->watch = NULL;
2467 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_CLOSED], 0, NULL);
2468 g_object_unref (client);
2473 * gst_rtsp_client_attach:
2474 * @client: a #GstRTSPClient
2475 * @channel: a #GIOChannel
2477 * Accept a new connection for @client on the socket in @channel.
2479 * This function should be called when the client properties and urls are fully
2480 * configured and the client is ready to start.
2482 * Returns: %TRUE if the client could be accepted.
2485 gst_rtsp_client_accept (GstRTSPClient * client, int sock)
2488 GstRTSPConnection *conn;
2491 GMainContext *context;
2493 struct sockaddr_storage addr;
2495 gchar ip[INET6_ADDRSTRLEN];
2497 // TODO: try about SIGIO or select or poll calls apart from waiting...
2499 GST_ERROR_OBJECT (client, "Enter accept client...");
2501 GST_RTSP_CHECK (gst_rtsp_connection_accept (sock, &conn), accept_failed);
2503 fd = gst_rtsp_connection_get_readfd (conn);
2505 addrlen = sizeof (addr);
2506 if (getsockname (fd, (struct sockaddr *) &addr, &addrlen) < 0)
2507 goto getpeername_failed;
2509 client->is_ipv6 = addr.ss_family == AF_INET6;
2511 if (getnameinfo ((struct sockaddr *) &addr, addrlen, ip, sizeof (ip), NULL, 0,
2512 NI_NUMERICHOST) != 0)
2513 goto getnameinfo_failed;
2515 /* keep the original ip that the client connected to */
2516 g_free (client->server_ip);
2517 client->server_ip = g_strndup (ip, sizeof (ip));
2519 GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client,
2520 client->server_ip, client->is_ipv6);
2522 url = gst_rtsp_connection_get_url (conn);
2523 GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port);
2525 client->connection = conn;
2527 /* create watch for the connection and attach */
2528 client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs,
2529 g_object_ref (client), (GDestroyNotify) client_watch_notify);
2531 source = client->watch;
2533 GST_DEBUG (" source = %p", source);
2535 // naveen: we are not creating source before below call.. so context will be NULL.. which means, we are attaching
2536 // to main context...
2538 /* find the context to add the watch */
2539 if ((source = g_main_current_source ()))
2540 context = g_source_get_context (source);
2544 GST_DEBUG (" source = %p", source);
2547 GST_INFO ("attaching to context %p", context);
2549 client->watchid = gst_rtsp_watch_attach (client->watch, context);
2551 GST_DEBUG_OBJECT (client, "watch_id = %u", client->watchid);
2552 gst_rtsp_watch_unref (client->watch);
2559 gchar *str = gst_rtsp_strresult (res);
2561 GST_ERROR ("Could not accept client on server socket %d: %s", sock, str);
2567 GST_ERROR ("getpeername failed: %s", g_strerror (errno));
2572 GST_ERROR ("getnameinfo failed: %s", g_strerror (errno));
2578 * gst_rtsp_client_attach:
2579 * @client: a #GstRTSPClient
2580 * @channel: a #GIOChannel
2582 * Accept a new connection for @client on the socket in @channel.
2584 * This function should be called when the client properties and urls are fully
2585 * configured and the client is ready to start.
2587 * Returns: %TRUE if the client could be accepted.
2590 gst_rtsp_client_accept (GstRTSPClient * client, GIOChannel * channel, GSource *source)
2593 GstRTSPConnection *conn;
2595 GMainContext *context;
2597 struct sockaddr_storage addr;
2599 gchar ip[INET6_ADDRSTRLEN];
2600 GSocket *socket, *readsocket;
2602 GST_ERROR_OBJECT (client, "Enter accept client...");
2604 /* a new client connected. */
2605 sock = g_io_channel_unix_get_fd (channel);
2606 socket = g_socket_new_from_fd(sock, NULL);
2608 GST_INFO_OBJECT (client, "sock fd = %d", sock);
2610 GST_RTSP_CHECK (gst_rtsp_connection_accept (socket, &conn, NULL), accept_failed);
2611 g_object_unref(socket);
2612 readsocket = gst_rtsp_connection_get_read_socket (conn);
2613 fd = g_socket_get_fd(readsocket);
2615 res = GST_RTSP_EINVAL;
2619 addrlen = sizeof (addr);
2620 if (getsockname (fd, (struct sockaddr *) &addr, &addrlen) < 0)
2621 goto getpeername_failed;
2623 client->is_ipv6 = addr.ss_family == AF_INET6;
2625 if (getnameinfo ((struct sockaddr *) &addr, addrlen, ip, sizeof (ip), NULL, 0,
2626 NI_NUMERICHOST) != 0)
2627 goto getnameinfo_failed;
2629 /* keep the original ip that the client connected to */
2630 g_free (client->server_ip);
2631 client->server_ip = g_strndup (ip, sizeof (ip));
2633 GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client,
2634 client->server_ip, client->is_ipv6);
2636 url = gst_rtsp_connection_get_url (conn);
2637 GST_INFO ("added new client %p ip %s:%d", client, url->host, url->port);
2639 client->wfdsink_ip = url->host;
2640 GST_INFO ("WFD Sink IP : %s", client->wfdsink_ip);
2642 client->connection = conn;
2643 /* create watch for the connection and attach */
2644 client->watch = gst_rtsp_watch_new (client->connection, &watch_funcs, client, (GDestroyNotify) client_watch_notify);
2647 /* find the context to add the watch */
2648 if ((source = g_main_current_source ()))
2649 context = g_source_get_context (source);
2653 context = g_source_get_context (source);
2657 GST_DEBUG (" source = %p", source);
2660 GST_INFO ("attaching to context %p", context);
2663 client->watchid = gst_rtsp_watch_attach (client->watch, context);
2664 gst_rtsp_watch_unref (client->watch);
2671 gchar *str = gst_rtsp_strresult (res);
2673 GST_ERROR ("Could not accept client on server socket %d: %s", sock, str);
2679 GST_ERROR ("getpeername failed: %s", g_strerror (errno));
2684 GST_ERROR ("getnameinfo failed: %s", g_strerror (errno));
2692 * @client: client object
2693 * @request : requst message to be prepared
2694 * @method : RTSP method of the request
2695 * @url : url need to be in the request
2696 * @message_type : WFD message type
2697 * @trigger_type : trigger method to be used for M5 mainly
2699 * Prepares request based on @method & @message_type
2701 * Returns: a #GstRTSPResult.
2703 static GstRTSPResult
2704 prepare_request (GstRTSPClient *client, GstRTSPMessage *request,
2705 GstRTSPMethod method, gchar *url, WFDMessageType message_type, WFDTrigger trigger_type)
2707 GstRTSPResult res = GST_RTSP_OK;
2709 WFDResult wfd_res = WFD_OK;
2711 /* initialize the request */
2712 res = gst_rtsp_message_init_request (request, method, url);
2714 GST_ERROR ("init request failed");
2720 /* Prepare OPTIONS request to send */
2721 case GST_RTSP_OPTIONS: {
2722 /* add wfd specific require filed "org.wfa.wfd1.0" */
2723 str = g_strdup ("org.wfa.wfd1.0");
2724 res = gst_rtsp_message_add_header (request, GST_RTSP_HDR_REQUIRE, str);
2726 GST_ERROR ("Failed to add header");
2734 /* Prepare GET_PARAMETER request */
2735 case GST_RTSP_GET_PARAMETER: {
2741 /* add content type */
2742 res = gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE, "text/parameters");
2744 GST_ERROR ("Failed to add header");
2748 /* create M3 message to be sent in the request */
2749 wfd_res = wfdconfig_message_new(&msg3);
2750 if (wfd_res != WFD_OK) {
2751 GST_ERROR_OBJECT (client, "Failed to create wfd message...");
2752 res = GST_RTSP_ERROR;
2756 wfd_res = wfdconfig_message_init(msg3);
2757 if (wfd_res != WFD_OK) {
2758 GST_ERROR_OBJECT (client, "Failed to init wfd message...");
2759 res = GST_RTSP_ERROR;
2763 /* set the supported audio formats by the WFD server*/
2764 wfd_res = wfdconfig_set_supported_audio_format(msg3, WFD_AUDIO_UNKNOWN, WFD_FREQ_UNKNOWN,WFD_CHANNEL_UNKNOWN, 0, 0);
2765 if (wfd_res != WFD_OK) {
2766 GST_ERROR_OBJECT (client, "Failed to set supported audio formats on wfd message...");
2767 res = GST_RTSP_ERROR;
2771 /* set the supported Video formats by the WFD server*/
2772 wfd_res = wfdconfig_set_supported_video_format(msg3, WFD_VIDEO_UNKNOWN, WFD_VIDEO_CEA_RESOLUTION, WFD_CEA_UNKNOWN,
2773 WFD_CEA_UNKNOWN, WFD_VESA_UNKNOWN,WFD_HH_UNKNOWN, WFD_H264_UNKNOWN_PROFILE,
2774 WFD_H264_LEVEL_UNKNOWN,0,0, 0, 0, 0, 0);
2775 if (wfd_res != WFD_OK) {
2776 GST_ERROR_OBJECT (client, "Failed to set supported video formats on wfd message...");
2777 res = GST_RTSP_ERROR;
2781 GST_DEBUG ("wfdconfig_set_display_EDID...");
2782 wfd_res = wfdconfig_set_display_EDID(msg3, 0, 0, NULL);
2783 if (wfd_res != WFD_OK) {
2784 GST_ERROR_OBJECT (client, "Failed to set display EDID type on wfd message...");
2785 res = GST_RTSP_ERROR;
2788 GST_DEBUG ("wfdconfig_set_contentprotection_type...");
2789 wfd_res = wfdconfig_set_contentprotection_type(msg3, WFD_HDCP_NONE, 0);
2790 if (wfd_res != WFD_OK) {
2791 GST_ERROR_OBJECT (client, "Failed to set supported content protection type on wfd message...");
2792 res = GST_RTSP_ERROR;
2795 /*GST_DEBUG ("wfdconfig_set_coupled_sink...");
2796 wfd_res = wfdconfig_set_coupled_sink(msg3, WFD_SINK_UNKNOWN, NULL);
2797 if (wfd_res != WFD_OK) {
2798 GST_ERROR_OBJECT (client, "Failed to set coupled sink type on wfd message...");
2799 res = GST_RTSP_ERROR;
2802 GST_DEBUG ("wfdconfig_set_I2C_port...");
2803 wfd_res = wfdconfig_set_I2C_port(msg3, FALSE, 0);
2804 if (wfd_res != WFD_OK) {
2805 GST_ERROR_OBJECT (client, "Failed to set coupled sink type on wfd message...");
2806 res = GST_RTSP_ERROR;
2809 GST_DEBUG ("wfdconfig_set_uibc_capability...");
2810 wfd_res = wfdconfig_set_uibc_capability(msg3, WFD_UIBC_INPUT_CAT_UNKNOWN, WFD_UIBC_INPUT_TYPE_UNKNOWN, NULL, 0, 0);
2811 if (wfd_res != WFD_OK) {
2812 GST_ERROR_OBJECT (client, "Failed to set coupled sink type on wfd message...");
2813 res = GST_RTSP_ERROR;
2816 GST_DEBUG ("wfdconfig_set_connector_type...");
2817 wfd_res = wfdconfig_set_connector_type(msg3, WFD_CONNECTOR_NO);
2818 if (wfd_res != WFD_OK) {
2819 GST_ERROR_OBJECT (client, "Failed to set coupled sink type on wfd message...");
2820 res = GST_RTSP_ERROR;
2823 #ifdef STANDBY_RESUME_CAPABILITY
2824 GST_DEBUG ("wfdconfig_set_standby_resume_capability...");
2825 wfd_res = wfdconfig_set_standby_resume_capability(msg3, FALSE);
2826 if (wfd_res != WFD_OK) {
2827 GST_ERROR_OBJECT (client, "Failed to set coupled sink type on wfd message...");
2828 res = GST_RTSP_ERROR;
2832 /* set the preffered RTP ports for the WFD server*/
2833 wfd_res = wfdconfig_set_prefered_RTP_ports(msg3, WFD_RTSP_TRANS_UNKNOWN, WFD_RTSP_PROFILE_UNKNOWN,
2834 WFD_RTSP_LOWER_TRANS_UNKNOWN, 0, 0);
2835 if (wfd_res != WFD_OK) {
2836 GST_ERROR_OBJECT (client, "Failed to set supported video formats on wfd message...");
2837 res = GST_RTSP_ERROR;
2840 GST_DEBUG ("wfdconfig_parameter_names_as_text...");
2843 wfd_res = wfdconfig_message_dump(msg3);
2844 if (wfd_res != WFD_OK) {
2845 GST_ERROR_OBJECT (client, "Failed to set supported video formats on wfd message...");
2846 res = GST_RTSP_ERROR;
2850 msg = wfdconfig_parameter_names_as_text(msg3);
2852 GST_ERROR_OBJECT (client, "Failed to get wfd message as text...");
2853 res = GST_RTSP_ERROR;
2856 GST_DEBUG ("wfdconfig_message_as_text...");
2857 msglen = strlen(msg);
2858 msglength = g_string_new ("");
2859 g_string_append_printf (msglength,"%d",msglen);
2860 GST_DEBUG("M3 server side message body: %s", msg);
2862 /* add content-length type */
2863 res = gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH, g_string_free (msglength, FALSE));
2864 if (res != GST_RTSP_OK) {
2865 GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
2869 /* adding wfdconfig data to request */
2870 res = gst_rtsp_message_set_body (request, (guint8*)msg, msglen);
2871 if (res != GST_RTSP_OK) {
2872 GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
2876 wfdconfig_message_free(msg3);
2880 /* Prepare SET_PARAMETER request */
2881 case GST_RTSP_SET_PARAMETER: {
2882 /* add content type */
2883 res = gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE, "text/parameters");
2884 if (res != GST_RTSP_OK) {
2885 GST_ERROR_OBJECT (client, "Failed to add header to rtsp request...");
2889 switch (message_type) {
2890 case WFD_MESSAGE_4: {
2898 /* create M4 message to be sent in the request */
2899 wfd_res = wfdconfig_message_new(&msg4);
2900 if (wfd_res != WFD_OK) {
2901 GST_ERROR_OBJECT (client, "Failed to create wfd message...");
2902 res = GST_RTSP_ERROR;
2906 wfd_res = wfdconfig_message_init(msg4);
2907 if (wfd_res != WFD_OK) {
2908 GST_ERROR_OBJECT (client, "Failed to init wfd message...");
2909 res = GST_RTSP_ERROR;
2912 lines = g_string_new ("");
2913 g_string_append_printf (lines,"rtsp://");
2914 g_string_append_printf (lines, "%s", client->server_ip);
2915 g_string_append_printf (lines,"/wfd1.0/streamid=0");
2916 wfd_res = wfdconfig_set_presentation_url(msg4, g_string_free (lines, FALSE), NULL);
2917 if (wfd_res != WFD_OK) {
2918 GST_ERROR_OBJECT (client, "Failed to set preffered video formats...");
2919 res = GST_RTSP_ERROR;
2923 /* set the preffered audio formats for the WFD server*/
2925 WFDAudioFormats taudiocodec = WFD_AUDIO_UNKNOWN;
2926 WFDAudioFreq taudiofreq = WFD_FREQ_UNKNOWN;
2927 WFDAudioChannels taudiochannels = WFD_CHANNEL_UNKNOWN;
2928 if(client->caCodec & WFD_AUDIO_AC3) taudiocodec = WFD_AUDIO_AAC; // TODO Currently AC3 encoder is not present
2929 else if(client->caCodec & WFD_AUDIO_AAC) taudiocodec = WFD_AUDIO_AAC;
2930 else if(client->caCodec & WFD_AUDIO_LPCM) taudiocodec = WFD_AUDIO_LPCM;
2931 client->caCodec = taudiocodec;
2933 if(client->cFreq & WFD_FREQ_48000) taudiofreq = WFD_FREQ_48000;
2934 else if(client->cFreq & WFD_FREQ_44100) taudiofreq = WFD_FREQ_44100;
2935 client->cFreq = taudiofreq;
2937 if(client->cChanels & WFD_CHANNEL_8) taudiochannels = WFD_CHANNEL_2; // TODO Currently only 2 channels is present
2938 else if(client->cChanels & WFD_CHANNEL_6) taudiochannels = WFD_CHANNEL_2;
2939 else if(client->cChanels & WFD_CHANNEL_4) taudiochannels = WFD_CHANNEL_2;
2940 else if(client->cChanels & WFD_CHANNEL_2) taudiochannels = WFD_CHANNEL_2;
2941 client->cChanels = taudiochannels;
2943 wfd_res = wfdconfig_set_prefered_audio_format(msg4, taudiocodec, taudiofreq, taudiochannels, client->cBitwidth, client->caLatency);
2944 if (wfd_res != WFD_OK) {
2945 GST_ERROR_OBJECT (client, "Failed to set preffered audio formats...");
2946 res = GST_RTSP_ERROR;
2951 WFDVideoCEAResolution tcCEAResolution = WFD_CEA_UNKNOWN;
2952 WFDVideoVESAResolution tcVESAResolution = WFD_VESA_UNKNOWN;
2953 WFDVideoHHResolution tcHHResolution = WFD_HH_UNKNOWN;
2954 WFDVideoH264Profile tcProfile;
2955 WFDVideoH264Level tcLevel;
2956 /* set the preffered video formats for the WFD server*/
2957 tcCEAResolution = WFD_CEA_1280x720P30; // TODO need to fetch from INI file
2958 client->cvCodec = WFD_VIDEO_H264;
2959 client->cProfile = tcProfile = WFD_H264_BASE_PROFILE; // TODO need to fetch from INI file
2960 client->cLevel = tcLevel = WFD_H264_LEVEL_3_1; // TODO need to fetch from INI file
2961 client->cMaxWidth = 1280;
2962 client->cMaxHeight = 720;
2963 wfd_res = wfdconfig_set_prefered_video_format(msg4, client->cvCodec, WFD_VIDEO_CEA_RESOLUTION, WFD_CEA_UNKNOWN,
2964 tcCEAResolution, tcVESAResolution, tcHHResolution, tcProfile,
2965 tcLevel, client->cvLatency, client->cMaxHeight,client->cMaxWidth, client->cmin_slice_size, client->cslice_enc_params, client->cframe_rate_control);
2966 if (wfd_res != WFD_OK) {
2967 GST_ERROR_OBJECT (client, "Failed to set preffered video formats...");
2968 res = GST_RTSP_ERROR;
2972 GST_DEBUG("wfd config set presentation URL %s",url);
2974 /* set the preffered RTP ports for the WFD server*/
2975 GST_LOG("Port are %d, %d\n", client->crtp_port0, client->crtp_port1);
2976 wfd_res = wfdconfig_set_prefered_RTP_ports(msg4, WFD_RTSP_TRANS_RTP, WFD_RTSP_PROFILE_AVP,
2977 WFD_RTSP_LOWER_TRANS_UDP, client->crtp_port0, client->crtp_port1);
2978 if (wfd_res != WFD_OK) {
2979 GST_ERROR_OBJECT (client, "Failed to set preffered RTP ports...");
2980 res = GST_RTSP_ERROR;
2983 /*set the preffered hdcp version and port for the WFD server*/
2984 if (client->hdcp_support) {
2985 GST_DEBUG("hdcp version =%d, tcp port = %d", client->hdcp_version, client->hdcp_tcpport);
2986 wfd_res = wfdconfig_set_contentprotection_type(msg4, client->hdcp_version, client->hdcp_tcpport);
2987 if (wfd_res != WFD_OK) {
2988 GST_ERROR_OBJECT (client, "Failed to set supported content protection type on wfd message...");
2989 res = GST_RTSP_ERROR;
2993 #ifdef STANDBY_RESUME_CAPABILITY
2994 if(client->standby_resume_capability_support){
2995 wfd_res = wfdconfig_set_standby_resume_capability(msg4, TRUE);
2996 if (wfd_res != WFD_OK) {
2997 GST_ERROR_OBJECT (client, "Failed to set supported standby resume capability type on wfd message...");
2998 res = GST_RTSP_ERROR;
3003 wfd_res = wfdconfig_message_dump(msg4);
3004 if (wfd_res != WFD_OK) {
3005 GST_ERROR_OBJECT (client, "Failed to dump wfd message...");
3006 res = GST_RTSP_ERROR;
3010 msg = wfdconfig_message_as_text(msg4);
3012 GST_ERROR_OBJECT (client, "Failed to get wfd message as text...");
3013 res = GST_RTSP_ERROR;
3017 msglen = strlen(msg);
3018 msglength = g_string_new ("");
3019 g_string_append_printf (msglength,"%d",msglen);
3020 GST_DEBUG("M4 message body server side : %s", msg);
3022 /* add content-length type */
3023 res = gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH, g_string_free (msglength, FALSE));
3024 if (res != GST_RTSP_OK) {
3025 GST_ERROR_OBJECT (client, "Failed to add header to rtsp request...");
3029 /* adding wfdconfig data to request */
3030 res = gst_rtsp_message_set_body (request, (guint8*)msg, msglen);
3031 if (res != GST_RTSP_OK) {
3032 GST_ERROR_OBJECT (client, "Failed to set body to rtsp request...");
3036 wfdconfig_message_free(msg4);
3039 case WFD_MESSAGE_5: {
3045 /* create M4 message to be sent in the request */
3046 wfd_res = wfdconfig_message_new(&msg5);
3047 if (wfd_res != WFD_OK) {
3048 GST_ERROR_OBJECT (client, "Failed to create wfd message...");
3049 res = GST_RTSP_ERROR;
3053 wfd_res = wfdconfig_message_init(msg5);
3054 if (wfd_res != WFD_OK) {
3055 GST_ERROR_OBJECT (client, "Failed to init wfd message...");
3056 res = GST_RTSP_ERROR;
3060 /* preparing SETUP trigger message. After client receving this request, client has to send SETUP request */
3061 wfd_res = wfdconfig_set_trigger_type(msg5, trigger_type);
3062 if (wfd_res != WFD_OK) {
3063 GST_ERROR_OBJECT (client, "Failed to trigger type...");
3064 res = GST_RTSP_ERROR;
3068 wfd_res = wfdconfig_message_dump(msg5);
3069 if (wfd_res != WFD_OK) {
3070 GST_ERROR_OBJECT (client, "Failed to dump wfd message...");
3071 res = GST_RTSP_ERROR;
3075 msg = wfdconfig_message_as_text(msg5);
3077 GST_ERROR_OBJECT (client, "Failed to get wfd message as text...");
3078 res = GST_RTSP_ERROR;
3082 msglen = strlen(msg);
3083 msglength = g_string_new ("");
3084 g_string_append_printf (msglength,"%d",msglen);
3086 GST_DEBUG ("M5 trigger message body: %s", msg);
3088 /* add content-length type */
3089 res = gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH, g_string_free (msglength, FALSE));
3090 if (res != GST_RTSP_OK) {
3091 GST_ERROR_OBJECT (client, "Failed to add header to rtsp request...");
3095 /* adding wfdconfig data to request */
3096 res = gst_rtsp_message_set_body (request, (guint8*)msg, msglen);
3097 if (res != GST_RTSP_OK) {
3098 GST_ERROR_OBJECT (client, "Failed to set body to rtsp request...");
3102 wfdconfig_message_free(msg5);
3105 case WFD_MESSAGE_12: {
3111 /* create M4 message to be sent in the request */
3112 wfd_res = wfdconfig_message_new(&msg12);
3113 if (wfd_res != WFD_OK) {
3114 GST_ERROR_OBJECT (client, "Failed to create wfd message...");
3115 res = GST_RTSP_ERROR;
3119 wfd_res = wfdconfig_message_init(msg12);
3120 if (wfd_res != WFD_OK) {
3121 GST_ERROR_OBJECT (client, "Failed to init wfd message...");
3122 res = GST_RTSP_ERROR;
3126 /* preparing SETUP trigger message. After client receving this request, client has to send SETUP request */
3127 wfd_res = wfdconfig_set_standby(msg12, TRUE);
3128 if (wfd_res != WFD_OK) {
3129 GST_ERROR_OBJECT (client, "Failed to trigger type...");
3130 res = GST_RTSP_ERROR;
3134 wfd_res = wfdconfig_message_dump(msg12);
3135 if (wfd_res != WFD_OK) {
3136 GST_ERROR_OBJECT (client, "Failed to dump wfd message...");
3137 res = GST_RTSP_ERROR;
3141 msg = wfdconfig_message_as_text(msg12);
3143 GST_ERROR_OBJECT (client, "Failed to get wfd message as text...");
3144 res = GST_RTSP_ERROR;
3148 msglen = strlen(msg);
3149 msglength = g_string_new ("");
3150 g_string_append_printf (msglength,"%d",msglen);
3152 GST_DEBUG ("M12 standby message body: %s", msg);
3154 /* add content-length type */
3155 res = gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH, g_string_free (msglength, FALSE));
3156 if (res != GST_RTSP_OK) {
3157 GST_ERROR_OBJECT (client, "Failed to add header to rtsp request...");
3161 /* adding wfdconfig data to request */
3162 res = gst_rtsp_message_set_body (request, (guint8*)msg, msglen);
3163 if (res != GST_RTSP_OK) {
3164 GST_ERROR_OBJECT (client, "Failed to set body to rtsp request...");
3168 wfdconfig_message_free(msg12);
3171 case WFD_MESSAGE_14: {
3176 WFDHIDCTypePathPair inp_pair[] = {{WFD_UIBC_INPUT_TYPE_KEYBOARD,WFD_UIBC_INPUT_PATH_USB},{WFD_UIBC_INPUT_TYPE_MOUSE,WFD_UIBC_INPUT_PATH_BT},{WFD_UIBC_INPUT_TYPE_MULTITOUCH,WFD_UIBC_INPUT_PATH_WIFI},{WFD_UIBC_INPUT_TYPE_GESTURE,WFD_UIBC_INPUT_PATH_BT}};
3178 /* create M4 message to be sent in the request */
3179 wfd_res = wfdconfig_message_new(&msg14);
3180 if (wfd_res != WFD_OK) {
3181 GST_ERROR_OBJECT (client, "Failed to create wfd message...");
3182 res = GST_RTSP_ERROR;
3186 wfd_res = wfdconfig_message_init(msg14);
3187 if (wfd_res != WFD_OK) {
3188 GST_ERROR_OBJECT (client, "Failed to init wfd message...");
3189 res = GST_RTSP_ERROR;
3193 /* preparing SETUP trigger message. After client receving this request, client has to send SETUP request */
3194 wfd_res = wfdconfig_set_uibc_capability(msg14, WFD_UIBC_INPUT_CAT_GENERIC,
3195 WFD_UIBC_INPUT_TYPE_MOUSE|WFD_UIBC_INPUT_TYPE_MULTITOUCH|WFD_UIBC_INPUT_TYPE_GESTURE, inp_pair, 4, 8558);
3196 if (wfd_res != WFD_OK) {
3197 GST_ERROR_OBJECT (client, "Failed to trigger type...");
3198 res = GST_RTSP_ERROR;
3202 wfd_res = wfdconfig_message_dump(msg14);
3203 if (wfd_res != WFD_OK) {
3204 GST_ERROR_OBJECT (client, "Failed to dump wfd message...");
3205 res = GST_RTSP_ERROR;
3209 msg = wfdconfig_message_as_text(msg14);
3211 GST_ERROR_OBJECT (client, "Failed to get wfd message as text...");
3212 res = GST_RTSP_ERROR;
3216 msglen = strlen(msg);
3217 msglength = g_string_new ("");
3218 g_string_append_printf (msglength,"%d",msglen);
3220 GST_DEBUG ("M14 UIBC message body: %s", msg);
3222 /* add content-length type */
3223 res = gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH, g_string_free (msglength, FALSE));
3224 if (res != GST_RTSP_OK) {
3225 GST_ERROR_OBJECT (client, "Failed to add header to rtsp request...");
3229 /* adding wfdconfig data to request */
3230 res = gst_rtsp_message_set_body (request, (guint8*)msg, msglen);
3231 if (res != GST_RTSP_OK) {
3232 GST_ERROR_OBJECT (client, "Failed to set body to rtsp request...");
3236 wfdconfig_message_free(msg14);
3239 case WFD_MESSAGE_15: {
3245 /* create M4 message to be sent in the request */
3246 wfd_res = wfdconfig_message_new(&msg15);
3247 if (wfd_res != WFD_OK) {
3248 GST_ERROR_OBJECT (client, "Failed to create wfd message...");
3249 res = GST_RTSP_ERROR;
3253 wfd_res = wfdconfig_message_init(msg15);
3254 if (wfd_res != WFD_OK) {
3255 GST_ERROR_OBJECT (client, "Failed to init wfd message...");
3256 res = GST_RTSP_ERROR;
3260 /* preparing SETUP trigger message. After client receving this request, client has to send SETUP request */
3261 wfd_res = wfdconfig_set_uibc_status(msg15, TRUE);
3262 if (wfd_res != WFD_OK) {
3263 GST_ERROR_OBJECT (client, "Failed to trigger type...");
3264 res = GST_RTSP_ERROR;
3268 wfd_res = wfdconfig_message_dump(msg15);
3269 if (wfd_res != WFD_OK) {
3270 GST_ERROR_OBJECT (client, "Failed to dump wfd message...");
3271 res = GST_RTSP_ERROR;
3275 msg = wfdconfig_message_as_text(msg15);
3277 GST_ERROR_OBJECT (client, "Failed to get wfd message as text...");
3278 res = GST_RTSP_ERROR;
3282 msglen = strlen(msg);
3283 msglength = g_string_new ("");
3284 g_string_append_printf (msglength,"%d",msglen);
3286 GST_DEBUG ("M15 UIBC enable message body: %s", msg);
3288 /* add content-length type */
3289 res = gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH, g_string_free (msglength, FALSE));
3290 if (res != GST_RTSP_OK) {
3291 GST_ERROR_OBJECT (client, "Failed to add header to rtsp request...");
3295 /* adding wfdconfig data to request */
3296 res = gst_rtsp_message_set_body (request, (guint8*)msg, msglen);
3297 if (res != GST_RTSP_OK) {
3298 GST_ERROR_OBJECT (client, "Failed to set body to rtsp request...");
3302 wfdconfig_message_free(msg15);
3306 GST_ERROR_OBJECT (client, "Unhandled WFD message type...");
3307 return GST_RTSP_EINVAL;
3314 GST_ERROR_OBJECT (client, "Unhandled method...");
3315 return GST_RTSP_EINVAL;
3327 * @client: client object
3328 * @request : requst message received
3329 * @response : response to be prepare based on request
3330 * @method : RTSP method
3332 * prepare response to the request based on @method & @message_type
3334 * Returns: a #GstRTSPResult.
3336 static GstRTSPResult
3337 prepare_response (GstRTSPClient *client, GstRTSPMessage *request, GstRTSPMessage *response, GstRTSPMethod method)
3339 GstRTSPResult res = GST_RTSP_OK;
3342 /* prepare OPTIONS response */
3343 case GST_RTSP_OPTIONS: {
3344 GstRTSPMethod options;
3347 gchar *user_agent = NULL;
3349 options = GST_RTSP_OPTIONS |
3353 GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
3355 str = gst_rtsp_options_as_text (options);
3357 /*append WFD specific method */
3358 tmp = g_strdup (", org.wfa.wfd1.0");
3359 g_strlcat (str, tmp, strlen (tmp) + strlen (str) + 1);
3361 gst_rtsp_message_init_response (response, GST_RTSP_STS_OK,
3362 gst_rtsp_status_as_text (GST_RTSP_STS_OK), request);
3364 gst_rtsp_message_add_header (response, GST_RTSP_HDR_PUBLIC, str);
3367 res = gst_rtsp_message_get_header (request, GST_RTSP_HDR_USER_AGENT, &user_agent, 0);
3368 if (res == GST_RTSP_OK)
3370 gst_rtsp_message_add_header (response, GST_RTSP_HDR_USER_AGENT, user_agent);
3372 else res = GST_RTSP_OK;
3376 GST_ERROR_OBJECT (client, "Unhandled method...");
3377 return GST_RTSP_EINVAL;
3385 * handle_M1_message:
3386 * @client: client object
3388 * Handles M1 WFD message.
3389 * This API will send OPTIONS request to WFDSink & waits for the relavent response.
3390 * After getting the response, this will check whether all mandatory messages are supported by the WFDSink or NOT.
3392 * Returns: a #GstRTSPResult.
3395 static GstRTSPResult
3396 handle_M1_message (GstRTSPClient * client)
3398 GstRTSPResult res = GST_RTSP_OK;
3399 GstRTSPMessage request = { 0 };
3400 GstRTSPMessage response = { 0 };
3401 gboolean bret = FALSE;
3403 res = prepare_request (client, &request, GST_RTSP_OPTIONS, "*", WFD_MESSAGE_1, WFD_TRIGGER_UNKNOWN);
3404 if (GST_RTSP_OK != res) {
3405 GST_ERROR_OBJECT (client, "Failed to prepare M1 request....\n");
3409 GST_DEBUG_OBJECT (client, "Sending OPTIONS request message (M1)...");
3411 // TODO: need to add session i.e. 2nd variable
3412 send_request (client, NULL, &request);
3414 /* Wait for OPTIONS response (M1 response) */
3415 res = gst_rtsp_connection_receive (client->connection, &response, NULL);
3416 if (GST_RTSP_OK != res) {
3417 GST_ERROR_OBJECT (client, "Failed to receive M1 response....\n");
3421 if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
3422 gst_rtsp_message_dump (&response);
3425 bret = gst_rtsp_client_parse_methods (client, &response);
3426 if (FALSE == bret) {
3427 return GST_RTSP_ERROR;
3435 * handle_M2_message:
3436 * @client: client object
3438 * Handles M2 WFD message.
3439 * This API will waits for OPTIONS request from WFDSink & responds to the same.
3441 * Returns: a #GstRTSPResult.
3443 static GstRTSPResult
3444 handle_M2_message (GstRTSPClient * client)
3446 GstRTSPResult res = GST_RTSP_OK;
3447 GstRTSPMessage request = { 0 };
3448 GstRTSPMessage response = { 0 };
3449 GstRTSPMethod method;
3450 const gchar *uristr;
3451 GstRTSPVersion version;
3452 GstRTSPClientState state = { NULL };
3454 /* Wait for OPTIONS request from client (M2 request) */
3455 res = gst_rtsp_connection_receive (client->connection, &request, NULL);
3456 if (GST_RTSP_OK != res) {
3457 GST_ERROR_OBJECT (client, "Failed to receiv M2 request....\n");
3460 /*dump M2 request message*/
3461 if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
3462 gst_rtsp_message_dump (&request);
3465 /* Parse the request received */
3466 res = gst_rtsp_message_parse_request (&request, &method, &uristr, &version);
3467 if (GST_RTSP_OK != res) {
3468 GST_ERROR_OBJECT (client, "Failed to parse request....\n");
3472 state.request = &request;
3473 state.response = &response;
3475 if (version != GST_RTSP_VERSION_1_0) {
3476 /* we can only handle 1.0 requests */
3477 send_generic_response (client, GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
3482 if (method != GST_RTSP_OPTIONS) {
3483 GST_ERROR_OBJECT (client, "Received WRONG request, when server is Waiting for OPTIONS request...");
3484 return GST_RTSP_ERROR;
3487 /* we always try to parse the url first */
3488 if (gst_rtsp_url_parse (uristr, &uri) != GST_RTSP_OK) {
3489 send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, &state);
3490 return GST_RTSP_ERROR;
3493 /* not using the uri at this moment */
3494 gst_rtsp_url_free (uri);
3497 GST_DEBUG_OBJECT (client, "Received OPTIONS Request (M2 request)...");
3499 /* prepare the response for WFDsink request */
3500 res = prepare_response (client, &request, &response, GST_RTSP_OPTIONS);
3501 if (GST_RTSP_OK != res) {
3502 GST_ERROR_OBJECT (client, "Failed to prepare M2 request....\n");
3506 send_response (client, NULL, &response);
3508 GST_DEBUG_OBJECT (client, "Sent OPTIONS Response (M2 response)...");
3515 * handle_M3_message:
3516 * @client: client object
3518 * Handles M3 WFD message.
3519 * This API will send M3 message (GET_PARAMETER) to WFDSink to query supported formats by the WFDSink.
3520 * After getting supported formats info, this API will set those values on WFDConfigMessage obj
3522 * Returns: a #GstRTSPResult.
3524 static GstRTSPResult
3525 handle_M3_message (GstRTSPClient * client)
3527 GstRTSPResult res = GST_RTSP_OK;
3528 GstRTSPMessage request = { 0 };
3529 GstRTSPMessage response = { 0 };
3530 GstRTSPUrl *url = NULL;
3531 gchar *url_str = NULL;
3533 client->caCodec = WFD_AUDIO_UNKNOWN;
3534 client->cFreq = WFD_FREQ_UNKNOWN;
3535 client->cChanels = WFD_CHANNEL_UNKNOWN;
3536 client->cBitwidth = 0;
3537 client->caLatency = 0;
3538 client->cvCodec = WFD_VIDEO_H264;
3539 client->cNative = WFD_VIDEO_CEA_RESOLUTION;
3540 client->cNativeResolution = 0;
3541 client->cCEAResolution = WFD_CEA_UNKNOWN;
3542 client->cVESAResolution = WFD_VESA_UNKNOWN;
3543 client->cHHResolution = WFD_HH_UNKNOWN;
3544 client->cProfile = WFD_H264_UNKNOWN_PROFILE;
3545 client->cLevel = WFD_H264_LEVEL_UNKNOWN;
3546 client->cMaxHeight = 0;
3547 client->cMaxWidth = 0;
3548 client->cmin_slice_size = 0;
3549 client->cslice_enc_params = 0;
3550 client->cframe_rate_control = 0;
3551 client->cvLatency = 0;
3552 client->ctrans = WFD_RTSP_TRANS_UNKNOWN;
3553 client->cprofile = WFD_RTSP_PROFILE_UNKNOWN;
3554 client->clowertrans = WFD_RTSP_LOWER_TRANS_UNKNOWN;
3555 client->crtp_port0 = 0;
3556 client->crtp_port1 = 0;
3557 client->hdcp_version = WFD_HDCP_NONE;
3558 client->hdcp_tcpport = 0;
3559 client->hdcp_support = FALSE;
3560 #ifdef STANDBY_RESUME_CAPABILITY
3561 client->standby_resume_capability_support = FALSE;
3564 url = gst_rtsp_connection_get_url (client->connection);
3566 GST_ERROR_OBJECT (client, "Failed to get connection URL");
3567 return GST_RTSP_ERROR;
3570 url_str = gst_rtsp_url_get_request_uri (url);
3571 if (url_str == NULL) {
3572 GST_ERROR_OBJECT (client, "Failed to get connection URL");
3573 return GST_RTSP_ERROR;
3576 res = prepare_request (client, &request, GST_RTSP_GET_PARAMETER, url_str, WFD_MESSAGE_3, WFD_TRIGGER_UNKNOWN);
3577 if (GST_RTSP_OK != res) {
3578 GST_ERROR_OBJECT (client, "Failed to prepare M3 request....\n");
3582 GST_DEBUG_OBJECT (client, "Sending GET_PARAMETER request message (M3)...");
3584 // TODO: need to add session i.e. 2nd variable
3585 send_request (client, NULL, &request);
3587 /* Wait for the response */
3588 res = gst_rtsp_connection_receive (client->connection, &response, NULL);
3589 if (GST_RTSP_OK != res) {
3590 GST_ERROR ("Failed to received response....\n");
3594 if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
3595 gst_rtsp_message_dump (&response);
3598 /* parsing the GET_PARAMTER response */
3602 WFDMessage *msg3res;
3603 WFDResult wfd_res = WFD_OK;
3605 res = gst_rtsp_message_get_body (&response, (guint8**)&data, &size);
3606 if (res != GST_RTSP_OK) {
3607 GST_ERROR_OBJECT (client, "Failed to get body of response...");
3611 /* create M3 response message */
3612 wfd_res = wfdconfig_message_new(&msg3res);
3613 if (wfd_res != WFD_OK) {
3614 GST_ERROR_OBJECT (client, "Failed to prepare wfd message...");
3618 wfd_res = wfdconfig_message_init(msg3res);
3619 if (wfd_res != WFD_OK) {
3620 GST_ERROR_OBJECT (client, "Failed to init wfd message...");
3624 wfd_res = wfdconfig_message_parse_buffer((guint8*)data,size,msg3res);
3625 if (wfd_res != WFD_OK) {
3626 GST_ERROR_OBJECT (client, "Failed to init wfd message...");
3630 GST_DEBUG_OBJECT(client, "M3 response server side message body: %s", wfdconfig_message_as_text(msg3res));
3632 /* Get the audio formats supported by WFDSink */
3633 if (msg3res->audio_codecs) {
3634 wfd_res = wfdconfig_get_supported_audio_format(msg3res, &client->caCodec, &client->cFreq, &client->cChanels, &client->cBitwidth, &client->caLatency);
3635 if (wfd_res != WFD_OK) {
3636 GST_WARNING_OBJECT (client, "Failed to get wfd support audio formats...");
3642 /* Get the Video formats supported by WFDSink */
3643 wfd_res = wfdconfig_get_supported_video_format(msg3res, &client->cvCodec, &client->cNative, &client->cNativeResolution,
3644 (guint64*)&client->cCEAResolution, (guint64*)&client->cVESAResolution, (guint64*)&client->cHHResolution,
3645 &client->cProfile, &client->cLevel, &client->cvLatency, &client->cMaxHeight,
3646 &client->cMaxWidth, &client->cmin_slice_size, &client->cslice_enc_params, &client->cframe_rate_control);
3647 if (wfd_res != WFD_OK) {
3648 GST_WARNING_OBJECT (client, "Failed to get wfd supported video formats...");
3652 if (msg3res->client_rtp_ports) {
3653 /* Get the RTP ports preferred by WFDSink */
3654 wfd_res = wfdconfig_get_prefered_RTP_ports(msg3res, &client->ctrans, &client->cprofile, &client->clowertrans, &client->crtp_port0, &client->crtp_port1);
3655 if (wfd_res != WFD_OK) {
3656 GST_WARNING_OBJECT (client, "Failed to get wfd prefered RTP ports...");
3661 if (msg3res->display_edid) {
3662 gboolean edid_supported = FALSE;
3663 guint32 edid_block_count = 0;
3664 gchar *edid_payload = NULL;
3665 /* Get the display edid preferred by WFDSink */
3666 wfd_res = wfdconfig_get_display_EDID(msg3res, &edid_supported, &edid_block_count, &edid_payload);
3667 if (wfd_res != WFD_OK) {
3668 GST_WARNING_OBJECT (client, "Failed to get wfd display edid...");
3671 GST_DEBUG_OBJECT (client, " edid supported: %d edid_block_count: %d", edid_supported, edid_block_count);
3672 GST_DEBUG_OBJECT (client, "set_edid_info");
3673 set_edid_info(edid_payload, TRUE);
3675 if (msg3res->content_protection) {
3676 /*Get the hdcp version and tcp port by WFDSink*/
3677 wfd_res = wfdconfig_get_contentprotection_type(msg3res, &client->hdcp_version, &client->hdcp_tcpport);
3678 GST_DEBUG("hdcp version =%d, tcp port = %d", client->hdcp_version, client->hdcp_tcpport);
3679 if (client->hdcp_version > 0 && client->hdcp_tcpport > 0)
3680 client->hdcp_support = TRUE;
3682 if (wfd_res != WFD_OK) {
3683 GST_WARNING_OBJECT (client, "Failed to get wfd content protection...");
3687 #ifdef STANDBY_RESUME_CAPABILITY
3688 if (msg3res->standby_resume_capability) {
3689 /*Get the standby_resume_capability value by WFDSink*/
3690 wfd_res = wfdconfig_get_standby_resume_capability(msg3res, &client->standby_resume_capability_support );
3691 if (wfd_res != WFD_OK) {
3692 GST_WARNING_OBJECT (client, "Failed to get wfd standby resume capability...");
3697 wfdconfig_message_dump(msg3res);
3703 return GST_RTSP_ERROR;
3708 * handle_M4_message:
3709 * @client: client object
3711 * Handles M4 WFD message.
3712 * This API will send M4 message (SET_PARAMETER) to WFDSink to set the format to be used in session
3714 * Returns: a #GstRTSPResult.
3716 static GstRTSPResult
3717 handle_M4_message (GstRTSPClient * client)
3719 GstRTSPResult res = GST_RTSP_OK;
3720 GstRTSPMessage request = { 0 };
3721 GstRTSPMessage response = { 0 };
3722 GstRTSPUrl *url = NULL;
3723 gchar *url_str = NULL;
3725 url = gst_rtsp_connection_get_url (client->connection);
3727 GST_ERROR_OBJECT (client, "Failed to get connection URL");
3728 return GST_RTSP_ERROR;
3731 url_str = gst_rtsp_url_get_request_uri (url);
3732 if (url_str == NULL) {
3733 GST_ERROR_OBJECT (client, "Failed to get connection URL");
3734 return GST_RTSP_ERROR;
3737 /* prepare the request for M4 message */
3738 res = prepare_request (client, &request, GST_RTSP_SET_PARAMETER, url_str, WFD_MESSAGE_4, WFD_TRIGGER_UNKNOWN);
3739 if (GST_RTSP_OK != res) {
3740 GST_ERROR_OBJECT (client, "Failed to prepare M4 request....\n");
3744 GST_DEBUG_OBJECT (client, "Sending SET_PARAMETER request message (M4)...");
3746 // TODO: need to add session i.e. 2nd variable
3747 send_request (client, NULL, &request);
3749 /* Wait for the M4 response from WFDSink */
3750 res = gst_rtsp_connection_receive (client->connection, &response, NULL);
3751 if (GST_RTSP_OK != res) {
3752 GST_ERROR ("Failed to received response....\n");
3756 if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
3757 gst_rtsp_message_dump (&response);
3766 * handle_M5_message:
3767 * @client: client object
3769 * Handles M5 WFD message.
3770 * This API will send M5 SETUP trigger message using SET_PARAMETER to WFDSink to intimate that client request SETUP now.
3772 * Returns: a #GstRTSPResult.
3774 static GstRTSPResult
3775 handle_M5_message (GstRTSPClient * client, WFDTrigger trigger_type)
3777 GstRTSPResult res = GST_RTSP_OK;
3778 GstRTSPMessage request = { 0 };
3779 GstRTSPMessage response = { 0 };
3780 GstRTSPUrl *url = NULL;
3781 gchar *url_str = NULL;
3782 GstRTSPSession *session = NULL;
3784 url = gst_rtsp_connection_get_url (client->connection);
3786 GST_ERROR_OBJECT (client, "Failed to get connection URL");
3787 return GST_RTSP_ERROR;
3790 url_str = gst_rtsp_url_get_request_uri (url);
3791 if (url_str == NULL) {
3792 GST_ERROR_OBJECT (client, "Failed to get connection URL");
3793 return GST_RTSP_ERROR;
3796 /* prepare the request for M5 message */
3797 res = prepare_request (client, &request, GST_RTSP_SET_PARAMETER, url_str, WFD_MESSAGE_5, trigger_type);
3798 if (GST_RTSP_OK != res) {
3799 GST_ERROR_OBJECT (client, "Failed to prepare M5 request....\n");
3803 GST_DEBUG_OBJECT (client, "Sending SET_PARAMETER request message (M5)...");
3805 // TODO: need to add session i.e. 2nd variable
3806 if (client->sessionid) {
3807 session = gst_rtsp_session_pool_find (client->session_pool, client->sessionid);
3808 GST_INFO_OBJECT (client, "session = %p & sessionid = %s", session, session->sessionid);
3810 send_request (client, session, &request);
3812 /* Wait for the M5 response from WFDSink */
3813 res = gst_rtsp_connection_receive (client->connection, &response, NULL);
3814 if (GST_RTSP_OK != res) {
3815 GST_ERROR ("Failed to received response....\n");
3819 if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
3820 gst_rtsp_message_dump (&response);
3829 * handle_M12_message:
3830 * @client: client object
3832 * Handles M12 WFD message.
3833 * This API will send M5 SETUP trigger message using SET_PARAMETER to WFDSink to intimate that client request SETUP now.
3835 * Returns: a #GstRTSPResult.
3837 static GstRTSPResult
3838 handle_M12_message (GstRTSPClient * client)
3840 GstRTSPResult res = GST_RTSP_OK;
3841 GstRTSPMessage request = { 0 };
3842 GstRTSPMessage response = { 0 };
3843 GstRTSPUrl *url = NULL;
3844 gchar *url_str = NULL;
3845 GstRTSPSession *session = NULL;
3846 GstRTSPSessionMedia *media;
3847 GstRTSPStatusCode code;
3849 url = gst_rtsp_connection_get_url (client->connection);
3851 GST_ERROR_OBJECT (client, "Failed to get connection URL");
3852 return GST_RTSP_ERROR;
3855 url_str = gst_rtsp_url_get_request_uri (url);
3856 if (url_str == NULL) {
3857 GST_ERROR_OBJECT (client, "Failed to get connection URL");
3858 return GST_RTSP_ERROR;
3861 /* prepare the request for M12 message */
3862 res = prepare_request (client, &request, GST_RTSP_SET_PARAMETER, url_str, WFD_MESSAGE_12, WFD_TRIGGER_UNKNOWN);
3863 if (GST_RTSP_OK != res) {
3864 GST_ERROR_OBJECT (client, "Failed to prepare M12 request....\n");
3868 GST_DEBUG_OBJECT (client, "Sending SET_PARAMETER request message (M12)...");
3870 // TODO: need to add session i.e. 2nd variable
3871 if (client->sessionid) {
3872 session = gst_rtsp_session_pool_find (client->session_pool, client->sessionid);
3873 GST_INFO_OBJECT (client, "session = %p & sessionid = %s", session, session->sessionid);
3875 send_request (client, session, &request);
3877 /* Wait for the M12 response from WFDSink */
3878 res = gst_rtsp_connection_receive (client->connection, &response, NULL);
3879 if (GST_RTSP_OK != res) {
3880 GST_ERROR ("Failed to received response....\n");
3884 if (gst_debug_category_get_threshold (rtsp_client_debug) >= GST_LEVEL_LOG) {
3885 gst_rtsp_message_dump (&response);
3887 if (!(session = gst_rtsp_session_pool_find (client->session_pool, client->sessionID)))
3889 GST_ERROR_OBJECT (client, "Failed to handle B1 message...");
3892 GST_DEBUG ("sessid = %s", client->sessionID);
3894 media = session->medias->data;
3896 /* unlink the all TCP callbacks */
3897 unlink_session_streams (client, session, media);
3899 /* then pause sending */
3900 gst_rtsp_session_media_set_state (media, GST_STATE_PAUSED);
3902 /* the state is now READY */
3903 media->state = GST_RTSP_STATE_READY;
3909 * gst_rtsp_client_negotiate:
3910 * @client: client object
3912 * This will handle capability negotiation part of WFD session
3914 * Returns: a #gboolean. return TRUE on success / FALSE on failure
3917 gst_rtsp_client_negotiate (GstRTSPClient * client)
3919 GstRTSPResult res = GST_RTSP_OK;
3921 /* handle M1 OPTIONS message */
3922 res = handle_M1_message (client);
3923 if (GST_RTSP_OK != res) {
3924 GST_ERROR_OBJECT (client, "Failed to handle M1 message...");
3925 goto rtsp_method_failed;
3928 /* handle M2 OPTIONS message */
3929 res = handle_M2_message (client);
3930 if (GST_RTSP_OK != res) {
3931 GST_ERROR_OBJECT (client, "Failed to handle M2 message...");
3932 goto rtsp_method_failed;
3935 /* handle M3 GET_PARAMETER request message */
3936 res = handle_M3_message (client);
3937 if (GST_RTSP_OK != res) {
3938 GST_ERROR_OBJECT (client, "Failed to handle M3 message...");
3939 goto rtsp_method_failed;
3942 /* handle M4 SET_PARAMETER request message */
3943 res = handle_M4_message (client);
3944 if (GST_RTSP_OK != res) {
3945 GST_ERROR_OBJECT (client, "Failed to handle M4 message...");
3946 goto rtsp_method_failed;
3952 GST_ERROR_OBJECT (client, "Failed to handle rtsp method : %d", res);
3958 * gst_rtsp_client_start:
3959 * @client: client object
3961 * This will handle M5 message & asks the client to start session
3963 * Returns: a #gboolean. return TRUE on success / FALSE on failure
3966 gst_rtsp_client_start (GstRTSPClient * client)
3968 GstRTSPResult res = GST_RTSP_OK;
3970 res = handle_M5_message (client, WFD_TRIGGER_SETUP);
3971 if (GST_RTSP_OK != res) {
3972 GST_ERROR_OBJECT (client, "Failed to handle M5 message...");
3980 gst_rtsp_client_set_params (GstRTSPClient *client, int videosrc_type, gint session_mode, int videobitrate, gint mtu_size, gchar *infile)
3982 client->videosrc_type = videosrc_type;
3983 client->session_mode = session_mode;
3984 client->bitrate = videobitrate;
3985 client->MTUsize = mtu_size;
3986 client->infile = g_strdup (infile);
3988 g_print ("\n\n\nvideo src type = %d & session_mode = %d & filename = %s\n",
3989 videosrc_type, session_mode, client->infile);
3993 gst_rtsp_client_pause (GstRTSPClient * client)
3995 GstRTSPResult res = GST_RTSP_OK;
3997 res = handle_M5_message (client, WFD_TRIGGER_PAUSE);
3998 if (GST_RTSP_OK != res) {
3999 GST_ERROR_OBJECT (client, "Failed to handle M5 message...");
4007 gst_rtsp_client_resume (GstRTSPClient * client)
4009 GstRTSPResult res = GST_RTSP_OK;
4011 res = handle_M5_message (client, WFD_TRIGGER_PLAY);
4012 if (GST_RTSP_OK != res) {
4013 GST_ERROR_OBJECT (client, "Failed to handle M5 message...");
4021 gst_rtsp_client_standby(GstRTSPClient * client)
4023 GstRTSPResult res = GST_RTSP_OK;
4024 res = handle_M12_message (client);
4025 if (GST_RTSP_OK != res) {
4026 GST_ERROR_OBJECT (client, "Failed to handle M12 message...");
4034 gst_rtsp_client_stop (GstRTSPClient * client)
4036 GstRTSPResult res = GST_RTSP_OK;
4038 res = handle_M5_message (client, WFD_TRIGGER_TEARDOWN);
4039 if (GST_RTSP_OK != res) {
4040 GST_ERROR_OBJECT (client, "Failed to handle M5 message...");
4048 gst_rtsp_client_parse_methods (GstRTSPClient * client, GstRTSPMessage * response)
4050 GstRTSPHeaderField field;
4055 gboolean found_wfd_method = FALSE;
4057 /* reset supported methods */
4058 client->methods = 0;
4060 /* Try Allow Header first */
4061 field = GST_RTSP_HDR_ALLOW;
4064 gst_rtsp_message_get_header (response, field, &respoptions, indx);
4065 if (indx == 0 && !respoptions) {
4066 /* if no Allow header was found then try the Public header... */
4067 field = GST_RTSP_HDR_PUBLIC;
4068 gst_rtsp_message_get_header (response, field, &respoptions, indx);
4073 /* If we get here, the server gave a list of supported methods, parse
4074 * them here. The string is like:
4076 * OPTIONS, PLAY, SETUP, ...
4078 options = g_strsplit (respoptions, ",", 0);
4080 for (i = 0; options[i]; i++) {
4084 stripped = g_strstrip (options[i]);
4085 method = gst_rtsp_find_method (stripped);
4087 if (!g_ascii_strcasecmp ("org.wfa.wfd1.0", stripped))
4088 found_wfd_method = TRUE;
4090 /* keep bitfield of supported methods */
4091 if (method != GST_RTSP_INVALID)
4092 client->methods |= method;
4094 g_strfreev (options);
4099 if (!found_wfd_method) {
4100 GST_ERROR_OBJECT (client, "WFD client is not supporting WFD mandatory message : org.wfa.wfd1.0...");
4101 goto no_required_methods;
4104 /* Checking mandatory method */
4105 if (!(client->methods & GST_RTSP_SET_PARAMETER)) {
4106 GST_ERROR_OBJECT (client, "WFD client is not supporting WFD mandatory message : SET_PARAMETER...");
4107 goto no_required_methods;
4110 /* Checking mandatory method */
4111 if (!(client->methods & GST_RTSP_GET_PARAMETER)) {
4112 GST_ERROR_OBJECT (client, "WFD client is not supporting WFD mandatory message : GET_PARAMETER...");
4113 goto no_required_methods;
4116 if (!(client->methods & GST_RTSP_OPTIONS)) {
4117 GST_INFO_OBJECT (client, "assuming OPTIONS is supported by client...");
4118 client->methods |= GST_RTSP_OPTIONS;
4124 no_required_methods:
4126 GST_ELEMENT_ERROR (client, RESOURCE, OPEN_READ, (NULL),
4127 ("WFD Client does not support mandatory methods."));
4128 // TODO: temporary hack
4135 pad_added (GstElement* ele, GstPad* pad, gpointer data)
4137 GstRTSPClient *client = (GstRTSPClient *)data;
4138 gchar* name = gst_pad_get_name (pad);
4140 if (name[0] == 'v') {
4141 GstPad* spad = NULL;
4143 g_print (" =========== >>>>>>>>>> Received VIDEO pad...\n");
4145 spad = gst_element_get_request_pad(GST_ELEMENT(client->srcbin->vparse), "sink");
4146 if (gst_pad_link(pad, spad) != GST_PAD_LINK_OK) {
4147 GST_ERROR ("Failed to link video demuxer pad & video parser sink pad...\n");
4150 gst_object_unref(spad);
4152 } else if (name[0] == 'a') {
4153 GstPad* spad = NULL;
4154 GstElement *aparse = NULL;
4157 aparse = gst_element_factory_make ("aacparse", "aparser");
4159 GST_ERROR("failed to create audio parse element");
4162 gst_bin_add (srcbin->srcbin, aparse);
4164 if (!gst_element_link (aparse, srcbin->aqueue)) {
4165 GST_ERROR ("failed to link aparse & aqueue...\n");
4170 g_print (" =========== >>>>>>>>>> Received AUDIO pad...\n");
4171 spad = gst_element_get_request_pad(GST_ELEMENT(client->srcbin->aqueue), "sink");
4172 if (gst_pad_link(pad, spad) != GST_PAD_LINK_OK) {
4173 GST_ERROR ("Failed to link audio demuxer pad & audio parse pad...\n");
4176 gst_object_unref(spad);
4178 GST_ERROR ("not handling.....\n\n\n");
4185 gst_rtsp_client_create_audio_capture_bin (GstRTSPClient * client, GstRTSPClientSrcBin *srcbin)
4187 GstElement *audiosrc = NULL;
4188 GstElement *acaps = NULL;
4189 GstElement *aenc = NULL;
4190 GstElement *aencsrccaps = NULL;
4193 gchar *acodec = NULL;
4195 /* create audio src element */
4196 audiosrc = gst_element_factory_make ("pulsesrc", "audiosrc");
4198 GST_ERROR_OBJECT (client, "failed to create audiosrc element");
4201 g_object_set (audiosrc, "device", "alsa_output.0.analog-stereo.monitor", NULL);
4202 //g_object_set (audiosrc, "provide-clock", 0, NULL);
4203 //g_object_set (audiosrc, "latency-time", 1000, NULL);
4204 //g_object_set (audiosrc, "actual-latency-time", 1000, NULL);
4206 g_object_set (audiosrc, "is-live", 1, NULL);
4207 g_object_set (audiosrc, "do-timestamp", 1, NULL);
4208 /* create audio caps element */
4209 acaps = gst_element_factory_make ("capsfilter", "audiocaps");
4210 if (NULL == acaps) {
4211 GST_ERROR_OBJECT (client, "failed to create audio capsilfter element");
4215 if(client->cChanels == WFD_CHANNEL_2)
4217 else if(client->cChanels == WFD_CHANNEL_4)
4219 else if(client->cChanels == WFD_CHANNEL_6)
4221 else if(client->cChanels == WFD_CHANNEL_8)
4226 if(client->cFreq == WFD_FREQ_44100)
4228 else if(client->cFreq == WFD_FREQ_48000)
4233 if(client->caCodec == WFD_AUDIO_LPCM) {
4234 g_object_set (G_OBJECT (acaps), "caps",
4235 gst_caps_new_simple ("audio/x-lpcm",
4236 "width", G_TYPE_INT, client->cBitwidth,
4237 "rate", G_TYPE_INT, freq,
4238 "channels", G_TYPE_INT, channels, NULL), NULL);
4239 } else if((client->caCodec == WFD_AUDIO_AAC) || (client->caCodec == WFD_AUDIO_AC3)) {
4240 g_object_set (G_OBJECT (acaps), "caps",
4241 gst_caps_new_simple ("audio/x-raw-int",
4242 "width", G_TYPE_INT, client->cBitwidth,
4243 "endianess", G_TYPE_INT, 1234,
4244 "signed", G_TYPE_BOOLEAN, TRUE,
4245 "depth", G_TYPE_INT, 16,
4246 "rate", G_TYPE_INT, freq,
4247 "channels", G_TYPE_INT, channels, NULL), NULL);
4250 if(client->caCodec == WFD_AUDIO_AAC)
4251 acodec = g_strdup("ffenc_aac");
4252 else if(client->caCodec == WFD_AUDIO_AC3)
4253 acodec = g_strdup("savsenc_ac3");
4255 GST_ERROR_OBJECT (client, "Yet to support other than H264 format");
4259 aenc = gst_element_factory_make (acodec, "audioenc");
4261 GST_ERROR_OBJECT (client, "failed to create audio encoder element");
4264 aencsrccaps = gst_element_factory_make ("capsfilter", "audioencsrccaps");
4265 if (NULL == aencsrccaps) {
4266 GST_ERROR_OBJECT (client, "failed to create audio capsilfter element");
4269 g_object_set (G_OBJECT (aencsrccaps), "caps",
4270 gst_caps_new_simple ("audio/mpeg",
4271 "stream-format", G_TYPE_STRING, "adts", NULL), NULL);
4273 srcbin->aqueue = gst_element_factory_make ("queue", "audio-queue");
4274 if (!srcbin->aqueue) {
4275 GST_ERROR_OBJECT (client, "failed to create audio queue element");
4279 gst_bin_add_many (srcbin->srcbin, audiosrc, acaps, aenc, aencsrccaps, srcbin->aqueue, NULL);
4281 if (!gst_element_link_many (audiosrc, acaps, aenc, aencsrccaps, srcbin->aqueue, NULL)) {
4282 GST_ERROR_OBJECT (client, "Failed to link audio src elements...");
4293 gst_rtsp_client_create_xvcapture_bin (GstRTSPClient * client, GstRTSPClientSrcBin *srcbin)
4295 GstElement *videosrc = NULL;
4296 GstElement *vcaps = NULL;
4297 gchar *vcodec = NULL;
4299 videosrc = gst_element_factory_make ("xvimagesrc", "videosrc");
4300 if (NULL == videosrc) {
4301 GST_ERROR_OBJECT (client, "failed to create xvimagesrc element");
4305 /* create video caps element */
4306 vcaps = gst_element_factory_make ("capsfilter", "videocaps");
4307 if (NULL == vcaps) {
4308 GST_ERROR_OBJECT (client, "failed to create video capsilfter element");
4312 GST_INFO_OBJECT (client, "picked xvimagesrc as video source");
4313 g_object_set (G_OBJECT (vcaps), "caps",
4314 gst_caps_new_simple ("video/x-raw",
4315 "width", G_TYPE_INT, client->cMaxWidth,
4316 "height", G_TYPE_INT, client->cMaxHeight,
4317 "format", G_TYPE_STRING, "SN12",
4318 "framerate", GST_TYPE_FRACTION, 30, 1, NULL), NULL);
4320 if(client->cvCodec == WFD_VIDEO_H264)
4321 vcodec = g_strdup("omx_h264enc");
4323 GST_ERROR_OBJECT (client, "Yet to support other than H264 format");
4327 srcbin->venc = gst_element_factory_make (vcodec, "videoenc");
4328 if (!srcbin->venc) {
4329 GST_ERROR_OBJECT (client, "failed to create video encoder element");
4332 g_object_set (srcbin->venc, "bitrate", client->bitrate, NULL);
4333 g_object_set (srcbin->venc, "byte-stream", 1, NULL);
4334 g_object_set (srcbin->venc, "append-dci", 1, NULL);
4337 srcbin->vqueue = gst_element_factory_make ("queue", "video-queue");
4338 if (!srcbin->vqueue) {
4339 GST_ERROR_OBJECT (client, "failed to create video queue element");
4343 // TODO: check whether queue is required to have default values
4345 gst_bin_add_many (srcbin->srcbin, videosrc, vcaps, srcbin->venc, srcbin->vqueue, NULL);
4346 if (!gst_element_link_many (videosrc, vcaps, srcbin->venc, srcbin->vqueue,NULL)) {
4347 GST_ERROR_OBJECT (client, "Failed to link video src elements...");
4358 gst_rtsp_client_create_filesrc_bin (GstRTSPClient * client, GstRTSPClientSrcBin *srcbin)
4360 GstElement *vdec = NULL;
4361 GstElement *videosrc = NULL;
4362 GstElement *srcdemux = NULL;
4364 videosrc = gst_element_factory_make ("filesrc", "videosrc");
4365 if (NULL == videosrc) {
4366 GST_ERROR_OBJECT (client, "failed to create filesrc element");
4369 g_object_set (videosrc, "location", client->infile, NULL);
4371 GST_INFO_OBJECT (client, "picked filesrc as video source");
4373 // TODO: need to add support for remaing demuxers
4374 srcdemux = gst_element_factory_make ("qtdemux", "demuxer");
4376 GST_ERROR_OBJECT (client, "failed to create demuxer element");
4379 g_signal_connect (srcdemux, "pad-added", G_CALLBACK(pad_added), client);
4381 srcbin->vparse = gst_element_factory_make ("legacyh264parse", "parser");
4382 if (!srcbin->vparse) {
4383 GST_ERROR_OBJECT(client, "failed to create video parse element");
4386 g_object_set (srcbin->vparse, "config-interval", 1, NULL);
4387 g_object_set (srcbin->vparse, "output-format", 1, NULL);
4389 vdec = gst_element_factory_make ("omx_h264dec", "video-dec");
4391 GST_ERROR_OBJECT(client, "failed to create video decoder element");
4395 srcbin->venc = gst_element_factory_make ("omx_h264enc", "video-enc");
4396 if (!srcbin->venc) {
4397 GST_ERROR_OBJECT(client, "failed to create video encoder element");
4400 g_object_set (srcbin->venc, "bitrate", client->bitrate, NULL);
4401 g_object_set (srcbin->venc, "byte-stream", 1, NULL);
4402 g_object_set (srcbin->venc, "append-dci", 1, NULL);
4404 srcbin->vqueue = gst_element_factory_make ("queue", "video-queue");
4405 if (!srcbin->vqueue) {
4406 GST_ERROR_OBJECT (client, "failed to create video queue element");
4410 srcbin->aqueue = gst_element_factory_make ("queue", "audio-queue");
4411 if (!srcbin->aqueue) {
4412 GST_ERROR_OBJECT (client, "failed to create audio queue element");
4416 gst_bin_add_many (srcbin->srcbin, videosrc, srcdemux, srcbin->vparse, vdec,
4417 srcbin->venc, srcbin->vqueue, srcbin->aqueue, NULL);
4419 gst_element_link (videosrc, srcdemux);
4421 if (!gst_element_link_many (srcbin->vparse, vdec, srcbin->venc, srcbin->vqueue, NULL)) {
4422 GST_ERROR_OBJECT(client,"failed to link vparse &vqueue...\n");
4433 * gst_rtsp_client_create_srcbin:
4434 * @client: client object
4436 * Creates the server source bin
4441 gst_rtsp_client_create_srcbin (GstRTSPClient * client)
4443 GstRTSPClientSrcBin *srcbin = NULL;
4444 GstElement *mux = NULL;
4445 GstElement *payload = NULL;
4446 GstPad *srcpad = NULL;
4448 srcbin = g_slice_new0 (GstRTSPClientSrcBin);
4450 /* create source bin */
4451 srcbin->srcbin = GST_BIN_CAST(gst_bin_new ("srcbin"));
4452 if (!srcbin->srcbin) {
4453 GST_ERROR_OBJECT (client, "failed to create source bin...");
4457 /* create video src element */
4458 switch (client->videosrc_type) {
4459 /* using xvimagesrc */
4460 case WFD_INI_VSRC_XVIMAGESRC: {
4461 if (!gst_rtsp_client_create_xvcapture_bin (client, srcbin)) {
4462 GST_ERROR_OBJECT (client, "failed to create xvcapture bin...");
4467 case WFD_INI_VSRC_FILESRC: {
4469 if (!gst_rtsp_client_create_filesrc_bin (client, srcbin)) {
4470 GST_ERROR_OBJECT (client, "failed to create xvcapture bin...");
4475 case WFD_INI_VSRC_CAMERASRC:
4476 case WFD_INI_VSRC_VIDEOTESTSRC:
4478 GST_ERROR_OBJECT (client, "unknow mode selected...");
4482 mux = gst_element_factory_make ("mpegtsmux", "tsmux");
4484 GST_ERROR_OBJECT (client, "failed to create muxer element");
4487 if (client->hdcp_support) {
4488 g_object_set(mux, "HDCP-IP", client->wfdsink_ip, NULL);
4489 g_object_set(mux, "HDCP-port", client->hdcp_tcpport, NULL);
4492 payload = gst_element_factory_make ("rtpmp2tpay", "pay0");
4494 GST_ERROR_OBJECT (client, "failed to create payload element");
4498 g_object_set (payload, "pt", 33, NULL);
4499 g_object_set (payload, "mtu", client->MTUsize, NULL);
4501 gst_bin_add_many (srcbin->srcbin, mux, payload, NULL);
4503 if (!gst_element_link_many (mux, payload, NULL)) {
4504 GST_ERROR_OBJECT (client, "Failed to link muxer & payload...");
4508 /* request sink pad from muxer */
4509 srcbin->mux_vsinkpad = gst_element_get_request_pad (mux, "sink_%d");
4510 if (!srcbin->mux_vsinkpad) {
4511 GST_ERROR_OBJECT (client, "Failed to get sink pad from muxer...");
4515 /* request srcpad from video queue */
4516 srcpad = gst_element_get_static_pad (srcbin->vqueue, "src");
4518 GST_ERROR_OBJECT (client, "Failed to get srcpad from video queue...");
4522 if (gst_pad_link (srcpad, srcbin->mux_vsinkpad) != GST_PAD_LINK_OK) {
4523 GST_ERROR_OBJECT (client, "Failed to link video queue src pad & muxer video sink pad...");
4527 gst_object_unref (srcpad);
4530 if (client->session_mode != WFD_INI_VIDEO_ONLY) {
4532 if (client->videosrc_type != WFD_INI_VSRC_FILESRC) {
4533 /* create audio source elements & add to pipeline */
4534 if (!gst_rtsp_client_create_audio_capture_bin (client, srcbin))
4538 /* request sink pad from muxer */
4539 srcbin->mux_asinkpad = gst_element_get_request_pad (mux, "sink_%d");
4540 if (!srcbin->mux_asinkpad) {
4541 GST_ERROR_OBJECT (client, "Failed to get sinkpad from muxer...");
4545 /* request srcpad from audio queue */
4546 srcpad = gst_element_get_static_pad (srcbin->aqueue, "src");
4548 GST_ERROR_OBJECT (client, "Failed to get srcpad from audio queue...");
4552 /* link audio queue's srcpad & muxer sink pad */
4553 if (gst_pad_link (srcpad, srcbin->mux_asinkpad) != GST_PAD_LINK_OK) {
4554 GST_ERROR_OBJECT (client, "Failed to link audio queue src pad & muxer audio sink pad...");
4558 #ifdef WFD_PAD_PROBE
4559 GstPad *pad_probe = NULL;
4560 pad_probe = gst_element_get_static_pad (mux, "src");
4561 if(NULL == pad_probe)
4563 GST_INFO("pad for probe not created");
4565 GST_INFO("pad for probe SUCCESSFUL");
4566 gst_pad_add_data_probe (pad_probe, G_CALLBACK (gst_dump_data), client);
4569 gst_object_unref (srcpad);
4573 client->srcbin = srcbin;
4575 GST_DEBUG_OBJECT (client, "successfully created source bin...");
4580 g_slice_free (GstRTSPClientSrcBin, srcbin);
4582 // TODO: Need to clean everything
4586 #ifdef WFD_PAD_PROBE
4587 static gboolean gst_dump_data (GstPad * pad, GstMiniObject * obj, gpointer u_data)
4591 GstElement *bin = (GstElement *) u_data;
4592 if (GST_IS_BUFFER (obj)) {
4593 GstBuffer *buffer = GST_BUFFER_CAST (obj);
4594 GST_LOG ("got buffer %p with size %d", buffer, GST_BUFFER_SIZE (buffer));
4595 data = GST_BUFFER_DATA(buffer);
4596 size = GST_BUFFER_SIZE(buffer);
4597 f = fopen("probe.ts", "a");
4598 fwrite(data, size, 1, f);
4606 keep_alive_response_check (gpointer userdata)
4608 GstRTSPClient *client = (GstRTSPClient *)userdata;
4612 if (client->keep_alive_flag) {
4616 GST_INFO ("%p: source error notification", client);
4617 g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_ERROR], 0, NULL);
4622 /*CHecking whether source has got response of any request.
4623 * If yes, keep alive message is sent otherwise error message
4624 * will be displayed.*/
4626 keep_alive_condition(gpointer userdata)
4628 GstRTSPClient *client;
4630 client = (GstRTSPClient *)userdata;
4634 if(client->keep_alive_lock)
4635 g_mutex_lock(client->keep_alive_lock);
4638 if(!client->keep_alive_flag) {
4639 g_timeout_add(5000, keep_alive_response_check, client);
4642 GST_DEBUG_OBJECT (client, "have received last keep alive message response");
4644 GST_DEBUG("sending keep alive message");
4645 res = gst_rtsp_client_sending_m16_message(client);
4647 client->keep_alive_flag = FALSE;
4650 GST_ERROR_OBJECT (client, "Failed to send Keep Alive Message");
4651 g_mutex_unlock(client->keep_alive_lock);
4654 g_mutex_unlock(client->keep_alive_lock);
4657 /*Sending keep_alive (M16) message.
4658 Without calling prepare_request function.*/
4661 gst_rtsp_client_sending_m16_message (GstRTSPClient * client)
4663 GstRTSPResult res = GST_RTSP_OK;
4664 GstRTSPUrl *url = NULL;
4665 GstRTSPMessage request = { 0 };
4666 gchar *url_str = NULL;
4667 GstRTSPSession *session = NULL;
4669 url = gst_rtsp_connection_get_url (client->connection);
4671 GST_ERROR_OBJECT (client, "Failed to get connection URL");
4675 url_str = gst_rtsp_url_get_request_uri (url);
4676 if (url_str == NULL) {
4677 GST_ERROR_OBJECT (client, "Failed to get connection URL");
4681 res = gst_rtsp_message_init_request (&request, GST_RTSP_GET_PARAMETER, url_str);
4683 GST_ERROR ("init request failed");
4687 if (client->sessionid) {
4688 session = gst_rtsp_session_pool_find (client->session_pool, client->sessionid);
4689 GST_INFO_OBJECT (client, "session = %p & sessionid = %s", session, session->sessionid);
4691 send_request (client, session, &request);