2 * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 * @short_description: A client connection state
22 * @see_also: #GstRTSPServer, #GstRTSPThreadPool
24 * The client object handles the connection with a client for as long as a TCP
27 * A #GstRTSPWFDClient is created by #GstRTSPServer when a new connection is
28 * accepted and it inherits the #GstRTSPMountPoints, #GstRTSPSessionPool,
29 * #GstRTSPAuth and #GstRTSPThreadPool from the server.
31 * The client connection should be configured with the #GstRTSPConnection using
32 * gst_rtsp_wfd_client_set_connection() before it can be attached to a #GMainContext
33 * using gst_rtsp_wfd_client_attach(). From then on the client will handle requests
36 * Use gst_rtsp_wfd_client_session_filter() to iterate or modify all the
37 * #GstRTSPSession objects managed by the client object.
39 * Last reviewed on 2013-07-11 (1.0.0)
45 #include "rtsp-client-wfd.h"
46 #include "rtsp-media-factory-wfd.h"
48 #include "rtsp-params.h"
50 #define GST_RTSP_WFD_CLIENT_GET_PRIVATE(obj) \
51 (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_WFD_CLIENT, GstRTSPWFDClientPrivate))
54 * send_lock, lock, tunnels_lock
57 struct _GstRTSPWFDClientPrivate
59 GstRTSPWFDClientSendFunc send_func; /* protected by send_lock */
60 gpointer send_data; /* protected by send_lock */
61 GDestroyNotify send_notify; /* protected by send_lock */
63 /* used to cache the media in the last requested DESCRIBE so that
64 * we can pick it up in the next SETUP immediately */
78 /* Parameters for WIFI-DISPLAY */
87 guint64 cNativeResolution;
88 guint64 video_resolution_supported;
89 gint video_native_resolution;
91 guint cVESAResolution;
99 guint32 cmin_slice_size;
100 guint32 cslice_enc_params;
101 guint cframe_rate_control;
109 gboolean protection_enabled;
110 GstWFDHDCPProtection hdcp_version;
111 guint32 hdcp_tcpport;
113 gboolean edid_supported;
117 guint8 keep_alive_flag;
118 GMutex keep_alive_lock;
121 #define DEFAULT_WFD_TIMEOUT 60
122 #define WFD_MOUNT_POINT "/wfd1.0/streamid=0"
126 SIGNAL_WFD_OPTIONS_REQUEST,
127 SIGNAL_WFD_GET_PARAMETER_REQUEST,
131 GST_DEBUG_CATEGORY_STATIC (rtsp_wfd_client_debug);
132 #define GST_CAT_DEFAULT rtsp_wfd_client_debug
134 static guint gst_rtsp_client_wfd_signals[SIGNAL_WFD_LAST] = { 0 };
136 static void gst_rtsp_wfd_client_get_property (GObject * object, guint propid,
137 GValue * value, GParamSpec * pspec);
138 static void gst_rtsp_wfd_client_set_property (GObject * object, guint propid,
139 const GValue * value, GParamSpec * pspec);
140 static void gst_rtsp_wfd_client_finalize (GObject * obj);
142 static gboolean handle_wfd_options_request (GstRTSPClient * client,
143 GstRTSPContext * ctx);
144 static gboolean handle_wfd_set_param_request (GstRTSPClient * client,
145 GstRTSPContext * ctx);
146 static gboolean handle_wfd_get_param_request (GstRTSPClient * client,
147 GstRTSPContext * ctx);
149 static void send_generic_wfd_response (GstRTSPWFDClient * client,
150 GstRTSPStatusCode code, GstRTSPContext * ctx);
151 static gchar *wfd_make_path_from_uri (GstRTSPClient * client,
152 const GstRTSPUrl * uri);
153 static void wfd_options_request_done (GstRTSPWFDClient * client);
154 static void wfd_get_param_request_done (GstRTSPWFDClient * client);
155 static void handle_wfd_response (GstRTSPClient * client, GstRTSPContext * ctx);
156 static void handle_wfd_play (GstRTSPClient * client, GstRTSPContext * ctx);
157 static void wfd_set_keep_alive_condition(GstRTSPClient * client);
158 static gboolean wfd_ckeck_keep_alive_response (gpointer userdata);
159 static gboolean keep_alive_condition(gpointer userdata);
161 GstRTSPResult prepare_trigger_request (GstRTSPWFDClient * client,
162 GstRTSPMessage * request, GstWFDTriggerType trigger_type, gchar * url);
164 GstRTSPResult prepare_request (GstRTSPWFDClient * client,
165 GstRTSPMessage * request, GstRTSPMethod method, gchar * url);
168 send_request (GstRTSPWFDClient * client, GstRTSPSession * session,
169 GstRTSPMessage * request);
172 prepare_response (GstRTSPWFDClient * client, GstRTSPMessage * request,
173 GstRTSPMessage * response, GstRTSPMethod method);
175 static GstRTSPResult handle_M1_message (GstRTSPWFDClient * client);
176 static GstRTSPResult handle_M3_message (GstRTSPWFDClient * client);
177 static GstRTSPResult handle_M4_message (GstRTSPWFDClient * client);
178 static GstRTSPResult handle_M16_message (GstRTSPWFDClient * client);
180 G_DEFINE_TYPE (GstRTSPWFDClient, gst_rtsp_wfd_client, GST_TYPE_RTSP_CLIENT);
183 gst_rtsp_wfd_client_class_init (GstRTSPWFDClientClass * klass)
185 GObjectClass *gobject_class;
186 GstRTSPClientClass *rtsp_client_class;
188 g_type_class_add_private (klass, sizeof (GstRTSPWFDClientPrivate));
190 gobject_class = G_OBJECT_CLASS (klass);
191 rtsp_client_class = GST_RTSP_CLIENT_CLASS (klass);
193 gobject_class->get_property = gst_rtsp_wfd_client_get_property;
194 gobject_class->set_property = gst_rtsp_wfd_client_set_property;
195 gobject_class->finalize = gst_rtsp_wfd_client_finalize;
197 //klass->create_sdp = create_sdp;
198 //klass->configure_client_media = default_configure_client_media;
199 //klass->configure_client_transport = default_configure_client_transport;
200 //klass->params_set = default_params_set;
201 //klass->params_get = default_params_get;
203 rtsp_client_class->handle_options_request = handle_wfd_options_request;
204 rtsp_client_class->handle_set_param_request = handle_wfd_set_param_request;
205 rtsp_client_class->handle_get_param_request = handle_wfd_get_param_request;
206 rtsp_client_class->make_path_from_uri = wfd_make_path_from_uri;
208 rtsp_client_class->handle_response = handle_wfd_response;
209 rtsp_client_class->play_request = handle_wfd_play;
211 gst_rtsp_client_wfd_signals[SIGNAL_WFD_OPTIONS_REQUEST] =
212 g_signal_new ("wfd-options-request", G_TYPE_FROM_CLASS (klass),
213 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPWFDClientClass,
214 wfd_options_request), NULL, NULL, g_cclosure_marshal_VOID__POINTER,
215 G_TYPE_NONE, 1, G_TYPE_POINTER);
217 gst_rtsp_client_wfd_signals[SIGNAL_WFD_GET_PARAMETER_REQUEST] =
218 g_signal_new ("wfd-get-parameter-request", G_TYPE_FROM_CLASS (klass),
219 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPWFDClientClass,
220 wfd_get_param_request), NULL, NULL, g_cclosure_marshal_VOID__POINTER,
221 G_TYPE_NONE, 1, G_TYPE_POINTER);
223 klass->wfd_options_request = wfd_options_request_done;
224 klass->wfd_get_param_request = wfd_get_param_request_done;
226 GST_DEBUG_CATEGORY_INIT (rtsp_wfd_client_debug, "rtspwfdclient", 0,
231 gst_rtsp_wfd_client_init (GstRTSPWFDClient * client)
233 GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
235 g_return_if_fail (priv != NULL);
238 priv->protection_enabled = FALSE;
239 priv->video_native_resolution = GST_WFD_VIDEO_CEA_RESOLUTION;
240 priv->video_resolution_supported = GST_WFD_CEA_640x480P60;
241 priv->audio_codec = GST_WFD_AUDIO_AAC;
242 priv->keep_alive_flag = FALSE;
243 g_mutex_init (&priv->keep_alive_lock);
245 priv->host_address = NULL;
246 GST_INFO_OBJECT (client, "Client is initialized");
249 /* A client is finalized when the connection is broken */
251 gst_rtsp_wfd_client_finalize (GObject * obj)
253 GstRTSPWFDClient *client = GST_RTSP_WFD_CLIENT (obj);
254 GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
256 g_return_if_fail (GST_IS_RTSP_WFD_CLIENT (obj));
257 g_return_if_fail (priv != NULL);
259 GST_INFO ("finalize client %p", client);
261 g_mutex_clear (&priv->keep_alive_lock);
262 G_OBJECT_CLASS (gst_rtsp_wfd_client_parent_class)->finalize (obj);
266 gst_rtsp_wfd_client_get_property (GObject * object, guint propid,
267 GValue * value, GParamSpec * pspec)
269 //GstRTSPWFDClient *client = GST_RTSP_WFD_CLIENT (object);
273 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
278 gst_rtsp_wfd_client_set_property (GObject * object, guint propid,
279 const GValue * value, GParamSpec * pspec)
281 //GstRTSPWFDClient *client = GST_RTSP_WFD_CLIENT (object);
285 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
290 * gst_rtsp_wfd_client_new:
292 * Create a new #GstRTSPWFDClient instance.
294 * Returns: a new #GstRTSPWFDClient
297 gst_rtsp_wfd_client_new (void)
299 GstRTSPWFDClient *result;
301 result = g_object_new (GST_TYPE_RTSP_WFD_CLIENT, NULL);
307 gst_rtsp_wfd_client_start_wfd (GstRTSPWFDClient * client)
309 GstRTSPResult res = GST_RTSP_OK;
310 GST_INFO_OBJECT (client, "gst_rtsp_wfd_client_start_wfd");
312 res = handle_M1_message (client);
313 if (res < GST_RTSP_OK) {
314 GST_ERROR_OBJECT (client, "handle_M1_message failed : %d", res);
321 wfd_options_request_done (GstRTSPWFDClient * client)
323 GstRTSPResult res = GST_RTSP_OK;
324 GST_INFO_OBJECT (client, "M2 done..");
326 res = handle_M3_message (client);
327 if (res < GST_RTSP_OK) {
328 GST_ERROR_OBJECT (client, "handle_M3_message failed : %d", res);
335 wfd_get_param_request_done (GstRTSPWFDClient * client)
337 GstRTSPResult res = GST_RTSP_OK;
338 GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
340 g_return_if_fail (priv != NULL);
342 priv->m3_done = TRUE;
343 GST_INFO_OBJECT (client, "M3 done..");
345 res = handle_M4_message (client);
346 if (res < GST_RTSP_OK) {
347 GST_ERROR_OBJECT (client, "handle_M4_message failed : %d", res);
354 wfd_get_prefered_audio_codec (guint8 srcAudioCodec,
355 guint sinkAudioCodec)
359 for (i = 0; i < 8; i++) {
360 if (((sinkAudioCodec << i) & 0x80)
361 && ((srcAudioCodec << i) & 0x80)) {
362 codec = (0x01 << (7 - i));
370 wfd_get_prefered_resolution (guint64 srcResolution,
371 guint64 sinkResolution,
372 GstWFDVideoNativeResolution native,
374 guint32 * cMaxHeight, guint32 * cFramerate, guint32 * interleaved)
377 guint64 resolution = 0;
378 for (i = 0; i < 32; i++) {
379 if (((sinkResolution << i) & 0x80000000)
380 && ((srcResolution << i) & 0x80000000)) {
381 resolution = (0x00000001 << (31 - i));
386 case GST_WFD_VIDEO_CEA_RESOLUTION:
388 switch (resolution) {
389 case GST_WFD_CEA_640x480P60:
395 case GST_WFD_CEA_720x480P60:
401 case GST_WFD_CEA_720x480I60:
407 case GST_WFD_CEA_720x576P50:
413 case GST_WFD_CEA_720x576I50:
419 case GST_WFD_CEA_1280x720P30:
425 case GST_WFD_CEA_1280x720P60:
431 case GST_WFD_CEA_1920x1080P30:
437 case GST_WFD_CEA_1920x1080P60:
443 case GST_WFD_CEA_1920x1080I60:
449 case GST_WFD_CEA_1280x720P25:
455 case GST_WFD_CEA_1280x720P50:
461 case GST_WFD_CEA_1920x1080P25:
467 case GST_WFD_CEA_1920x1080P50:
473 case GST_WFD_CEA_1920x1080I50:
479 case GST_WFD_CEA_1280x720P24:
485 case GST_WFD_CEA_1920x1080P24:
500 case GST_WFD_VIDEO_VESA_RESOLUTION:
502 switch (resolution) {
503 case GST_WFD_VESA_800x600P30:
509 case GST_WFD_VESA_800x600P60:
515 case GST_WFD_VESA_1024x768P30:
521 case GST_WFD_VESA_1024x768P60:
527 case GST_WFD_VESA_1152x864P30:
533 case GST_WFD_VESA_1152x864P60:
539 case GST_WFD_VESA_1280x768P30:
545 case GST_WFD_VESA_1280x768P60:
551 case GST_WFD_VESA_1280x800P30:
557 case GST_WFD_VESA_1280x800P60:
563 case GST_WFD_VESA_1360x768P30:
569 case GST_WFD_VESA_1360x768P60:
575 case GST_WFD_VESA_1366x768P30:
581 case GST_WFD_VESA_1366x768P60:
587 case GST_WFD_VESA_1280x1024P30:
593 case GST_WFD_VESA_1280x1024P60:
599 case GST_WFD_VESA_1400x1050P30:
605 case GST_WFD_VESA_1400x1050P60:
611 case GST_WFD_VESA_1440x900P30:
617 case GST_WFD_VESA_1440x900P60:
623 case GST_WFD_VESA_1600x900P30:
629 case GST_WFD_VESA_1600x900P60:
635 case GST_WFD_VESA_1600x1200P30:
641 case GST_WFD_VESA_1600x1200P60:
647 case GST_WFD_VESA_1680x1024P30:
653 case GST_WFD_VESA_1680x1024P60:
659 case GST_WFD_VESA_1680x1050P30:
665 case GST_WFD_VESA_1680x1050P60:
671 case GST_WFD_VESA_1920x1200P30:
677 case GST_WFD_VESA_1920x1200P60:
692 case GST_WFD_VIDEO_HH_RESOLUTION:
695 switch (resolution) {
696 case GST_WFD_HH_800x480P30:
701 case GST_WFD_HH_800x480P60:
706 case GST_WFD_HH_854x480P30:
711 case GST_WFD_HH_854x480P60:
716 case GST_WFD_HH_864x480P30:
721 case GST_WFD_HH_864x480P60:
726 case GST_WFD_HH_640x360P30:
731 case GST_WFD_HH_640x360P60:
736 case GST_WFD_HH_960x540P30:
741 case GST_WFD_HH_960x540P60:
746 case GST_WFD_HH_848x480P30:
751 case GST_WFD_HH_848x480P60:
777 wfd_make_path_from_uri (GstRTSPClient * client, const GstRTSPUrl * uri)
781 GST_DEBUG_OBJECT (client, "Got URI host : %s", uri->host);
782 GST_DEBUG_OBJECT (client, "Got URI abspath : %s", uri->abspath);
784 path = g_strdup ("/wfd1.0/streamid=0");
790 handle_wfd_play (GstRTSPClient * client, GstRTSPContext * ctx)
792 wfd_set_keep_alive_condition(client);
796 handle_wfd_response (GstRTSPClient * client, GstRTSPContext * ctx)
798 GstRTSPResult res = GST_RTSP_OK;
802 GstRTSPWFDClient *_client = GST_RTSP_WFD_CLIENT (client);
803 GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
805 g_return_if_fail (priv != NULL);
807 GST_INFO_OBJECT (_client, "Handling response..");
810 GST_ERROR_OBJECT (_client, "Context is NULL");
814 if (!ctx->response) {
815 GST_ERROR_OBJECT (_client, "Response is NULL");
819 /* parsing the GET_PARAMTER response */
820 res = gst_rtsp_message_get_body (ctx->response, (guint8 **) & data, &size);
821 if (res != GST_RTSP_OK) {
822 GST_ERROR_OBJECT (_client, "Failed to get body of response...");
826 GST_INFO_OBJECT (_client, "Response body is %d", size);
828 if (!priv->m3_done) {
829 GstWFDResult wfd_res;
830 GstWFDMessage *msg = NULL;
831 /* Parse M3 response from sink */
832 wfd_res = gst_wfd_message_new (&msg);
833 if (wfd_res != GST_WFD_OK) {
834 GST_ERROR_OBJECT (client, "Failed to create wfd message...");
838 wfd_res = gst_wfd_message_init (msg);
839 if (wfd_res != GST_WFD_OK) {
840 GST_ERROR_OBJECT (client, "Failed to init wfd message...");
844 wfd_res = gst_wfd_message_parse_buffer (data, size, msg);
846 GST_DEBUG_OBJECT (client, "M3 response server side message body: %s",
847 gst_wfd_message_as_text (msg));
849 /* Get the audio formats supported by WFDSink */
850 if (msg->audio_codecs) {
852 gst_wfd_message_get_supported_audio_format (msg, &priv->caCodec,
853 &priv->cFreq, &priv->cChanels, &priv->cBitwidth, &priv->caLatency);
854 if (wfd_res != GST_WFD_OK) {
855 GST_WARNING_OBJECT (client,
856 "Failed to get wfd support audio formats...");
861 /* Get the Video formats supported by WFDSink */
863 gst_wfd_message_get_supported_video_format (msg, &priv->cvCodec,
864 &priv->cNative, &priv->cNativeResolution,
865 (guint64 *) & priv->cCEAResolution,
866 (guint64 *) & priv->cVESAResolution,
867 (guint64 *) & priv->cHHResolution, &priv->cProfile, &priv->cLevel,
868 &priv->cvLatency, &priv->cMaxHeight, &priv->cMaxWidth,
869 &priv->cmin_slice_size, &priv->cslice_enc_params,
870 &priv->cframe_rate_control);
871 if (wfd_res != GST_WFD_OK) {
872 GST_WARNING_OBJECT (client,
873 "Failed to get wfd supported video formats...");
877 if (msg->client_rtp_ports) {
878 /* Get the RTP ports preferred by WFDSink */
880 gst_wfd_message_get_prefered_rtp_ports (msg, &priv->ctrans,
881 &priv->cprofile, &priv->clowertrans, &priv->crtp_port0,
883 if (wfd_res != GST_WFD_OK) {
884 GST_WARNING_OBJECT (client,
885 "Failed to get wfd prefered RTP ports...");
890 if (msg->display_edid) {
891 guint32 edid_block_count = 0;
892 gchar *edid_payload = NULL;
893 priv->edid_supported = FALSE;
894 /* Get the display edid preferred by WFDSink */
895 GST_DEBUG_OBJECT (client, "Going to gst_wfd_message_get_display_edid");
897 gst_wfd_message_get_display_edid (msg, &priv->edid_supported,
898 &edid_block_count, &edid_payload);
899 if (wfd_res != GST_WFD_OK) {
900 GST_ERROR_OBJECT (client, "Failed to get wfd display edid...");
903 GST_DEBUG_OBJECT (client, " edid supported: %d edid_block_count: %d",
904 priv->edid_supported, edid_block_count);
905 if (priv->edid_supported) {
909 (guint32) (((edid_payload[54 + 4] >> 4) << 8) | edid_payload[54 +
912 (guint32) (((edid_payload[54 + 7] >> 4) << 8) | edid_payload[54 +
914 GST_DEBUG_OBJECT (client, " edid supported Hres: %d Wres: %d",
915 priv->edid_hres, priv->edid_vres);
916 if ((priv->edid_hres < 640) || (priv->edid_vres < 480)
917 || (priv->edid_hres > 1920) || (priv->edid_vres > 1080)) {
920 priv->edid_supported = FALSE;
921 GST_WARNING_OBJECT (client, " edid invalid resolutions");
926 if (msg->content_protection) {
928 /*Get the hdcp version and tcp port by WFDSink */
930 gst_wfd_message_get_contentprotection_type (msg,
931 &priv->hdcp_version, &priv->hdcp_tcpport);
932 GST_DEBUG ("hdcp version =%d, tcp port = %d", priv->hdcp_version,
934 if (priv->hdcp_version > 0 && priv->hdcp_tcpport > 0)
935 priv->protection_enabled = TRUE;
937 if (wfd_res != GST_WFD_OK) {
938 GST_WARNING_OBJECT (client,
939 "Failed to get wfd content protection...");
943 GST_WARNING_OBJECT (client, "Don't use content protection");
947 g_signal_emit (_client,
948 gst_rtsp_client_wfd_signals[SIGNAL_WFD_GET_PARAMETER_REQUEST], 0,
951 /* TODO-WFD: Handle another GET_PARAMETER response with body */
953 } else if (size == 0) {
954 if (!priv->m1_done) {
955 GST_INFO_OBJECT (_client, "M1 response is done");
956 priv->m1_done = TRUE;
957 } else if (!priv->m4_done) {
958 GST_INFO_OBJECT (_client, "M4 response is done");
959 priv->m4_done = TRUE;
961 gst_rtsp_wfd_client_trigger_request (_client, WFD_TRIGGER_SETUP);
963 g_mutex_lock(&priv->keep_alive_lock);
964 if (priv->keep_alive_flag == FALSE) {
965 GST_INFO_OBJECT (_client, "M16 response is done");
966 priv->keep_alive_flag = TRUE;
968 g_mutex_unlock(&priv->keep_alive_lock);
979 handle_wfd_options_request (GstRTSPClient * client, GstRTSPContext * ctx)
981 GstRTSPResult res = GST_RTSP_OK;
982 GstRTSPMethod options;
985 gchar *user_agent = NULL;
987 options = GST_RTSP_OPTIONS |
991 GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
993 str = gst_rtsp_options_as_text (options);
995 /*append WFD specific method */
996 tmp = g_strdup (", org.wfa.wfd1.0");
997 g_strlcat (str, tmp, strlen (tmp) + strlen (str) + 1);
999 gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
1000 gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
1002 gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_PUBLIC, str);
1007 gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_USER_AGENT,
1009 if (res == GST_RTSP_OK) {
1010 gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_USER_AGENT,
1016 res = gst_rtsp_client_send_message (client, NULL, ctx->response);
1017 if (res != GST_RTSP_OK) {
1018 GST_ERROR_OBJECT (client, "gst_rtsp_client_send_message failed : %d", res);
1022 GST_DEBUG_OBJECT (client, "Sent M2 response...");
1024 g_signal_emit (client,
1025 gst_rtsp_client_wfd_signals[SIGNAL_WFD_OPTIONS_REQUEST], 0, ctx);
1031 handle_wfd_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
1033 GstRTSPResult res = GST_RTSP_OK;
1034 guint8 *data = NULL;
1037 GstRTSPWFDClient *_client = GST_RTSP_WFD_CLIENT (client);
1039 /* parsing the GET_PARAMTER request */
1040 res = gst_rtsp_message_get_body (ctx->request, (guint8 **) & data, &size);
1041 if (res != GST_RTSP_OK) {
1042 GST_ERROR_OBJECT (_client, "Failed to get body of request...");
1047 send_generic_wfd_response (_client, GST_RTSP_STS_OK, ctx);
1049 /* TODO-WFD: Handle other GET_PARAMETER request from sink */
1056 handle_wfd_set_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
1058 GstRTSPResult res = GST_RTSP_OK;
1059 guint8 *data = NULL;
1062 GstRTSPWFDClient *_client = GST_RTSP_WFD_CLIENT (client);
1064 res = gst_rtsp_message_get_body (ctx->request, &data, &size);
1065 if (res != GST_RTSP_OK)
1069 /* no body, keep-alive request */
1070 send_generic_wfd_response (_client, GST_RTSP_STS_OK, ctx);
1073 GST_INFO_OBJECT (_client, "SET_PARAMETER Request : %s(%d)", data, size);
1074 if (g_strcmp0 ((const gchar *) data, "wfd_idr_request"))
1075 send_generic_wfd_response (_client, GST_RTSP_STS_OK, ctx);
1078 /* TODO-WFD : Handle other set param request */
1079 send_generic_wfd_response (_client, GST_RTSP_STS_OK, ctx);
1091 GST_ERROR ("_client %p: bad request", _client);
1092 send_generic_wfd_response (_client, GST_RTSP_STS_BAD_REQUEST, ctx);
1099 gst_rtsp_wfd_client_parse_methods (GstRTSPWFDClient * client,
1100 GstRTSPMessage * response)
1102 GstRTSPHeaderField field;
1107 gboolean found_wfd_method = FALSE;
1109 /* reset supported methods */
1110 client->supported_methods = 0;
1112 /* Try Allow Header first */
1113 field = GST_RTSP_HDR_ALLOW;
1116 gst_rtsp_message_get_header (response, field, &respoptions, indx);
1117 if (indx == 0 && !respoptions) {
1118 /* if no Allow header was found then try the Public header... */
1119 field = GST_RTSP_HDR_PUBLIC;
1120 gst_rtsp_message_get_header (response, field, &respoptions, indx);
1125 /* If we get here, the server gave a list of supported methods, parse
1126 * them here. The string is like:
1128 * OPTIONS, PLAY, SETUP, ...
1130 options = g_strsplit (respoptions, ",", 0);
1132 for (i = 0; options[i]; i++) {
1136 stripped = g_strstrip (options[i]);
1137 method = gst_rtsp_find_method (stripped);
1139 if (!g_ascii_strcasecmp ("org.wfa.wfd1.0", stripped))
1140 found_wfd_method = TRUE;
1142 /* keep bitfield of supported methods */
1143 if (method != GST_RTSP_INVALID)
1144 client->supported_methods |= method;
1146 g_strfreev (options);
1151 if (!found_wfd_method) {
1152 GST_ERROR_OBJECT (client,
1153 "WFD client is not supporting WFD mandatory message : org.wfa.wfd1.0...");
1154 goto no_required_methods;
1157 /* Checking mandatory method */
1158 if (!(client->supported_methods & GST_RTSP_SET_PARAMETER)) {
1159 GST_ERROR_OBJECT (client,
1160 "WFD client is not supporting WFD mandatory message : SET_PARAMETER...");
1161 goto no_required_methods;
1164 /* Checking mandatory method */
1165 if (!(client->supported_methods & GST_RTSP_GET_PARAMETER)) {
1166 GST_ERROR_OBJECT (client,
1167 "WFD client is not supporting WFD mandatory message : GET_PARAMETER...");
1168 goto no_required_methods;
1171 if (!(client->supported_methods & GST_RTSP_OPTIONS)) {
1172 GST_INFO_OBJECT (client, "assuming OPTIONS is supported by client...");
1173 client->supported_methods |= GST_RTSP_OPTIONS;
1179 no_required_methods:
1181 GST_ELEMENT_ERROR (client, RESOURCE, OPEN_READ, (NULL),
1182 ("WFD Client does not support mandatory methods."));
1202 } GstWFDMessageType;
1205 _set_negotiated_audio_codec (GstRTSPWFDClient *client,
1208 GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
1210 GstRTSPMediaFactory *factory = NULL;
1211 GstRTSPMountPoints *mount_points = NULL;
1214 gboolean ret = TRUE;
1216 if (!(mount_points = gst_rtsp_client_get_mount_points (parent_client))) {
1218 GST_ERROR_OBJECT (client, "Failed to set negotiated audio codec: no mount points...");
1219 goto no_mount_points;
1222 path = g_strdup(WFD_MOUNT_POINT);
1225 GST_ERROR_OBJECT (client, "Failed to set negotiated audio codec: no path...");
1229 if (!(factory = gst_rtsp_mount_points_match (mount_points,
1231 GST_ERROR_OBJECT (client, "Failed to set negotiated audio codec: no factory...");
1236 gst_rtsp_media_factory_wfd_set_audio_codec (factory,
1240 g_object_unref(factory);
1245 g_object_unref(mount_points);
1251 _set_negotiated_resolution(GstRTSPWFDClient *client,
1252 guint32 width, guint32 height)
1254 GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
1256 GstRTSPMediaFactory *factory = NULL;
1257 GstRTSPMountPoints *mount_points = NULL;
1260 gboolean ret = TRUE;
1262 if (!(mount_points = gst_rtsp_client_get_mount_points (parent_client))) {
1264 GST_ERROR_OBJECT (client, "Failed to set negotiated resolution: no mount points...");
1265 goto no_mount_points;
1268 path = g_strdup(WFD_MOUNT_POINT);
1271 GST_ERROR_OBJECT (client, "Failed to set negotiated resolution: no path...");
1275 if (!(factory = gst_rtsp_mount_points_match (mount_points,
1277 GST_ERROR_OBJECT (client, "Failed to set negotiated resolution: no factory...");
1282 gst_rtsp_media_factory_wfd_set_negotiated_resolution(factory,
1286 g_object_unref(factory);
1291 g_object_unref(mount_points);
1297 _set_wfd_message_body (GstRTSPWFDClient * client, GstWFDMessageType msg_type,
1298 gchar ** data, guint * len)
1300 GString *buf = NULL;
1301 GstWFDMessage *msg = NULL;
1302 GstWFDResult wfd_res = GST_WFD_EINVAL;
1303 GstRTSPWFDClientPrivate *priv = NULL;
1304 priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
1306 g_return_if_fail (priv != NULL);
1308 buf = g_string_new ("");
1309 g_return_if_fail (buf != NULL);
1311 if (msg_type == M3_REQ_MSG) {
1312 /* create M3 request to be sent */
1313 wfd_res = gst_wfd_message_new (&msg);
1314 if (wfd_res != GST_WFD_OK) {
1315 GST_ERROR_OBJECT (client, "Failed to create wfd message...");
1319 wfd_res = gst_wfd_message_init (msg);
1320 if (wfd_res != GST_WFD_OK) {
1321 GST_ERROR_OBJECT (client, "Failed to init wfd message...");
1325 /* set the supported audio formats by the WFD server */
1327 gst_wfd_message_set_supported_audio_format (msg, GST_WFD_AUDIO_UNKNOWN,
1328 GST_WFD_FREQ_UNKNOWN, GST_WFD_CHANNEL_UNKNOWN, 0, 0);
1329 if (wfd_res != GST_WFD_OK) {
1330 GST_ERROR_OBJECT (client,
1331 "Failed to set supported audio formats on wfd message...");
1335 /* set the supported Video formats by the WFD server */
1337 gst_wfd_message_set_supported_video_format (msg, GST_WFD_VIDEO_UNKNOWN,
1338 GST_WFD_VIDEO_CEA_RESOLUTION, GST_WFD_CEA_UNKNOWN, GST_WFD_CEA_UNKNOWN,
1339 GST_WFD_VESA_UNKNOWN, GST_WFD_HH_UNKNOWN, GST_WFD_H264_UNKNOWN_PROFILE,
1340 GST_WFD_H264_LEVEL_UNKNOWN, 0, 0, 0, 0, 0, 0);
1341 if (wfd_res != GST_WFD_OK) {
1342 GST_ERROR_OBJECT (client,
1343 "Failed to set supported video formats on wfd message...");
1347 wfd_res = gst_wfd_message_set_display_edid (msg, 0, 0, NULL);
1348 if (wfd_res != GST_WFD_OK) {
1349 GST_ERROR_OBJECT (client,
1350 "Failed to set display edid type on wfd message...");
1354 if (priv->protection_enabled) {
1356 gst_wfd_message_set_contentprotection_type (msg, GST_WFD_HDCP_NONE,
1358 if (wfd_res != GST_WFD_OK) {
1359 GST_ERROR_OBJECT (client,
1360 "Failed to set supported content protection type on wfd message...");
1365 /* set the preffered RTP ports for the WFD server */
1367 gst_wfd_messge_set_prefered_rtp_ports (msg, GST_WFD_RTSP_TRANS_UNKNOWN,
1368 GST_WFD_RTSP_PROFILE_UNKNOWN, GST_WFD_RTSP_LOWER_TRANS_UNKNOWN, 0, 0);
1369 if (wfd_res != GST_WFD_OK) {
1370 GST_ERROR_OBJECT (client,
1371 "Failed to set supported video formats on wfd message...");
1375 *data = gst_wfd_message_param_names_as_text (msg);
1376 if (*data == NULL) {
1377 GST_ERROR_OBJECT (client, "Failed to get wfd message as text...");
1380 *len = strlen (*data);
1382 } else if (msg_type == M4_REQ_MSG) {
1383 GstRTSPUrl *url = NULL;
1385 GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
1386 GstRTSPConnection *connection =
1387 gst_rtsp_client_get_connection (parent_client);
1389 /* Parameters for the preffered audio formats */
1390 GstWFDAudioFormats taudiocodec = GST_WFD_AUDIO_UNKNOWN;
1391 GstWFDAudioFreq taudiofreq = GST_WFD_FREQ_UNKNOWN;
1392 GstWFDAudioChannels taudiochannels = GST_WFD_CHANNEL_UNKNOWN;
1394 /* Parameters for the preffered video formats */
1395 GstWFDVideoCEAResolution tcCEAResolution = GST_WFD_CEA_UNKNOWN;
1396 GstWFDVideoVESAResolution tcVESAResolution = GST_WFD_VESA_UNKNOWN;
1397 GstWFDVideoHHResolution tcHHResolution = GST_WFD_HH_UNKNOWN;
1398 GstWFDVideoH264Profile tcProfile;
1399 GstWFDVideoH264Level tcLevel;
1400 guint64 resolution_supported = 0;
1402 url = gst_rtsp_connection_get_url (connection);
1404 GST_ERROR_OBJECT (client, "Failed to get connection URL");
1408 /* Logic to negotiate with information of M3 response */
1409 /* create M4 request to be sent */
1410 wfd_res = gst_wfd_message_new (&msg);
1411 if (wfd_res != GST_WFD_OK) {
1412 GST_ERROR_OBJECT (client, "Failed to create wfd message...");
1416 wfd_res = gst_wfd_message_init (msg);
1417 if (wfd_res != GST_WFD_OK) {
1418 GST_ERROR_OBJECT (client, "Failed to init wfd message...");
1422 g_string_append_printf (buf, "rtsp://");
1424 if (priv->host_address) {
1425 g_string_append (buf, priv->host_address);
1427 GST_ERROR_OBJECT (client, "Failed to get host address");
1428 if (buf) g_string_free (buf, FALSE);
1432 g_string_append_printf (buf, "/wfd1.0/streamid=0");
1434 gst_wfd_message_set_presentation_url (msg, g_string_free (buf, FALSE),
1437 if (wfd_res != GST_WFD_OK) {
1438 GST_ERROR_OBJECT (client, "Failed to set presentation url");
1442 taudiocodec = wfd_get_prefered_audio_codec (priv->audio_codec, priv->caCodec);
1443 priv->caCodec = taudiocodec;
1444 if (!_set_negotiated_audio_codec(client, priv->caCodec)) {
1445 GST_ERROR_OBJECT (client, "Failed to set negotiated "
1446 "audio codec to media factory...");
1449 if (priv->cFreq & GST_WFD_FREQ_48000)
1450 taudiofreq = GST_WFD_FREQ_48000;
1451 else if (priv->cFreq & GST_WFD_FREQ_44100)
1452 taudiofreq = GST_WFD_FREQ_44100;
1453 priv->cFreq = taudiofreq;
1455 /* TODO-WFD: Currently only 2 channels is present */
1456 if (priv->cChanels & GST_WFD_CHANNEL_8)
1457 taudiochannels = GST_WFD_CHANNEL_2;
1458 else if (priv->cChanels & GST_WFD_CHANNEL_6)
1459 taudiochannels = GST_WFD_CHANNEL_2;
1460 else if (priv->cChanels & GST_WFD_CHANNEL_4)
1461 taudiochannels = GST_WFD_CHANNEL_2;
1462 else if (priv->cChanels & GST_WFD_CHANNEL_2)
1463 taudiochannels = GST_WFD_CHANNEL_2;
1464 priv->cChanels = taudiochannels;
1467 gst_wfd_message_set_prefered_audio_format (msg, taudiocodec, taudiofreq,
1468 taudiochannels, priv->cBitwidth, priv->caLatency);
1469 if (wfd_res != GST_WFD_OK) {
1470 GST_ERROR_OBJECT (priv, "Failed to set preffered audio formats...");
1474 /* Set the preffered video formats */
1475 priv->cvCodec = GST_WFD_VIDEO_H264;
1476 priv->cProfile = tcProfile = GST_WFD_H264_BASE_PROFILE;
1477 priv->cLevel = tcLevel = GST_WFD_H264_LEVEL_3_1;
1479 resolution_supported = priv->video_resolution_supported;
1481 /* TODO-WFD: Need to verify this logic
1482 if(priv->edid_supported) {
1483 if (priv->edid_hres < 1920) resolution_supported = resolution_supported & 0x8C7F;
1484 if (priv->edid_hres < 1280) resolution_supported = resolution_supported & 0x1F;
1485 if (priv->edid_hres < 720) resolution_supported = resolution_supported & 0x01;
1489 if (priv->video_native_resolution == GST_WFD_VIDEO_CEA_RESOLUTION) {
1491 wfd_get_prefered_resolution (resolution_supported,
1492 priv->cCEAResolution, priv->video_native_resolution, &priv->cMaxWidth,
1493 &priv->cMaxHeight, &priv->cFramerate, &priv->cInterleaved);
1495 ("wfd negotiated resolution: %08x, width: %d, height: %d, framerate: %d, interleaved: %d",
1496 tcCEAResolution, priv->cMaxWidth, priv->cMaxHeight, priv->cFramerate,
1497 priv->cInterleaved);
1498 } else if (priv->video_native_resolution == GST_WFD_VIDEO_VESA_RESOLUTION) {
1500 wfd_get_prefered_resolution (resolution_supported,
1501 priv->cVESAResolution, priv->video_native_resolution,
1502 &priv->cMaxWidth, &priv->cMaxHeight, &priv->cFramerate,
1503 &priv->cInterleaved);
1505 ("wfd negotiated resolution: %08x, width: %d, height: %d, framerate: %d, interleaved: %d",
1506 tcVESAResolution, priv->cMaxWidth, priv->cMaxHeight, priv->cFramerate,
1507 priv->cInterleaved);
1508 } else if (priv->video_native_resolution == GST_WFD_VIDEO_HH_RESOLUTION) {
1510 wfd_get_prefered_resolution (resolution_supported,
1511 priv->cHHResolution, priv->video_native_resolution, &priv->cMaxWidth,
1512 &priv->cMaxHeight, &priv->cFramerate, &priv->cInterleaved);
1514 ("wfd negotiated resolution: %08x, width: %d, height: %d, framerate: %d, interleaved: %d",
1515 tcHHResolution, priv->cMaxWidth, priv->cMaxHeight, priv->cFramerate,
1516 priv->cInterleaved);
1519 if (!_set_negotiated_resolution(client, priv->cMaxWidth,
1520 priv->cMaxHeight)) {
1521 GST_ERROR_OBJECT (client, "Failed to set negotiated "
1522 "resolution to media factory...");
1526 gst_wfd_message_set_prefered_video_format (msg, priv->cvCodec,
1527 priv->video_native_resolution, GST_WFD_CEA_UNKNOWN, tcCEAResolution,
1528 tcVESAResolution, tcHHResolution, tcProfile, tcLevel, priv->cvLatency,
1529 priv->cMaxWidth, priv->cMaxHeight, priv->cmin_slice_size,
1530 priv->cslice_enc_params, priv->cframe_rate_control);
1532 if (wfd_res != GST_WFD_OK) {
1533 GST_ERROR_OBJECT (client, "Failed to set preffered video formats...");
1537 /* set the preffered RTP ports for the WFD server */
1539 gst_wfd_messge_set_prefered_rtp_ports (msg, GST_WFD_RTSP_TRANS_RTP,
1540 GST_WFD_RTSP_PROFILE_AVP, GST_WFD_RTSP_LOWER_TRANS_UDP, priv->crtp_port0, priv->crtp_port1);
1541 if (wfd_res != GST_WFD_OK) {
1542 GST_ERROR_OBJECT (client,
1543 "Failed to set supported video formats on wfd message...");
1547 *data = gst_wfd_message_as_text (msg);
1548 if (*data == NULL) {
1549 GST_ERROR_OBJECT (client, "Failed to get wfd message as text...");
1552 *len = strlen (*data);
1554 } else if (msg_type == M5_REQ_MSG) {
1555 g_string_append (buf, "wfd_trigger_method: SETUP");
1556 g_string_append (buf, "\r\n");
1558 *data = g_string_free (buf, FALSE);
1559 } else if (msg_type == TEARDOWN_TRIGGER) {
1560 g_string_append (buf, "wfd_trigger_method: TEARDOWN");
1561 g_string_append (buf, "\r\n");
1563 *data = g_string_free (buf, FALSE);
1564 } else if (msg_type == PLAY_TRIGGER) {
1565 g_string_append (buf, "wfd_trigger_method: PLAY");
1566 g_string_append (buf, "\r\n");
1568 *data = g_string_free (buf, FALSE);
1569 } else if (msg_type == PAUSE_TRIGGER) {
1570 g_string_append (buf, "wfd_trigger_method: PAUSE");
1571 g_string_append (buf, "\r\n");
1573 *data = g_string_free (buf, FALSE);
1589 * @client: client object
1590 * @request : requst message to be prepared
1591 * @method : RTSP method of the request
1592 * @url : url need to be in the request
1593 * @message_type : WFD message type
1594 * @trigger_type : trigger method to be used for M5 mainly
1596 * Prepares request based on @method & @message_type
1598 * Returns: a #GstRTSPResult.
1601 prepare_request (GstRTSPWFDClient * client, GstRTSPMessage * request,
1602 GstRTSPMethod method, gchar * url)
1604 GstRTSPResult res = GST_RTSP_OK;
1607 if (method == GST_RTSP_GET_PARAMETER || method == GST_RTSP_SET_PARAMETER) {
1609 url = g_strdup ("rtsp://localhost/wfd1.0");
1612 GST_DEBUG_OBJECT (client, "Preparing request: %d", method);
1614 /* initialize the request */
1615 res = gst_rtsp_message_init_request (request, method, url);
1617 GST_ERROR ("init request failed");
1622 /* Prepare OPTIONS request to send */
1623 case GST_RTSP_OPTIONS:{
1624 /* add wfd specific require filed "org.wfa.wfd1.0" */
1625 str = g_strdup ("org.wfa.wfd1.0");
1626 res = gst_rtsp_message_add_header (request, GST_RTSP_HDR_REQUIRE, str);
1628 GST_ERROR ("Failed to add header");
1637 /* Prepare GET_PARAMETER request */
1638 case GST_RTSP_GET_PARAMETER:{
1643 /* add content type */
1645 gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE,
1648 GST_ERROR ("Failed to add header");
1652 _set_wfd_message_body (client, M3_REQ_MSG, &msg, &msglen);
1653 msglength = g_string_new ("");
1654 g_string_append_printf (msglength, "%d", msglen);
1655 GST_DEBUG ("M3 server side message body: %s", msg);
1657 /* add content-length type */
1659 gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH,
1660 g_string_free (msglength, FALSE));
1661 if (res != GST_RTSP_OK) {
1662 GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
1666 res = gst_rtsp_message_set_body (request, (guint8 *) msg, msglen);
1667 if (res != GST_RTSP_OK) {
1668 GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
1676 /* Prepare SET_PARAMETER request */
1677 case GST_RTSP_SET_PARAMETER:{
1682 /* add content type */
1684 gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE,
1686 if (res != GST_RTSP_OK) {
1687 GST_ERROR_OBJECT (client, "Failed to add header to rtsp request...");
1691 _set_wfd_message_body (client, M4_REQ_MSG, &msg, &msglen);
1692 msglength = g_string_new ("");
1693 g_string_append_printf (msglength, "%d", msglen);
1694 GST_DEBUG ("M4 server side message body: %s", msg);
1696 /* add content-length type */
1698 gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH,
1699 g_string_free (msglength, FALSE));
1700 if (res != GST_RTSP_OK) {
1701 GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
1705 res = gst_rtsp_message_set_body (request, (guint8 *) msg, msglen);
1706 if (res != GST_RTSP_OK) {
1707 GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
1722 return GST_RTSP_ERROR;
1726 prepare_trigger_request (GstRTSPWFDClient * client, GstRTSPMessage * request,
1727 GstWFDTriggerType trigger_type, gchar * url)
1729 GstRTSPResult res = GST_RTSP_OK;
1731 /* initialize the request */
1732 res = gst_rtsp_message_init_request (request, GST_RTSP_SET_PARAMETER, url);
1734 GST_ERROR ("init request failed");
1738 switch (trigger_type) {
1739 case WFD_TRIGGER_SETUP:{
1744 /* add content type */
1746 gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE,
1748 if (res != GST_RTSP_OK) {
1749 GST_ERROR_OBJECT (client, "Failed to add header to rtsp request...");
1753 _set_wfd_message_body (client, M5_REQ_MSG, &msg, &msglen);
1754 msglength = g_string_new ("");
1755 g_string_append_printf (msglength, "%d", msglen);
1756 GST_DEBUG ("M5 server side message body: %s", msg);
1758 /* add content-length type */
1760 gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH,
1761 g_string_free (msglength, FALSE));
1762 if (res != GST_RTSP_OK) {
1763 GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
1767 res = gst_rtsp_message_set_body (request, (guint8 *) msg, msglen);
1768 if (res != GST_RTSP_OK) {
1769 GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
1776 case WFD_TRIGGER_TEARDOWN:{
1781 /* add content type */
1783 gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE,
1785 if (res != GST_RTSP_OK) {
1786 GST_ERROR_OBJECT (client, "Failed to add header to rtsp request...");
1790 _set_wfd_message_body (client, TEARDOWN_TRIGGER, &msg, &msglen);
1791 msglength = g_string_new ("");
1792 g_string_append_printf (msglength, "%d", msglen);
1793 GST_DEBUG ("Trigger TEARDOWN server side message body: %s", msg);
1795 /* add content-length type */
1797 gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH,
1798 g_string_free (msglength, FALSE));
1799 if (res != GST_RTSP_OK) {
1800 GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
1804 res = gst_rtsp_message_set_body (request, (guint8 *) msg, msglen);
1805 if (res != GST_RTSP_OK) {
1806 GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
1813 case WFD_TRIGGER_PLAY:{
1818 /* add content type */
1820 gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE,
1822 if (res != GST_RTSP_OK) {
1823 GST_ERROR_OBJECT (client, "Failed to add header to rtsp request...");
1827 _set_wfd_message_body (client, PLAY_TRIGGER, &msg, &msglen);
1828 msglength = g_string_new ("");
1829 g_string_append_printf (msglength, "%d", msglen);
1830 GST_DEBUG ("Trigger PLAY server side message body: %s", msg);
1832 /* add content-length type */
1834 gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH,
1835 g_string_free (msglength, FALSE));
1836 if (res != GST_RTSP_OK) {
1837 GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
1841 res = gst_rtsp_message_set_body (request, (guint8 *) msg, msglen);
1842 if (res != GST_RTSP_OK) {
1843 GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
1850 case WFD_TRIGGER_PAUSE:{
1855 /* add content type */
1857 gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE,
1859 if (res != GST_RTSP_OK) {
1860 GST_ERROR_OBJECT (client, "Failed to add header to rtsp request...");
1864 _set_wfd_message_body (client, PAUSE_TRIGGER, &msg, &msglen);
1865 msglength = g_string_new ("");
1866 g_string_append_printf (msglength, "%d", msglen);
1867 GST_DEBUG ("Trigger PAUSE server side message body: %s", msg);
1869 /* add content-length type */
1871 gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH,
1872 g_string_free (msglength, FALSE));
1873 if (res != GST_RTSP_OK) {
1874 GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
1878 res = gst_rtsp_message_set_body (request, (guint8 *) msg, msglen);
1879 if (res != GST_RTSP_OK) {
1880 GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
1887 /* TODO-WFD: implement to handle other trigger type */
1900 send_request (GstRTSPWFDClient * client, GstRTSPSession * session,
1901 GstRTSPMessage * request)
1903 GstRTSPResult res = GST_RTSP_OK;
1904 GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
1906 /* remove any previous header */
1907 gst_rtsp_message_remove_header (request, GST_RTSP_HDR_SESSION, -1);
1909 /* add the new session header for new session ids */
1912 const gchar *sessionid = NULL;
1915 sessionid = gst_rtsp_session_get_sessionid (session);
1916 GST_INFO_OBJECT (client, "Session id : %s", sessionid);
1918 timeout = gst_rtsp_session_get_timeout (session);
1919 if (timeout != DEFAULT_WFD_TIMEOUT)
1920 str = g_strdup_printf ("%s; timeout=%d", sessionid, timeout);
1922 str = g_strdup (sessionid);
1924 gst_rtsp_message_take_header (request, GST_RTSP_HDR_SESSION, str);
1927 if (gst_debug_category_get_threshold (rtsp_wfd_client_debug) >= GST_LEVEL_LOG) {
1928 gst_rtsp_message_dump (request);
1931 res = gst_rtsp_client_send_message (parent_client, session, request);
1932 if (res != GST_RTSP_OK) {
1933 GST_ERROR_OBJECT (client, "gst_rtsp_client_send_message failed : %d", res);
1936 gst_rtsp_message_unset (request);
1941 * @client: client object
1942 * @request : requst message received
1943 * @response : response to be prepare based on request
1944 * @method : RTSP method
1946 * prepare response to the request based on @method & @message_type
1948 * Returns: a #GstRTSPResult.
1951 prepare_response (GstRTSPWFDClient * client, GstRTSPMessage * request,
1952 GstRTSPMessage * response, GstRTSPMethod method)
1954 GstRTSPResult res = GST_RTSP_OK;
1957 /* prepare OPTIONS response */
1958 case GST_RTSP_OPTIONS:{
1959 GstRTSPMethod options;
1962 gchar *user_agent = NULL;
1964 options = GST_RTSP_OPTIONS |
1968 GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
1970 str = gst_rtsp_options_as_text (options);
1972 /*append WFD specific method */
1973 tmp = g_strdup (", org.wfa.wfd1.0");
1974 g_strlcat (str, tmp, strlen (tmp) + strlen (str) + 1);
1976 gst_rtsp_message_init_response (response, GST_RTSP_STS_OK,
1977 gst_rtsp_status_as_text (GST_RTSP_STS_OK), request);
1979 gst_rtsp_message_add_header (response, GST_RTSP_HDR_PUBLIC, str);
1983 gst_rtsp_message_get_header (request, GST_RTSP_HDR_USER_AGENT,
1985 if (res == GST_RTSP_OK) {
1986 gst_rtsp_message_add_header (response, GST_RTSP_HDR_USER_AGENT,
1993 GST_ERROR_OBJECT (client, "Unhandled method...");
1994 return GST_RTSP_EINVAL;
2002 send_generic_wfd_response (GstRTSPWFDClient * client, GstRTSPStatusCode code,
2003 GstRTSPContext * ctx)
2005 GstRTSPResult res = GST_RTSP_OK;
2006 GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
2008 gst_rtsp_message_init_response (ctx->response, code,
2009 gst_rtsp_status_as_text (code), ctx->request);
2011 res = gst_rtsp_client_send_message (parent_client, NULL, ctx->response);
2012 if (res != GST_RTSP_OK) {
2013 GST_ERROR_OBJECT (client, "gst_rtsp_client_send_message failed : %d", res);
2018 static GstRTSPResult
2019 handle_M1_message (GstRTSPWFDClient * client)
2021 GstRTSPResult res = GST_RTSP_OK;
2022 GstRTSPMessage request = { 0 };
2024 res = prepare_request (client, &request, GST_RTSP_OPTIONS, (gchar *) "*");
2025 if (GST_RTSP_OK != res) {
2026 GST_ERROR_OBJECT (client, "Failed to prepare M1 request....\n");
2030 GST_DEBUG_OBJECT (client, "Sending M1 request.. (OPTIONS request)");
2032 send_request (client, NULL, &request);
2038 * handle_M3_message:
2039 * @client: client object
2041 * Handles M3 WFD message.
2042 * This API will send M3 message (GET_PARAMETER) to WFDSink to query supported formats by the WFDSink.
2043 * After getting supported formats info, this API will set those values on WFDConfigMessage obj
2045 * Returns: a #GstRTSPResult.
2047 static GstRTSPResult
2048 handle_M3_message (GstRTSPWFDClient * client)
2050 GstRTSPResult res = GST_RTSP_OK;
2051 GstRTSPMessage request = { 0 };
2052 GstRTSPUrl *url = NULL;
2053 gchar *url_str = NULL;
2055 GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
2056 GstRTSPConnection *connection =
2057 gst_rtsp_client_get_connection (parent_client);
2059 url = gst_rtsp_connection_get_url (connection);
2061 GST_ERROR_OBJECT (client, "Failed to get connection URL");
2062 res = GST_RTSP_ERROR;
2066 url_str = gst_rtsp_url_get_request_uri (url);
2067 if (url_str == NULL) {
2068 GST_ERROR_OBJECT (client, "Failed to get connection URL");
2069 res = GST_RTSP_ERROR;
2073 res = prepare_request (client, &request, GST_RTSP_GET_PARAMETER, url_str);
2074 if (GST_RTSP_OK != res) {
2075 GST_ERROR_OBJECT (client, "Failed to prepare M3 request....\n");
2079 GST_DEBUG_OBJECT (client, "Sending GET_PARAMETER request message (M3)...");
2081 send_request (client, NULL, &request);
2089 static GstRTSPResult
2090 handle_M4_message (GstRTSPWFDClient * client)
2092 GstRTSPResult res = GST_RTSP_OK;
2093 GstRTSPMessage request = { 0 };
2094 GstRTSPUrl *url = NULL;
2095 gchar *url_str = NULL;
2097 GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
2098 GstRTSPConnection *connection =
2099 gst_rtsp_client_get_connection (parent_client);
2101 url = gst_rtsp_connection_get_url (connection);
2103 GST_ERROR_OBJECT (client, "Failed to get connection URL");
2104 res = GST_RTSP_ERROR;
2108 url_str = gst_rtsp_url_get_request_uri (url);
2109 if (url_str == NULL) {
2110 GST_ERROR_OBJECT (client, "Failed to get connection URL");
2111 res = GST_RTSP_ERROR;
2115 res = prepare_request (client, &request, GST_RTSP_SET_PARAMETER, url_str);
2116 if (GST_RTSP_OK != res) {
2117 GST_ERROR_OBJECT (client, "Failed to prepare M4 request....\n");
2121 GST_DEBUG_OBJECT (client, "Sending SET_PARAMETER request message (M4)...");
2123 send_request (client, NULL, &request);
2132 gst_rtsp_wfd_client_trigger_request (GstRTSPWFDClient * client,
2133 GstWFDTriggerType type)
2135 GstRTSPResult res = GST_RTSP_OK;
2136 GstRTSPMessage request = { 0 };
2137 GstRTSPUrl *url = NULL;
2138 gchar *url_str = NULL;
2140 GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
2141 GstRTSPConnection *connection =
2142 gst_rtsp_client_get_connection (parent_client);
2144 url = gst_rtsp_connection_get_url (connection);
2146 GST_ERROR_OBJECT (client, "Failed to get connection URL");
2147 res = GST_RTSP_ERROR;
2151 url_str = gst_rtsp_url_get_request_uri (url);
2152 if (url_str == NULL) {
2153 GST_ERROR_OBJECT (client, "Failed to get connection URL");
2154 res = GST_RTSP_ERROR;
2158 res = prepare_trigger_request (client, &request, type, url_str);
2159 if (GST_RTSP_OK != res) {
2160 GST_ERROR_OBJECT (client, "Failed to prepare M5 request....\n");
2164 GST_DEBUG_OBJECT (client, "Sending trigger request message...: %d", type);
2166 send_request (client, NULL, &request);
2175 gst_rtsp_wfd_client_set_video_supported_resolution (GstRTSPWFDClient * client,
2176 guint64 supported_reso)
2178 GstRTSPResult res = GST_RTSP_OK;
2179 GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
2181 g_return_val_if_fail (priv != NULL, GST_RTSP_EINVAL);
2183 priv->video_resolution_supported = supported_reso;
2184 GST_DEBUG ("Resolution : %"G_GUINT64_FORMAT, supported_reso);
2190 gst_rtsp_wfd_client_set_video_native_resolution (GstRTSPWFDClient * client,
2191 guint64 native_reso)
2193 GstRTSPResult res = GST_RTSP_OK;
2194 GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
2196 g_return_val_if_fail (priv != NULL, GST_RTSP_EINVAL);
2198 priv->video_native_resolution = native_reso;
2199 GST_DEBUG ("Native Resolution : %"G_GUINT64_FORMAT, native_reso);
2205 gst_rtsp_wfd_client_set_audio_codec (GstRTSPWFDClient * client,
2208 GstRTSPResult res = GST_RTSP_OK;
2209 GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
2211 g_return_val_if_fail (priv != NULL, GST_RTSP_EINVAL);
2213 priv->audio_codec = audio_codec;
2214 GST_DEBUG ("Audio codec : %d", audio_codec);
2220 wfd_ckeck_keep_alive_response (gpointer userdata)
2222 GstRTSPWFDClient *client = (GstRTSPWFDClient *)userdata;
2223 GstRTSPWFDClientPrivate *priv = NULL;
2228 priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
2229 g_return_val_if_fail (priv != NULL, GST_RTSP_EINVAL);
2231 if (priv->keep_alive_flag) {
2235 GST_INFO ("%p: source error notification", client);
2236 // FIXME Do something here. Maybe emit some signal?
2241 /*Sending keep_alive (M16) message.
2242 Without calling prepare_request function.*/
2243 static GstRTSPResult
2244 handle_M16_message (GstRTSPWFDClient * client)
2246 GstRTSPResult res = GST_RTSP_OK;
2247 GstRTSPMessage request = { 0 };
2248 gchar *url_str = NULL;
2250 url_str = g_strdup("rtsp://localhost/wfd1.0");
2252 res = gst_rtsp_message_init_request (&request, GST_RTSP_GET_PARAMETER, url_str);
2254 GST_ERROR ("init request failed");
2258 send_request (client, NULL, &request);
2262 /*CHecking whether source has got response of any request.
2263 * If yes, keep alive message is sent otherwise error message
2264 * will be displayed.*/
2266 keep_alive_condition(gpointer userdata)
2268 GstRTSPWFDClient *client;
2269 GstRTSPWFDClientPrivate *priv;
2271 client = (GstRTSPWFDClient *)userdata;
2275 priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
2277 g_return_val_if_fail (priv != NULL, FALSE);
2279 g_mutex_lock(&priv->keep_alive_lock);
2280 if(!priv->keep_alive_flag) {
2281 g_timeout_add(5000, wfd_ckeck_keep_alive_response, client);
2284 GST_DEBUG_OBJECT (client, "have received last keep alive message response");
2287 GST_DEBUG("sending keep alive message");
2288 res = handle_M16_message(client);
2289 if(res == GST_RTSP_OK) {
2290 priv->keep_alive_flag = FALSE;
2292 GST_ERROR_OBJECT (client, "Failed to send Keep Alive Message");
2293 g_mutex_unlock(&priv->keep_alive_lock);
2297 g_mutex_unlock(&priv->keep_alive_lock);
2302 void wfd_set_keep_alive_condition(GstRTSPClient * client)
2304 GstRTSPWFDClient *wfd_client;
2305 wfd_client = GST_RTSP_WFD_CLIENT(client);
2307 g_timeout_add((DEFAULT_WFD_TIMEOUT-5)*1000, keep_alive_condition, wfd_client);
2311 gst_rtsp_wfd_client_set_host_address (GstRTSPWFDClient *client, const gchar * address)
2313 GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
2315 g_return_if_fail (priv != NULL);
2317 if (priv->host_address) {
2318 g_free (priv->host_address);
2321 priv->host_address = g_strdup (address);