Add AL-FEC feature
[platform/upstream/gst-rtsp-server.git] / gst / rtsp-server / rtsp-client-ext.c
1 /* GStreamer
2  * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
3  *
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.
8  *
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.
13  *
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.
18  */
19 /**
20  * SECTION:rtsp-client
21  * @short_description: A client connection state
22  * @see_also: #GstRTSPServer, #GstRTSPThreadPool
23  *
24  * The client object handles the connection with a client for as long as a TCP
25  * connection is open.
26  *
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.
30  *
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
34  * on the connection.
35  *
36  * Use gst_rtsp_wfd_client_session_filter() to iterate or modify all the
37  * #GstRTSPSession objects managed by the client object.
38  *
39  * Last reviewed on 2013-07-11 (1.0.0)
40  */
41
42 #include <stdio.h>
43 #include <string.h>
44
45 #include "rtsp-client-ext.h"
46 #include "rtsp-media-factory-wfd.h"
47 #include "rtsp-sdp.h"
48 #include "rtsp-params.h"
49 #include "rtsp-media-ext.h"
50 #include "gstwfdmessage-ext.h"
51
52 #define GST_RTSP_EXT_CLIENT_GET_PRIVATE(obj)  \
53    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_EXT_CLIENT, GstRTSPExtClientPrivate))
54
55 struct _GstRTSPExtClientPrivate
56 {
57   GstRTSPMediaExt *media;
58   guint resend_packets;
59   guint prev_max_seqnum;
60   guint prev_fraction_lost;
61   guint32 prev_max_packets_lost;
62   gboolean first_rtcp;
63   guint consecutive_low_bitrate_count;
64
65   guint tizen_retransmission_rtp_port;
66   guint tizen_retransmission_rtcp_port;
67   guint tizen_fec_t_max;
68   guint tizen_fec_p_max;
69   guint tizen_latency_mode;
70 };
71
72 #define WFD_MOUNT_POINT "/wfd1.0/streamid=0"
73 #define UNSTABLE_NETWORK_INTERVAL 15
74 #define MIN_PORT_NUM 1024
75 #define MAX_PORT_NUM 65535
76 #define TIZEN_RETRANSMISSION_RTP_PORT_NONE 0
77 #define TIZEN_RETRANSMISSION_RTCP_PORT_NONE 0
78 #define MIN_FEC_T_NUM 2
79 #define MAX_FEC_T_NUM 100
80 #define MIN_FEC_P_NUM 2
81 #define MAX_FEC_P_NUM 100
82 #define TIZEN_T_MAX_NONE 0
83 #define TIZEN_P_MAX_NONE 0
84 #define TIZEN_USER_AGENT "TIZEN"
85 #define DEFAULT_WFD_TIMEOUT 60
86
87 GST_DEBUG_CATEGORY_STATIC (rtsp_ext_client_debug);
88 #define GST_CAT_DEFAULT rtsp_ext_client_debug
89
90 static gboolean ext_configure_client_media (GstRTSPClient * client,
91     GstRTSPMedia * media, GstRTSPStream * stream, GstRTSPContext * ctx);
92 static void handle_ext_stats (GstRTSPWFDClient * client, GstStructure * stats);
93 static gchar* handle_ext_m3_req_msg (GstRTSPWFDClient * client, gchar * data);
94 static void handle_ext_set_param_msg (GstRTSPWFDClient * client, gchar * data);
95
96 static void handle_ext_m3_res_msg (GstRTSPWFDClient * client, gchar * data);
97 static gchar* handle_ext_m4_req_msg (GstRTSPWFDClient * client, gchar * data);
98
99 static void gst_rtsp_ext_client_finalize (GObject * obj);
100
101 G_DEFINE_TYPE (GstRTSPExtClient, gst_rtsp_ext_client, GST_TYPE_RTSP_WFD_CLIENT);
102
103 static void
104 gst_rtsp_ext_client_class_init (GstRTSPExtClientClass * klass)
105 {
106   GObjectClass *gobject_class;
107   GstRTSPClientClass *rtsp_client_class;
108   GstRTSPWFDClientClass *wfd_client_class;
109
110   g_type_class_add_private (klass, sizeof (GstRTSPExtClientPrivate));
111
112   gobject_class = G_OBJECT_CLASS (klass);
113   rtsp_client_class = GST_RTSP_CLIENT_CLASS (klass);
114   wfd_client_class = GST_RTSP_WFD_CLIENT_CLASS (klass);
115
116   gobject_class->finalize = gst_rtsp_ext_client_finalize;
117
118   rtsp_client_class->configure_client_media = ext_configure_client_media;
119   wfd_client_class->wfd_rtp_stats = handle_ext_stats;
120   wfd_client_class->wfd_handle_m3_req_msg = handle_ext_m3_req_msg;
121   wfd_client_class->wfd_handle_m3_res_msg = handle_ext_m3_res_msg;
122   wfd_client_class->wfd_handle_m4_req_msg = handle_ext_m4_req_msg;
123   wfd_client_class->wfd_handle_set_param_msg = handle_ext_set_param_msg;
124
125   GST_DEBUG_CATEGORY_INIT (rtsp_ext_client_debug, "rtspextclient", 0,
126       "GstRTSPExtClient");
127 }
128
129 static void
130 gst_rtsp_ext_client_init (GstRTSPExtClient * client)
131 {
132   GstRTSPExtClientPrivate *priv = GST_RTSP_EXT_CLIENT_GET_PRIVATE (client);
133
134   client->priv = priv;
135   priv->resend_packets = 0;
136   priv->prev_max_seqnum = 0;
137   priv->prev_fraction_lost = 0;
138   priv->prev_max_packets_lost = 0;
139   priv->first_rtcp = FALSE;
140   priv->consecutive_low_bitrate_count = 0;
141   priv->tizen_retransmission_rtp_port = TIZEN_RETRANSMISSION_RTP_PORT_NONE;
142   priv->tizen_retransmission_rtcp_port = TIZEN_RETRANSMISSION_RTCP_PORT_NONE;
143   priv->tizen_fec_t_max = TIZEN_T_MAX_NONE;
144   priv->tizen_fec_p_max = TIZEN_P_MAX_NONE;
145   priv->tizen_latency_mode = GST_WFD_TIZEN_LATENCY_NONE;
146
147   GST_INFO_OBJECT (client, "Client is initialized");
148
149   return;
150 }
151
152 /* A client is finalized when the connection is broken */
153 static void
154 gst_rtsp_ext_client_finalize (GObject * obj)
155 {
156   GstRTSPExtClient *client = GST_RTSP_EXT_CLIENT (obj);
157 //  GstRTSPExtClientPrivate *priv = GST_RTSP_EXT_CLIENT_GET_PRIVATE (client);
158
159   GST_INFO ("finalize client %p", client);
160
161   G_OBJECT_CLASS (gst_rtsp_ext_client_parent_class)->finalize (obj);
162 }
163
164 /**
165  * gst_rtsp_ext_client_new:
166  *
167  * Create a new #GstRTSPExtClient instance.
168  *
169  * Returns: a new #GstRTSPExtClient
170  */
171 GstRTSPExtClient *
172 gst_rtsp_ext_client_new (void)
173 {
174   GstRTSPExtClient *result;
175
176   result = g_object_new (GST_TYPE_RTSP_EXT_CLIENT, NULL);
177
178   return result;
179 }
180
181 static gboolean
182 ext_configure_client_media (GstRTSPClient * client, GstRTSPMedia * media,
183     GstRTSPStream * stream, GstRTSPContext * ctx)
184 {
185   GstRTSPMediaExt* _media = NULL;
186   GstRTSPExtClient *_client = GST_RTSP_EXT_CLIENT (client);
187   GstRTSPExtClientPrivate *priv = GST_RTSP_EXT_CLIENT_GET_PRIVATE (_client);
188
189   _media = GST_RTSP_MEDIA_EXT (media);
190
191   if (GST_IS_RTSP_MEDIA_EXT (_media)) {
192     if (_media != priv->media) {
193       GST_ERROR_OBJECT (client, "Different media!");
194       priv->media = _media;
195     }
196   }
197
198   return GST_RTSP_WFD_CLIENT_CLASS (gst_rtsp_ext_client_parent_class)->
199       configure_client_media (client, media, stream, ctx);
200 }
201
202 static gboolean
203 _set_venc_bitrate (GstRTSPWFDClient * client, gint bitrate)
204 {
205   GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
206
207   GstRTSPMediaFactory *factory = NULL;
208   GstRTSPMountPoints *mount_points = NULL;
209   gchar *path = NULL;
210   gint matched = 0;
211   gboolean ret = TRUE;
212
213   if (!(mount_points = gst_rtsp_client_get_mount_points (parent_client))) {
214     ret = FALSE;
215     GST_ERROR_OBJECT (client,
216         "Failed to set negotiated resolution: no mount points...");
217     goto no_mount_points;
218   }
219
220   path = g_strdup (WFD_MOUNT_POINT);
221   if (!path) {
222     ret = FALSE;
223     GST_ERROR_OBJECT (client,
224         "Failed to set negotiated resolution: no path...");
225     goto no_path;
226   }
227
228   if (!(factory = gst_rtsp_mount_points_match (mount_points, path, &matched))) {
229     GST_ERROR_OBJECT (client,
230         "Failed to set negotiated resolution: no factory...");
231     ret = FALSE;
232     goto no_factory;
233   }
234
235   gst_rtsp_media_factory_wfd_set_venc_bitrate (factory, bitrate);
236   ret = TRUE;
237
238   g_object_unref (factory);
239
240 no_factory:
241   g_free (path);
242 no_path:
243   g_object_unref (mount_points);
244 no_mount_points:
245   return ret;
246 }
247
248 static gboolean
249 _get_venc_bitrate (GstRTSPWFDClient * client, gint * bitrate)
250 {
251   GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
252
253   GstRTSPMediaFactory *factory = NULL;
254   GstRTSPMountPoints *mount_points = NULL;
255   gchar *path = NULL;
256   gint matched = 0;
257   gboolean ret = TRUE;
258
259   if (!(mount_points = gst_rtsp_client_get_mount_points (parent_client))) {
260     ret = FALSE;
261     GST_ERROR_OBJECT (client,
262         "Failed to set negotiated resolution: no mount points...");
263     goto no_mount_points;
264   }
265
266   path = g_strdup (WFD_MOUNT_POINT);
267   if (!path) {
268     ret = FALSE;
269     GST_ERROR_OBJECT (client,
270         "Failed to set negotiated resolution: no path...");
271     goto no_path;
272   }
273
274   if (!(factory = gst_rtsp_mount_points_match (mount_points, path, &matched))) {
275     GST_ERROR_OBJECT (client,
276         "Failed to set negotiated resolution: no factory...");
277     ret = FALSE;
278     goto no_factory;
279   }
280
281   gst_rtsp_media_factory_wfd_get_venc_bitrate (factory, bitrate);
282   ret = TRUE;
283
284   g_object_unref (factory);
285
286 no_factory:
287   g_free (path);
288 no_path:
289   g_object_unref (mount_points);
290 no_mount_points:
291   return ret;
292 }
293
294 static gboolean
295 _get_config_bitrate (GstRTSPWFDClient * client, guint32 * min, guint32 * max)
296 {
297   GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
298
299   GstRTSPMediaFactory *factory = NULL;
300   GstRTSPMountPoints *mount_points = NULL;
301   gchar *path = NULL;
302   gint matched = 0;
303   gboolean ret = TRUE;
304
305   if (!(mount_points = gst_rtsp_client_get_mount_points (parent_client))) {
306     ret = FALSE;
307     GST_ERROR_OBJECT (client,
308         "Failed to set negotiated resolution: no mount points...");
309     goto no_mount_points;
310   }
311
312   path = g_strdup (WFD_MOUNT_POINT);
313   if (!path) {
314     ret = FALSE;
315     GST_ERROR_OBJECT (client,
316         "Failed to set negotiated resolution: no path...");
317     goto no_path;
318   }
319
320   if (!(factory = gst_rtsp_mount_points_match (mount_points, path, &matched))) {
321     GST_ERROR_OBJECT (client,
322         "Failed to set negotiated resolution: no factory...");
323     ret = FALSE;
324     goto no_factory;
325   }
326
327   gst_rtsp_media_factory_wfd_get_config_bitrate (factory, min, max);
328   ret = TRUE;
329
330   g_object_unref (factory);
331
332 no_factory:
333   g_free (path);
334 no_path:
335   g_object_unref (mount_points);
336 no_mount_points:
337   return ret;
338 }
339
340 static gboolean
341 _bitrate_config (GstRTSPWFDClient * client, gint bitrate, guint32 min_bitrate)
342 {
343   GstRTSPExtClient *_client = GST_RTSP_EXT_CLIENT (client);
344   GstRTSPExtClientPrivate *priv = GST_RTSP_EXT_CLIENT_GET_PRIVATE (_client);
345   gint prev_bitrate;
346
347   _get_venc_bitrate (client, &prev_bitrate);
348
349   if (prev_bitrate != bitrate) {
350     _set_venc_bitrate (client, bitrate);
351     GST_INFO_OBJECT (client, "[UDP] New Bitrate value [%d]", bitrate);
352   }
353
354   if (prev_bitrate == min_bitrate && prev_bitrate == bitrate)
355     priv->consecutive_low_bitrate_count++;
356   else
357     priv->consecutive_low_bitrate_count = 0;
358
359   if (priv->consecutive_low_bitrate_count >= UNSTABLE_NETWORK_INTERVAL) {
360     /* Network congestion happens. Add logic for popup warning or something else */
361     GST_WARNING_OBJECT (client, "Network unstable");
362     priv->consecutive_low_bitrate_count = 0;
363   }
364
365   return TRUE;
366 }
367
368 static void
369 handle_ext_stats (GstRTSPWFDClient * client, GstStructure * stats)
370 {
371   GstRTSPExtClient *_client = GST_RTSP_EXT_CLIENT (client);
372   GstRTSPExtClientPrivate *priv = GST_RTSP_EXT_CLIENT_GET_PRIVATE (_client);
373   guint latest_resend_packets = 0;
374
375   g_return_val_if_fail (priv != NULL, FALSE);
376
377   latest_resend_packets = gst_rtsp_media_ext_get_resent_packets (priv->media);
378
379   GST_INFO_OBJECT (client, "Re-sent RTP packets : %d", latest_resend_packets);
380
381   /* calculation to decide bitrate */
382   {
383     static gint32 next_k = 40;
384     static gint32 next_p = 0;
385     guint32 min_bitrate = 0;
386     guint32 max_bitrate = 0;
387     guint fraction_lost = 0;
388     guint max_seqnum = 0;
389     gint packetslost;
390     gint bitrate = 0;
391     gint temp_fraction_lost = 0;
392     gint statistics_fraction_lost = 0;
393     gfloat thretholdValue = 0;
394     static gint fraction_lost_MA = 0;
395
396     gst_structure_get_uint (stats, "rb-fractionlost", &fraction_lost);
397     gst_structure_get_uint (stats, "rb-exthighestseq", &max_seqnum);
398     gst_structure_get_int (stats, "rb-packetslost", &packetslost);
399
400     _get_venc_bitrate (client, &bitrate);
401     GST_INFO_OBJECT (client, "[UDP] Current Bitrate value [%d]", bitrate);
402
403     _get_config_bitrate (client, &min_bitrate, &max_bitrate);
404     GST_INFO_OBJECT (client, "[UDP] min [%d], max [%d]", min_bitrate,
405         max_bitrate);
406
407     if (priv->resend_packets == latest_resend_packets)
408       fraction_lost = 0;
409     priv->resend_packets = latest_resend_packets;
410
411     if (priv->prev_max_seqnum == max_seqnum)
412       goto config;
413
414     if (priv->first_rtcp == FALSE) {
415       GST_DEBUG_OBJECT (client, "Ignoring first receiver report");
416       priv->prev_fraction_lost = 0;
417       priv->prev_max_packets_lost = packetslost;
418       priv->prev_max_seqnum = max_seqnum;
419       fraction_lost_MA = 0;
420       priv->first_rtcp = TRUE;
421       return;
422     }
423
424     if (priv->prev_fraction_lost == 0)
425       thretholdValue = 1.0;
426     else
427       thretholdValue = 0.8;
428
429     if (fraction_lost > 0) {
430       temp_fraction_lost = fraction_lost * 100 / 256;
431       GST_DEBUG_OBJECT (client, "fraction lost from sink RR [%d]",
432           temp_fraction_lost);
433     } else {
434       if ((max_seqnum > priv->prev_max_seqnum)
435           && (packetslost > priv->prev_max_packets_lost))
436         temp_fraction_lost =
437             (((packetslost - priv->prev_max_packets_lost) * 100) / (max_seqnum -
438                 priv->prev_max_seqnum));
439       GST_DEBUG_OBJECT (client, "fraction lost calculated [%d]",
440           temp_fraction_lost);
441     }
442     statistics_fraction_lost =
443         (gint) (temp_fraction_lost * thretholdValue +
444         priv->prev_fraction_lost * (1 - thretholdValue));
445     fraction_lost_MA =
446         (fraction_lost_MA * 7 + statistics_fraction_lost * 5) / 8;
447
448     if (fraction_lost_MA > 100)
449       fraction_lost_MA = 100;
450
451     GST_DEBUG_OBJECT (client,
452         "statistics fraction lost = %d, fraction lost MA = %d",
453         statistics_fraction_lost, fraction_lost_MA);
454
455     if (temp_fraction_lost > 0) {
456       guint32 temp_change_bandwith_amount = 0;
457       gint32 fec_step = 0;
458
459       if (statistics_fraction_lost >= 5) {
460         temp_change_bandwith_amount = max_bitrate - min_bitrate;
461         fec_step = 10;
462       } else if (temp_fraction_lost >= 3) {
463         temp_change_bandwith_amount = (max_bitrate - min_bitrate) / 2;
464         fec_step = 5;
465       } else {
466         temp_change_bandwith_amount = (max_bitrate - min_bitrate) / 4;
467         fec_step = 3;
468       }
469
470       GST_DEBUG_OBJECT (client,
471           "LOSS case, statistics fraction lost = %d percent, temp change"
472           "bandwith amount = %d bit", statistics_fraction_lost,
473           temp_change_bandwith_amount);
474
475       if (next_p >= 100)
476         next_k -= fec_step;
477       else
478         next_p += fec_step;
479
480       if (next_k < 10)
481         next_k = 10;
482
483       if (next_p > 100)
484         next_p = 100;
485
486       if (bitrate <= min_bitrate) {
487         bitrate = min_bitrate;
488         priv->prev_fraction_lost = statistics_fraction_lost;
489         priv->prev_max_packets_lost = packetslost;
490         goto config;
491       }
492
493       bitrate -= temp_change_bandwith_amount;
494
495       if (bitrate < min_bitrate)
496         bitrate = min_bitrate;
497
498     } else if (0 == temp_fraction_lost && fraction_lost_MA < 1) {
499       gint32 fec_step = 0;
500
501       if (0 == priv->prev_fraction_lost) {
502         bitrate += 512 * 1024;
503         fec_step = 10;
504       } else {
505         bitrate += 100 * 1024;
506         fec_step = 5;
507       }
508
509       if (bitrate > max_bitrate)
510         bitrate = max_bitrate;
511
512       if (next_p <= 0)
513         next_k += fec_step;
514       else
515         next_p -= fec_step;
516
517       if (next_k > 100)
518         next_k = 100;
519
520       if (next_p < 0)
521         next_p = 0;
522
523       if (bitrate >= max_bitrate) {
524         GST_DEBUG_OBJECT (client, "bitrate can not be increased");
525         bitrate = max_bitrate;
526         priv->prev_fraction_lost = statistics_fraction_lost;
527         priv->prev_max_seqnum = max_seqnum;
528         priv->prev_max_packets_lost = packetslost;
529         goto config;
530       }
531
532     }
533
534     priv->prev_fraction_lost = statistics_fraction_lost;
535     priv->prev_max_seqnum = max_seqnum;
536     priv->prev_max_packets_lost = packetslost;
537
538     GST_INFO_OBJECT (client, "final bitrate is %d", bitrate);
539
540   config:
541     _bitrate_config (client, bitrate, min_bitrate);
542     gst_rtsp_media_ext_set_next_param (priv->media, next_k, next_p);
543   }
544 }
545
546 static gchar *
547 handle_ext_m3_req_msg (GstRTSPWFDClient * client, gchar * data)
548 {
549   gchar *tmp = NULL;
550   gchar *sink_user_agent = NULL;
551   GstWFDExtMessage *msg = NULL;
552   GstWFDResult wfd_res = GST_WFD_EINVAL;
553   gboolean is_appended = FALSE;
554
555   g_return_if_fail (client != NULL);
556   g_return_val_if_fail (data != NULL, NULL);
557
558   sink_user_agent = gst_rtsp_wfd_client_get_sink_user_agent (client);
559
560   if (sink_user_agent && strstr (sink_user_agent, TIZEN_USER_AGENT)) {
561
562     GST_INFO_OBJECT (client,
563         "Setting tizen extended features on wfd message...");
564
565     wfd_res = gst_wfd_ext_message_new (&msg);
566     if (wfd_res != GST_WFD_OK) {
567       GST_ERROR_OBJECT (client, "Failed to create wfd message...");
568       goto error;
569     }
570
571     wfd_res = gst_wfd_ext_message_init (msg);
572     if (wfd_res != GST_WFD_OK) {
573       GST_ERROR_OBJECT (client, "Failed to init wfd message...");
574       goto error;
575     }
576
577     GST_INFO_OBJECT (client,
578         "Setting tizen extended features on wfd message...");
579
580     wfd_res = gst_wfd_ext_message_set_tizen_retransmission (msg, 0, 0);
581     if (wfd_res != GST_WFD_OK) {
582       GST_ERROR_OBJECT (client,
583           "Failed to set tizen retransmission on wfd message...");
584       goto error;
585     }
586
587     wfd_res = gst_wfd_ext_message_set_tizen_fec (msg, 0, 0);
588     if (wfd_res != GST_WFD_OK) {
589       GST_ERROR_OBJECT (client, "Failed to set tizen fec on wfd message...");
590       goto error;
591     }
592
593     wfd_res = gst_wfd_ext_message_set_tizen_latency_mode (msg, 0);
594     if (wfd_res != GST_WFD_OK) {
595       GST_ERROR_OBJECT (client,
596           "Failed to set tizen latency mode on wfd message...");
597       goto error;
598     }
599
600     tmp = gst_wfd_ext_message_param_names_as_text (msg);
601     if (tmp) {
602       data = g_strconcat (data, tmp, NULL);
603       g_free (tmp);
604       is_appended = TRUE;
605     } else {
606       GST_ERROR_OBJECT (client,
607           "Failed to gst_wfd_ext_message_param_names_as_text");
608       goto error;
609     }
610   }
611   if (msg != NULL)
612     gst_wfd_ext_message_free (msg);
613
614   if (sink_user_agent != NULL)
615     g_free (sink_user_agent);
616
617   if (is_appended == FALSE)
618     return NULL;
619   else
620     return data;
621
622 error:
623   if (msg != NULL)
624     gst_wfd_ext_message_free (msg);
625
626   if (sink_user_agent != NULL)
627     g_free (sink_user_agent);
628
629   return NULL;
630 }
631
632 static void
633 handle_ext_m3_res_msg (GstRTSPWFDClient * client, gchar * data)
634 {
635   GstWFDExtMessage *msg = NULL;
636   GstRTSPExtClientPrivate *ext_priv = GST_RTSP_EXT_CLIENT_GET_PRIVATE (client);
637   GstWFDResult wfd_res = GST_WFD_EINVAL;
638
639   g_return_if_fail (ext_priv != NULL);
640   g_return_val_if_fail (data != NULL, NULL);
641
642   wfd_res = gst_wfd_ext_message_new (&msg);
643   if (wfd_res != GST_WFD_OK) {
644     GST_ERROR_OBJECT (client, "Failed to create wfd message...");
645     goto error;
646   }
647
648   wfd_res = gst_wfd_ext_message_init (msg);
649   if (wfd_res != GST_WFD_OK) {
650     GST_ERROR_OBJECT (client, "Failed to init wfd message...");
651     goto error;
652   }
653
654   wfd_res =
655       gst_wfd_ext_message_parse_buffer ((const guint8 *) data, strlen (data),
656       msg);
657   if (wfd_res != GST_WFD_OK) {
658     GST_ERROR_OBJECT (client, "Failed to parse buffer...");
659     goto error;
660   }
661
662   /* Get tizen extended features from WFD message. */
663   if (msg->tizen_retransmission) {
664
665     guint rtp_port = TIZEN_RETRANSMISSION_RTP_PORT_NONE;
666     guint rtcp_port = TIZEN_RETRANSMISSION_RTCP_PORT_NONE;
667     wfd_res =
668         gst_wfd_ext_message_get_tizen_retransmission (msg, &rtp_port,
669         &rtcp_port);
670     if (wfd_res != GST_WFD_OK) {
671       GST_ERROR_OBJECT (client,
672           "Failed to get tizen retransmission from wfd message...");
673       goto error;
674     }
675
676     if (rtp_port >= MIN_PORT_NUM && rtp_port <= MAX_PORT_NUM)
677       ext_priv->tizen_retransmission_rtp_port = rtp_port;
678
679     if (rtcp_port >= MIN_PORT_NUM && rtcp_port <= MAX_PORT_NUM)
680       ext_priv->tizen_retransmission_rtcp_port = rtcp_port;
681
682     GST_DEBUG_OBJECT (client, "Tizen retransmission rtp_port[%d] rtcp_port[%d]",
683         ext_priv->tizen_retransmission_rtp_port,
684         ext_priv->tizen_retransmission_rtcp_port);
685   }
686
687   if (msg->tizen_fec) {
688
689     guint fec_t_max = TIZEN_T_MAX_NONE;
690     guint fec_p_max = TIZEN_P_MAX_NONE;
691
692     wfd_res = gst_wfd_ext_message_get_tizen_fec (msg, &fec_t_max, &fec_p_max);
693     if (wfd_res != GST_WFD_OK) {
694       GST_ERROR_OBJECT (client, "Failed to get tizen fec from wfd message...");
695       goto error;
696     }
697
698     if (fec_t_max >= MIN_FEC_T_NUM && fec_t_max <= MAX_FEC_T_NUM)
699       ext_priv->tizen_fec_t_max = fec_t_max;
700
701     if (fec_p_max >= MIN_FEC_P_NUM && fec_p_max <= MAX_FEC_P_NUM)
702       ext_priv->tizen_fec_p_max = fec_p_max;
703
704     GST_DEBUG_OBJECT (client, "Tizen fec t_max[%d] p_max[%d]",
705         ext_priv->tizen_fec_t_max, ext_priv->tizen_fec_p_max);
706   }
707
708   if (msg->tizen_latency_mode) {
709     wfd_res =
710         gst_wfd_ext_message_get_tizen_latency_mode (msg,
711         &ext_priv->tizen_latency_mode);
712     if (wfd_res != GST_WFD_OK) {
713       GST_ERROR_OBJECT (client,
714           "Failed to get tizen latency mode on wfd message...");
715       goto error;
716     }
717     GST_DEBUG_OBJECT (client, "Tizen latency mode[%d]",
718         ext_priv->tizen_latency_mode);
719   }
720
721   if (msg != NULL)
722     gst_wfd_ext_message_free (msg);
723
724   return;
725 error:
726
727   if (msg != NULL)
728     gst_wfd_ext_message_free (msg);
729
730   return;
731 }
732
733 static void
734 media_ext_constructed (GstRTSPMediaFactory * factory, GstRTSPMedia * media,
735     GstRTSPExtClient * client)
736 {
737   GstRTSPExtClientPrivate *priv = GST_RTSP_EXT_CLIENT_GET_PRIVATE (client);
738   g_return_if_fail (priv != NULL);
739
740   priv->media = GST_RTSP_MEDIA_EXT (media);
741
742   if (priv->tizen_retransmission_rtp_port != TIZEN_RETRANSMISSION_RTP_PORT_NONE
743       && priv->tizen_retransmission_rtcp_port !=
744       TIZEN_RETRANSMISSION_RTCP_PORT_NONE) {
745     GST_DEBUG_OBJECT (client, "Tizen retransmission rtp_port[%d] rtcp_port[%d]",
746         priv->tizen_retransmission_rtp_port,
747         priv->tizen_retransmission_rtcp_port);
748     gst_rtsp_media_ext_set_extended_mode (priv->media, MEDIA_EXT_MODE_RESEND);
749     gst_rtsp_media_ext_set_retrans_port (priv->media,
750         priv->tizen_retransmission_rtp_port);
751   }
752   if (priv->tizen_fec_t_max != TIZEN_T_MAX_NONE
753       && priv->tizen_fec_p_max != TIZEN_P_MAX_NONE) {
754     GST_DEBUG_OBJECT (client, "Tizen fec t_max[%d] p_max[%d]",
755         priv->tizen_fec_t_max, priv->tizen_fec_p_max);
756     gst_rtsp_media_ext_set_extended_mode (priv->media, MEDIA_EXT_MODE_FEC);
757     gst_rtsp_media_ext_set_fec_value (priv->media, priv->tizen_fec_t_max,
758         priv->tizen_fec_p_max);
759   }
760   if (priv->tizen_latency_mode != GST_WFD_TIZEN_LATENCY_NONE) {
761     GST_DEBUG_OBJECT (client, "Tizen latency mode[%d]",
762         priv->tizen_latency_mode);
763     gst_rtsp_media_ext_set_latency_mode (priv->media, priv->tizen_latency_mode);
764   }
765 }
766
767 static void
768 gst_wfd_ext_listen_media_constructed (GstRTSPWFDClient * client)
769 {
770   GstRTSPMediaFactory *factory = NULL;
771   GstRTSPMountPoints *mount_points = NULL;
772   gchar *path = NULL;
773   gint matched = 0;
774   GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
775
776   GstRTSPExtClient *_client = GST_RTSP_EXT_CLIENT (client);
777
778   if (!(mount_points = gst_rtsp_client_get_mount_points (parent_client))) {
779     GST_ERROR_OBJECT (client,
780         "Failed to set negotiated resolution: no mount points...");
781     goto no_mount_points;
782   }
783
784   path = g_strdup (WFD_MOUNT_POINT);
785   if (!path) {
786     GST_ERROR_OBJECT (client,
787         "Failed to set negotiated resolution: no path...");
788     goto no_path;
789   }
790
791   if (!(factory = gst_rtsp_mount_points_match (mount_points, path, &matched))) {
792     GST_ERROR_OBJECT (client,
793         "Failed to set negotiated resolution: no factory...");
794     goto no_factory;
795   }
796
797   g_signal_connect (factory, "media-constructed",
798       (GCallback) media_ext_constructed, _client);
799
800 no_factory:
801   g_free (path);
802 no_path:
803   g_object_unref (mount_points);
804 no_mount_points:
805   return;
806 }
807
808 static void
809 handle_ext_set_param_msg (GstRTSPWFDClient * client, gchar * data)
810 {
811   GstRTSPExtClientPrivate *priv = GST_RTSP_EXT_CLIENT_GET_PRIVATE (client);
812
813   g_return_if_fail (priv != NULL);
814   g_return_val_if_fail (data != NULL, NULL);
815
816   return;
817 }
818
819 static gchar *
820 handle_ext_m4_req_msg (GstRTSPWFDClient * client, gchar * data)
821 {
822   GstWFDExtMessage *msg = NULL;
823   gchar *tmp = NULL;
824   GstRTSPExtClientPrivate *ext_priv = GST_RTSP_EXT_CLIENT_GET_PRIVATE (client);
825   GstWFDResult wfd_res = GST_WFD_EINVAL;
826   gboolean is_appended = FALSE;
827
828   g_return_if_fail (ext_priv != NULL);
829   g_return_val_if_fail (data != NULL, NULL);
830
831   wfd_res = gst_wfd_ext_message_new (&msg);
832   if (wfd_res != GST_WFD_OK) {
833     GST_ERROR_OBJECT (client, "Failed to create wfd message...");
834     goto error;
835   }
836
837   wfd_res = gst_wfd_ext_message_init (msg);
838   if (wfd_res != GST_WFD_OK) {
839     GST_ERROR_OBJECT (client, "Failed to init wfd message...");
840     goto error;
841   }
842
843   GST_INFO_OBJECT (client, "Setting extended features on wfd message...");
844
845   if (ext_priv->tizen_retransmission_rtp_port !=
846       TIZEN_RETRANSMISSION_RTP_PORT_NONE
847       && ext_priv->tizen_retransmission_rtcp_port !=
848       TIZEN_RETRANSMISSION_RTCP_PORT_NONE) {
849
850     wfd_res =
851         gst_wfd_ext_message_set_tizen_retransmission (msg,
852         ext_priv->tizen_retransmission_rtp_port,
853         ext_priv->tizen_retransmission_rtcp_port);
854     if (wfd_res != GST_WFD_OK) {
855       GST_ERROR_OBJECT (client,
856           "Failed to set tizen retransmission on wfd message...");
857       goto error;
858     }
859     GST_DEBUG_OBJECT (client, "Tizen retransmission rtp_port[%d] rtcp_port[%d]",
860         ext_priv->tizen_retransmission_rtp_port,
861         ext_priv->tizen_retransmission_rtcp_port);
862   }
863
864   if (ext_priv->tizen_fec_t_max != TIZEN_T_MAX_NONE
865       && ext_priv->tizen_fec_p_max != TIZEN_P_MAX_NONE) {
866
867     wfd_res =
868         gst_wfd_ext_message_set_tizen_fec (msg, ext_priv->tizen_fec_t_max,
869         ext_priv->tizen_fec_p_max);
870     if (wfd_res != GST_WFD_OK) {
871       GST_ERROR_OBJECT (client, "Failed to set tizen fec on wfd message...");
872       goto error;
873     }
874     GST_DEBUG_OBJECT (client, "Tizen fec t_max[%d] p_max[%d]",
875         ext_priv->tizen_fec_t_max, ext_priv->tizen_fec_p_max);
876   }
877
878   if (ext_priv->tizen_latency_mode != GST_WFD_TIZEN_LATENCY_NONE) {
879
880     wfd_res =
881         gst_wfd_ext_message_set_tizen_latency_mode (msg,
882         ext_priv->tizen_latency_mode);
883     if (wfd_res != GST_WFD_OK) {
884       GST_ERROR_OBJECT (client,
885           "Failed to set tizen latency mode on wfd message...");
886       goto error;
887     }
888     GST_DEBUG_OBJECT (client, "Tizen latency mode[%d]",
889         ext_priv->tizen_latency_mode);
890   }
891
892   tmp = gst_wfd_ext_message_as_text (msg);
893   if (tmp) {
894     data = g_strconcat (data, tmp, NULL);
895     g_free (tmp);
896     is_appended = TRUE;
897   } else {
898     GST_ERROR_OBJECT (client, "Failed to gst_wfd_ext_message_as_text");
899     goto error;
900   }
901
902   if (msg != NULL)
903     gst_wfd_ext_message_free (msg);
904
905   gst_wfd_ext_listen_media_constructed (client);
906
907   if (is_appended == FALSE) {
908     return NULL;
909   } else {
910     return data;
911   };
912
913   return data;
914 error:
915   if (tmp != NULL)
916     g_free (tmp);
917
918   if (msg != NULL)
919     gst_wfd_ext_message_free (msg);
920
921   return NULL;
922 }