Apply Wifi Display feature 34/52634/1 submit/tizen/20151127.020604 submit/tizen/20151127.065352 submit/tizen/20151201.024149
authorHyunjun Ko <zzoon.ko@samsung.com>
Wed, 25 Nov 2015 08:24:27 +0000 (17:24 +0900)
committerHyunjun Ko <zzoon.ko@samsung.com>
Wed, 25 Nov 2015 08:24:27 +0000 (17:24 +0900)
Change-Id: I5c928adb9525f9c69bafcd263d0d538490ce42c1

18 files changed:
.gitignore [deleted file]
.gitmodules [deleted file]
gst-rtsp-server.manifest [new file with mode: 0644]
gst/rtsp-server/Makefile.am
gst/rtsp-server/gstwfdmessage.c [new file with mode: 0755]
gst/rtsp-server/gstwfdmessage.h [new file with mode: 0755]
gst/rtsp-server/rtsp-client-wfd.c [new file with mode: 0644]
gst/rtsp-server/rtsp-client-wfd.h [new file with mode: 0644]
gst/rtsp-server/rtsp-client.c
gst/rtsp-server/rtsp-client.h
gst/rtsp-server/rtsp-media-factory-wfd.c [new file with mode: 0644]
gst/rtsp-server/rtsp-media-factory-wfd.h [new file with mode: 0644]
gst/rtsp-server/rtsp-server-wfd.c [new file with mode: 0644]
gst/rtsp-server/rtsp-server-wfd.h [new file with mode: 0644]
gst/rtsp-server/rtsp-stream.c
gst/rtsp-server/rtsp-stream.h
packaging/common.tar.bz2 [new file with mode: 0644]
packaging/gst-rtsp-server.spec [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
deleted file mode 100644 (file)
index 574f665..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-*.[oa]
-*.pyc
-*.gcda
-*.gcno
-*.la
-*.lo
-*.loT
-*.sw[po]
-*.tar.*
-*~
-*.gc??
-.deps
-.libs
-ABOUT-NLS
-INSTALL
-Makefile
-Makefile.in
-aclocal.m4
-autom4te.cache
-autoregen.sh
-compile
-config.guess
-config.h
-config.h.in
-config.log
-config.rpath
-config.status
-config.sub
-configure
-depcomp
-install-sh
-libtool
-ltmain.sh
-missing
-stamp-h1
-tags
-gst-rtsp.spec
-stamp-h.in
-.dirstamp
-
-/m4/*m4
-
-/gst/rtsp-server/GstRtspServer-1.0.gir
-/gst/rtsp-server/GstRtspServer-1.0.typelib
-
-/examples/test-multicast
-/examples/test-multicast2
-
-/test-driver
-/tests/check/gst/*.log
-/tests/check/gst/*.trs
-/tests/check/test-suite.log
-/tests/check/gst/addresspool
-/tests/check/gst/client
-/tests/check/gst/media
-/tests/check/gst/mediafactory
-/tests/check/gst/mountpoints
-/tests/check/gst/permissions
-/tests/check/gst/rtspserver
-/tests/check/gst/sessionmedia
-/tests/check/gst/sessionpool
-/tests/check/gst/stream
-/tests/check/gst/threadpool
-/tests/check/gst/token
-/tests/check/test-registry.reg
-/tests/test-reuse
-
-/po
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644 (file)
index a6b1eda..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "common"]
-       path = common
-       url = git://anongit.freedesktop.org/gstreamer/common
diff --git a/gst-rtsp-server.manifest b/gst-rtsp-server.manifest
new file mode 100644 (file)
index 0000000..a76fdba
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_" />
+       </request>
+</manifest>
index 4fcd366..60eaf3e 100644 (file)
@@ -7,6 +7,7 @@ public_headers = \
                rtsp-thread-pool.h \
                rtsp-media.h \
                rtsp-media-factory.h \
+               rtsp-media-factory-wfd.h \
                rtsp-media-factory-uri.h \
                rtsp-mount-points.h \
                rtsp-permissions.h \
@@ -16,8 +17,11 @@ public_headers = \
                rtsp-session-media.h \
                rtsp-session-pool.h \
                rtsp-token.h \
+               rtsp-client-wfd.h \
                rtsp-client.h \
-               rtsp-server.h
+               rtsp-server-wfd.h \
+               rtsp-server.h \
+               gstwfdmessage.h
 
 c_sources = \
        rtsp-auth.c \
@@ -28,6 +32,7 @@ c_sources = \
        rtsp-thread-pool.c \
        rtsp-media.c \
        rtsp-media-factory.c \
+       rtsp-media-factory-wfd.c \
        rtsp-media-factory-uri.c \
        rtsp-mount-points.c \
        rtsp-permissions.c \
@@ -37,7 +42,10 @@ c_sources = \
        rtsp-session-media.c \
        rtsp-session-pool.c \
        rtsp-token.c \
+       gstwfdmessage.c \
+       rtsp-client-wfd.c \
        rtsp-client.c \
+       rtsp-server-wfd.c \
        rtsp-server.c
 
 noinst_HEADERS = 
diff --git a/gst/rtsp-server/gstwfdmessage.c b/gst/rtsp-server/gstwfdmessage.c
new file mode 100755 (executable)
index 0000000..b70e57d
--- /dev/null
@@ -0,0 +1,1968 @@
+/* GStreamer
+ * Copyright (C) 2015 Samsung Electronics Hyunjun Ko <zzoon.ko@samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/**
+ * SECTION:gstwfdmessage
+ * @short_description: Helper methods for dealing with WFD messages
+ *
+ * <refsect2>
+ * <para>
+ * The GstWFDMessage helper functions makes it easy to parse and create WFD
+ * messages.
+ * </para>
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gio/gio.h>
+
+#include "gstwfdmessage.h"
+
+#define EDID_BLOCK_SIZE 128
+#define EDID_BLOCK_COUNT_MAX_SIZE 256
+#define MAX_PORT_SIZE 65535
+
+#define FREE_STRING(field)              g_free (field); (field) = NULL
+#define REPLACE_STRING(field, val)      FREE_STRING(field); (field) = g_strdup (val)
+
+#define INIT_ARRAY(field, type, init_func)              \
+G_STMT_START {                                          \
+  if (field) {                                          \
+    guint i;                                            \
+    for(i = 0; i < (field)->len; i++)                   \
+      init_func (&g_array_index ((field), type, i));    \
+    g_array_set_size ((field), 0);                      \
+  }                                                     \
+  else                                                  \
+    (field) = g_array_new (FALSE, TRUE, sizeof (type)); \
+} G_STMT_END
+
+#define FREE_ARRAY(field)         \
+G_STMT_START {                    \
+  if (field)                      \
+    g_array_free ((field), TRUE); \
+  (field) = NULL;                 \
+} G_STMT_END
+
+#define DEFINE_STRING_SETTER(field)                                     \
+GstWFDResult gst_wfd_message_set_##field (GstWFDMessage *msg, const gchar *val) { \
+  g_free (msg->field);                                                  \
+  msg->field = g_strdup (val);                                          \
+  return GST_WFD_OK;                                                    \
+}
+#define DEFINE_STRING_GETTER(field)                                     \
+const gchar* gst_wfd_message_get_##field (const GstWFDMessage *msg) {   \
+  return msg->field;                                                    \
+}
+
+#define DEFINE_ARRAY_LEN(field)                                         \
+guint gst_wfd_message_##field##_len (const GstWFDMessage *msg) {        \
+  return msg->field->len;                                               \
+}
+#define DEFINE_ARRAY_GETTER(method, field, type)                        \
+const type * gst_wfd_message_get_##method (const GstWFDMessage *msg, guint idx) {  \
+  return &g_array_index (msg->field, type, idx);                        \
+}
+#define DEFINE_PTR_ARRAY_GETTER(method, field, type)                    \
+const type gst_wfd_message_get_##method (const GstWFDMessage *msg, guint idx) {    \
+  return g_array_index (msg->field, type, idx);                         \
+}
+#define DEFINE_ARRAY_INSERT(method, field, intype, dup_method, type)         \
+GstWFDResult gst_wfd_message_insert_##method (GstWFDMessage *msg, gint idx, intype val) {   \
+  type vt;                                                              \
+  type* v = &vt;                                                         \
+  dup_method (v, val);                                                  \
+  if (idx == -1)                                                        \
+    g_array_append_val (msg->field, vt);                                \
+  else                                                                  \
+    g_array_insert_val (msg->field, idx, vt);                           \
+  return GST_WFD_OK;                                                    \
+}
+
+#define DEFINE_ARRAY_REPLACE(method, field, intype, free_method, dup_method, type)         \
+GstWFDResult gst_wfd_message_replace_##method (GstWFDMessage *msg, guint idx, intype val) {   \
+  type *v = &g_array_index (msg->field, type, idx);                   \
+  free_method (v);                                                    \
+  dup_method (v, val);                                                  \
+  return GST_WFD_OK;                                                    \
+}
+#define DEFINE_ARRAY_REMOVE(method, field, type, free_method)                        \
+GstWFDResult gst_wfd_message_remove_##method (GstWFDMessage *msg, guint idx) {  \
+  type *v = &g_array_index (msg->field, type, idx);                     \
+  free_method (v);                                                      \
+  g_array_remove_index (msg->field, idx);                               \
+  return GST_WFD_OK;                                                    \
+}
+#define DEFINE_ARRAY_ADDER(method, type)                                \
+GstWFDResult gst_wfd_message_add_##method (GstWFDMessage *msg, const type val) {   \
+  return gst_wfd_message_insert_##method (msg, -1, val);                \
+}
+
+#define dup_string(v,val) ((*v) = g_strdup (val))
+#define INIT_STR_ARRAY(field) \
+    INIT_ARRAY (field, gchar *, free_string)
+#define DEFINE_STR_ARRAY_GETTER(method, field) \
+    DEFINE_PTR_ARRAY_GETTER(method, field, gchar *)
+#define DEFINE_STR_ARRAY_INSERT(method, field) \
+    DEFINE_ARRAY_INSERT (method, field, const gchar *, dup_string, gchar *)
+#define DEFINE_STR_ARRAY_ADDER(method, field) \
+    DEFINE_ARRAY_ADDER (method, gchar *)
+#define DEFINE_STR_ARRAY_REPLACE(method, field) \
+    DEFINE_ARRAY_REPLACE (method, field, const gchar *, free_string, dup_string, gchar *)
+#define DEFINE_STR_ARRAY_REMOVE(method, field) \
+    DEFINE_ARRAY_REMOVE (method, field, gchar *, free_string)
+
+static GstWFDMessage *gst_wfd_message_boxed_copy (GstWFDMessage * orig);
+static void gst_wfd_message_boxed_free (GstWFDMessage * msg);
+
+G_DEFINE_BOXED_TYPE (GstWFDMessage, gst_wfd_message, gst_wfd_message_boxed_copy,
+    gst_wfd_message_boxed_free);
+
+static GstWFDMessage *
+gst_wfd_message_boxed_copy (GstWFDMessage * orig)
+{
+  GstWFDMessage *copy;
+
+  if (gst_wfd_message_copy (orig, &copy) == GST_WFD_OK)
+    return copy;
+
+  return NULL;
+}
+
+static void
+gst_wfd_message_boxed_free (GstWFDMessage * msg)
+{
+  gst_wfd_message_free (msg);
+}
+
+/**
+ * gst_wfd_message_new:
+ * @msg: (out) (transfer full): pointer to new #GstWFDMessage
+ *
+ * Allocate a new GstWFDMessage and store the result in @msg.
+ *
+ * Returns: a #GstWFDResult.
+ */
+GstWFDResult
+gst_wfd_message_new (GstWFDMessage ** msg)
+{
+  GstWFDMessage *newmsg;
+
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+
+  newmsg = g_new0 (GstWFDMessage, 1);
+
+  *msg = newmsg;
+
+  return gst_wfd_message_init (newmsg);
+}
+
+/**
+ * gst_wfd_message_init:
+ * @msg: a #GstWFDMessage
+ *
+ * Initialize @msg so that its contents are as if it was freshly allocated
+ * with gst_wfd_message_new(). This function is mostly used to initialize a message
+ * allocated on the stack. gst_wfd_message_uninit() undoes this operation.
+ *
+ * When this function is invoked on newly allocated data (with malloc or on the
+ * stack), its contents should be set to 0 before calling this function.
+ *
+ * Returns: a #GstWFDResult.
+ */
+GstWFDResult
+gst_wfd_message_init (GstWFDMessage * msg)
+{
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+
+  return GST_WFD_OK;
+}
+
+/**
+ * gst_wfd_message_uninit:
+ * @msg: a #GstWFDMessage
+ *
+ * Free all resources allocated in @msg. @msg should not be used anymore after
+ * this function. This function should be used when @msg was allocated on the
+ * stack and initialized with gst_wfd_message_init().
+ *
+ * Returns: a #GstWFDResult.
+ */
+GstWFDResult
+gst_wfd_message_uninit (GstWFDMessage * msg)
+{
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+
+  if (msg->audio_codecs) {
+    guint i = 0;
+    if (msg->audio_codecs->list) {
+      for (; i < msg->audio_codecs->count; i++) {
+        FREE_STRING(msg->audio_codecs->list[i].audio_format);
+        msg->audio_codecs->list[i].modes = 0;
+        msg->audio_codecs->list[i].latency = 0;
+      }
+      FREE_STRING(msg->audio_codecs->list);
+    }
+    FREE_STRING(msg->audio_codecs);
+  }
+
+  if (msg->video_formats) {
+    FREE_STRING(msg->video_formats->list);
+    FREE_STRING(msg->video_formats);
+  }
+
+  if (msg->video_3d_formats) {
+    FREE_STRING(msg->video_3d_formats->list);
+    FREE_STRING(msg->video_3d_formats);
+  }
+
+  if (msg->content_protection) {
+    if (msg->content_protection->hdcp2_spec) {
+      FREE_STRING(msg->content_protection->hdcp2_spec->hdcpversion);
+      FREE_STRING(msg->content_protection->hdcp2_spec->TCPPort);
+      FREE_STRING(msg->content_protection->hdcp2_spec);
+    }
+    FREE_STRING(msg->content_protection);
+  }
+
+  if (msg->display_edid) {
+    if (msg->display_edid->edid_payload)
+      FREE_STRING(msg->display_edid->edid_payload);
+    FREE_STRING(msg->display_edid);
+  }
+
+  if (msg->coupled_sink) {
+    if (msg->coupled_sink->coupled_sink_cap) {
+      FREE_STRING(msg->coupled_sink->coupled_sink_cap->sink_address);
+      FREE_STRING(msg->coupled_sink->coupled_sink_cap);
+    }
+    FREE_STRING(msg->coupled_sink);
+  }
+
+  if (msg->trigger_method) {
+    FREE_STRING(msg->trigger_method->wfd_trigger_method);
+    FREE_STRING(msg->trigger_method);
+  }
+
+  if (msg->presentation_url) {
+    FREE_STRING(msg->presentation_url->wfd_url0);
+    FREE_STRING(msg->presentation_url->wfd_url1);
+    FREE_STRING(msg->presentation_url);
+  }
+
+  if (msg->client_rtp_ports) {
+    FREE_STRING(msg->client_rtp_ports->profile);
+    FREE_STRING(msg->client_rtp_ports->mode);
+    FREE_STRING(msg->client_rtp_ports);
+  }
+
+  if (msg->route) {
+    FREE_STRING(msg->route->destination);
+    FREE_STRING(msg->route);
+  }
+
+  if (msg->I2C) {
+    FREE_STRING(msg->I2C);
+  }
+
+  if (msg->av_format_change_timing) {
+    FREE_STRING(msg->av_format_change_timing);
+  }
+
+  if (msg->preferred_display_mode) {
+    FREE_STRING(msg->preferred_display_mode);
+  }
+
+  if (msg->standby_resume_capability) {
+    FREE_STRING(msg->standby_resume_capability);
+  }
+
+  if (msg->standby) {
+    FREE_STRING(msg->standby);
+  }
+
+  if (msg->connector_type) {
+    FREE_STRING(msg->connector_type);
+  }
+
+  if (msg->idr_request) {
+    FREE_STRING(msg->idr_request);
+  }
+
+  return GST_WFD_OK;
+}
+
+/**
+ * gst_wfd_message_copy:
+ * @msg: a #GstWFDMessage
+ * @copy: (out) (transfer full): pointer to new #GstWFDMessage
+ *
+ * Allocate a new copy of @msg and store the result in @copy. The value in
+ * @copy should be release with gst_wfd_message_free function.
+ *
+ * Returns: a #GstWFDResult
+ *
+ * Since: 1.6
+ */
+GstWFDResult
+gst_wfd_message_copy (const GstWFDMessage * msg, GstWFDMessage ** copy)
+{
+  GstWFDResult ret;
+  GstWFDMessage *cp;
+
+  if (msg == NULL)
+    return GST_WFD_EINVAL;
+
+  ret = gst_wfd_message_new (copy);
+  if (ret != GST_WFD_OK)
+    return ret;
+
+  cp = *copy;
+
+  /* TODO-WFD */
+  if (msg->client_rtp_ports) {
+    cp->client_rtp_ports = g_malloc (sizeof (GstWFDClientRtpPorts));
+    if (cp->client_rtp_ports) {
+      cp->client_rtp_ports->profile = g_strdup (msg->client_rtp_ports->profile);
+      cp->client_rtp_ports->rtp_port0 = msg->client_rtp_ports->rtp_port0;
+      cp->client_rtp_ports->rtp_port1 = msg->client_rtp_ports->rtp_port1;
+      cp->client_rtp_ports->mode = g_strdup (msg->client_rtp_ports->mode);
+    }
+  }
+
+  return GST_WFD_OK;
+}
+
+
+static void
+_read_string_space_ended (gchar * dest, guint size, gchar * src)
+{
+  guint idx = 0;
+
+  while (!g_ascii_isspace (*src) && *src != '\0') {
+    if (idx < size - 1)
+      dest[idx++] = *src;
+    src++;
+  }
+
+  if (size > 0)
+    dest[idx] = '\0';
+
+  return;
+}
+
+static void
+_read_string_attr_and_value (gchar * attr, gchar * value, guint tsize,
+    guint vsize, gchar del, gchar * src)
+{
+  guint idx;
+
+  idx = 0;
+
+  while (*src != del && *src != '\0') {
+    if (idx < tsize - 1)
+      attr[idx++] = *src;
+    src++;
+  }
+
+  if (tsize > 0)
+    attr[idx] = '\0';
+
+  src++;
+  idx = 0;
+
+  while (*src != '\0') {
+    if (idx < vsize - 1)
+      value[idx++] = *src;
+    src++;
+  }
+
+  if (vsize > 0)
+    value[idx] = '\0';
+
+  return;
+}
+
+static void
+gst_wfd_parse_attribute (gchar * buffer, GstWFDMessage * msg)
+{
+  gchar attr[8192] = { 0 };
+  gchar value[8192] = { 0 };
+  gchar temp[8192] = { 0 };
+  gchar *p = buffer;
+  gchar *v = value;
+
+#define WFD_SKIP_SPACE(q) if (*q && g_ascii_isspace (*q)) q++
+#define WFD_SKIP_EQUAL(q) if (*q && *q == '=') q++
+#define WFD_SKIP_COMMA(q) if (*q && g_ascii_ispunct (*q)) q++
+#define WFD_READ_STRING(field) _read_string_space_ended (temp, sizeof (temp), v); v+=strlen(temp); REPLACE_STRING (field, temp)
+#define WFD_READ_UINT32(field) _read_string_space_ended (temp, sizeof (temp), v); v+=strlen(temp); field = strtoul (temp, NULL, 16)
+#define WFD_READ_UINT32_DIGIT(field) _read_string_space_ended (temp, sizeof (temp), v); v+=strlen(temp); field = strtoul (temp, NULL, 10)
+
+  _read_string_attr_and_value (attr, value, sizeof (attr), sizeof (value), ':',
+      p);
+
+  if (!g_strcmp0 (attr, GST_STRING_WFD_AUDIO_CODECS)) {
+    msg->audio_codecs = g_new0 (GstWFDAudioCodeclist, 1);
+    if (strlen (v)) {
+      guint i = 0;
+      msg->audio_codecs->count = strlen (v) / 16;
+      msg->audio_codecs->list =
+          g_new0 (GstWFDAudioCodec, msg->audio_codecs->count);
+      for (; i < msg->audio_codecs->count; i++) {
+        WFD_SKIP_SPACE (v);
+        WFD_READ_STRING (msg->audio_codecs->list[i].audio_format);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->audio_codecs->list[i].modes);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->audio_codecs->list[i].latency);
+        WFD_SKIP_COMMA (v);
+      }
+    }
+  } else if (!g_strcmp0 (attr, GST_STRING_WFD_VIDEO_FORMATS)) {
+    msg->video_formats = g_new0 (GstWFDVideoCodeclist, 1);
+    if (strlen (v)) {
+      msg->video_formats->count = 1;
+      msg->video_formats->list = g_new0 (GstWFDVideoCodec, 1);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_formats->list->native);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_formats->
+          list->preferred_display_mode_supported);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_formats->list->H264_codec.profile);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_formats->list->H264_codec.level);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_formats->list->H264_codec.
+          misc_params.CEA_Support);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_formats->list->H264_codec.
+          misc_params.VESA_Support);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_formats->list->H264_codec.
+          misc_params.HH_Support);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_formats->list->H264_codec.
+          misc_params.latency);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_formats->list->H264_codec.
+          misc_params.min_slice_size);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_formats->list->H264_codec.
+          misc_params.slice_enc_params);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_formats->list->H264_codec.
+          misc_params.frame_rate_control_support);
+      WFD_SKIP_SPACE (v);
+      if (msg->video_formats->list->preferred_display_mode_supported == 1) {
+        WFD_READ_UINT32 (msg->video_formats->list->H264_codec.max_hres);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->video_formats->list->H264_codec.max_vres);
+        WFD_SKIP_SPACE (v);
+      }
+    }
+  } else if (!g_strcmp0 (attr, GST_STRING_WFD_3D_VIDEO_FORMATS)) {
+    msg->video_3d_formats = g_new0 (GstWFD3DFormats, 1);
+    if (strlen (v)) {
+      msg->video_3d_formats->count = 1;
+      msg->video_3d_formats->list = g_new0 (GstWFD3dCapList, 1);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_3d_formats->list->native);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_3d_formats->
+          list->preferred_display_mode_supported);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_3d_formats->list->H264_codec.profile);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_3d_formats->list->H264_codec.level);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_3d_formats->list->H264_codec.
+          misc_params.video_3d_capability);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_3d_formats->list->H264_codec.
+          misc_params.latency);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_3d_formats->list->H264_codec.
+          misc_params.min_slice_size);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_3d_formats->list->H264_codec.
+          misc_params.slice_enc_params);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->video_3d_formats->list->H264_codec.
+          misc_params.frame_rate_control_support);
+      WFD_SKIP_SPACE (v);
+      if (msg->video_formats->list->preferred_display_mode_supported == 1) {
+        WFD_READ_UINT32 (msg->video_formats->list->H264_codec.max_hres);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->video_formats->list->H264_codec.max_vres);
+        WFD_SKIP_SPACE (v);
+      }
+    }
+  } else if (!g_strcmp0 (attr, GST_STRING_WFD_CONTENT_PROTECTION)) {
+    msg->content_protection = g_new0 (GstWFDContentProtection, 1);
+    if (strlen (v)) {
+      WFD_SKIP_SPACE (v);
+      msg->content_protection->hdcp2_spec = g_new0 (GstWFDHdcp2Spec, 1);
+      if (strstr (v, "none")) {
+        msg->content_protection->hdcp2_spec->hdcpversion = g_strdup ("none");
+      } else {
+        WFD_READ_STRING (msg->content_protection->hdcp2_spec->hdcpversion);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_STRING (msg->content_protection->hdcp2_spec->TCPPort);
+      }
+    }
+  } else if (!g_strcmp0 (attr, GST_STRING_WFD_DISPLAY_EDID)) {
+    msg->display_edid = g_new0 (GstWFDDisplayEdid, 1);
+    if (strlen (v)) {
+      WFD_SKIP_SPACE (v);
+      if (strstr (v, "none")) {
+        msg->display_edid->edid_supported = 0;
+      } else {
+        msg->display_edid->edid_supported = 1;
+        WFD_READ_UINT32 (msg->display_edid->edid_block_count);
+        WFD_SKIP_SPACE (v);
+        if (msg->display_edid->edid_block_count) {
+          gchar *edid_string = v;
+          int i = 0, j = 0;
+          guint32 payload_size =
+              EDID_BLOCK_SIZE * msg->display_edid->edid_block_count;
+          msg->display_edid->edid_payload = g_malloc (payload_size);
+          for (;
+              i < (EDID_BLOCK_SIZE * msg->display_edid->edid_block_count * 2);
+              j++) {
+            int k = 0, kk = 0;
+            if (edid_string[i] > 0x29 && edid_string[i] < 0x40)
+              k = edid_string[i] - 48;
+            else if (edid_string[i] > 0x60 && edid_string[i] < 0x67)
+              k = edid_string[i] - 87;
+            else if (edid_string[i] > 0x40 && edid_string[i] < 0x47)
+              k = edid_string[i] - 55;
+
+            if (edid_string[i + 1] > 0x29 && edid_string[i + 1] < 0x40)
+              kk = edid_string[i + 1] - 48;
+            else if (edid_string[i + 1] > 0x60 && edid_string[i + 1] < 0x67)
+              kk = edid_string[i + 1] - 87;
+            else if (edid_string[i + 1] > 0x40 && edid_string[i + 1] < 0x47)
+              kk = edid_string[i + 1] - 55;
+
+            msg->display_edid->edid_payload[j] = (k << 4) | kk;
+            i += 2;
+          }
+          //memcpy(msg->display_edid->edid_payload, v, payload_size);
+          v += (payload_size * 2);
+        } else
+          v += strlen (v);
+      }
+    }
+  } else if (!g_strcmp0 (attr, GST_STRING_WFD_COUPLED_SINK)) {
+    msg->coupled_sink = g_new0 (GstWFDCoupledSink, 1);
+    if (strlen (v)) {
+      msg->coupled_sink->coupled_sink_cap = g_new0 (GstWFDCoupled_sink_cap, 1);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->coupled_sink->coupled_sink_cap->status);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_STRING (msg->coupled_sink->coupled_sink_cap->sink_address);
+    }
+  } else if (!g_strcmp0 (attr, GST_STRING_WFD_TRIGGER_METHOD)) {
+    msg->trigger_method = g_new0 (GstWFDTriggerMethod, 1);
+    if (strlen (v)) {
+      WFD_SKIP_SPACE (v);
+      WFD_READ_STRING (msg->trigger_method->wfd_trigger_method);
+    }
+  } else if (!g_strcmp0 (attr, GST_STRING_WFD_PRESENTATION_URL)) {
+    msg->presentation_url = g_new0 (GstWFDPresentationUrl, 1);
+    if (strlen (v)) {
+      WFD_SKIP_SPACE (v);
+      WFD_READ_STRING (msg->presentation_url->wfd_url0);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_STRING (msg->presentation_url->wfd_url1);
+    }
+  } else if (!g_strcmp0 (attr, GST_STRING_WFD_CLIENT_RTP_PORTS)) {
+    msg->client_rtp_ports = g_new0 (GstWFDClientRtpPorts, 1);
+    if (strlen (v)) {
+      WFD_SKIP_SPACE (v);
+      WFD_READ_STRING (msg->client_rtp_ports->profile);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32_DIGIT (msg->client_rtp_ports->rtp_port0);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32_DIGIT (msg->client_rtp_ports->rtp_port1);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_STRING (msg->client_rtp_ports->mode);
+    }
+  } else if (!g_strcmp0 (attr, GST_STRING_WFD_ROUTE)) {
+    msg->route = g_new0 (GstWFDRoute, 1);
+    if (strlen (v)) {
+      WFD_SKIP_SPACE (v);
+      WFD_READ_STRING (msg->route->destination);
+    }
+  } else if (!g_strcmp0 (attr, GST_STRING_WFD_I2C)) {
+    msg->I2C = g_new0 (GstWFDI2C, 1);
+    if (strlen (v)) {
+      msg->I2C->I2CPresent = TRUE;
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32_DIGIT (msg->I2C->I2C_port);
+      if (msg->I2C->I2C_port)
+        msg->I2C->I2CPresent = TRUE;
+    }
+  } else if (!g_strcmp0 (attr, GST_STRING_WFD_AV_FORMAT_CHANGE_TIMING)) {
+    msg->av_format_change_timing = g_new0 (GstWFDAVFormatChangeTiming, 1);
+    if (strlen (v)) {
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->av_format_change_timing->PTS);
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->av_format_change_timing->DTS);
+    }
+  } else if (!g_strcmp0 (attr, GST_STRING_WFD_PREFERRED_DISPLAY_MODE)) {
+    msg->preferred_display_mode = g_new0 (GstWFDPreferredDisplayMode, 1);
+    if (strlen (v)) {
+      WFD_SKIP_SPACE (v);
+      if (!strstr (v, "none")) {
+        msg->preferred_display_mode->displaymodesupported = FALSE;
+      } else {
+        WFD_READ_UINT32 (msg->preferred_display_mode->p_clock);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->H);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->HB);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->HSPOL_HSOFF);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->HSW);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->V);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->VB);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->VSPOL_VSOFF);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->VSW);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->VBS3D);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->V2d_s3d_modes);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->P_depth);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->H264_codec.profile);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->H264_codec.level);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->H264_codec.
+            misc_params.CEA_Support);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->H264_codec.
+            misc_params.VESA_Support);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->H264_codec.
+            misc_params.HH_Support);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->H264_codec.
+            misc_params.latency);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->H264_codec.
+            misc_params.min_slice_size);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->H264_codec.
+            misc_params.slice_enc_params);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->H264_codec.
+            misc_params.frame_rate_control_support);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->H264_codec.max_hres);
+        WFD_SKIP_SPACE (v);
+        WFD_READ_UINT32 (msg->preferred_display_mode->H264_codec.max_vres);
+        WFD_SKIP_SPACE (v);
+      }
+    }
+  } else if (!g_strcmp0 (attr, GST_STRING_WFD_STANDBY_RESUME_CAPABILITY)) {
+    msg->standby_resume_capability = g_new0 (GstWFDStandbyResumeCapability, 1);
+    if (strlen (v)) {
+      WFD_SKIP_SPACE (v);
+      if (!g_strcmp0 (v, "supported"))
+        msg->standby_resume_capability->standby_resume_cap = TRUE;
+      else
+        msg->standby_resume_capability->standby_resume_cap = FALSE;
+    }
+  } else if (!g_strcmp0 (attr, GST_STRING_WFD_STANDBY)) {
+    msg->standby = g_new0 (GstWFDStandby, 1);
+    msg->standby->wfd_standby = TRUE;
+  } else if (!g_strcmp0 (attr, GST_STRING_WFD_CONNECTOR_TYPE)) {
+    msg->connector_type = g_new0 (GstWFDConnectorType, 1);
+    if (strlen (v)) {
+      msg->connector_type->supported = TRUE;
+      WFD_SKIP_SPACE (v);
+      WFD_READ_UINT32 (msg->connector_type->connector_type);
+    }
+  } else if (!g_strcmp0 (attr, GST_STRING_WFD_IDR_REQUEST)) {
+    msg->idr_request = g_new0 (GstWFDIdrRequest, 1);
+    msg->idr_request->idr_request = TRUE;
+  }
+  return;
+}
+
+/**
+ * gst_wfd_message_parse_buffer:
+ * @data: the start of the buffer
+ * @size: the size of the buffer
+ * @msg: the result #GstSDPMessage
+ *
+ * Parse the contents of @size bytes pointed to by @data and store the result in
+ * @msg.
+ *
+ * Returns: #GST_SDP_OK on success.
+ */
+GstWFDResult
+gst_wfd_message_parse_buffer (const guint8 * data, guint size,
+    GstWFDMessage * msg)
+{
+  gchar *p;
+  gchar buffer[255] = { 0 };
+  guint idx = 0;
+
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+  g_return_val_if_fail (data != NULL, GST_WFD_EINVAL);
+  g_return_val_if_fail (size != 0, GST_WFD_EINVAL);
+
+  p = (gchar *) data;
+  while (TRUE) {
+
+    if (*p == '\0')
+      break;
+
+    idx = 0;
+    while (*p != '\n' && *p != '\r' && *p != '\0') {
+      if (idx < sizeof (buffer) - 1)
+        buffer[idx++] = *p;
+      p++;
+    }
+    buffer[idx] = '\0';
+    gst_wfd_parse_attribute (buffer, msg);
+
+    if (*p == '\0')
+      break;
+    p += 2;
+  }
+  return GST_WFD_OK;
+}
+
+/**
+ * gst_wfd_message_free:
+ * @msg: a #GstWFDMessage
+ *
+ * Free all resources allocated by @msg. @msg should not be used anymore after
+ * this function. This function should be used when @msg was dynamically
+ * allocated with gst_wfd_message_new().
+ *
+ * Returns: a #GstWFDResult.
+ */
+GstWFDResult
+gst_wfd_message_free (GstWFDMessage * msg)
+{
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+
+  gst_wfd_message_uninit (msg);
+  g_free (msg);
+
+  return GST_WFD_OK;
+}
+
+/**
+ * gst_wfd_message_as_text:
+ * @msg: a #GstWFDMessage
+ *
+ * Convert the contents of @msg to a text string.
+ *
+ * Returns: A dynamically allocated string representing the WFD description.
+ */
+gchar *
+gst_wfd_message_as_text (const GstWFDMessage * msg)
+{
+  /* change all vars so they match rfc? */
+  GString *lines;
+  guint i;
+
+  g_return_val_if_fail (msg != NULL, NULL);
+
+  lines = g_string_new ("");
+
+  /* list of audio codecs */
+  if (msg->audio_codecs) {
+    g_string_append_printf (lines, GST_STRING_WFD_AUDIO_CODECS);
+    if (msg->audio_codecs->list) {
+      g_string_append_printf (lines, ":");
+      for (i = 0; i < msg->audio_codecs->count; i++) {
+        g_string_append_printf (lines, " %s",
+            msg->audio_codecs->list[i].audio_format);
+        g_string_append_printf (lines, " %08x",
+            msg->audio_codecs->list[i].modes);
+        g_string_append_printf (lines, " %02x",
+            msg->audio_codecs->list[i].latency);
+        if ((i + 1) < msg->audio_codecs->count)
+          g_string_append_printf (lines, ",");
+      }
+    }
+    g_string_append_printf (lines, "\r\n");
+  }
+
+  /* list of video codecs */
+  if (msg->video_formats) {
+    g_string_append_printf (lines, GST_STRING_WFD_VIDEO_FORMATS);
+    if (msg->video_formats->list) {
+      g_string_append_printf (lines, ":");
+      g_string_append_printf (lines, " %02x", msg->video_formats->list->native);
+      g_string_append_printf (lines, " %02x",
+          msg->video_formats->list->preferred_display_mode_supported);
+      g_string_append_printf (lines, " %02x",
+          msg->video_formats->list->H264_codec.profile);
+      g_string_append_printf (lines, " %02x",
+          msg->video_formats->list->H264_codec.level);
+      g_string_append_printf (lines, " %08x",
+          msg->video_formats->list->H264_codec.misc_params.CEA_Support);
+      g_string_append_printf (lines, " %08x",
+          msg->video_formats->list->H264_codec.misc_params.VESA_Support);
+      g_string_append_printf (lines, " %08x",
+          msg->video_formats->list->H264_codec.misc_params.HH_Support);
+      g_string_append_printf (lines, " %02x",
+          msg->video_formats->list->H264_codec.misc_params.latency);
+      g_string_append_printf (lines, " %04x",
+          msg->video_formats->list->H264_codec.misc_params.min_slice_size);
+      g_string_append_printf (lines, " %04x",
+          msg->video_formats->list->H264_codec.misc_params.slice_enc_params);
+      g_string_append_printf (lines, " %02x",
+          msg->video_formats->list->H264_codec.
+          misc_params.frame_rate_control_support);
+
+      if (msg->video_formats->list->H264_codec.max_hres)
+        g_string_append_printf (lines, " %04x",
+            msg->video_formats->list->H264_codec.max_hres);
+      else
+        g_string_append_printf (lines, " none");
+
+      if (msg->video_formats->list->H264_codec.max_vres)
+        g_string_append_printf (lines, " %04x",
+            msg->video_formats->list->H264_codec.max_vres);
+      else
+        g_string_append_printf (lines, " none");
+    }
+    g_string_append_printf (lines, "\r\n");
+  }
+
+  /* list of video 3D codecs */
+  if (msg->video_3d_formats) {
+    g_string_append_printf (lines, GST_STRING_WFD_3D_VIDEO_FORMATS);
+    g_string_append_printf (lines, ":");
+    if (msg->video_3d_formats->list) {
+      g_string_append_printf (lines, " %02x",
+          msg->video_3d_formats->list->native);
+      g_string_append_printf (lines, " %02x",
+          msg->video_3d_formats->list->preferred_display_mode_supported);
+      g_string_append_printf (lines, " %02x",
+          msg->video_3d_formats->list->H264_codec.profile);
+      g_string_append_printf (lines, " %02x",
+          msg->video_3d_formats->list->H264_codec.level);
+      g_string_append_printf (lines, " %16x",
+          msg->video_3d_formats->list->H264_codec.
+          misc_params.video_3d_capability);
+      g_string_append_printf (lines, " %02x",
+          msg->video_3d_formats->list->H264_codec.misc_params.latency);
+      g_string_append_printf (lines, " %04x",
+          msg->video_3d_formats->list->H264_codec.misc_params.min_slice_size);
+      g_string_append_printf (lines, " %04x",
+          msg->video_3d_formats->list->H264_codec.misc_params.slice_enc_params);
+      g_string_append_printf (lines, " %02x",
+          msg->video_3d_formats->list->H264_codec.
+          misc_params.frame_rate_control_support);
+      if (msg->video_3d_formats->list->H264_codec.max_hres)
+        g_string_append_printf (lines, " %04x",
+            msg->video_3d_formats->list->H264_codec.max_hres);
+      else
+        g_string_append_printf (lines, " none");
+      if (msg->video_3d_formats->list->H264_codec.max_vres)
+        g_string_append_printf (lines, " %04x",
+            msg->video_3d_formats->list->H264_codec.max_vres);
+      else
+        g_string_append_printf (lines, " none");
+    } else {
+      g_string_append_printf (lines, " none");
+    }
+    g_string_append_printf (lines, "\r\n");
+  }
+
+  if (msg->content_protection) {
+    g_string_append_printf (lines, GST_STRING_WFD_CONTENT_PROTECTION);
+    g_string_append_printf (lines, ":");
+    if (msg->content_protection->hdcp2_spec) {
+      if (msg->content_protection->hdcp2_spec->hdcpversion) {
+        g_string_append_printf (lines, " %s",
+            msg->content_protection->hdcp2_spec->hdcpversion);
+        g_string_append_printf (lines, " %s",
+            msg->content_protection->hdcp2_spec->TCPPort);
+      } else {
+        g_string_append_printf (lines, " none");
+      }
+    } else {
+      g_string_append_printf (lines, " none");
+    }
+    g_string_append_printf (lines, "\r\n");
+  }
+
+  if (msg->display_edid) {
+    g_string_append_printf (lines, GST_STRING_WFD_DISPLAY_EDID);
+    g_string_append_printf (lines, ":");
+    if (msg->display_edid->edid_supported) {
+      if (msg->display_edid->edid_block_count > 0 &&
+          msg->display_edid->edid_block_count <= EDID_BLOCK_COUNT_MAX_SIZE) {
+        g_string_append_printf (lines," %04x", msg->display_edid->edid_block_count);
+        g_string_append_printf(lines, " %s", msg->display_edid->edid_payload);
+      } else
+        g_string_append_printf (lines, " none");
+    } else {
+      g_string_append_printf (lines, " none");
+    }
+    g_string_append_printf (lines, "\r\n");
+  }
+
+  if (msg->coupled_sink) {
+    g_string_append_printf (lines, GST_STRING_WFD_COUPLED_SINK);
+    g_string_append_printf (lines, ":");
+    if (msg->coupled_sink->coupled_sink_cap) {
+      g_string_append_printf (lines, " %02x",
+          msg->coupled_sink->coupled_sink_cap->status);
+      if (msg->coupled_sink->coupled_sink_cap->sink_address)
+        g_string_append_printf (lines, " %s",
+            msg->coupled_sink->coupled_sink_cap->sink_address);
+      else
+        g_string_append_printf (lines, " none");
+    } else {
+      g_string_append_printf (lines, " none");
+    }
+    g_string_append_printf (lines, "\r\n");
+  }
+
+  if (msg->trigger_method) {
+    g_string_append_printf (lines, GST_STRING_WFD_TRIGGER_METHOD);
+    g_string_append_printf (lines, ":");
+    g_string_append_printf (lines, " %s",
+        msg->trigger_method->wfd_trigger_method);
+    g_string_append_printf (lines, "\r\n");
+  }
+
+  if (msg->presentation_url) {
+    g_string_append_printf (lines, GST_STRING_WFD_PRESENTATION_URL);
+    g_string_append_printf (lines, ":");
+    if (msg->presentation_url->wfd_url0)
+      g_string_append_printf (lines, " %s", msg->presentation_url->wfd_url0);
+    else
+      g_string_append_printf (lines, " none");
+    if (msg->presentation_url->wfd_url1)
+      g_string_append_printf (lines, " %s", msg->presentation_url->wfd_url1);
+    else
+      g_string_append_printf (lines, " none");
+    g_string_append_printf (lines, "\r\n");
+  }
+
+  if (msg->client_rtp_ports) {
+    g_string_append_printf (lines, GST_STRING_WFD_CLIENT_RTP_PORTS);
+    if (msg->client_rtp_ports->profile) {
+      g_string_append_printf (lines, ":");
+      g_string_append_printf (lines, " %s", msg->client_rtp_ports->profile);
+      g_string_append_printf (lines, " %d", msg->client_rtp_ports->rtp_port0);
+      g_string_append_printf (lines, " %d", msg->client_rtp_ports->rtp_port1);
+      g_string_append_printf (lines, " %s", msg->client_rtp_ports->mode);
+    }
+    g_string_append_printf (lines, "\r\n");
+  }
+
+  if (msg->route) {
+    g_string_append_printf (lines, GST_STRING_WFD_ROUTE);
+    g_string_append_printf (lines, ":");
+    g_string_append_printf (lines, " %s", msg->route->destination);
+    g_string_append_printf (lines, "\r\n");
+  }
+
+  if (msg->I2C) {
+    g_string_append_printf (lines, GST_STRING_WFD_I2C);
+    g_string_append_printf (lines, ":");
+    if (msg->I2C->I2CPresent)
+      g_string_append_printf (lines, " %x", msg->I2C->I2C_port);
+    else
+      g_string_append_printf (lines, " none");
+    g_string_append_printf (lines, "\r\n");
+  }
+
+  if (msg->av_format_change_timing) {
+    g_string_append_printf (lines, GST_STRING_WFD_AV_FORMAT_CHANGE_TIMING);
+    g_string_append_printf (lines, ":");
+    g_string_append_printf (lines, " %010llx",
+        msg->av_format_change_timing->PTS);
+    g_string_append_printf (lines, " %010llx",
+        msg->av_format_change_timing->DTS);
+    g_string_append_printf (lines, "\r\n");
+  }
+
+  if (msg->preferred_display_mode) {
+    g_string_append_printf (lines, GST_STRING_WFD_PREFERRED_DISPLAY_MODE);
+    g_string_append_printf (lines, ":");
+    if (msg->preferred_display_mode->displaymodesupported) {
+      g_string_append_printf (lines, " %06llx",
+          msg->preferred_display_mode->p_clock);
+      g_string_append_printf (lines, " %04x", msg->preferred_display_mode->H);
+      g_string_append_printf (lines, " %04x", msg->preferred_display_mode->HB);
+      g_string_append_printf (lines, " %04x",
+          msg->preferred_display_mode->HSPOL_HSOFF);
+      g_string_append_printf (lines, " %04x", msg->preferred_display_mode->HSW);
+      g_string_append_printf (lines, " %04x", msg->preferred_display_mode->V);
+      g_string_append_printf (lines, " %04x", msg->preferred_display_mode->VB);
+      g_string_append_printf (lines, " %04x",
+          msg->preferred_display_mode->VSPOL_VSOFF);
+      g_string_append_printf (lines, " %04x", msg->preferred_display_mode->VSW);
+      g_string_append_printf (lines, " %02x",
+          msg->preferred_display_mode->VBS3D);
+      g_string_append_printf (lines, " %02x",
+          msg->preferred_display_mode->V2d_s3d_modes);
+      g_string_append_printf (lines, " %02x",
+          msg->preferred_display_mode->P_depth);
+    } else
+      g_string_append_printf (lines, " none");
+    g_string_append_printf (lines, "\r\n");
+  }
+
+  if (msg->standby_resume_capability) {
+    g_string_append_printf (lines, GST_STRING_WFD_STANDBY_RESUME_CAPABILITY);
+    g_string_append_printf (lines, ":");
+    if (msg->standby_resume_capability->standby_resume_cap)
+      g_string_append_printf (lines, " supported");
+    else
+      g_string_append_printf (lines, " none");
+    g_string_append_printf (lines, "\r\n");
+  }
+
+  if (msg->standby) {
+    g_string_append_printf (lines, GST_STRING_WFD_STANDBY);
+    g_string_append_printf (lines, "\r\n");
+  }
+
+  if (msg->connector_type) {
+    g_string_append_printf (lines, GST_STRING_WFD_CONNECTOR_TYPE);
+    g_string_append_printf (lines, ":");
+    if (msg->connector_type->connector_type)
+      g_string_append_printf (lines, " %02x",
+          msg->connector_type->connector_type);
+    else
+      g_string_append_printf (lines, " none");
+    g_string_append_printf (lines, "\r\n");
+  }
+
+  if (msg->idr_request) {
+    g_string_append_printf (lines, GST_STRING_WFD_IDR_REQUEST);
+    g_string_append_printf (lines, "\r\n");
+  }
+
+  return g_string_free (lines, FALSE);
+}
+
+gchar *
+gst_wfd_message_param_names_as_text (const GstWFDMessage * msg)
+{
+  /* change all vars so they match rfc? */
+  GString *lines;
+  g_return_val_if_fail (msg != NULL, NULL);
+
+  lines = g_string_new ("");
+
+  /* list of audio codecs */
+  if (msg->audio_codecs) {
+    g_string_append_printf (lines, GST_STRING_WFD_AUDIO_CODECS);
+    g_string_append_printf (lines, "\r\n");
+  }
+  /* list of video codecs */
+  if (msg->video_formats) {
+    g_string_append_printf (lines, GST_STRING_WFD_VIDEO_FORMATS);
+    g_string_append_printf (lines, "\r\n");
+  }
+  /* list of video 3D codecs */
+  if (msg->video_3d_formats) {
+    g_string_append_printf (lines, GST_STRING_WFD_3D_VIDEO_FORMATS);
+    g_string_append_printf (lines, "\r\n");
+  }
+  if (msg->content_protection) {
+    g_string_append_printf (lines, GST_STRING_WFD_CONTENT_PROTECTION);
+    g_string_append_printf (lines, "\r\n");
+  }
+  if (msg->display_edid) {
+    g_string_append_printf (lines, GST_STRING_WFD_DISPLAY_EDID);
+    g_string_append_printf (lines, "\r\n");
+  }
+  if (msg->coupled_sink) {
+    g_string_append_printf (lines, GST_STRING_WFD_COUPLED_SINK);
+    g_string_append_printf (lines, "\r\n");
+  }
+  if (msg->trigger_method) {
+    g_string_append_printf (lines, GST_STRING_WFD_TRIGGER_METHOD);
+    g_string_append_printf (lines, "\r\n");
+  }
+  if (msg->presentation_url) {
+    g_string_append_printf (lines, GST_STRING_WFD_PRESENTATION_URL);
+    g_string_append_printf (lines, "\r\n");
+  }
+  if (msg->client_rtp_ports) {
+    g_string_append_printf (lines, GST_STRING_WFD_CLIENT_RTP_PORTS);
+    g_string_append_printf (lines, "\r\n");
+  }
+  if (msg->route) {
+    g_string_append_printf (lines, GST_STRING_WFD_ROUTE);
+    g_string_append_printf (lines, "\r\n");
+  }
+  if (msg->I2C) {
+    g_string_append_printf (lines, GST_STRING_WFD_I2C);
+    g_string_append_printf (lines, "\r\n");
+  }
+  if (msg->av_format_change_timing) {
+    g_string_append_printf (lines, GST_STRING_WFD_AV_FORMAT_CHANGE_TIMING);
+    g_string_append_printf (lines, "\r\n");
+  }
+  if (msg->preferred_display_mode) {
+    g_string_append_printf (lines, GST_STRING_WFD_PREFERRED_DISPLAY_MODE);
+    g_string_append_printf (lines, "\r\n");
+  }
+  if (msg->standby_resume_capability) {
+    g_string_append_printf (lines, GST_STRING_WFD_STANDBY_RESUME_CAPABILITY);
+    g_string_append_printf (lines, "\r\n");
+  }
+  if (msg->standby) {
+    g_string_append_printf (lines, GST_STRING_WFD_STANDBY);
+    g_string_append_printf (lines, "\r\n");
+  }
+  if (msg->connector_type) {
+    g_string_append_printf (lines, GST_STRING_WFD_CONNECTOR_TYPE);
+    g_string_append_printf (lines, "\r\n");
+  }
+  if (msg->idr_request) {
+    g_string_append_printf (lines, GST_STRING_WFD_IDR_REQUEST);
+    g_string_append_printf (lines, "\r\n");
+  }
+
+  return g_string_free (lines, FALSE);
+}
+
+/**
+ * gst_wfd_message_dump:
+ * @msg: a #GstWFDMessage
+ *
+ * Dump the parsed contents of @msg to stdout.
+ *
+ * Returns: a #GstWFDResult.
+ */
+GstWFDResult
+gst_wfd_message_dump (const GstWFDMessage * msg)
+{
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+
+  if (msg->audio_codecs) {
+    guint i = 0;
+    g_print ("Audio supported formats : \n");
+    for (; i < msg->audio_codecs->count; i++) {
+      g_print ("Codec: %s\n", msg->audio_codecs->list[i].audio_format);
+      if (!strcmp (msg->audio_codecs->list[i].audio_format, "LPCM")) {
+        if (msg->audio_codecs->list[i].modes & GST_WFD_FREQ_44100)
+          g_print ("   Freq: %d\n", 44100);
+        if (msg->audio_codecs->list[i].modes & GST_WFD_FREQ_48000)
+          g_print ("   Freq: %d\n", 48000);
+        g_print ("     Channels: %d\n", 2);
+      }
+      if (!strcmp (msg->audio_codecs->list[i].audio_format, "AAC")) {
+        g_print ("     Freq: %d\n", 48000);
+        if (msg->audio_codecs->list[i].modes & GST_WFD_CHANNEL_2)
+          g_print ("   Channels: %d\n", 2);
+        if (msg->audio_codecs->list[i].modes & GST_WFD_CHANNEL_4)
+          g_print ("   Channels: %d\n", 4);
+        if (msg->audio_codecs->list[i].modes & GST_WFD_CHANNEL_6)
+          g_print ("   Channels: %d\n", 6);
+        if (msg->audio_codecs->list[i].modes & GST_WFD_CHANNEL_8)
+          g_print ("   Channels: %d\n", 8);
+      }
+      if (!strcmp (msg->audio_codecs->list[i].audio_format, "AC3")) {
+        g_print ("     Freq: %d\n", 48000);
+        if (msg->audio_codecs->list[i].modes & GST_WFD_CHANNEL_2)
+          g_print ("   Channels: %d\n", 2);
+        if (msg->audio_codecs->list[i].modes & GST_WFD_CHANNEL_4)
+          g_print ("   Channels: %d\n", 4);
+        if (msg->audio_codecs->list[i].modes & GST_WFD_CHANNEL_6)
+          g_print ("   Channels: %d\n", 6);
+      }
+      g_print ("       Bitwidth: %d\n", 16);
+      g_print ("       Latency: %d\n", msg->audio_codecs->list[i].latency);
+    }
+  }
+
+
+  if (msg->video_formats) {
+    g_print ("Video supported formats : \n");
+    if (msg->video_formats->list) {
+      guint nativeindex = 0;
+      g_print ("Codec: H264\n");
+      if ((msg->video_formats->list->native & 0x7) ==
+          GST_WFD_VIDEO_CEA_RESOLUTION) {
+        g_print ("     Native type: CEA\n");
+      } else if ((msg->video_formats->list->native & 0x7) ==
+          GST_WFD_VIDEO_VESA_RESOLUTION) {
+        g_print ("     Native type: VESA\n");
+      } else if ((msg->video_formats->list->native & 0x7) ==
+          GST_WFD_VIDEO_HH_RESOLUTION) {
+        g_print ("     Native type: HH\n");
+      }
+      nativeindex = msg->video_formats->list->native >> 3;
+      g_print ("       Resolution: %d\n", (1 << nativeindex));
+
+      if (msg->video_formats->list->
+          H264_codec.profile & GST_WFD_H264_BASE_PROFILE) {
+        g_print ("     Profile: BASE\n");
+      } else if (msg->video_formats->list->
+          H264_codec.profile & GST_WFD_H264_HIGH_PROFILE) {
+        g_print ("     Profile: HIGH\n");
+      }
+      if (msg->video_formats->list->H264_codec.level & GST_WFD_H264_LEVEL_3_1) {
+        g_print ("     Level: 3.1\n");
+      } else if (msg->video_formats->list->
+          H264_codec.level & GST_WFD_H264_LEVEL_3_2) {
+        g_print ("     Level: 3.2\n");
+      } else if (msg->video_formats->list->
+          H264_codec.level & GST_WFD_H264_LEVEL_4) {
+        g_print ("     Level: 4\n");
+      } else if (msg->video_formats->list->
+          H264_codec.level & GST_WFD_H264_LEVEL_4_1) {
+        g_print ("     Level: 4.1\n");
+      } else if (msg->video_formats->list->
+          H264_codec.level & GST_WFD_H264_LEVEL_4_2) {
+        g_print ("     Level: 4.2\n");
+      }
+      g_print ("       Latency: %d\n",
+          msg->video_formats->list->H264_codec.misc_params.latency);
+      g_print ("       min_slice_size: %x\n",
+          msg->video_formats->list->H264_codec.misc_params.min_slice_size);
+      g_print ("       slice_enc_params: %x\n",
+          msg->video_formats->list->H264_codec.misc_params.slice_enc_params);
+      g_print ("       frame_rate_control_support: %x\n",
+          msg->video_formats->list->H264_codec.
+          misc_params.frame_rate_control_support);
+      if (msg->video_formats->list->H264_codec.max_hres) {
+        g_print ("     Max Height: %04d\n",
+            msg->video_formats->list->H264_codec.max_hres);
+      }
+      if (msg->video_formats->list->H264_codec.max_vres) {
+        g_print ("     Max Width: %04d\n",
+            msg->video_formats->list->H264_codec.max_vres);
+      }
+    }
+  }
+
+  if (msg->video_3d_formats) {
+    g_print ("wfd_3d_formats");
+    g_print ("\r\n");
+  }
+
+  if (msg->content_protection) {
+    g_print (GST_STRING_WFD_CONTENT_PROTECTION);
+    g_print ("\r\n");
+  }
+
+  if (msg->display_edid) {
+    g_print (GST_STRING_WFD_DISPLAY_EDID);
+    g_print ("\r\n");
+  }
+
+  if (msg->coupled_sink) {
+    g_print (GST_STRING_WFD_COUPLED_SINK);
+    g_print ("\r\n");
+  }
+
+  if (msg->trigger_method) {
+    g_print (" Trigger type: %s\n", msg->trigger_method->wfd_trigger_method);
+  }
+
+  if (msg->presentation_url) {
+    g_print (GST_STRING_WFD_PRESENTATION_URL);
+    g_print ("\r\n");
+  }
+
+  if (msg->client_rtp_ports) {
+    g_print (" Client RTP Ports : \n");
+    if (msg->client_rtp_ports->profile) {
+      g_print ("%s\n", msg->client_rtp_ports->profile);
+      g_print ("       %d\n", msg->client_rtp_ports->rtp_port0);
+      g_print ("       %d\n", msg->client_rtp_ports->rtp_port1);
+      g_print ("       %s\n", msg->client_rtp_ports->mode);
+    }
+    g_print ("\r\n");
+  }
+
+  if (msg->route) {
+    g_print (GST_STRING_WFD_ROUTE);
+    g_print ("\r\n");
+  }
+
+  if (msg->I2C) {
+    g_print (GST_STRING_WFD_I2C);
+    g_print ("\r\n");
+  }
+
+  if (msg->av_format_change_timing) {
+    g_print (GST_STRING_WFD_AV_FORMAT_CHANGE_TIMING);
+    g_print ("\r\n");
+  }
+
+  if (msg->preferred_display_mode) {
+    g_print (GST_STRING_WFD_PREFERRED_DISPLAY_MODE);
+    g_print ("\r\n");
+  }
+
+  if (msg->standby_resume_capability) {
+    g_print (GST_STRING_WFD_STANDBY_RESUME_CAPABILITY);
+    g_print ("\r\n");
+  }
+
+  if (msg->standby) {
+    g_print (GST_STRING_WFD_STANDBY);
+    g_print ("\r\n");
+  }
+
+  if (msg->connector_type) {
+    g_print (GST_STRING_WFD_CONNECTOR_TYPE);
+    g_print ("\r\n");
+  }
+
+  if (msg->idr_request) {
+    g_print (GST_STRING_WFD_IDR_REQUEST);
+    g_print ("\r\n");
+  }
+
+  return GST_WFD_OK;
+}
+
+GstWFDResult
+gst_wfd_message_set_supported_audio_format (GstWFDMessage * msg,
+    GstWFDAudioFormats a_codec,
+    guint a_freq, guint a_channels, guint a_bitwidth, guint32 a_latency)
+{
+  guint temp = a_codec;
+  guint i = 0;
+  guint pcm = 0, aac = 0, ac3 = 0;
+
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+
+  if (!msg->audio_codecs)
+    msg->audio_codecs = g_new0 (GstWFDAudioCodeclist, 1);
+
+  if (a_codec != GST_WFD_AUDIO_UNKNOWN) {
+    while (temp) {
+      msg->audio_codecs->count++;
+      temp >>= 1;
+    }
+    msg->audio_codecs->list =
+        g_new0 (GstWFDAudioCodec, msg->audio_codecs->count);
+    for (; i < msg->audio_codecs->count; i++) {
+      if ((a_codec & GST_WFD_AUDIO_LPCM) && (!pcm)) {
+        msg->audio_codecs->list[i].audio_format = g_strdup ("LPCM");
+        msg->audio_codecs->list[i].modes = a_freq;
+        msg->audio_codecs->list[i].latency = a_latency;
+        pcm = 1;
+      } else if ((a_codec & GST_WFD_AUDIO_AAC) && (!aac)) {
+        msg->audio_codecs->list[i].audio_format = g_strdup ("AAC");
+        msg->audio_codecs->list[i].modes = a_channels;
+        msg->audio_codecs->list[i].latency = a_latency;
+        aac = 1;
+      } else if ((a_codec & GST_WFD_AUDIO_AC3) && (!ac3)) {
+        msg->audio_codecs->list[i].audio_format = g_strdup ("AC3");
+        msg->audio_codecs->list[i].modes = a_channels;
+        msg->audio_codecs->list[i].latency = a_latency;
+        ac3 = 1;
+      }
+    }
+  }
+  return GST_WFD_OK;
+}
+
+GstWFDResult
+gst_wfd_message_set_prefered_audio_format (GstWFDMessage * msg,
+    GstWFDAudioFormats a_codec,
+    GstWFDAudioFreq a_freq,
+    GstWFDAudioChannels a_channels, guint a_bitwidth, guint32 a_latency)
+{
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+
+  if (!msg->audio_codecs)
+    msg->audio_codecs = g_new0 (GstWFDAudioCodeclist, 1);
+
+  msg->audio_codecs->list = g_new0 (GstWFDAudioCodec, 1);
+  msg->audio_codecs->count = 1;
+  if (a_codec == GST_WFD_AUDIO_LPCM) {
+    msg->audio_codecs->list->audio_format = g_strdup ("LPCM");
+    msg->audio_codecs->list->modes = a_freq;
+    msg->audio_codecs->list->latency = a_latency;
+  } else if (a_codec == GST_WFD_AUDIO_AAC) {
+    msg->audio_codecs->list->audio_format = g_strdup ("AAC");
+    msg->audio_codecs->list->modes = a_channels;
+    msg->audio_codecs->list->latency = a_latency;
+  } else if (a_codec == GST_WFD_AUDIO_AC3) {
+    msg->audio_codecs->list->audio_format = g_strdup ("AC3");
+    msg->audio_codecs->list->modes = a_channels;
+    msg->audio_codecs->list->latency = a_latency;
+  }
+  return GST_WFD_OK;
+}
+
+GstWFDResult
+gst_wfd_message_get_supported_audio_format (GstWFDMessage * msg,
+    guint * a_codec,
+    guint * a_freq, guint * a_channels, guint * a_bitwidth, guint32 * a_latency)
+{
+  guint i = 0;
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+  g_return_val_if_fail (msg->audio_codecs != NULL, GST_WFD_EINVAL);
+
+  for (; i < msg->audio_codecs->count; i++) {
+    if (!g_strcmp0 (msg->audio_codecs->list[i].audio_format, "LPCM")) {
+      *a_codec |= GST_WFD_AUDIO_LPCM;
+      *a_freq |= msg->audio_codecs->list[i].modes;
+      *a_channels |= GST_WFD_CHANNEL_2;
+      *a_bitwidth = 16;
+      *a_latency = msg->audio_codecs->list[i].latency;
+    } else if (!g_strcmp0 (msg->audio_codecs->list[i].audio_format, "AAC")) {
+      *a_codec |= GST_WFD_AUDIO_AAC;
+      *a_freq |= GST_WFD_FREQ_48000;
+      *a_channels |= msg->audio_codecs->list[i].modes;
+      *a_bitwidth = 16;
+      *a_latency = msg->audio_codecs->list[i].latency;
+    } else if (!g_strcmp0 (msg->audio_codecs->list[i].audio_format, "AC3")) {
+      *a_codec |= GST_WFD_AUDIO_AC3;
+      *a_freq |= GST_WFD_FREQ_48000;
+      *a_channels |= msg->audio_codecs->list[i].modes;
+      *a_bitwidth = 16;
+      *a_latency = msg->audio_codecs->list[i].latency;
+    }
+  }
+  return GST_WFD_OK;
+}
+
+GstWFDResult
+gst_wfd_message_get_prefered_audio_format (GstWFDMessage * msg,
+    GstWFDAudioFormats * a_codec,
+    GstWFDAudioFreq * a_freq,
+    GstWFDAudioChannels * a_channels, guint * a_bitwidth, guint32 * a_latency)
+{
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+
+  if (!g_strcmp0 (msg->audio_codecs->list->audio_format, "LPCM")) {
+    *a_codec = GST_WFD_AUDIO_LPCM;
+    *a_freq = msg->audio_codecs->list->modes;
+    *a_channels = GST_WFD_CHANNEL_2;
+    *a_bitwidth = 16;
+    *a_latency = msg->audio_codecs->list->latency;
+  } else if (!g_strcmp0 (msg->audio_codecs->list->audio_format, "AAC")) {
+    *a_codec = GST_WFD_AUDIO_AAC;
+    *a_freq = GST_WFD_FREQ_48000;
+    *a_channels = msg->audio_codecs->list->modes;
+    *a_bitwidth = 16;
+    *a_latency = msg->audio_codecs->list->latency;
+  } else if (!g_strcmp0 (msg->audio_codecs->list->audio_format, "AC3")) {
+    *a_codec = GST_WFD_AUDIO_AC3;
+    *a_freq = GST_WFD_FREQ_48000;
+    *a_channels = msg->audio_codecs->list->modes;
+    *a_bitwidth = 16;
+    *a_latency = msg->audio_codecs->list->latency;
+  }
+  return GST_WFD_OK;
+}
+
+GstWFDResult
+gst_wfd_message_set_supported_video_format (GstWFDMessage * msg,
+    GstWFDVideoCodecs v_codec,
+    GstWFDVideoNativeResolution v_native,
+    guint64 v_native_resolution,
+    guint64 v_cea_resolution,
+    guint64 v_vesa_resolution,
+    guint64 v_hh_resolution,
+    guint v_profile,
+    guint v_level,
+    guint32 v_latency,
+    guint32 v_max_height,
+    guint32 v_max_width,
+    guint32 min_slice_size, guint32 slice_enc_params, guint frame_rate_control)
+{
+  guint nativeindex = 0;
+  guint64 temp = v_native_resolution;
+
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+
+  if (!msg->video_formats)
+    msg->video_formats = g_new0 (GstWFDVideoCodeclist, 1);
+
+  if (v_codec != GST_WFD_VIDEO_UNKNOWN) {
+    msg->video_formats->list = g_new0 (GstWFDVideoCodec, 1);
+    while (temp) {
+      nativeindex++;
+      temp >>= 1;
+    }
+
+    msg->video_formats->list->native = nativeindex - 1;
+    msg->video_formats->list->native <<= 3;
+
+    if (v_native == GST_WFD_VIDEO_VESA_RESOLUTION)
+      msg->video_formats->list->native |= 1;
+    else if (v_native == GST_WFD_VIDEO_HH_RESOLUTION)
+      msg->video_formats->list->native |= 2;
+
+    msg->video_formats->list->preferred_display_mode_supported = 1;
+    msg->video_formats->list->H264_codec.profile = v_profile;
+    msg->video_formats->list->H264_codec.level = v_level;
+    msg->video_formats->list->H264_codec.max_hres = v_max_height;
+    msg->video_formats->list->H264_codec.max_vres = v_max_width;
+    msg->video_formats->list->H264_codec.misc_params.CEA_Support =
+        v_cea_resolution;
+    msg->video_formats->list->H264_codec.misc_params.VESA_Support =
+        v_vesa_resolution;
+    msg->video_formats->list->H264_codec.misc_params.HH_Support =
+        v_hh_resolution;
+    msg->video_formats->list->H264_codec.misc_params.latency = v_latency;
+    msg->video_formats->list->H264_codec.misc_params.min_slice_size =
+        min_slice_size;
+    msg->video_formats->list->H264_codec.misc_params.slice_enc_params =
+        slice_enc_params;
+    msg->video_formats->list->H264_codec.
+        misc_params.frame_rate_control_support = frame_rate_control;
+  }
+  return GST_WFD_OK;
+}
+
+GstWFDResult
+gst_wfd_message_set_prefered_video_format (GstWFDMessage * msg,
+    GstWFDVideoCodecs v_codec,
+    GstWFDVideoNativeResolution v_native,
+    guint64 v_native_resolution,
+    GstWFDVideoCEAResolution v_cea_resolution,
+    GstWFDVideoVESAResolution v_vesa_resolution,
+    GstWFDVideoHHResolution v_hh_resolution,
+    GstWFDVideoH264Profile v_profile,
+    GstWFDVideoH264Level v_level,
+    guint32 v_latency,
+    guint32 v_max_height,
+    guint32 v_max_width,
+    guint32 min_slice_size, guint32 slice_enc_params, guint frame_rate_control)
+{
+  guint nativeindex = 0;
+  guint64 temp = v_native_resolution;
+
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+
+  if (!msg->video_formats)
+    msg->video_formats = g_new0 (GstWFDVideoCodeclist, 1);
+  msg->video_formats->list = g_new0 (GstWFDVideoCodec, 1);
+
+  while (temp) {
+    nativeindex++;
+    temp >>= 1;
+  }
+
+  if (nativeindex)
+    msg->video_formats->list->native = nativeindex - 1;
+  msg->video_formats->list->native <<= 3;
+
+  if (v_native == GST_WFD_VIDEO_VESA_RESOLUTION)
+    msg->video_formats->list->native |= 1;
+  else if (v_native == GST_WFD_VIDEO_HH_RESOLUTION)
+    msg->video_formats->list->native |= 2;
+
+  msg->video_formats->list->preferred_display_mode_supported = 0;
+  msg->video_formats->list->H264_codec.profile = v_profile;
+  msg->video_formats->list->H264_codec.level = v_level;
+  msg->video_formats->list->H264_codec.max_hres = v_max_height;
+  msg->video_formats->list->H264_codec.max_vres = v_max_width;
+  msg->video_formats->list->H264_codec.misc_params.CEA_Support =
+      v_cea_resolution;
+  msg->video_formats->list->H264_codec.misc_params.VESA_Support =
+      v_vesa_resolution;
+  msg->video_formats->list->H264_codec.misc_params.HH_Support = v_hh_resolution;
+  msg->video_formats->list->H264_codec.misc_params.latency = v_latency;
+  msg->video_formats->list->H264_codec.misc_params.min_slice_size =
+      min_slice_size;
+  msg->video_formats->list->H264_codec.misc_params.slice_enc_params =
+      slice_enc_params;
+  msg->video_formats->list->H264_codec.misc_params.frame_rate_control_support =
+      frame_rate_control;
+  return GST_WFD_OK;
+}
+
+GstWFDResult
+gst_wfd_message_get_supported_video_format (GstWFDMessage * msg,
+    GstWFDVideoCodecs * v_codec,
+    GstWFDVideoNativeResolution * v_native,
+    guint64 * v_native_resolution,
+    guint64 * v_cea_resolution,
+    guint64 * v_vesa_resolution,
+    guint64 * v_hh_resolution,
+    guint * v_profile,
+    guint * v_level,
+    guint32 * v_latency,
+    guint32 * v_max_height,
+    guint32 * v_max_width,
+    guint32 * min_slice_size,
+    guint32 * slice_enc_params, guint * frame_rate_control)
+{
+  guint nativeindex = 0;
+
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+  *v_codec = GST_WFD_VIDEO_H264;
+  *v_native = msg->video_formats->list->native & 0x7;
+  nativeindex = msg->video_formats->list->native >> 3;
+  *v_native_resolution = ((guint64) 1) << nativeindex;
+  *v_profile = msg->video_formats->list->H264_codec.profile;
+  *v_level = msg->video_formats->list->H264_codec.level;
+  *v_max_height = msg->video_formats->list->H264_codec.max_hres;
+  *v_max_width = msg->video_formats->list->H264_codec.max_vres;
+  *v_cea_resolution =
+      msg->video_formats->list->H264_codec.misc_params.CEA_Support;
+  *v_vesa_resolution =
+      msg->video_formats->list->H264_codec.misc_params.VESA_Support;
+  *v_hh_resolution =
+      msg->video_formats->list->H264_codec.misc_params.HH_Support;
+  *v_latency = msg->video_formats->list->H264_codec.misc_params.latency;
+  *min_slice_size =
+      msg->video_formats->list->H264_codec.misc_params.min_slice_size;
+  *slice_enc_params =
+      msg->video_formats->list->H264_codec.misc_params.slice_enc_params;
+  *frame_rate_control =
+      msg->video_formats->list->H264_codec.
+      misc_params.frame_rate_control_support;
+  return GST_WFD_OK;
+}
+
+GstWFDResult
+gst_wfd_message_get_prefered_video_format (GstWFDMessage * msg,
+    GstWFDVideoCodecs * v_codec,
+    GstWFDVideoNativeResolution * v_native,
+    guint64 * v_native_resolution,
+    GstWFDVideoCEAResolution * v_cea_resolution,
+    GstWFDVideoVESAResolution * v_vesa_resolution,
+    GstWFDVideoHHResolution * v_hh_resolution,
+    GstWFDVideoH264Profile * v_profile,
+    GstWFDVideoH264Level * v_level,
+    guint32 * v_latency,
+    guint32 * v_max_height,
+    guint32 * v_max_width,
+    guint32 * min_slice_size,
+    guint32 * slice_enc_params, guint * frame_rate_control)
+{
+  guint nativeindex = 0;
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+
+  *v_codec = GST_WFD_VIDEO_H264;
+  *v_native = msg->video_formats->list->native & 0x7;
+  nativeindex = msg->video_formats->list->native >> 3;
+  *v_native_resolution = ((guint64) 1) << nativeindex;
+  *v_profile = msg->video_formats->list->H264_codec.profile;
+  *v_level = msg->video_formats->list->H264_codec.level;
+  *v_max_height = msg->video_formats->list->H264_codec.max_hres;
+  *v_max_width = msg->video_formats->list->H264_codec.max_vres;
+  *v_cea_resolution =
+      msg->video_formats->list->H264_codec.misc_params.CEA_Support;
+  *v_vesa_resolution =
+      msg->video_formats->list->H264_codec.misc_params.VESA_Support;
+  *v_hh_resolution =
+      msg->video_formats->list->H264_codec.misc_params.HH_Support;
+  *v_latency = msg->video_formats->list->H264_codec.misc_params.latency;
+  *min_slice_size =
+      msg->video_formats->list->H264_codec.misc_params.min_slice_size;
+  *slice_enc_params =
+      msg->video_formats->list->H264_codec.misc_params.slice_enc_params;
+  *frame_rate_control =
+      msg->video_formats->list->H264_codec.
+      misc_params.frame_rate_control_support;
+  return GST_WFD_OK;
+}
+
+GstWFDResult
+gst_wfd_message_set_display_edid (GstWFDMessage * msg,
+    gboolean edid_supported, guint32 edid_blockcount, gchar * edid_playload)
+{
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+  if (!msg->display_edid)
+    msg->display_edid = g_new0 (GstWFDDisplayEdid, 1);
+  msg->display_edid->edid_supported = edid_supported;
+  if (!edid_supported)
+    return GST_WFD_OK;
+  if (edid_blockcount > 0 && edid_blockcount <= EDID_BLOCK_COUNT_MAX_SIZE) {
+    msg->display_edid->edid_block_count = edid_blockcount;
+    msg->display_edid->edid_payload = g_malloc(EDID_BLOCK_SIZE * edid_blockcount);
+    if (msg->display_edid->edid_payload)
+      memcpy(msg->display_edid->edid_payload, edid_playload, EDID_BLOCK_SIZE * edid_blockcount);
+    else
+      msg->display_edid->edid_supported = FALSE;
+  } else
+    msg->display_edid->edid_supported = FALSE;
+
+  return GST_WFD_OK;
+}
+
+GstWFDResult
+gst_wfd_message_get_display_edid (GstWFDMessage * msg,
+    gboolean * edid_supported,
+    guint32 * edid_blockcount, gchar ** edid_playload)
+{
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+  g_return_val_if_fail (edid_supported != NULL, GST_WFD_EINVAL);
+  g_return_val_if_fail (edid_blockcount != NULL, GST_WFD_EINVAL);
+  g_return_val_if_fail (edid_playload != NULL, GST_WFD_EINVAL);
+
+  *edid_supported = FALSE;
+  if (msg->display_edid) {
+    if (msg->display_edid->edid_supported) {
+      *edid_blockcount = msg->display_edid->edid_block_count;
+      if (msg->display_edid->edid_block_count > 0 && msg->display_edid->edid_block_count <= EDID_BLOCK_COUNT_MAX_SIZE) {
+        char *temp;
+        temp = g_malloc0(EDID_BLOCK_SIZE * msg->display_edid->edid_block_count);
+        if (temp) {
+          memcpy(temp, msg->display_edid->edid_payload, EDID_BLOCK_SIZE * msg->display_edid->edid_block_count);
+          *edid_playload = temp;
+          *edid_supported = TRUE;
+        }
+      }
+    }
+  }
+  return GST_WFD_OK;
+}
+
+
+GstWFDResult
+gst_wfd_message_set_contentprotection_type (GstWFDMessage * msg,
+    GstWFDHDCPProtection hdcpversion, guint32 TCPPort)
+{
+  char str[11] = { 0, };
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+  g_return_val_if_fail (TCPPort <= MAX_PORT_SIZE, GST_WFD_EINVAL);
+
+  if (!msg->content_protection)
+    msg->content_protection = g_new0 (GstWFDContentProtection, 1);
+  if (hdcpversion == GST_WFD_HDCP_NONE)
+    return GST_WFD_OK;
+  msg->content_protection->hdcp2_spec = g_new0 (GstWFDHdcp2Spec, 1);
+  if (hdcpversion == GST_WFD_HDCP_2_0)
+    msg->content_protection->hdcp2_spec->hdcpversion = g_strdup ("HDCP2.0");
+  else if (hdcpversion == GST_WFD_HDCP_2_1)
+    msg->content_protection->hdcp2_spec->hdcpversion = g_strdup ("HDCP2.1");
+  snprintf (str, sizeof (str), "port=%d", TCPPort);
+  msg->content_protection->hdcp2_spec->TCPPort = g_strdup (str);
+  return GST_WFD_OK;
+}
+
+GstWFDResult
+gst_wfd_message_get_contentprotection_type (GstWFDMessage * msg,
+    GstWFDHDCPProtection * hdcpversion, guint32 * TCPPort)
+{
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+  if (msg->content_protection && msg->content_protection->hdcp2_spec) {
+    char *result = NULL;
+    char *ptr = NULL;
+    if (!g_strcmp0 (msg->content_protection->hdcp2_spec->hdcpversion, "none")) {
+      *hdcpversion = GST_WFD_HDCP_NONE;
+      *TCPPort = 0;
+      return GST_WFD_OK;
+    }
+    if (!g_strcmp0 (msg->content_protection->hdcp2_spec->hdcpversion,
+            "HDCP2.0"))
+      *hdcpversion = GST_WFD_HDCP_2_0;
+    else if (!g_strcmp0 (msg->content_protection->hdcp2_spec->hdcpversion,
+            "HDCP2.1"))
+      *hdcpversion = GST_WFD_HDCP_2_1;
+    else {
+      *hdcpversion = GST_WFD_HDCP_NONE;
+      *TCPPort = 0;
+      return GST_WFD_OK;
+    }
+
+    result = strtok_r (msg->content_protection->hdcp2_spec->TCPPort, "=", &ptr);
+    while (result != NULL) {
+      result = strtok_r (NULL, "=", &ptr);
+      *TCPPort = atoi (result);
+      break;
+    }
+  } else
+    *hdcpversion = GST_WFD_HDCP_NONE;
+  return GST_WFD_OK;
+}
+
+
+GstWFDResult
+gst_wfd_messge_set_prefered_rtp_ports (GstWFDMessage * msg,
+    GstWFDRTSPTransMode trans,
+    GstWFDRTSPProfile profile,
+    GstWFDRTSPLowerTrans lowertrans, guint32 rtp_port0, guint32 rtp_port1)
+{
+  GString *lines;
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+
+  if (!msg->client_rtp_ports)
+    msg->client_rtp_ports = g_new0 (GstWFDClientRtpPorts, 1);
+
+  if (trans != GST_WFD_RTSP_TRANS_UNKNOWN) {
+    lines = g_string_new ("");
+    if (trans == GST_WFD_RTSP_TRANS_RTP)
+      g_string_append_printf (lines, "RTP");
+    else if (trans == GST_WFD_RTSP_TRANS_RDT)
+      g_string_append_printf (lines, "RDT");
+
+    if (profile == GST_WFD_RTSP_PROFILE_AVP)
+      g_string_append_printf (lines, "/AVP");
+    else if (profile == GST_WFD_RTSP_PROFILE_SAVP)
+      g_string_append_printf (lines, "/SAVP");
+
+    if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_UDP)
+      g_string_append_printf (lines, "/UDP;unicast");
+    else if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_UDP_MCAST)
+      g_string_append_printf (lines, "/UDP;multicast");
+    else if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_TCP)
+      g_string_append_printf (lines, "/TCP;unicast");
+    else if (lowertrans == GST_WFD_RTSP_LOWER_TRANS_HTTP)
+      g_string_append_printf (lines, "/HTTP");
+
+    msg->client_rtp_ports->profile = g_string_free (lines, FALSE);
+    msg->client_rtp_ports->rtp_port0 = rtp_port0;
+    msg->client_rtp_ports->rtp_port1 = rtp_port1;
+    msg->client_rtp_ports->mode = g_strdup ("mode=play");
+  }
+  return GST_WFD_OK;
+}
+
+GstWFDResult
+gst_wfd_message_get_prefered_rtp_ports (GstWFDMessage * msg,
+    GstWFDRTSPTransMode * trans,
+    GstWFDRTSPProfile * profile,
+    GstWFDRTSPLowerTrans * lowertrans, guint32 * rtp_port0, guint32 * rtp_port1)
+{
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+  g_return_val_if_fail (msg->client_rtp_ports != NULL, GST_WFD_EINVAL);
+
+  if (g_strrstr (msg->client_rtp_ports->profile, "RTP"))
+    *trans = GST_WFD_RTSP_TRANS_RTP;
+  if (g_strrstr (msg->client_rtp_ports->profile, "RDT"))
+    *trans = GST_WFD_RTSP_TRANS_RDT;
+  if (g_strrstr (msg->client_rtp_ports->profile, "AVP"))
+    *profile = GST_WFD_RTSP_PROFILE_AVP;
+  if (g_strrstr (msg->client_rtp_ports->profile, "SAVP"))
+    *profile = GST_WFD_RTSP_PROFILE_SAVP;
+  if (g_strrstr (msg->client_rtp_ports->profile, "UDP;unicast"))
+    *lowertrans = GST_WFD_RTSP_LOWER_TRANS_UDP;
+  if (g_strrstr (msg->client_rtp_ports->profile, "UDP;multicast"))
+    *lowertrans = GST_WFD_RTSP_LOWER_TRANS_UDP_MCAST;
+  if (g_strrstr (msg->client_rtp_ports->profile, "TCP;unicast"))
+    *lowertrans = GST_WFD_RTSP_LOWER_TRANS_TCP;
+  if (g_strrstr (msg->client_rtp_ports->profile, "HTTP"))
+    *lowertrans = GST_WFD_RTSP_LOWER_TRANS_HTTP;
+
+  *rtp_port0 = msg->client_rtp_ports->rtp_port0;
+  *rtp_port1 = msg->client_rtp_ports->rtp_port1;
+
+  return GST_WFD_OK;
+}
+
+GstWFDResult
+gst_wfd_message_set_presentation_url (GstWFDMessage * msg, gchar * wfd_url0,
+    gchar * wfd_url1)
+{
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+
+  if (!msg->presentation_url)
+    msg->presentation_url = g_new0 (GstWFDPresentationUrl, 1);
+  if (wfd_url0)
+    msg->presentation_url->wfd_url0 = g_strdup (wfd_url0);
+  if (wfd_url1)
+    msg->presentation_url->wfd_url1 = g_strdup (wfd_url1);
+  return GST_WFD_OK;
+}
+
+GstWFDResult
+gst_wfd_message_get_presentation_url (GstWFDMessage * msg, gchar ** wfd_url0,
+    gchar ** wfd_url1)
+{
+  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
+
+  if (msg->presentation_url) {
+    *wfd_url0 = g_strdup (msg->presentation_url->wfd_url0);
+    *wfd_url1 = g_strdup (msg->presentation_url->wfd_url1);
+  }
+  return GST_WFD_OK;
+}
+
+GstWFDResult
+gst_wfd_message_set_av_format_change_timing(GstWFDMessage *msg, guint64 PTS, guint64 DTS)
+{
+  g_return_val_if_fail(msg != NULL, GST_WFD_EINVAL);
+
+  if (!msg->av_format_change_timing)
+    msg->av_format_change_timing = g_new0(GstWFDAVFormatChangeTiming, 1);
+
+  msg->av_format_change_timing->PTS = PTS;
+  msg->av_format_change_timing->DTS = DTS;
+  return GST_WFD_OK;
+}
+
+GstWFDResult
+gst_wfd_message_get_av_format_change_timing(GstWFDMessage *msg, guint64 *PTS, guint64 *DTS)
+{
+  g_return_val_if_fail(msg != NULL, GST_WFD_EINVAL);
+  g_return_val_if_fail(PTS != NULL, GST_WFD_EINVAL);
+  g_return_val_if_fail(DTS != NULL, GST_WFD_EINVAL);
+
+  if (msg->av_format_change_timing) {
+    *PTS = msg->av_format_change_timing->PTS;
+    *DTS = msg->av_format_change_timing->DTS;
+  }
+
+  return GST_WFD_OK;
+}
diff --git a/gst/rtsp-server/gstwfdmessage.h b/gst/rtsp-server/gstwfdmessage.h
new file mode 100755 (executable)
index 0000000..b390ef3
--- /dev/null
@@ -0,0 +1,618 @@
+/* GStreamer
+ * Copyright (C) 2015 Samsung Electronics Hyunjun Ko <zzoon.ko@samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __GST_WFD_MESSAGE_H__
+#define __GST_WFD_MESSAGE_H__
+
+#include <glib.h>
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_STRING_WFD_AUDIO_CODECS               "wfd_audio_codecs"
+#define GST_STRING_WFD_VIDEO_FORMATS              "wfd_video_formats"
+#define GST_STRING_WFD_3D_VIDEO_FORMATS           "wfd_3d_video_formats"
+#define GST_STRING_WFD_CONTENT_PROTECTION         "wfd_content_protection"
+#define GST_STRING_WFD_DISPLAY_EDID               "wfd_display_edid"
+#define GST_STRING_WFD_COUPLED_SINK               "wfd_coupled_sink"
+#define GST_STRING_WFD_TRIGGER_METHOD             "wfd_trigger_method"
+#define GST_STRING_WFD_PRESENTATION_URL           "wfd_presentation_URL"
+#define GST_STRING_WFD_CLIENT_RTP_PORTS           "wfd_client_rtp_ports"
+#define GST_STRING_WFD_ROUTE                      "wfd_route"
+#define GST_STRING_WFD_I2C                        "wfd_I2C"
+#define GST_STRING_WFD_AV_FORMAT_CHANGE_TIMING    "wfd_av_format_change_timing"
+#define GST_STRING_WFD_PREFERRED_DISPLAY_MODE     "wfd_preferred_display_mode"
+#define GST_STRING_WFD_STANDBY_RESUME_CAPABILITY  "wfd_standby_resume_capability"
+#define GST_STRING_WFD_STANDBY                    "wfd_standby"
+#define GST_STRING_WFD_CONNECTOR_TYPE             "wfd_connector_type"
+#define GST_STRING_WFD_IDR_REQUEST                "wfd_idr_request"
+
+/**
+ * GstWFDResult:
+ * @GST_WFD_OK: A successful return value
+ * @GST_WFD_EINVAL: a function was given invalid parameters
+ *
+ * Return values for the WFD functions.
+ */
+typedef enum {
+  GST_WFD_OK     = 0,
+  GST_WFD_EINVAL = -1
+} GstWFDResult;
+
+
+typedef enum {
+  GST_WFD_AUDIO_UNKNOWN        = 0,
+  GST_WFD_AUDIO_LPCM           = (1 << 0),
+  GST_WFD_AUDIO_AAC            = (1 << 1),
+  GST_WFD_AUDIO_AC3            = (1 << 2)
+} GstWFDAudioFormats;
+
+typedef enum {
+  GST_WFD_FREQ_UNKNOWN = 0,
+  GST_WFD_FREQ_44100    = (1 << 0),
+  GST_WFD_FREQ_48000    = (1 << 1)
+} GstWFDAudioFreq;
+
+typedef enum {
+  GST_WFD_CHANNEL_UNKNOWN = 0,
+  GST_WFD_CHANNEL_2            = (1 << 0),
+  GST_WFD_CHANNEL_4            = (1 << 1),
+  GST_WFD_CHANNEL_6            = (1 << 2),
+  GST_WFD_CHANNEL_8            = (1 << 3)
+} GstWFDAudioChannels;
+
+
+typedef enum {
+  GST_WFD_VIDEO_UNKNOWN = 0,
+  GST_WFD_VIDEO_H264     = (1 << 0)
+} GstWFDVideoCodecs;
+
+typedef enum {
+  GST_WFD_VIDEO_CEA_RESOLUTION = 0,
+  GST_WFD_VIDEO_VESA_RESOLUTION,
+  GST_WFD_VIDEO_HH_RESOLUTION
+} GstWFDVideoNativeResolution;
+
+typedef enum {
+  GST_WFD_CEA_UNKNOWN          = 0,
+  GST_WFD_CEA_640x480P60       = (1 << 0),
+  GST_WFD_CEA_720x480P60       = (1 << 1),
+  GST_WFD_CEA_720x480I60       = (1 << 2),
+  GST_WFD_CEA_720x576P50       = (1 << 3),
+  GST_WFD_CEA_720x576I50       = (1 << 4),
+  GST_WFD_CEA_1280x720P30      = (1 << 5),
+  GST_WFD_CEA_1280x720P60      = (1 << 6),
+  GST_WFD_CEA_1920x1080P30= (1 << 7),
+  GST_WFD_CEA_1920x1080P60= (1 << 8),
+  GST_WFD_CEA_1920x1080I60= (1 << 9),
+  GST_WFD_CEA_1280x720P25      = (1 << 10),
+  GST_WFD_CEA_1280x720P50      = (1 << 11),
+  GST_WFD_CEA_1920x1080P25= (1 << 12),
+  GST_WFD_CEA_1920x1080P50= (1 << 13),
+  GST_WFD_CEA_1920x1080I50= (1 << 14),
+  GST_WFD_CEA_1280x720P24      = (1 << 15),
+  GST_WFD_CEA_1920x1080P24= (1 << 16)
+} GstWFDVideoCEAResolution;
+
+typedef enum {
+  GST_WFD_VESA_UNKNOWN         = 0,
+  GST_WFD_VESA_800x600P30      = (1 << 0),
+  GST_WFD_VESA_800x600P60              = (1 << 1),
+  GST_WFD_VESA_1024x768P30     = (1 << 2),
+  GST_WFD_VESA_1024x768P60     = (1 << 3),
+  GST_WFD_VESA_1152x864P30     = (1 << 4),
+  GST_WFD_VESA_1152x864P60     = (1 << 5),
+  GST_WFD_VESA_1280x768P30     = (1 << 6),
+  GST_WFD_VESA_1280x768P60     = (1 << 7),
+  GST_WFD_VESA_1280x800P30     = (1 << 8),
+  GST_WFD_VESA_1280x800P60     = (1 << 9),
+  GST_WFD_VESA_1360x768P30     = (1 << 10),
+  GST_WFD_VESA_1360x768P60     = (1 << 11),
+  GST_WFD_VESA_1366x768P30     = (1 << 12),
+  GST_WFD_VESA_1366x768P60     = (1 << 13),
+  GST_WFD_VESA_1280x1024P30    = (1 << 14),
+  GST_WFD_VESA_1280x1024P60    = (1 << 15),
+  GST_WFD_VESA_1400x1050P30    = (1 << 16),
+  GST_WFD_VESA_1400x1050P60    = (1 << 17),
+  GST_WFD_VESA_1440x900P30     = (1 << 18),
+  GST_WFD_VESA_1440x900P60     = (1 << 19),
+  GST_WFD_VESA_1600x900P30     = (1 << 20),
+  GST_WFD_VESA_1600x900P60     = (1 << 21),
+  GST_WFD_VESA_1600x1200P30    = (1 << 22),
+  GST_WFD_VESA_1600x1200P60    = (1 << 23),
+  GST_WFD_VESA_1680x1024P30    = (1 << 24),
+  GST_WFD_VESA_1680x1024P60    = (1 << 25),
+  GST_WFD_VESA_1680x1050P30    = (1 << 26),
+  GST_WFD_VESA_1680x1050P60    = (1 << 27),
+  GST_WFD_VESA_1920x1200P30    = (1 << 28),
+  GST_WFD_VESA_1920x1200P60    = (1 << 29)
+} GstWFDVideoVESAResolution;
+
+typedef enum {
+  GST_WFD_HH_UNKNOWN           = 0,
+  GST_WFD_HH_800x480P30        = (1 << 0),
+  GST_WFD_HH_800x480P60        = (1 << 1),
+  GST_WFD_HH_854x480P30        = (1 << 2),
+  GST_WFD_HH_854x480P60        = (1 << 3),
+  GST_WFD_HH_864x480P30        = (1 << 4),
+  GST_WFD_HH_864x480P60        = (1 << 5),
+  GST_WFD_HH_640x360P30        = (1 << 6),
+  GST_WFD_HH_640x360P60        = (1 << 7),
+  GST_WFD_HH_960x540P30        = (1 << 8),
+  GST_WFD_HH_960x540P60        = (1 << 9),
+  GST_WFD_HH_848x480P30        = (1 << 10),
+  GST_WFD_HH_848x480P60        = (1 << 11)
+} GstWFDVideoHHResolution;
+
+typedef enum {
+  GST_WFD_H264_UNKNOWN_PROFILE= 0,
+  GST_WFD_H264_BASE_PROFILE    = (1 << 0),
+  GST_WFD_H264_HIGH_PROFILE    = (1 << 1)
+} GstWFDVideoH264Profile;
+
+typedef enum {
+  GST_WFD_H264_LEVEL_UNKNOWN = 0,
+  GST_WFD_H264_LEVEL_3_1   = (1 << 0),
+  GST_WFD_H264_LEVEL_3_2   = (1 << 1),
+  GST_WFD_H264_LEVEL_4       = (1 << 2),
+  GST_WFD_H264_LEVEL_4_1   = (1 << 3),
+  GST_WFD_H264_LEVEL_4_2   = (1 << 4)
+} GstWFDVideoH264Level;
+
+typedef enum {
+  GST_WFD_HDCP_NONE    = 0,
+  GST_WFD_HDCP_2_0     = (1 << 0),
+  GST_WFD_HDCP_2_1     = (1 << 1)
+} GstWFDHDCPProtection;
+
+typedef enum {
+  GST_WFD_SINK_UNKNOWN = -1,
+  GST_WFD_SINK_NOT_COUPLED     = 0,
+  GST_WFD_SINK_COUPLED,
+  GST_WFD_SINK_TEARDOWN_COUPLING,
+  GST_WFD_SINK_RESERVED
+} GstWFDCoupledSinkStatus;
+
+typedef enum {
+  GST_WFD_TRIGGER_UNKNOWN = 0,
+  GST_WFD_TRIGGER_SETUP,
+  GST_WFD_TRIGGER_PAUSE,
+  GST_WFD_TRIGGER_TEARDOWN,
+  GST_WFD_TRIGGER_PLAY
+} GstWFDTrigger;
+
+typedef enum {
+  GST_WFD_RTSP_TRANS_UNKNOWN =  0,
+  GST_WFD_RTSP_TRANS_RTP     = (1 << 0),
+  GST_WFD_RTSP_TRANS_RDT     = (1 << 1)
+} GstWFDRTSPTransMode;
+
+typedef enum {
+  GST_WFD_RTSP_PROFILE_UNKNOWN =  0,
+  GST_WFD_RTSP_PROFILE_AVP     = (1 << 0),
+  GST_WFD_RTSP_PROFILE_SAVP    = (1 << 1)
+} GstWFDRTSPProfile;
+
+typedef enum {
+  GST_WFD_RTSP_LOWER_TRANS_UNKNOWN   = 0,
+  GST_WFD_RTSP_LOWER_TRANS_UDP       = (1 << 0),
+  GST_WFD_RTSP_LOWER_TRANS_UDP_MCAST = (1 << 1),
+  GST_WFD_RTSP_LOWER_TRANS_TCP       = (1 << 2),
+  GST_WFD_RTSP_LOWER_TRANS_HTTP      = (1 << 3)
+} GstWFDRTSPLowerTrans;
+
+typedef enum {
+  GST_WFD_PRIMARY_SINK   = 0,
+  GST_WFD_SECONDARY_SINK
+} GstWFDSinkType;
+
+typedef enum {
+  GST_WFD_CONNECTOR_VGA           = 0,
+  GST_WFD_CONNECTOR_S,
+  GST_WFD_CONNECTOR_COMPOSITE,
+  GST_WFD_CONNECTOR_COMPONENT,
+  GST_WFD_CONNECTOR_DVI,
+  GST_WFD_CONNECTOR_HDMI,
+  GST_WFD_CONNECTOR_LVDS,
+  GST_WFD_CONNECTOR_RESERVED_7,
+  GST_WFD_CONNECTOR_JAPANESE_D,
+  GST_WFD_CONNECTOR_SDI,
+  GST_WFD_CONNECTOR_DP,
+  GST_WFD_CONNECTOR_RESERVED_11,
+  GST_WFD_CONNECTOR_UDI,
+  GST_WFD_CONNECTOR_NO           = 254,
+  GST_WFD_CONNECTOR_PHYSICAL     = 255
+} GstWFDConnector;
+
+
+typedef struct {
+  gchar        *audio_format;
+  guint32 modes;
+  guint latency;
+} GstWFDAudioCodec;
+
+typedef struct {
+  guint        count;
+  GstWFDAudioCodec *list;
+} GstWFDAudioCodeclist;
+
+
+typedef struct {
+  guint CEA_Support;
+  guint VESA_Support;
+  guint HH_Support;
+  guint latency;
+  guint min_slice_size;
+  guint slice_enc_params;
+  guint frame_rate_control_support;
+} GstWFDVideoH264MiscParams;
+
+typedef struct {
+  guint profile;
+  guint level;
+  guint max_hres;
+  guint max_vres;
+  GstWFDVideoH264MiscParams misc_params;
+} GstWFDVideoH264Codec;
+
+typedef struct {
+  guint        native;
+  guint preferred_display_mode_supported;
+  GstWFDVideoH264Codec H264_codec;
+} GstWFDVideoCodec;
+
+typedef struct {
+  guint                        count;
+  GstWFDVideoCodec *list;
+} GstWFDVideoCodeclist;
+
+typedef struct {
+  guint video_3d_capability;
+  guint latency;
+  guint min_slice_size;
+  guint slice_enc_params;
+  guint frame_rate_control_support;
+} GstWFD3DVideoH264MiscParams;
+
+typedef struct {
+  guint profile;
+  guint level;
+  GstWFD3DVideoH264MiscParams misc_params;
+  guint max_hres;
+  guint max_vres;
+} GstWFD3DVideoH264Codec;
+
+typedef struct {
+  guint native;
+  guint preferred_display_mode_supported;
+  GstWFD3DVideoH264Codec H264_codec;
+} GstWFD3dCapList;
+
+typedef struct {
+  guint                        count;
+  GstWFD3dCapList *list;
+} GstWFD3DFormats;
+
+typedef struct {
+  gchar *hdcpversion;
+  gchar *TCPPort;
+} GstWFDHdcp2Spec;
+
+typedef struct {
+  GstWFDHdcp2Spec *hdcp2_spec;
+} GstWFDContentProtection;
+
+typedef struct {
+  guint edid_supported;
+  guint edid_block_count;
+  gchar *edid_payload;
+} GstWFDDisplayEdid;
+
+
+typedef struct {
+  guint status;
+  gchar *sink_address;
+} GstWFDCoupled_sink_cap;
+
+typedef struct {
+  GstWFDCoupled_sink_cap *coupled_sink_cap;
+} GstWFDCoupledSink;
+
+typedef struct {
+  gchar *wfd_trigger_method;
+} GstWFDTriggerMethod;
+
+typedef struct {
+  gchar *wfd_url0;
+  gchar *wfd_url1;
+} GstWFDPresentationUrl;
+
+typedef struct {
+  gchar *profile;
+  guint32 rtp_port0;
+  guint32 rtp_port1;
+  gchar *mode;
+} GstWFDClientRtpPorts;
+
+typedef struct {
+ gchar *destination;
+} GstWFDRoute;
+
+typedef struct {
+  gboolean I2CPresent;
+  guint32 I2C_port;
+} GstWFDI2C;
+
+typedef struct {
+  guint64 PTS;
+  guint64 DTS;
+} GstWFDAVFormatChangeTiming;
+
+typedef struct {
+  gboolean displaymodesupported;
+  guint64 p_clock;
+  guint32 H;
+  guint32 HB;
+  guint32 HSPOL_HSOFF;
+  guint32 HSW;
+  guint32 V;
+  guint32 VB;
+  guint32 VSPOL_VSOFF;
+  guint32 VSW;
+  guint VBS3D;
+  guint R;
+  guint V2d_s3d_modes;
+  guint P_depth;
+  GstWFDVideoH264Codec H264_codec;
+} GstWFDPreferredDisplayMode;
+
+typedef struct {
+  gboolean standby_resume_cap;
+} GstWFDStandbyResumeCapability;
+
+typedef struct {
+  gboolean wfd_standby;
+} GstWFDStandby;
+
+typedef struct {
+  gboolean supported;
+  gint32 connector_type;
+} GstWFDConnectorType;
+
+typedef struct {
+  gboolean idr_request;
+} GstWFDIdrRequest;
+
+/**
+ * GstWFDMessage:
+ * @version: the protocol version
+ * @origin: owner/creator and session identifier
+ * @session_name: session name
+ * @information: session information
+ * @uri: URI of description
+ * @emails: array of #gchar with email addresses
+ * @phones: array of #gchar with phone numbers
+ * @connection: connection information for the session
+ * @bandwidths: array of #GstWFDBandwidth with bandwidth information
+ * @times: array of #GstWFDTime with time descriptions
+ * @zones: array of #GstWFDZone with time zone adjustments
+ * @key: encryption key
+ * @attributes: array of #GstWFDAttribute with session attributes
+ * @medias: array of #GstWFDMedia with media descriptions
+ *
+ * The contents of the WFD message.
+ */
+typedef struct {
+  GstWFDAudioCodeclist *audio_codecs;
+  GstWFDVideoCodeclist *video_formats;
+  GstWFD3DFormats *video_3d_formats;
+  GstWFDContentProtection *content_protection;
+  GstWFDDisplayEdid *display_edid;
+  GstWFDCoupledSink *coupled_sink;
+  GstWFDTriggerMethod *trigger_method;
+  GstWFDPresentationUrl *presentation_url;
+  GstWFDClientRtpPorts *client_rtp_ports;
+  GstWFDRoute *route;
+  GstWFDI2C *I2C;
+  GstWFDAVFormatChangeTiming *av_format_change_timing;
+  GstWFDPreferredDisplayMode *preferred_display_mode;
+  GstWFDStandbyResumeCapability *standby_resume_capability;
+  GstWFDStandby *standby;
+  GstWFDConnectorType *connector_type;
+  GstWFDIdrRequest *idr_request;
+} GstWFDMessage;
+
+GType                   gst_wfd_message_get_type            (void);
+
+#define GST_TYPE_WFD_MESSAGE           (gst_wfd_message_get_type())
+#define GST_WFD_MESSAGE_CAST(object)   ((GstWFDMessage *)(object))
+#define GST_WFD_MESSAGE(object)        (GST_WFD_MESSAGE_CAST(object))
+
+/* Session descriptions */
+GstWFDResult            gst_wfd_message_new                 (GstWFDMessage **msg);
+GstWFDResult            gst_wfd_message_init                (GstWFDMessage *msg);
+GstWFDResult            gst_wfd_message_uninit              (GstWFDMessage *msg);
+GstWFDResult            gst_wfd_message_free                (GstWFDMessage *msg);
+GstWFDResult            gst_wfd_message_copy                (const GstWFDMessage *msg, GstWFDMessage **copy);
+
+GstWFDResult            gst_wfd_message_parse_buffer        (const guint8 *data, guint size, GstWFDMessage *msg);
+gchar*                  gst_wfd_message_as_text             (const GstWFDMessage *msg);
+gchar*                  gst_wfd_message_param_names_as_text (const GstWFDMessage *msg);
+GstWFDResult            gst_wfd_message_dump                (const GstWFDMessage *msg);
+
+
+GstWFDResult gst_wfd_message_set_supported_audio_format(GstWFDMessage *msg,
+                                        GstWFDAudioFormats a_codec,
+                                        guint a_freq, guint a_channels,
+                                        guint a_bitwidth, guint32 a_latency);
+
+GstWFDResult gst_wfd_message_set_prefered_audio_format(GstWFDMessage *msg,
+                                        GstWFDAudioFormats a_codec,
+                                        GstWFDAudioFreq a_freq,
+                                        GstWFDAudioChannels a_channels,
+                                        guint a_bitwidth, guint32 a_latency);
+
+GstWFDResult gst_wfd_message_get_supported_audio_format (GstWFDMessage *msg,
+                                        guint *a_codec,
+                                        guint *a_freq,
+                                        guint *a_channels,
+                                        guint *a_bitwidth,
+                                        guint32 *a_latency);
+
+GstWFDResult gst_wfd_message_get_prefered_audio_format (GstWFDMessage *msg,
+                                        GstWFDAudioFormats *a_codec,
+                                        GstWFDAudioFreq *a_freq,
+                                        GstWFDAudioChannels *a_channels,
+                                        guint *a_bitwidth, guint32 *a_latency);
+
+GstWFDResult gst_wfd_message_set_supported_video_format (GstWFDMessage *msg,
+                                        GstWFDVideoCodecs v_codec,
+                                        GstWFDVideoNativeResolution v_native,
+                                        guint64 v_native_resolution,
+                                        guint64 v_cea_resolution,
+                                        guint64 v_vesa_resolution,
+                                        guint64 v_hh_resolution,
+                                        guint v_profile,
+                                        guint v_level,
+                                        guint32 v_latency,
+                                        guint32 v_max_height,
+                                        guint32 v_max_width,
+                                        guint32 min_slice_size,
+                                        guint32 slice_enc_params,
+                                        guint frame_rate_control);
+
+GstWFDResult gst_wfd_message_set_prefered_video_format(GstWFDMessage *msg,
+                                        GstWFDVideoCodecs v_codec,
+                                        GstWFDVideoNativeResolution v_native,
+                                        guint64 v_native_resolution,
+                                        GstWFDVideoCEAResolution v_cea_resolution,
+                                        GstWFDVideoVESAResolution v_vesa_resolution,
+                                        GstWFDVideoHHResolution v_hh_resolution,
+                                        GstWFDVideoH264Profile v_profile,
+                                        GstWFDVideoH264Level v_level,
+                                        guint32 v_latency,
+                                        guint32 v_max_height,
+                                        guint32 v_max_width,
+                                        guint32 min_slice_size,
+                                        guint32 slice_enc_params,
+                                        guint frame_rate_control);
+
+GstWFDResult gst_wfd_message_get_supported_video_format(GstWFDMessage *msg,
+                                        GstWFDVideoCodecs *v_codec,
+                                        GstWFDVideoNativeResolution *v_native,
+                                        guint64 *v_native_resolution,
+                                        guint64 *v_cea_resolution,
+                                        guint64 *v_vesa_resolution,
+                                        guint64 *v_hh_resolution,
+                                        guint *v_profile,
+                                        guint *v_level,
+                                        guint32 *v_latency,
+                                        guint32 *v_max_height,
+                                        guint32 *v_max_width,
+                                        guint32 *min_slice_size,
+                                        guint32 *slice_enc_params,
+                                        guint *frame_rate_control);
+
+GstWFDResult gst_wfd_message_get_prefered_video_format(GstWFDMessage *msg,
+                                        GstWFDVideoCodecs *v_codec,
+                                        GstWFDVideoNativeResolution *v_native,
+                                        guint64 *v_native_resolution,
+                                        GstWFDVideoCEAResolution *v_cea_resolution,
+                                        GstWFDVideoVESAResolution *v_vesa_resolution,
+                                        GstWFDVideoHHResolution *v_hh_resolution,
+                                        GstWFDVideoH264Profile *v_profile,
+                                        GstWFDVideoH264Level *v_level,
+                                        guint32 *v_latency,
+                                        guint32 *v_max_height,
+                                        guint32 *v_max_width,
+                                        guint32 *min_slice_size,
+                                        guint32 *slice_enc_params,
+                                        guint *frame_rate_control);
+
+GstWFDResult gst_wfd_message_set_display_edid (GstWFDMessage *msg,
+                                        gboolean edid_supported,
+                                        guint32 edid_blockcount,
+                                        gchar *edid_playload);
+
+GstWFDResult gst_wfd_message_get_display_edid (GstWFDMessage *msg,
+                                        gboolean *edid_supported,
+                                        guint32 *edid_blockcount,
+                                        gchar **edid_playload);
+
+GstWFDResult gst_wfd_message_set_contentprotection_type (GstWFDMessage *msg,
+                                        GstWFDHDCPProtection hdcpversion,
+                                        guint32 TCPPort);
+
+GstWFDResult gst_wfd_message_get_contentprotection_type (GstWFDMessage *msg,
+                                        GstWFDHDCPProtection *hdcpversion,
+                                        guint32 *TCPPort);
+
+GstWFDResult gst_wfd_messge_set_prefered_rtp_ports (GstWFDMessage *msg,
+                                        GstWFDRTSPTransMode trans,
+                                        GstWFDRTSPProfile profile,
+                                        GstWFDRTSPLowerTrans lowertrans,
+                                        guint32 rtp_port0,
+                                        guint32 rtp_port1);
+
+GstWFDResult gst_wfd_message_get_prefered_rtp_ports (GstWFDMessage *msg,
+                                        GstWFDRTSPTransMode *trans,
+                                        GstWFDRTSPProfile *profile,
+                                        GstWFDRTSPLowerTrans *lowertrans,
+                                        guint32 *rtp_port0,
+                                        guint32 *rtp_port1);
+
+GstWFDResult gst_wfd_message_set_presentation_url(GstWFDMessage *msg,
+                                        gchar *wfd_url0, gchar *wfd_url1);
+
+GstWFDResult gst_wfd_message_get_presentation_url(GstWFDMessage *msg, gchar **wfd_url0,
+                                        gchar **wfd_url1);
+
+GstWFDResult gst_wfd_message_set_av_format_change_timing(GstWFDMessage *msg,
+                                        guint64 PTS,
+                                        guint64 DTS);
+
+GstWFDResult gst_wfd_message_get_av_format_change_timing(GstWFDMessage *msg,
+                                        guint64 *PTS,
+                                        guint64 *DTS);
+G_END_DECLS
+
+#endif /* __GST_WFD_MESSAGE_H__ */
diff --git a/gst/rtsp-server/rtsp-client-wfd.c b/gst/rtsp-server/rtsp-client-wfd.c
new file mode 100644 (file)
index 0000000..561a722
--- /dev/null
@@ -0,0 +1,2959 @@
+/* GStreamer
+ * Copyright (C) 2015 Samsung Electronics Hyunjun Ko <zzoon.ko@samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:rtsp-client
+ * @short_description: A client connection state
+ * @see_also: #GstRTSPServer, #GstRTSPThreadPool
+ *
+ * The client object handles the connection with a client for as long as a TCP
+ * connection is open.
+ *
+ * A #GstRTSPWFDClient is created by #GstRTSPServer when a new connection is
+ * accepted and it inherits the #GstRTSPMountPoints, #GstRTSPSessionPool,
+ * #GstRTSPAuth and #GstRTSPThreadPool from the server.
+ *
+ * The client connection should be configured with the #GstRTSPConnection using
+ * gst_rtsp_wfd_client_set_connection() before it can be attached to a #GMainContext
+ * using gst_rtsp_wfd_client_attach(). From then on the client will handle requests
+ * on the connection.
+ *
+ * Use gst_rtsp_wfd_client_session_filter() to iterate or modify all the
+ * #GstRTSPSession objects managed by the client object.
+ *
+ * Last reviewed on 2013-07-11 (1.0.0)
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "rtsp-client-wfd.h"
+#include "rtsp-media-factory-wfd.h"
+#include "rtsp-sdp.h"
+#include "rtsp-params.h"
+
+#define GST_RTSP_WFD_CLIENT_GET_PRIVATE(obj)  \
+   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_WFD_CLIENT, GstRTSPWFDClientPrivate))
+
+typedef struct _GstRTSPClientRTPStats GstRTSPClientRTPStats;
+
+struct _GstRTSPClientRTPStats {
+  GstRTSPStream *stream;
+  guint64 last_sent_bytes;
+  guint64 sent_bytes;
+  guint last_seqnum;
+  guint seqnum;
+
+  /* Info in RR (Receiver Report) */
+  guint8 fraction_lost;
+  guint32 cumulative_lost_num;
+  guint16 max_seqnum;
+  guint32 arrival_jitter;
+  guint32 lsr;
+  guint32 dlsr;
+  guint32 rtt;
+  guint resent_packets;
+};
+
+struct _GstRTSPWFDClientPrivate
+{
+  GstRTSPWFDClientSendFunc send_func;   /* protected by send_lock */
+  gpointer send_data;           /* protected by send_lock */
+  GDestroyNotify send_notify;   /* protected by send_lock */
+
+  /* used to cache the media in the last requested DESCRIBE so that
+   * we can pick it up in the next SETUP immediately */
+  gchar *path;
+  GstRTSPMedia *media;
+
+  GList *transports;
+  GList *sessions;
+
+  guint8 m1_done;
+  guint8 m3_done;
+  guint8 m4_done;
+
+  /* Host's URL info */
+  gchar *host_address;
+
+  /* Parameters for WIFI-DISPLAY */
+  guint caCodec;
+  guint8 audio_codec;
+  guint cFreq;
+  guint cChanels;
+  guint cBitwidth;
+  guint caLatency;
+  guint cvCodec;
+  guint cNative;
+  guint64 cNativeResolution;
+  guint64 video_resolution_supported;
+  gint video_native_resolution;
+  guint64 cCEAResolution;
+  guint64 cVESAResolution;
+  guint64 cHHResolution;
+  guint cProfile;
+  guint cLevel;
+  guint32 cMaxHeight;
+  guint32 cMaxWidth;
+  guint32 cFramerate;
+  guint32 cInterleaved;
+  guint32 cmin_slice_size;
+  guint32 cslice_enc_params;
+  guint cframe_rate_control;
+  guint cvLatency;
+  guint ctrans;
+  guint cprofile;
+  guint clowertrans;
+  guint32 crtp_port0;
+  guint32 crtp_port1;
+
+  gboolean protection_enabled;
+  GstWFDHDCPProtection hdcp_version;
+  guint32 hdcp_tcpport;
+
+  gboolean edid_supported;
+  guint32 edid_hres;
+  guint32 edid_vres;
+
+  gboolean keep_alive_flag;
+  GMutex keep_alive_lock;
+
+  /* RTP statistics */
+  GstRTSPClientRTPStats stats;
+  GMutex stats_lock;
+  guint stats_timer_id;
+  gboolean rtcp_stats_enabled;
+};
+
+#define DEFAULT_WFD_TIMEOUT 60
+#define WFD_MOUNT_POINT "/wfd1.0/streamid=0"
+
+enum
+{
+  SIGNAL_WFD_OPTIONS_REQUEST,
+  SIGNAL_WFD_GET_PARAMETER_REQUEST,
+  SIGNAL_WFD_KEEP_ALIVE_FAIL,
+  SIGNAL_WFD_LAST
+};
+
+GST_DEBUG_CATEGORY_STATIC (rtsp_wfd_client_debug);
+#define GST_CAT_DEFAULT rtsp_wfd_client_debug
+
+static guint gst_rtsp_client_wfd_signals[SIGNAL_WFD_LAST] = { 0 };
+
+static void gst_rtsp_wfd_client_get_property (GObject * object, guint propid,
+    GValue * value, GParamSpec * pspec);
+static void gst_rtsp_wfd_client_set_property (GObject * object, guint propid,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtsp_wfd_client_finalize (GObject * obj);
+
+static gboolean handle_wfd_options_request (GstRTSPClient * client,
+    GstRTSPContext * ctx);
+static gboolean handle_wfd_set_param_request (GstRTSPClient * client,
+    GstRTSPContext * ctx);
+static gboolean handle_wfd_get_param_request (GstRTSPClient * client,
+    GstRTSPContext * ctx);
+
+static void send_generic_wfd_response (GstRTSPWFDClient * client,
+    GstRTSPStatusCode code, GstRTSPContext * ctx);
+static gchar *wfd_make_path_from_uri (GstRTSPClient * client,
+    const GstRTSPUrl * uri);
+static void wfd_options_request_done (GstRTSPWFDClient * client, GstRTSPContext *ctx);
+static void wfd_get_param_request_done (GstRTSPWFDClient * client, GstRTSPContext *ctx);
+static void handle_wfd_response (GstRTSPClient * client, GstRTSPContext * ctx);
+static void handle_wfd_play (GstRTSPClient * client, GstRTSPContext * ctx);
+static void wfd_set_keep_alive_condition(GstRTSPWFDClient * client);
+static gboolean wfd_ckeck_keep_alive_response (gpointer userdata);
+static gboolean keep_alive_condition(gpointer userdata);
+static gboolean wfd_configure_client_media (GstRTSPClient * client, GstRTSPMedia * media,
+    GstRTSPStream * stream, GstRTSPContext * ctx);
+
+GstRTSPResult prepare_trigger_request (GstRTSPWFDClient * client,
+    GstRTSPMessage * request, GstWFDTriggerType trigger_type, gchar * url);
+
+GstRTSPResult prepare_request (GstRTSPWFDClient * client,
+    GstRTSPMessage * request, GstRTSPMethod method, gchar * url);
+
+void
+send_request (GstRTSPWFDClient * client, GstRTSPSession * session,
+    GstRTSPMessage * request);
+
+GstRTSPResult
+prepare_response (GstRTSPWFDClient * client, GstRTSPMessage * request,
+    GstRTSPMessage * response, GstRTSPMethod method);
+
+static GstRTSPResult handle_M1_message (GstRTSPWFDClient * client);
+static GstRTSPResult handle_M3_message (GstRTSPWFDClient * client);
+static GstRTSPResult handle_M4_message (GstRTSPWFDClient * client);
+static GstRTSPResult handle_M16_message (GstRTSPWFDClient * client);
+
+G_DEFINE_TYPE (GstRTSPWFDClient, gst_rtsp_wfd_client, GST_TYPE_RTSP_CLIENT);
+
+static void
+gst_rtsp_wfd_client_class_init (GstRTSPWFDClientClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstRTSPClientClass *rtsp_client_class;
+
+  g_type_class_add_private (klass, sizeof (GstRTSPWFDClientPrivate));
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  rtsp_client_class = GST_RTSP_CLIENT_CLASS (klass);
+
+  gobject_class->get_property = gst_rtsp_wfd_client_get_property;
+  gobject_class->set_property = gst_rtsp_wfd_client_set_property;
+  gobject_class->finalize = gst_rtsp_wfd_client_finalize;
+
+  //klass->create_sdp = create_sdp;
+  //klass->configure_client_transport = default_configure_client_transport;
+  //klass->params_set = default_params_set;
+  //klass->params_get = default_params_get;
+
+  rtsp_client_class->handle_options_request = handle_wfd_options_request;
+  rtsp_client_class->handle_set_param_request = handle_wfd_set_param_request;
+  rtsp_client_class->handle_get_param_request = handle_wfd_get_param_request;
+  rtsp_client_class->make_path_from_uri = wfd_make_path_from_uri;
+  rtsp_client_class->configure_client_media = wfd_configure_client_media;
+
+  rtsp_client_class->handle_response = handle_wfd_response;
+  rtsp_client_class->play_request = handle_wfd_play;
+
+  gst_rtsp_client_wfd_signals[SIGNAL_WFD_OPTIONS_REQUEST] =
+      g_signal_new ("wfd-options-request", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPWFDClientClass,
+          wfd_options_request), NULL, NULL, g_cclosure_marshal_VOID__POINTER,
+      G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
+
+  gst_rtsp_client_wfd_signals[SIGNAL_WFD_GET_PARAMETER_REQUEST] =
+      g_signal_new ("wfd-get-parameter-request", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPWFDClientClass,
+          wfd_get_param_request), NULL, NULL, g_cclosure_marshal_VOID__POINTER,
+      G_TYPE_NONE, 1, GST_TYPE_RTSP_CONTEXT);
+
+  gst_rtsp_client_wfd_signals[SIGNAL_WFD_KEEP_ALIVE_FAIL] =
+      g_signal_new ("wfd-keep-alive-fail", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (GstRTSPWFDClientClass, wfd_keep_alive_fail), NULL, NULL,
+      g_cclosure_marshal_generic, G_TYPE_NONE, 0, G_TYPE_NONE);
+
+  klass->wfd_options_request = wfd_options_request_done;
+  klass->wfd_get_param_request = wfd_get_param_request_done;
+
+  GST_DEBUG_CATEGORY_INIT (rtsp_wfd_client_debug, "rtspwfdclient", 0,
+      "GstRTSPWFDClient");
+}
+
+static void
+gst_rtsp_wfd_client_init (GstRTSPWFDClient * client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+
+  g_return_if_fail (priv != NULL);
+
+  client->priv = priv;
+  priv->protection_enabled = FALSE;
+  priv->video_native_resolution = GST_WFD_VIDEO_CEA_RESOLUTION;
+  priv->video_resolution_supported = GST_WFD_CEA_640x480P60;
+  priv->audio_codec = GST_WFD_AUDIO_AAC;
+  priv->keep_alive_flag = FALSE;
+
+  g_mutex_init (&priv->keep_alive_lock);
+  g_mutex_init (&priv->stats_lock);
+
+  priv->host_address = NULL;
+
+  priv->stats_timer_id = -1;
+  priv->rtcp_stats_enabled = FALSE;
+  memset (&priv->stats, 0x00, sizeof (GstRTSPClientRTPStats));
+
+  GST_INFO_OBJECT (client, "Client is initialized");
+}
+
+/* A client is finalized when the connection is broken */
+static void
+gst_rtsp_wfd_client_finalize (GObject * obj)
+{
+  GstRTSPWFDClient *client = GST_RTSP_WFD_CLIENT (obj);
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+
+  g_return_if_fail (GST_IS_RTSP_WFD_CLIENT (obj));
+  g_return_if_fail (priv != NULL);
+
+  GST_INFO ("finalize client %p", client);
+
+  if (priv->host_address)
+    g_free (priv->host_address);
+
+  if (priv->stats_timer_id > 0)
+    g_source_remove(priv->stats_timer_id);
+
+  g_mutex_clear (&priv->keep_alive_lock);
+  g_mutex_clear (&priv->stats_lock);
+  G_OBJECT_CLASS (gst_rtsp_wfd_client_parent_class)->finalize (obj);
+}
+
+static void
+gst_rtsp_wfd_client_get_property (GObject * object, guint propid,
+    GValue * value, GParamSpec * pspec)
+{
+  //GstRTSPWFDClient *client = GST_RTSP_WFD_CLIENT (object);
+
+  switch (propid) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
+  }
+}
+
+static void
+gst_rtsp_wfd_client_set_property (GObject * object, guint propid,
+    const GValue * value, GParamSpec * pspec)
+{
+  //GstRTSPWFDClient *client = GST_RTSP_WFD_CLIENT (object);
+
+  switch (propid) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
+  }
+}
+
+/**
+ * gst_rtsp_wfd_client_new:
+ *
+ * Create a new #GstRTSPWFDClient instance.
+ *
+ * Returns: a new #GstRTSPWFDClient
+ */
+GstRTSPWFDClient *
+gst_rtsp_wfd_client_new (void)
+{
+  GstRTSPWFDClient *result;
+
+  result = g_object_new (GST_TYPE_RTSP_WFD_CLIENT, NULL);
+
+  return result;
+}
+
+void
+gst_rtsp_wfd_client_start_wfd (GstRTSPWFDClient * client)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GST_INFO_OBJECT (client, "gst_rtsp_wfd_client_start_wfd");
+
+  res = handle_M1_message (client);
+  if (res < GST_RTSP_OK) {
+    GST_ERROR_OBJECT (client, "handle_M1_message failed : %d", res);
+  }
+
+  return;
+}
+
+static gboolean
+wfd_display_rtp_stats (gpointer userdata)
+{
+  guint16 seqnum = 0;
+  guint64 bytes = 0;
+
+  GstRTSPWFDClient *client = NULL;
+  GstRTSPWFDClientPrivate *priv = NULL;
+
+  client = (GstRTSPWFDClient *) userdata;
+  priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+
+  if (!priv) {
+    GST_ERROR("No priv");
+    return FALSE;
+  }
+
+  g_mutex_lock(&priv->stats_lock);
+
+  seqnum = gst_rtsp_stream_get_current_seqnum (priv->stats.stream);
+  bytes = gst_rtsp_stream_get_udp_sent_bytes (priv->stats.stream);
+
+  GST_INFO ("----------------------------------------------------\n");
+  GST_INFO ("Sent RTP packets : %d", seqnum - priv->stats.last_seqnum);
+  GST_INFO ("Sent Bytes of RTP packets : %lld bytes", bytes - priv->stats.last_sent_bytes);
+
+  priv->stats.last_seqnum = seqnum;
+  priv->stats.last_sent_bytes = bytes;
+
+  if (priv->rtcp_stats_enabled) {
+    GST_INFO ("Fraction Lost: %d", priv->stats.fraction_lost);
+    GST_INFO ("Cumulative number of packets lost: %d", priv->stats.cumulative_lost_num);
+    GST_INFO ("Extended highest sequence number received: %d", priv->stats.max_seqnum);
+    GST_INFO ("Interarrival Jitter: %d", priv->stats.arrival_jitter);
+    GST_INFO ("Round trip time : %d", priv->stats.rtt);
+  }
+
+  GST_INFO ("----------------------------------------------------\n");
+
+  g_mutex_unlock(&priv->stats_lock);
+
+  return TRUE;
+}
+
+static void
+on_rtcp_stats (GstRTSPStream *stream, GstStructure *stats, GstRTSPClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+
+  guint fraction_lost, exthighestseq, jitter, lsr, dlsr, rtt;
+  gint packetslost;
+
+  if (!priv) return;
+
+  g_mutex_lock(&priv->stats_lock);
+
+  gst_structure_get_uint (stats, "rb-fractionlost", &fraction_lost);
+  gst_structure_get_int (stats, "rb-packetslost", &packetslost);
+  gst_structure_get_uint (stats, "rb-exthighestseq", &exthighestseq);
+  gst_structure_get_uint (stats, "rb-jitter", &jitter);
+  gst_structure_get_uint (stats, "rb-lsr", &lsr);
+  gst_structure_get_uint (stats, "rb-dlsr", &dlsr);
+  gst_structure_get_uint (stats, "rb-round-trip", &rtt);
+
+  if (!priv->rtcp_stats_enabled)
+    priv->rtcp_stats_enabled = TRUE;
+
+  priv->stats.stream = stream;
+  priv->stats.fraction_lost = (guint8)fraction_lost;
+  priv->stats.cumulative_lost_num += (guint32)fraction_lost;
+  priv->stats.max_seqnum = (guint16)exthighestseq;
+  priv->stats.arrival_jitter = (guint32)jitter;
+  priv->stats.lsr = (guint32)lsr;
+  priv->stats.dlsr = (guint32)dlsr;
+  priv->stats.rtt = (guint32)rtt;
+
+  g_mutex_unlock(&priv->stats_lock);
+}
+
+static gboolean
+wfd_configure_client_media (GstRTSPClient * client, GstRTSPMedia * media,
+    GstRTSPStream * stream, GstRTSPContext * ctx)
+{
+  if (stream) {
+    GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+    if (priv)
+      priv->stats.stream = stream;
+    g_signal_connect (stream, "rtcp-statistics", (GCallback) on_rtcp_stats, client);
+  }
+
+  return GST_RTSP_CLIENT_CLASS (gst_rtsp_wfd_client_parent_class)->configure_client_media (client, media, stream, ctx);
+}
+static void
+wfd_options_request_done (GstRTSPWFDClient * client, GstRTSPContext *ctx)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GstRTSPWFDClientClass *klass = GST_RTSP_WFD_CLIENT_GET_CLASS (client);
+
+  g_return_if_fail (klass != NULL);
+
+  GST_INFO_OBJECT (client, "M2 done..");
+
+  res = handle_M3_message (client);
+  if (res < GST_RTSP_OK) {
+    GST_ERROR_OBJECT (client, "handle_M3_message failed : %d", res);
+  }
+
+  if (klass->prepare_resource) {
+    klass->prepare_resource (client, ctx);
+  }
+
+  return;
+}
+
+static void
+wfd_get_param_request_done (GstRTSPWFDClient * client, GstRTSPContext *ctx)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  GstRTSPWFDClientClass *klass = GST_RTSP_WFD_CLIENT_GET_CLASS (client);
+
+  g_return_if_fail (priv != NULL && klass != NULL);
+
+  priv->m3_done = TRUE;
+  GST_INFO_OBJECT (client, "M3 done..");
+
+  res = handle_M4_message (client);
+  if (res < GST_RTSP_OK) {
+    GST_ERROR_OBJECT (client, "handle_M4_message failed : %d", res);
+  }
+
+  if (klass->confirm_resource) {
+    klass->confirm_resource (client, ctx);
+  }
+
+  return;
+}
+
+static guint
+wfd_get_prefered_audio_codec (guint8 srcAudioCodec,
+    guint sinkAudioCodec)
+{
+  int i = 0;
+  guint codec = 0;
+  for (i = 0; i < 8; i++) {
+    if (((sinkAudioCodec << i) & 0x80)
+        && ((srcAudioCodec << i) & 0x80)) {
+      codec = (0x01 << (7 - i));
+      break;
+    }
+  }
+  return codec;
+}
+
+static guint64
+wfd_get_prefered_resolution (guint64 srcResolution,
+    guint64 sinkResolution,
+    GstWFDVideoNativeResolution native,
+    guint32 * cMaxWidth,
+    guint32 * cMaxHeight, guint32 * cFramerate, guint32 * interleaved)
+{
+  int i = 0;
+  guint64 resolution = 0;
+  for (i = 0; i < 32; i++) {
+    if (((sinkResolution << i) & 0x80000000)
+        && ((srcResolution << i) & 0x80000000)) {
+      resolution = ((guint64) 0x00000001 << (31 - i));
+      break;
+    }
+  }
+  switch (native) {
+    case GST_WFD_VIDEO_CEA_RESOLUTION:
+    {
+      switch (resolution) {
+        case GST_WFD_CEA_640x480P60:
+          *cMaxWidth = 640;
+          *cMaxHeight = 480;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        case GST_WFD_CEA_720x480P60:
+          *cMaxWidth = 720;
+          *cMaxHeight = 480;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        case GST_WFD_CEA_720x480I60:
+          *cMaxWidth = 720;
+          *cMaxHeight = 480;
+          *cFramerate = 60;
+          *interleaved = 1;
+          break;
+        case GST_WFD_CEA_720x576P50:
+          *cMaxWidth = 720;
+          *cMaxHeight = 576;
+          *cFramerate = 50;
+          *interleaved = 0;
+          break;
+        case GST_WFD_CEA_720x576I50:
+          *cMaxWidth = 720;
+          *cMaxHeight = 576;
+          *cFramerate = 50;
+          *interleaved = 1;
+          break;
+        case GST_WFD_CEA_1280x720P30:
+          *cMaxWidth = 1280;
+          *cMaxHeight = 720;
+          *cFramerate = 30;
+          *interleaved = 0;
+          break;
+        case GST_WFD_CEA_1280x720P60:
+          *cMaxWidth = 1280;
+          *cMaxHeight = 720;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        case GST_WFD_CEA_1920x1080P30:
+          *cMaxWidth = 1920;
+          *cMaxHeight = 1080;
+          *cFramerate = 30;
+          *interleaved = 0;
+          break;
+        case GST_WFD_CEA_1920x1080P60:
+          *cMaxWidth = 1920;
+          *cMaxHeight = 1080;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        case GST_WFD_CEA_1920x1080I60:
+          *cMaxWidth = 1920;
+          *cMaxHeight = 1080;
+          *cFramerate = 60;
+          *interleaved = 1;
+          break;
+        case GST_WFD_CEA_1280x720P25:
+          *cMaxWidth = 1280;
+          *cMaxHeight = 720;
+          *cFramerate = 25;
+          *interleaved = 0;
+          break;
+        case GST_WFD_CEA_1280x720P50:
+          *cMaxWidth = 1280;
+          *cMaxHeight = 720;
+          *cFramerate = 50;
+          *interleaved = 0;
+          break;
+        case GST_WFD_CEA_1920x1080P25:
+          *cMaxWidth = 1920;
+          *cMaxHeight = 1080;
+          *cFramerate = 25;
+          *interleaved = 0;
+          break;
+        case GST_WFD_CEA_1920x1080P50:
+          *cMaxWidth = 1920;
+          *cMaxHeight = 1080;
+          *cFramerate = 50;
+          *interleaved = 0;
+          break;
+        case GST_WFD_CEA_1920x1080I50:
+          *cMaxWidth = 1920;
+          *cMaxHeight = 1080;
+          *cFramerate = 50;
+          *interleaved = 1;
+          break;
+        case GST_WFD_CEA_1280x720P24:
+          *cMaxWidth = 1280;
+          *cMaxHeight = 720;
+          *cFramerate = 24;
+          *interleaved = 0;
+          break;
+        case GST_WFD_CEA_1920x1080P24:
+          *cMaxWidth = 1920;
+          *cMaxHeight = 1080;
+          *cFramerate = 24;
+          *interleaved = 0;
+          break;
+        default:
+          *cMaxWidth = 0;
+          *cMaxHeight = 0;
+          *cFramerate = 0;
+          *interleaved = 0;
+          break;
+      }
+    }
+      break;
+    case GST_WFD_VIDEO_VESA_RESOLUTION:
+    {
+      switch (resolution) {
+        case GST_WFD_VESA_800x600P30:
+          *cMaxWidth = 800;
+          *cMaxHeight = 600;
+          *cFramerate = 30;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_800x600P60:
+          *cMaxWidth = 800;
+          *cMaxHeight = 600;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1024x768P30:
+          *cMaxWidth = 1024;
+          *cMaxHeight = 768;
+          *cFramerate = 30;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1024x768P60:
+          *cMaxWidth = 1024;
+          *cMaxHeight = 768;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1152x864P30:
+          *cMaxWidth = 1152;
+          *cMaxHeight = 864;
+          *cFramerate = 30;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1152x864P60:
+          *cMaxWidth = 1152;
+          *cMaxHeight = 864;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1280x768P30:
+          *cMaxWidth = 1280;
+          *cMaxHeight = 768;
+          *cFramerate = 30;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1280x768P60:
+          *cMaxWidth = 1280;
+          *cMaxHeight = 768;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1280x800P30:
+          *cMaxWidth = 1280;
+          *cMaxHeight = 800;
+          *cFramerate = 30;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1280x800P60:
+          *cMaxWidth = 1280;
+          *cMaxHeight = 800;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1360x768P30:
+          *cMaxWidth = 1360;
+          *cMaxHeight = 768;
+          *cFramerate = 30;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1360x768P60:
+          *cMaxWidth = 1360;
+          *cMaxHeight = 768;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1366x768P30:
+          *cMaxWidth = 1366;
+          *cMaxHeight = 768;
+          *cFramerate = 30;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1366x768P60:
+          *cMaxWidth = 1366;
+          *cMaxHeight = 768;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1280x1024P30:
+          *cMaxWidth = 1280;
+          *cMaxHeight = 1024;
+          *cFramerate = 30;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1280x1024P60:
+          *cMaxWidth = 1280;
+          *cMaxHeight = 1024;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1400x1050P30:
+          *cMaxWidth = 1400;
+          *cMaxHeight = 1050;
+          *cFramerate = 30;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1400x1050P60:
+          *cMaxWidth = 1400;
+          *cMaxHeight = 1050;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1440x900P30:
+          *cMaxWidth = 1440;
+          *cMaxHeight = 900;
+          *cFramerate = 30;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1440x900P60:
+          *cMaxWidth = 1440;
+          *cMaxHeight = 900;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1600x900P30:
+          *cMaxWidth = 1600;
+          *cMaxHeight = 900;
+          *cFramerate = 30;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1600x900P60:
+          *cMaxWidth = 1600;
+          *cMaxHeight = 900;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1600x1200P30:
+          *cMaxWidth = 1600;
+          *cMaxHeight = 1200;
+          *cFramerate = 30;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1600x1200P60:
+          *cMaxWidth = 1600;
+          *cMaxHeight = 1200;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1680x1024P30:
+          *cMaxWidth = 1680;
+          *cMaxHeight = 1024;
+          *cFramerate = 30;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1680x1024P60:
+          *cMaxWidth = 1680;
+          *cMaxHeight = 1024;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1680x1050P30:
+          *cMaxWidth = 1680;
+          *cMaxHeight = 1050;
+          *cFramerate = 30;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1680x1050P60:
+          *cMaxWidth = 1680;
+          *cMaxHeight = 1050;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1920x1200P30:
+          *cMaxWidth = 1920;
+          *cMaxHeight = 1200;
+          *cFramerate = 30;
+          *interleaved = 0;
+          break;
+        case GST_WFD_VESA_1920x1200P60:
+          *cMaxWidth = 1920;
+          *cMaxHeight = 1200;
+          *cFramerate = 60;
+          *interleaved = 0;
+          break;
+        default:
+          *cMaxWidth = 0;
+          *cMaxHeight = 0;
+          *cFramerate = 0;
+          *interleaved = 0;
+          break;
+      }
+    }
+      break;
+    case GST_WFD_VIDEO_HH_RESOLUTION:
+    {
+      *interleaved = 0;
+      switch (resolution) {
+        case GST_WFD_HH_800x480P30:
+          *cMaxWidth = 800;
+          *cMaxHeight = 480;
+          *cFramerate = 30;
+          break;
+        case GST_WFD_HH_800x480P60:
+          *cMaxWidth = 800;
+          *cMaxHeight = 480;
+          *cFramerate = 60;
+          break;
+        case GST_WFD_HH_854x480P30:
+          *cMaxWidth = 854;
+          *cMaxHeight = 480;
+          *cFramerate = 30;
+          break;
+        case GST_WFD_HH_854x480P60:
+          *cMaxWidth = 854;
+          *cMaxHeight = 480;
+          *cFramerate = 60;
+          break;
+        case GST_WFD_HH_864x480P30:
+          *cMaxWidth = 864;
+          *cMaxHeight = 480;
+          *cFramerate = 30;
+          break;
+        case GST_WFD_HH_864x480P60:
+          *cMaxWidth = 864;
+          *cMaxHeight = 480;
+          *cFramerate = 60;
+          break;
+        case GST_WFD_HH_640x360P30:
+          *cMaxWidth = 640;
+          *cMaxHeight = 360;
+          *cFramerate = 30;
+          break;
+        case GST_WFD_HH_640x360P60:
+          *cMaxWidth = 640;
+          *cMaxHeight = 360;
+          *cFramerate = 60;
+          break;
+        case GST_WFD_HH_960x540P30:
+          *cMaxWidth = 960;
+          *cMaxHeight = 540;
+          *cFramerate = 30;
+          break;
+        case GST_WFD_HH_960x540P60:
+          *cMaxWidth = 960;
+          *cMaxHeight = 540;
+          *cFramerate = 60;
+          break;
+        case GST_WFD_HH_848x480P30:
+          *cMaxWidth = 848;
+          *cMaxHeight = 480;
+          *cFramerate = 30;
+          break;
+        case GST_WFD_HH_848x480P60:
+          *cMaxWidth = 848;
+          *cMaxHeight = 480;
+          *cFramerate = 60;
+          break;
+        default:
+          *cMaxWidth = 0;
+          *cMaxHeight = 0;
+          *cFramerate = 0;
+          *interleaved = 0;
+          break;
+      }
+    }
+    break;
+
+    default:
+      *cMaxWidth = 0;
+      *cMaxHeight = 0;
+      *cFramerate = 0;
+      *interleaved = 0;
+      break;
+  }
+  return resolution;
+}
+
+static gchar *
+wfd_make_path_from_uri (GstRTSPClient * client, const GstRTSPUrl * uri)
+{
+  gchar *path;
+
+  GST_DEBUG_OBJECT (client, "Got URI host : %s", uri->host);
+  GST_DEBUG_OBJECT (client, "Got URI abspath : %s", uri->abspath);
+
+  path = g_strdup ("/wfd1.0/streamid=0");
+
+  return path;
+}
+
+static void
+handle_wfd_play (GstRTSPClient * client, GstRTSPContext * ctx)
+{
+  GstRTSPWFDClient *_client = GST_RTSP_WFD_CLIENT (client);
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+
+  g_return_if_fail (priv != NULL);
+
+  wfd_set_keep_alive_condition(_client);
+  
+  priv->stats_timer_id = g_timeout_add (2000, wfd_display_rtp_stats, _client);
+}
+
+static void
+handle_wfd_response (GstRTSPClient * client, GstRTSPContext * ctx)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  guint8 *data = NULL;
+  guint size = 0;
+
+  GstRTSPWFDClient *_client = GST_RTSP_WFD_CLIENT (client);
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+
+  g_return_if_fail (priv != NULL);
+
+  GST_INFO_OBJECT (_client, "Handling response..");
+
+  if (!ctx) {
+    GST_ERROR_OBJECT (_client, "Context is NULL");
+    goto error;
+  }
+
+  if (!ctx->response) {
+    GST_ERROR_OBJECT (_client, "Response is NULL");
+    goto error;
+  }
+
+  /* parsing the GET_PARAMTER response */
+  res = gst_rtsp_message_get_body (ctx->response, (guint8 **) & data, &size);
+  if (res != GST_RTSP_OK) {
+    GST_ERROR_OBJECT (_client, "Failed to get body of response...");
+    return;
+  }
+
+  GST_INFO_OBJECT (_client, "Response body is %d", size);
+  if (size > 0) {
+    if (!priv->m3_done) {
+      GstWFDResult wfd_res;
+      GstWFDMessage *msg = NULL;
+      /* Parse M3 response from sink */
+      wfd_res = gst_wfd_message_new (&msg);
+      if (wfd_res != GST_WFD_OK) {
+        GST_ERROR_OBJECT (client, "Failed to create wfd message...");
+        goto error;
+      }
+
+      wfd_res = gst_wfd_message_init (msg);
+      if (wfd_res != GST_WFD_OK) {
+        GST_ERROR_OBJECT (client, "Failed to init wfd message...");
+        goto error;
+      }
+
+      wfd_res = gst_wfd_message_parse_buffer (data, size, msg);
+
+      GST_DEBUG_OBJECT (client, "M3 response server side message body: %s",
+          gst_wfd_message_as_text (msg));
+
+      /* Get the audio formats supported by WFDSink */
+      if (msg->audio_codecs) {
+        wfd_res =
+            gst_wfd_message_get_supported_audio_format (msg, &priv->caCodec,
+            &priv->cFreq, &priv->cChanels, &priv->cBitwidth, &priv->caLatency);
+        if (wfd_res != GST_WFD_OK) {
+          GST_WARNING_OBJECT (client,
+              "Failed to get wfd support audio formats...");
+          goto error;
+        }
+      }
+
+      /* Get the Video formats supported by WFDSink */
+      wfd_res =
+          gst_wfd_message_get_supported_video_format (msg, &priv->cvCodec,
+          &priv->cNative, &priv->cNativeResolution,
+          (guint64 *) & priv->cCEAResolution,
+          (guint64 *) & priv->cVESAResolution,
+          (guint64 *) & priv->cHHResolution, &priv->cProfile, &priv->cLevel,
+          &priv->cvLatency, &priv->cMaxHeight, &priv->cMaxWidth,
+          &priv->cmin_slice_size, &priv->cslice_enc_params,
+          &priv->cframe_rate_control);
+      if (wfd_res != GST_WFD_OK) {
+        GST_WARNING_OBJECT (client,
+            "Failed to get wfd supported video formats...");
+        goto error;
+      }
+
+      if (msg->client_rtp_ports) {
+        /* Get the RTP ports preferred by WFDSink */
+        wfd_res =
+            gst_wfd_message_get_prefered_rtp_ports (msg, &priv->ctrans,
+            &priv->cprofile, &priv->clowertrans, &priv->crtp_port0,
+            &priv->crtp_port1);
+        if (wfd_res != GST_WFD_OK) {
+          GST_WARNING_OBJECT (client,
+              "Failed to get wfd prefered RTP ports...");
+          goto error;
+        }
+      }
+
+      if (msg->display_edid) {
+        guint32 edid_block_count = 0;
+        gchar *edid_payload = NULL;
+        priv->edid_supported = FALSE;
+        /* Get the display edid preferred by WFDSink */
+        GST_DEBUG_OBJECT (client, "Going to gst_wfd_message_get_display_edid");
+        wfd_res =
+            gst_wfd_message_get_display_edid (msg, &priv->edid_supported,
+            &edid_block_count, &edid_payload);
+        if (wfd_res != GST_WFD_OK) {
+          GST_ERROR_OBJECT (client, "Failed to get wfd display edid...");
+          goto error;
+        }
+        GST_DEBUG_OBJECT (client, " edid supported: %d edid_block_count: %d",
+            priv->edid_supported, edid_block_count);
+        if (priv->edid_supported) {
+          priv->edid_hres = 0;
+          priv->edid_vres = 0;
+          priv->edid_hres =
+              (guint32) (((edid_payload[54 + 4] >> 4) << 8) | edid_payload[54 +
+                  2]);
+          priv->edid_vres =
+              (guint32) (((edid_payload[54 + 7] >> 4) << 8) | edid_payload[54 +
+                  5]);
+          GST_DEBUG_OBJECT (client, " edid supported Hres: %d Wres: %d",
+              priv->edid_hres, priv->edid_vres);
+          if ((priv->edid_hres < 640) || (priv->edid_vres < 480)
+              || (priv->edid_hres > 1920) || (priv->edid_vres > 1080)) {
+            priv->edid_hres = 0;
+            priv->edid_vres = 0;
+            priv->edid_supported = FALSE;
+            GST_WARNING_OBJECT (client, " edid invalid resolutions");
+          }
+        }
+      }
+
+      if (msg->content_protection) {
+#if 0
+        /*Get the hdcp version and tcp port by WFDSink */
+        wfd_res =
+            gst_wfd_message_get_contentprotection_type (msg,
+            &priv->hdcp_version, &priv->hdcp_tcpport);
+        GST_DEBUG ("hdcp version =%d, tcp port = %d", priv->hdcp_version,
+            priv->hdcp_tcpport);
+        if (priv->hdcp_version > 0 && priv->hdcp_tcpport > 0)
+          priv->protection_enabled = TRUE;
+
+        if (wfd_res != GST_WFD_OK) {
+          GST_WARNING_OBJECT (client,
+              "Failed to get wfd content protection...");
+          goto error;
+        }
+#else
+        GST_WARNING_OBJECT (client, "Don't use content protection");
+#endif
+      }
+
+      g_signal_emit (_client,
+          gst_rtsp_client_wfd_signals[SIGNAL_WFD_GET_PARAMETER_REQUEST], 0,
+          ctx);
+    } else {
+      /* TODO-WFD: Handle another GET_PARAMETER response with body */
+    }
+  } else if (size == 0) {
+    if (!priv->m1_done) {
+      GST_INFO_OBJECT (_client, "M1 response is done");
+      priv->m1_done = TRUE;
+    } else if (!priv->m4_done) {
+      GST_INFO_OBJECT (_client, "M4 response is done");
+      priv->m4_done = TRUE;
+
+      gst_rtsp_wfd_client_trigger_request (_client, WFD_TRIGGER_SETUP);
+    } else {
+      g_mutex_lock(&priv->keep_alive_lock);
+      if (priv->keep_alive_flag == FALSE) {
+        GST_INFO_OBJECT (_client, "M16 response is done");
+        priv->keep_alive_flag = TRUE;
+      }
+      g_mutex_unlock(&priv->keep_alive_lock);
+    }
+  }
+
+  return;
+
+error:
+  return;
+}
+
+static gboolean
+handle_wfd_options_request (GstRTSPClient * client, GstRTSPContext * ctx)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GstRTSPMethod options;
+  gchar *tmp = NULL;
+  gchar *str = NULL;
+  gchar *user_agent = NULL;
+
+  GstRTSPWFDClient *_client = GST_RTSP_WFD_CLIENT (client);
+
+  options = GST_RTSP_OPTIONS |
+      GST_RTSP_PAUSE |
+      GST_RTSP_PLAY |
+      GST_RTSP_SETUP |
+      GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
+
+  str = gst_rtsp_options_as_text (options);
+
+  /*append WFD specific method */
+  tmp = g_strdup (", org.wfa.wfd1.0");
+  g_strlcat (str, tmp, strlen (tmp) + strlen (str) + 1);
+
+  gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
+      gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
+
+  gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_PUBLIC, str);
+  g_free (str);
+  str = NULL;
+
+  res =
+      gst_rtsp_message_get_header (ctx->request, GST_RTSP_HDR_USER_AGENT,
+      &user_agent, 0);
+  if (res == GST_RTSP_OK) {
+    gst_rtsp_message_add_header (ctx->response, GST_RTSP_HDR_USER_AGENT,
+        user_agent);
+  } else {
+    return FALSE;
+  }
+
+  res = gst_rtsp_client_send_message (client, NULL, ctx->response);
+  if (res != GST_RTSP_OK) {
+    GST_ERROR_OBJECT (client, "gst_rtsp_client_send_message failed : %d", res);
+    return FALSE;
+  }
+
+  GST_DEBUG_OBJECT (client, "Sent M2 response...");
+
+  g_signal_emit (_client,
+      gst_rtsp_client_wfd_signals[SIGNAL_WFD_OPTIONS_REQUEST], 0, ctx);
+
+  return TRUE;
+}
+
+static gboolean
+handle_wfd_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  guint8 *data = NULL;
+  guint size = 0;
+
+  GstRTSPWFDClient *_client = GST_RTSP_WFD_CLIENT (client);
+
+  /* parsing the GET_PARAMTER request */
+  res = gst_rtsp_message_get_body (ctx->request, (guint8 **) & data, &size);
+  if (res != GST_RTSP_OK) {
+    GST_ERROR_OBJECT (_client, "Failed to get body of request...");
+    return FALSE;
+  }
+
+  if (size == 0) {
+    send_generic_wfd_response (_client, GST_RTSP_STS_OK, ctx);
+  } else {
+    /* TODO-WFD: Handle other GET_PARAMETER request from sink */
+  }
+
+  return TRUE;
+}
+
+static gboolean
+handle_wfd_set_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  guint8 *data = NULL;
+  guint size = 0;
+
+  GstRTSPWFDClient *_client = GST_RTSP_WFD_CLIENT (client);
+
+  res = gst_rtsp_message_get_body (ctx->request, &data, &size);
+  if (res != GST_RTSP_OK)
+    goto bad_request;
+
+  if (size == 0) {
+    /* no body, keep-alive request */
+    send_generic_wfd_response (_client, GST_RTSP_STS_OK, ctx);
+  } else {
+    if (data != NULL) {
+      GST_INFO_OBJECT (_client, "SET_PARAMETER Request : %s(%d)", data, size);
+      if (g_strcmp0 ((const gchar *) data, "wfd_idr_request"))
+        send_generic_wfd_response (_client, GST_RTSP_STS_OK, ctx);
+#if 0
+      else
+        /* TODO-WFD : Handle other set param request */
+        send_generic_wfd_response (_client, GST_RTSP_STS_OK, ctx);
+#endif
+    } else {
+      goto bad_request;
+    }
+  }
+
+  return TRUE;
+
+  /* ERRORS */
+bad_request:
+  {
+    GST_ERROR ("_client %p: bad request", _client);
+    send_generic_wfd_response (_client, GST_RTSP_STS_BAD_REQUEST, ctx);
+    return FALSE;
+  }
+}
+
+#if 0
+static gboolean
+gst_rtsp_wfd_client_parse_methods (GstRTSPWFDClient * client,
+    GstRTSPMessage * response)
+{
+  GstRTSPHeaderField field;
+  gchar *respoptions;
+  gchar **options;
+  gint indx = 0;
+  gint i;
+  gboolean found_wfd_method = FALSE;
+
+  /* reset supported methods */
+  client->supported_methods = 0;
+
+  /* Try Allow Header first */
+  field = GST_RTSP_HDR_ALLOW;
+  while (TRUE) {
+    respoptions = NULL;
+    gst_rtsp_message_get_header (response, field, &respoptions, indx);
+    if (indx == 0 && !respoptions) {
+      /* if no Allow header was found then try the Public header... */
+      field = GST_RTSP_HDR_PUBLIC;
+      gst_rtsp_message_get_header (response, field, &respoptions, indx);
+    }
+    if (!respoptions)
+      break;
+
+    /* If we get here, the server gave a list of supported methods, parse
+     * them here. The string is like:
+     *
+     * OPTIONS,  PLAY, SETUP, ...
+     */
+    options = g_strsplit (respoptions, ",", 0);
+
+    for (i = 0; options[i]; i++) {
+      gchar *stripped;
+      gint method;
+
+      stripped = g_strstrip (options[i]);
+      method = gst_rtsp_find_method (stripped);
+
+      if (!g_ascii_strcasecmp ("org.wfa.wfd1.0", stripped))
+        found_wfd_method = TRUE;
+
+      /* keep bitfield of supported methods */
+      if (method != GST_RTSP_INVALID)
+        client->supported_methods |= method;
+    }
+    g_strfreev (options);
+
+    indx++;
+  }
+
+  if (!found_wfd_method) {
+    GST_ERROR_OBJECT (client,
+        "WFD client is not supporting WFD mandatory message : org.wfa.wfd1.0...");
+    goto no_required_methods;
+  }
+
+  /* Checking mandatory method */
+  if (!(client->supported_methods & GST_RTSP_SET_PARAMETER)) {
+    GST_ERROR_OBJECT (client,
+        "WFD client is not supporting WFD mandatory message : SET_PARAMETER...");
+    goto no_required_methods;
+  }
+
+  /* Checking mandatory method */
+  if (!(client->supported_methods & GST_RTSP_GET_PARAMETER)) {
+    GST_ERROR_OBJECT (client,
+        "WFD client is not supporting WFD mandatory message : GET_PARAMETER...");
+    goto no_required_methods;
+  }
+
+  if (!(client->supported_methods & GST_RTSP_OPTIONS)) {
+    GST_INFO_OBJECT (client, "assuming OPTIONS is supported by client...");
+    client->supported_methods |= GST_RTSP_OPTIONS;
+  }
+
+  return TRUE;
+
+/* ERRORS */
+no_required_methods:
+  {
+    GST_ELEMENT_ERROR (client, RESOURCE, OPEN_READ, (NULL),
+        ("WFD Client does not support mandatory methods."));
+    return FALSE;
+  }
+}
+#endif
+
+typedef enum
+{
+  M1_REQ_MSG,
+  M1_RES_MSG,
+  M2_REQ_MSG,
+  M2_RES_MSG,
+  M3_REQ_MSG,
+  M3_RES_MSG,
+  M4_REQ_MSG,
+  M4_RES_MSG,
+  M5_REQ_MSG,
+  TEARDOWN_TRIGGER,
+  PLAY_TRIGGER,
+  PAUSE_TRIGGER,
+} GstWFDMessageType;
+
+static gboolean
+_set_negotiated_audio_codec (GstRTSPWFDClient *client,
+    guint audio_codec)
+{
+  GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
+
+  GstRTSPMediaFactory *factory = NULL;
+  GstRTSPMountPoints *mount_points = NULL;
+  gchar *path = NULL;
+  gint matched = 0;
+  gboolean ret = TRUE;
+
+  if (!(mount_points = gst_rtsp_client_get_mount_points (parent_client))) {
+    ret = FALSE;
+    GST_ERROR_OBJECT (client, "Failed to set negotiated audio codec: no mount points...");
+    goto no_mount_points;
+  }
+
+  path = g_strdup(WFD_MOUNT_POINT);
+  if (!path) {
+    ret = FALSE;
+    GST_ERROR_OBJECT (client, "Failed to set negotiated audio codec: no path...");
+    goto no_path;
+  }
+
+  if (!(factory = gst_rtsp_mount_points_match (mount_points,
+          path, &matched))) {
+    GST_ERROR_OBJECT (client, "Failed to set negotiated audio codec: no factory...");
+    ret = FALSE;
+    goto no_factory;
+  }
+
+  gst_rtsp_media_factory_wfd_set_audio_codec (factory,
+      audio_codec);
+  ret = TRUE;
+
+  g_object_unref(factory);
+
+no_factory:
+  g_free(path);
+no_path:
+  g_object_unref(mount_points);
+no_mount_points:
+  return ret;
+}
+
+static gboolean
+_set_negotiated_resolution(GstRTSPWFDClient *client,
+    guint32 width, guint32 height)
+{
+  GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
+
+  GstRTSPMediaFactory *factory = NULL;
+  GstRTSPMountPoints *mount_points = NULL;
+  gchar *path = NULL;
+  gint matched = 0;
+  gboolean ret = TRUE;
+
+  if (!(mount_points = gst_rtsp_client_get_mount_points (parent_client))) {
+    ret = FALSE;
+    GST_ERROR_OBJECT (client, "Failed to set negotiated resolution: no mount points...");
+    goto no_mount_points;
+  }
+
+  path = g_strdup(WFD_MOUNT_POINT);
+  if (!path) {
+    ret = FALSE;
+    GST_ERROR_OBJECT (client, "Failed to set negotiated resolution: no path...");
+    goto no_path;
+  }
+
+  if (!(factory = gst_rtsp_mount_points_match (mount_points,
+          path, &matched))) {
+    GST_ERROR_OBJECT (client, "Failed to set negotiated resolution: no factory...");
+    ret = FALSE;
+    goto no_factory;
+  }
+
+  gst_rtsp_media_factory_wfd_set_negotiated_resolution(factory,
+      width, height);
+  ret = TRUE;
+
+  g_object_unref(factory);
+
+no_factory:
+  g_free(path);
+no_path:
+  g_object_unref(mount_points);
+no_mount_points:
+  return ret;
+}
+
+static void
+_set_wfd_message_body (GstRTSPWFDClient * client, GstWFDMessageType msg_type,
+    gchar ** data, guint * len)
+{
+  GString *buf = NULL;
+  GstWFDMessage *msg = NULL;
+  GstWFDResult wfd_res = GST_WFD_EINVAL;
+  GstRTSPWFDClientPrivate *priv = NULL;
+  priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+
+  g_return_if_fail (priv != NULL);
+
+  buf = g_string_new ("");
+  g_return_if_fail (buf != NULL);
+
+  if (msg_type == M3_REQ_MSG) {
+    /* create M3 request to be sent */
+    wfd_res = gst_wfd_message_new (&msg);
+    if (wfd_res != GST_WFD_OK) {
+      GST_ERROR_OBJECT (client, "Failed to create wfd message...");
+      goto error;
+    }
+
+    wfd_res = gst_wfd_message_init (msg);
+    if (wfd_res != GST_WFD_OK) {
+      GST_ERROR_OBJECT (client, "Failed to init wfd message...");
+      goto error;
+    }
+
+    /* set the supported audio formats by the WFD server */
+    wfd_res =
+        gst_wfd_message_set_supported_audio_format (msg, GST_WFD_AUDIO_UNKNOWN,
+        GST_WFD_FREQ_UNKNOWN, GST_WFD_CHANNEL_UNKNOWN, 0, 0);
+    if (wfd_res != GST_WFD_OK) {
+      GST_ERROR_OBJECT (client,
+          "Failed to set supported audio formats on wfd message...");
+      goto error;
+    }
+
+    /* set the supported Video formats by the WFD server */
+    wfd_res =
+        gst_wfd_message_set_supported_video_format (msg, GST_WFD_VIDEO_UNKNOWN,
+        GST_WFD_VIDEO_CEA_RESOLUTION, GST_WFD_CEA_UNKNOWN, GST_WFD_CEA_UNKNOWN,
+        GST_WFD_VESA_UNKNOWN, GST_WFD_HH_UNKNOWN, GST_WFD_H264_UNKNOWN_PROFILE,
+        GST_WFD_H264_LEVEL_UNKNOWN, 0, 0, 0, 0, 0, 0);
+    if (wfd_res != GST_WFD_OK) {
+      GST_ERROR_OBJECT (client,
+          "Failed to set supported video formats on wfd message...");
+      goto error;
+    }
+
+    wfd_res = gst_wfd_message_set_display_edid (msg, 0, 0, NULL);
+    if (wfd_res != GST_WFD_OK) {
+      GST_ERROR_OBJECT (client,
+          "Failed to set display edid type on wfd message...");
+      goto error;
+    }
+
+    if (priv->protection_enabled) {
+      wfd_res =
+          gst_wfd_message_set_contentprotection_type (msg, GST_WFD_HDCP_NONE,
+          0);
+      if (wfd_res != GST_WFD_OK) {
+        GST_ERROR_OBJECT (client,
+            "Failed to set supported content protection type on wfd message...");
+        goto error;
+      }
+    }
+
+    /* set the preffered RTP ports for the WFD server */
+    wfd_res =
+        gst_wfd_messge_set_prefered_rtp_ports (msg, GST_WFD_RTSP_TRANS_UNKNOWN,
+        GST_WFD_RTSP_PROFILE_UNKNOWN, GST_WFD_RTSP_LOWER_TRANS_UNKNOWN, 0, 0);
+    if (wfd_res != GST_WFD_OK) {
+      GST_ERROR_OBJECT (client,
+          "Failed to set supported video formats on wfd message...");
+      goto error;
+    }
+
+    *data = gst_wfd_message_param_names_as_text (msg);
+    if (*data == NULL) {
+      GST_ERROR_OBJECT (client, "Failed to get wfd message as text...");
+      goto error;
+    } else {
+      *len = strlen (*data);
+    }
+  } else if (msg_type == M4_REQ_MSG) {
+    GstRTSPUrl *url = NULL;
+
+    GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
+    GstRTSPConnection *connection =
+        gst_rtsp_client_get_connection (parent_client);
+
+    /* Parameters for the preffered audio formats */
+    GstWFDAudioFormats taudiocodec = GST_WFD_AUDIO_UNKNOWN;
+    GstWFDAudioFreq taudiofreq = GST_WFD_FREQ_UNKNOWN;
+    GstWFDAudioChannels taudiochannels = GST_WFD_CHANNEL_UNKNOWN;
+
+    /* Parameters for the preffered video formats */
+    GstWFDVideoCEAResolution tcCEAResolution = GST_WFD_CEA_UNKNOWN;
+    GstWFDVideoVESAResolution tcVESAResolution = GST_WFD_VESA_UNKNOWN;
+    GstWFDVideoHHResolution tcHHResolution = GST_WFD_HH_UNKNOWN;
+    GstWFDVideoH264Profile tcProfile;
+    GstWFDVideoH264Level tcLevel;
+    guint64 resolution_supported = 0;
+
+    url = gst_rtsp_connection_get_url (connection);
+    if (url == NULL) {
+      GST_ERROR_OBJECT (client, "Failed to get connection URL");
+      return;
+    }
+
+    /* Logic to negotiate with information of M3 response */
+    /* create M4 request to be sent */
+    wfd_res = gst_wfd_message_new (&msg);
+    if (wfd_res != GST_WFD_OK) {
+      GST_ERROR_OBJECT (client, "Failed to create wfd message...");
+      goto error;
+    }
+
+    wfd_res = gst_wfd_message_init (msg);
+    if (wfd_res != GST_WFD_OK) {
+      GST_ERROR_OBJECT (client, "Failed to init wfd message...");
+      goto error;
+    }
+
+    g_string_append_printf (buf, "rtsp://");
+
+    if (priv->host_address) {
+      g_string_append (buf, priv->host_address);
+    } else {
+      GST_ERROR_OBJECT (client, "Failed to get host address");
+      if (buf) g_string_free (buf, TRUE);
+      goto error;
+    }
+
+    g_string_append_printf (buf, "/wfd1.0/streamid=0");
+    wfd_res =
+        gst_wfd_message_set_presentation_url (msg, g_string_free (buf, FALSE),
+        NULL);
+
+    if (wfd_res != GST_WFD_OK) {
+      GST_ERROR_OBJECT (client, "Failed to set presentation url");
+      goto error;
+    }
+
+    taudiocodec = wfd_get_prefered_audio_codec (priv->audio_codec, priv->caCodec);
+    priv->caCodec = taudiocodec;
+    if (!_set_negotiated_audio_codec(client, priv->caCodec)) {
+      GST_ERROR_OBJECT (client, "Failed to set negotiated "
+          "audio codec to media factory...");
+    }
+
+    if (priv->cFreq & GST_WFD_FREQ_48000)
+      taudiofreq = GST_WFD_FREQ_48000;
+    else if (priv->cFreq & GST_WFD_FREQ_44100)
+      taudiofreq = GST_WFD_FREQ_44100;
+    priv->cFreq = taudiofreq;
+
+    /* TODO-WFD: Currently only 2 channels is present */
+    if (priv->cChanels & GST_WFD_CHANNEL_8)
+      taudiochannels = GST_WFD_CHANNEL_2;
+    else if (priv->cChanels & GST_WFD_CHANNEL_6)
+      taudiochannels = GST_WFD_CHANNEL_2;
+    else if (priv->cChanels & GST_WFD_CHANNEL_4)
+      taudiochannels = GST_WFD_CHANNEL_2;
+    else if (priv->cChanels & GST_WFD_CHANNEL_2)
+      taudiochannels = GST_WFD_CHANNEL_2;
+    priv->cChanels = taudiochannels;
+
+    wfd_res =
+        gst_wfd_message_set_prefered_audio_format (msg, taudiocodec, taudiofreq,
+        taudiochannels, priv->cBitwidth, priv->caLatency);
+    if (wfd_res != GST_WFD_OK) {
+      GST_ERROR_OBJECT (priv, "Failed to set preffered audio formats...");
+      goto error;
+    }
+
+    /* Set the preffered video formats */
+    priv->cvCodec = GST_WFD_VIDEO_H264;
+    priv->cProfile = tcProfile = GST_WFD_H264_BASE_PROFILE;
+    priv->cLevel = tcLevel = GST_WFD_H264_LEVEL_3_1;
+
+    resolution_supported = priv->video_resolution_supported;
+
+    /* TODO-WFD: Need to verify this logic
+       if(priv->edid_supported) {
+       if (priv->edid_hres < 1920) resolution_supported = resolution_supported & 0x8C7F;
+       if (priv->edid_hres < 1280) resolution_supported = resolution_supported & 0x1F;
+       if (priv->edid_hres < 720) resolution_supported = resolution_supported & 0x01;
+       }
+     */
+
+    if (priv->video_native_resolution == GST_WFD_VIDEO_CEA_RESOLUTION) {
+      tcCEAResolution =
+          wfd_get_prefered_resolution (resolution_supported,
+          priv->cCEAResolution, priv->video_native_resolution, &priv->cMaxWidth,
+          &priv->cMaxHeight, &priv->cFramerate, &priv->cInterleaved);
+      GST_DEBUG
+          ("wfd negotiated resolution: %08x, width: %d, height: %d, framerate: %d, interleaved: %d",
+          tcCEAResolution, priv->cMaxWidth, priv->cMaxHeight, priv->cFramerate,
+          priv->cInterleaved);
+    } else if (priv->video_native_resolution == GST_WFD_VIDEO_VESA_RESOLUTION) {
+      tcVESAResolution =
+          wfd_get_prefered_resolution (resolution_supported,
+          priv->cVESAResolution, priv->video_native_resolution,
+          &priv->cMaxWidth, &priv->cMaxHeight, &priv->cFramerate,
+          &priv->cInterleaved);
+      GST_DEBUG
+          ("wfd negotiated resolution: %08x, width: %d, height: %d, framerate: %d, interleaved: %d",
+          tcVESAResolution, priv->cMaxWidth, priv->cMaxHeight, priv->cFramerate,
+          priv->cInterleaved);
+    } else if (priv->video_native_resolution == GST_WFD_VIDEO_HH_RESOLUTION) {
+      tcHHResolution =
+          wfd_get_prefered_resolution (resolution_supported,
+          priv->cHHResolution, priv->video_native_resolution, &priv->cMaxWidth,
+          &priv->cMaxHeight, &priv->cFramerate, &priv->cInterleaved);
+      GST_DEBUG
+          ("wfd negotiated resolution: %08x, width: %d, height: %d, framerate: %d, interleaved: %d",
+          tcHHResolution, priv->cMaxWidth, priv->cMaxHeight, priv->cFramerate,
+          priv->cInterleaved);
+    }
+
+    if (!_set_negotiated_resolution(client, priv->cMaxWidth,
+          priv->cMaxHeight)) {
+      GST_ERROR_OBJECT (client, "Failed to set negotiated "
+          "resolution to media factory...");
+    }
+
+    wfd_res =
+        gst_wfd_message_set_prefered_video_format (msg, priv->cvCodec,
+        priv->video_native_resolution, GST_WFD_CEA_UNKNOWN, tcCEAResolution,
+        tcVESAResolution, tcHHResolution, tcProfile, tcLevel, priv->cvLatency,
+        priv->cMaxWidth, priv->cMaxHeight, priv->cmin_slice_size,
+        priv->cslice_enc_params, priv->cframe_rate_control);
+
+    if (wfd_res != GST_WFD_OK) {
+      GST_ERROR_OBJECT (client, "Failed to set preffered video formats...");
+      goto error;
+    }
+
+    /* set the preffered RTP ports for the WFD server */
+    wfd_res =
+        gst_wfd_messge_set_prefered_rtp_ports (msg, GST_WFD_RTSP_TRANS_RTP,
+        GST_WFD_RTSP_PROFILE_AVP, GST_WFD_RTSP_LOWER_TRANS_UDP, priv->crtp_port0, priv->crtp_port1);
+    if (wfd_res != GST_WFD_OK) {
+      GST_ERROR_OBJECT (client,
+          "Failed to set supported video formats on wfd message...");
+      goto error;
+    }
+
+    *data = gst_wfd_message_as_text (msg);
+    if (*data == NULL) {
+      GST_ERROR_OBJECT (client, "Failed to get wfd message as text...");
+      goto error;
+    } else {
+      *len = strlen (*data);
+    }
+  } else if (msg_type == M5_REQ_MSG) {
+    g_string_append (buf, "wfd_trigger_method: SETUP");
+    g_string_append (buf, "\r\n");
+    *len = buf->len;
+    *data = g_string_free (buf, FALSE);
+  } else if (msg_type == TEARDOWN_TRIGGER) {
+    g_string_append (buf, "wfd_trigger_method: TEARDOWN");
+    g_string_append (buf, "\r\n");
+    *len = buf->len;
+    *data = g_string_free (buf, FALSE);
+  } else if (msg_type == PLAY_TRIGGER) {
+    g_string_append (buf, "wfd_trigger_method: PLAY");
+    g_string_append (buf, "\r\n");
+    *len = buf->len;
+    *data = g_string_free (buf, FALSE);
+  } else if (msg_type == PAUSE_TRIGGER) {
+    g_string_append (buf, "wfd_trigger_method: PAUSE");
+    g_string_append (buf, "\r\n");
+    *len = buf->len;
+    *data = g_string_free (buf, FALSE);
+  } else {
+    return;
+  }
+
+  return;
+
+error:
+  *data = NULL;
+  *len = 0;
+
+  return;
+}
+
+/**
+* prepare_request:
+* @client: client object
+* @request : requst message to be prepared
+* @method : RTSP method of the request
+* @url : url need to be in the request
+* @message_type : WFD message type
+* @trigger_type : trigger method to be used for M5 mainly
+*
+* Prepares request based on @method & @message_type
+*
+* Returns: a #GstRTSPResult.
+*/
+GstRTSPResult
+prepare_request (GstRTSPWFDClient * client, GstRTSPMessage * request,
+    GstRTSPMethod method, gchar * url)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  gchar *str = NULL;
+
+  if (method == GST_RTSP_GET_PARAMETER || method == GST_RTSP_SET_PARAMETER) {
+    g_free (url);
+    url = g_strdup ("rtsp://localhost/wfd1.0");
+  }
+
+  GST_DEBUG_OBJECT (client, "Preparing request: %d", method);
+
+  /* initialize the request */
+  res = gst_rtsp_message_init_request (request, method, url);
+  if (res < 0) {
+    GST_ERROR ("init request failed");
+    return res;
+  }
+
+  switch (method) {
+      /* Prepare OPTIONS request to send */
+    case GST_RTSP_OPTIONS:{
+      /* add wfd specific require filed "org.wfa.wfd1.0" */
+      str = g_strdup ("org.wfa.wfd1.0");
+      res = gst_rtsp_message_add_header (request, GST_RTSP_HDR_REQUIRE, str);
+      if (res < 0) {
+        GST_ERROR ("Failed to add header");
+        g_free (str);
+        return res;
+      }
+
+      g_free (str);
+      break;
+    }
+
+      /* Prepare GET_PARAMETER request */
+    case GST_RTSP_GET_PARAMETER:{
+      gchar *msg = NULL;
+      guint msglen = 0;
+      GString *msglength;
+
+      /* add content type */
+      res =
+          gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE,
+          "text/parameters");
+      if (res < 0) {
+        GST_ERROR ("Failed to add header");
+        return res;
+      }
+
+      _set_wfd_message_body (client, M3_REQ_MSG, &msg, &msglen);
+      msglength = g_string_new ("");
+      g_string_append_printf (msglength, "%d", msglen);
+      GST_DEBUG ("M3 server side message body: %s", msg);
+
+      /* add content-length type */
+      res =
+          gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH,
+          g_string_free (msglength, FALSE));
+      if (res != GST_RTSP_OK) {
+        GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
+        goto error;
+      }
+
+      res = gst_rtsp_message_set_body (request, (guint8 *) msg, msglen);
+      if (res != GST_RTSP_OK) {
+        GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
+        goto error;
+      }
+
+      g_free (msg);
+      break;
+    }
+
+      /* Prepare SET_PARAMETER request */
+    case GST_RTSP_SET_PARAMETER:{
+      gchar *msg = NULL;
+      guint msglen = 0;
+      GString *msglength;
+
+      /* add content type */
+      res =
+          gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE,
+          "text/parameters");
+      if (res != GST_RTSP_OK) {
+        GST_ERROR_OBJECT (client, "Failed to add header to rtsp request...");
+        goto error;
+      }
+
+      _set_wfd_message_body (client, M4_REQ_MSG, &msg, &msglen);
+      msglength = g_string_new ("");
+      g_string_append_printf (msglength, "%d", msglen);
+      GST_DEBUG ("M4 server side message body: %s", msg);
+
+      /* add content-length type */
+      res =
+          gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH,
+          g_string_free (msglength, FALSE));
+      if (res != GST_RTSP_OK) {
+        GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
+        goto error;
+      }
+
+      res = gst_rtsp_message_set_body (request, (guint8 *) msg, msglen);
+      if (res != GST_RTSP_OK) {
+        GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
+        goto error;
+      }
+
+      g_free (msg);
+      break;
+    }
+
+    default:{
+    }
+  }
+
+  return res;
+
+error:
+  return GST_RTSP_ERROR;
+}
+
+GstRTSPResult
+prepare_trigger_request (GstRTSPWFDClient * client, GstRTSPMessage * request,
+    GstWFDTriggerType trigger_type, gchar * url)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+
+  /* initialize the request */
+  res = gst_rtsp_message_init_request (request, GST_RTSP_SET_PARAMETER, url);
+  if (res < 0) {
+    GST_ERROR ("init request failed");
+    return res;
+  }
+
+  switch (trigger_type) {
+    case WFD_TRIGGER_SETUP:{
+      gchar *msg;
+      guint msglen = 0;
+      GString *msglength;
+
+      /* add content type */
+      res =
+          gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE,
+          "text/parameters");
+      if (res != GST_RTSP_OK) {
+        GST_ERROR_OBJECT (client, "Failed to add header to rtsp request...");
+        goto error;
+      }
+
+      _set_wfd_message_body (client, M5_REQ_MSG, &msg, &msglen);
+      msglength = g_string_new ("");
+      g_string_append_printf (msglength, "%d", msglen);
+      GST_DEBUG ("M5 server side message body: %s", msg);
+
+      /* add content-length type */
+      res =
+          gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH,
+          g_string_free (msglength, FALSE));
+      if (res != GST_RTSP_OK) {
+        GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
+        goto error;
+      }
+
+      res = gst_rtsp_message_set_body (request, (guint8 *) msg, msglen);
+      if (res != GST_RTSP_OK) {
+        GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
+        goto error;
+      }
+
+      g_free (msg);
+      break;
+    }
+    case WFD_TRIGGER_TEARDOWN:{
+      gchar *msg;
+      guint msglen = 0;
+      GString *msglength;
+
+      /* add content type */
+      res =
+          gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE,
+          "text/parameters");
+      if (res != GST_RTSP_OK) {
+        GST_ERROR_OBJECT (client, "Failed to add header to rtsp request...");
+        goto error;
+      }
+
+      _set_wfd_message_body (client, TEARDOWN_TRIGGER, &msg, &msglen);
+      msglength = g_string_new ("");
+      g_string_append_printf (msglength, "%d", msglen);
+      GST_DEBUG ("Trigger TEARDOWN server side message body: %s", msg);
+
+      /* add content-length type */
+      res =
+          gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH,
+          g_string_free (msglength, FALSE));
+      if (res != GST_RTSP_OK) {
+        GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
+        goto error;
+      }
+
+      res = gst_rtsp_message_set_body (request, (guint8 *) msg, msglen);
+      if (res != GST_RTSP_OK) {
+        GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
+        goto error;
+      }
+
+      g_free (msg);
+      break;
+    }
+    case WFD_TRIGGER_PLAY:{
+      gchar *msg;
+      guint msglen = 0;
+      GString *msglength;
+
+      /* add content type */
+      res =
+          gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE,
+          "text/parameters");
+      if (res != GST_RTSP_OK) {
+        GST_ERROR_OBJECT (client, "Failed to add header to rtsp request...");
+        goto error;
+      }
+
+      _set_wfd_message_body (client, PLAY_TRIGGER, &msg, &msglen);
+      msglength = g_string_new ("");
+      g_string_append_printf (msglength, "%d", msglen);
+      GST_DEBUG ("Trigger PLAY server side message body: %s", msg);
+
+      /* add content-length type */
+      res =
+          gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH,
+          g_string_free (msglength, FALSE));
+      if (res != GST_RTSP_OK) {
+        GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
+        goto error;
+      }
+
+      res = gst_rtsp_message_set_body (request, (guint8 *) msg, msglen);
+      if (res != GST_RTSP_OK) {
+        GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
+        goto error;
+      }
+
+      g_free (msg);
+      break;
+    }
+    case WFD_TRIGGER_PAUSE:{
+      gchar *msg;
+      guint msglen = 0;
+      GString *msglength;
+
+      /* add content type */
+      res =
+          gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE,
+          "text/parameters");
+      if (res != GST_RTSP_OK) {
+        GST_ERROR_OBJECT (client, "Failed to add header to rtsp request...");
+        goto error;
+      }
+
+      _set_wfd_message_body (client, PAUSE_TRIGGER, &msg, &msglen);
+      msglength = g_string_new ("");
+      g_string_append_printf (msglength, "%d", msglen);
+      GST_DEBUG ("Trigger PAUSE server side message body: %s", msg);
+
+      /* add content-length type */
+      res =
+          gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_LENGTH,
+          g_string_free (msglength, FALSE));
+      if (res != GST_RTSP_OK) {
+        GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
+        goto error;
+      }
+
+      res = gst_rtsp_message_set_body (request, (guint8 *) msg, msglen);
+      if (res != GST_RTSP_OK) {
+        GST_ERROR_OBJECT (client, "Failed to add header to rtsp message...");
+        goto error;
+      }
+
+      g_free (msg);
+      break;
+    }
+      /* TODO-WFD: implement to handle other trigger type */
+    default:{
+    }
+  }
+
+  return res;
+
+error:
+  return res;
+}
+
+
+void
+send_request (GstRTSPWFDClient * client, GstRTSPSession * session,
+    GstRTSPMessage * request)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
+
+  /* remove any previous header */
+  gst_rtsp_message_remove_header (request, GST_RTSP_HDR_SESSION, -1);
+
+  /* add the new session header for new session ids */
+  if (session) {
+    guint timeout;
+    const gchar *sessionid = NULL;
+    gchar *str;
+
+    sessionid = gst_rtsp_session_get_sessionid (session);
+    GST_INFO_OBJECT (client, "Session id : %s", sessionid);
+
+    timeout = gst_rtsp_session_get_timeout (session);
+    if (timeout != DEFAULT_WFD_TIMEOUT)
+      str = g_strdup_printf ("%s; timeout=%d", sessionid, timeout);
+    else
+      str = g_strdup (sessionid);
+
+    gst_rtsp_message_take_header (request, GST_RTSP_HDR_SESSION, str);
+  }
+#if 0
+  if (gst_debug_category_get_threshold (rtsp_wfd_client_debug) >= GST_LEVEL_LOG) {
+    gst_rtsp_message_dump (request);
+  }
+#endif
+  res = gst_rtsp_client_send_message (parent_client, session, request);
+  if (res != GST_RTSP_OK) {
+    GST_ERROR_OBJECT (client, "gst_rtsp_client_send_message failed : %d", res);
+  }
+
+  gst_rtsp_message_unset (request);
+}
+
+/**
+* prepare_response:
+* @client: client object
+* @request : requst message received
+* @response : response to be prepare based on request
+* @method : RTSP method
+*
+* prepare response to the request based on @method & @message_type
+*
+* Returns: a #GstRTSPResult.
+*/
+GstRTSPResult
+prepare_response (GstRTSPWFDClient * client, GstRTSPMessage * request,
+    GstRTSPMessage * response, GstRTSPMethod method)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+
+  switch (method) {
+      /* prepare OPTIONS response */
+    case GST_RTSP_OPTIONS:{
+      GstRTSPMethod options;
+      gchar *tmp = NULL;
+      gchar *str = NULL;
+      gchar *user_agent = NULL;
+
+      options = GST_RTSP_OPTIONS |
+          GST_RTSP_PAUSE |
+          GST_RTSP_PLAY |
+          GST_RTSP_SETUP |
+          GST_RTSP_GET_PARAMETER | GST_RTSP_SET_PARAMETER | GST_RTSP_TEARDOWN;
+
+      str = gst_rtsp_options_as_text (options);
+
+      /*append WFD specific method */
+      tmp = g_strdup (", org.wfa.wfd1.0");
+      g_strlcat (str, tmp, strlen (tmp) + strlen (str) + 1);
+
+      gst_rtsp_message_init_response (response, GST_RTSP_STS_OK,
+          gst_rtsp_status_as_text (GST_RTSP_STS_OK), request);
+
+      gst_rtsp_message_add_header (response, GST_RTSP_HDR_PUBLIC, str);
+      g_free (str);
+      str = NULL;
+      res =
+          gst_rtsp_message_get_header (request, GST_RTSP_HDR_USER_AGENT,
+          &user_agent, 0);
+      if (res == GST_RTSP_OK) {
+        gst_rtsp_message_add_header (response, GST_RTSP_HDR_USER_AGENT,
+            user_agent);
+      } else
+        res = GST_RTSP_OK;
+      break;
+    }
+    default:
+      GST_ERROR_OBJECT (client, "Unhandled method...");
+      return GST_RTSP_EINVAL;
+      break;
+  }
+
+  return res;
+}
+
+static void
+send_generic_wfd_response (GstRTSPWFDClient * client, GstRTSPStatusCode code,
+    GstRTSPContext * ctx)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
+
+  gst_rtsp_message_init_response (ctx->response, code,
+      gst_rtsp_status_as_text (code), ctx->request);
+
+  res = gst_rtsp_client_send_message (parent_client, NULL, ctx->response);
+  if (res != GST_RTSP_OK) {
+    GST_ERROR_OBJECT (client, "gst_rtsp_client_send_message failed : %d", res);
+  }
+}
+
+
+static GstRTSPResult
+handle_M1_message (GstRTSPWFDClient * client)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GstRTSPMessage request = { 0 };
+
+  res = prepare_request (client, &request, GST_RTSP_OPTIONS, (gchar *) "*");
+  if (GST_RTSP_OK != res) {
+    GST_ERROR_OBJECT (client, "Failed to prepare M1 request....\n");
+    return res;
+  }
+
+  GST_DEBUG_OBJECT (client, "Sending M1 request.. (OPTIONS request)");
+
+  send_request (client, NULL, &request);
+
+  return res;
+}
+
+/**
+* handle_M3_message:
+* @client: client object
+*
+* Handles M3 WFD message.
+* This API will send M3 message (GET_PARAMETER) to WFDSink to query supported formats by the WFDSink.
+* After getting supported formats info, this API will set those values on WFDConfigMessage obj
+*
+* Returns: a #GstRTSPResult.
+*/
+static GstRTSPResult
+handle_M3_message (GstRTSPWFDClient * client)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GstRTSPMessage request = { 0 };
+  GstRTSPUrl *url = NULL;
+  gchar *url_str = NULL;
+
+  GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
+  GstRTSPConnection *connection =
+      gst_rtsp_client_get_connection (parent_client);
+
+  url = gst_rtsp_connection_get_url (connection);
+  if (url == NULL) {
+    GST_ERROR_OBJECT (client, "Failed to get connection URL");
+    res = GST_RTSP_ERROR;
+    goto error;
+  }
+
+  url_str = gst_rtsp_url_get_request_uri (url);
+  if (url_str == NULL) {
+    GST_ERROR_OBJECT (client, "Failed to get connection URL");
+    res = GST_RTSP_ERROR;
+    goto error;
+  }
+
+  res = prepare_request (client, &request, GST_RTSP_GET_PARAMETER, url_str);
+  if (GST_RTSP_OK != res) {
+    GST_ERROR_OBJECT (client, "Failed to prepare M3 request....\n");
+    goto error;
+  }
+
+  GST_DEBUG_OBJECT (client, "Sending GET_PARAMETER request message (M3)...");
+
+  send_request (client, NULL, &request);
+
+  return res;
+
+error:
+  return res;
+}
+
+static GstRTSPResult
+handle_M4_message (GstRTSPWFDClient * client)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GstRTSPMessage request = { 0 };
+  GstRTSPUrl *url = NULL;
+  gchar *url_str = NULL;
+
+  GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
+  GstRTSPConnection *connection =
+      gst_rtsp_client_get_connection (parent_client);
+
+  url = gst_rtsp_connection_get_url (connection);
+  if (url == NULL) {
+    GST_ERROR_OBJECT (client, "Failed to get connection URL");
+    res = GST_RTSP_ERROR;
+    goto error;
+  }
+
+  url_str = gst_rtsp_url_get_request_uri (url);
+  if (url_str == NULL) {
+    GST_ERROR_OBJECT (client, "Failed to get connection URL");
+    res = GST_RTSP_ERROR;
+    goto error;
+  }
+
+  res = prepare_request (client, &request, GST_RTSP_SET_PARAMETER, url_str);
+  if (GST_RTSP_OK != res) {
+    GST_ERROR_OBJECT (client, "Failed to prepare M4 request....\n");
+    goto error;
+  }
+
+  GST_DEBUG_OBJECT (client, "Sending SET_PARAMETER request message (M4)...");
+
+  send_request (client, NULL, &request);
+
+  return res;
+
+error:
+  return res;
+}
+
+GstRTSPResult
+gst_rtsp_wfd_client_trigger_request (GstRTSPWFDClient * client,
+    GstWFDTriggerType type)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GstRTSPMessage request = { 0 };
+  GstRTSPUrl *url = NULL;
+  gchar *url_str = NULL;
+
+  GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
+  GstRTSPConnection *connection =
+      gst_rtsp_client_get_connection (parent_client);
+
+  url = gst_rtsp_connection_get_url (connection);
+  if (url == NULL) {
+    GST_ERROR_OBJECT (client, "Failed to get connection URL");
+    res = GST_RTSP_ERROR;
+    goto error;
+  }
+
+  url_str = gst_rtsp_url_get_request_uri (url);
+  if (url_str == NULL) {
+    GST_ERROR_OBJECT (client, "Failed to get connection URL");
+    res = GST_RTSP_ERROR;
+    goto error;
+  }
+
+  res = prepare_trigger_request (client, &request, type, url_str);
+  if (GST_RTSP_OK != res) {
+    GST_ERROR_OBJECT (client, "Failed to prepare M5 request....\n");
+    goto error;
+  }
+
+  GST_DEBUG_OBJECT (client, "Sending trigger request message...: %d", type);
+
+  send_request (client, NULL, &request);
+
+  return res;
+
+error:
+  return res;
+}
+
+GstRTSPResult
+gst_rtsp_wfd_client_set_video_supported_resolution (GstRTSPWFDClient * client,
+    guint64 supported_reso)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+
+  g_return_val_if_fail (priv != NULL, GST_RTSP_EINVAL);
+
+  priv->video_resolution_supported = supported_reso;
+  GST_DEBUG ("Resolution : %"G_GUINT64_FORMAT, supported_reso);
+
+  return res;
+}
+
+GstRTSPResult
+gst_rtsp_wfd_client_set_video_native_resolution (GstRTSPWFDClient * client,
+    guint64 native_reso)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+
+  g_return_val_if_fail (priv != NULL, GST_RTSP_EINVAL);
+
+  priv->video_native_resolution = native_reso;
+  GST_DEBUG ("Native Resolution : %"G_GUINT64_FORMAT, native_reso);
+
+  return res;
+}
+
+GstRTSPResult
+gst_rtsp_wfd_client_set_audio_codec (GstRTSPWFDClient * client,
+    guint8 audio_codec)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+
+  g_return_val_if_fail (priv != NULL, GST_RTSP_EINVAL);
+
+  priv->audio_codec = audio_codec;
+  GST_DEBUG ("Audio codec : %d", audio_codec);
+
+  return res;
+}
+
+static gboolean
+wfd_ckeck_keep_alive_response (gpointer userdata)
+{
+  GstRTSPWFDClient *client = (GstRTSPWFDClient *)userdata;
+  GstRTSPWFDClientPrivate *priv = NULL;
+  if (!client) {
+    return FALSE;
+  }
+
+  priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, GST_RTSP_EINVAL);
+
+  if (priv->keep_alive_flag) {
+    return FALSE;
+  }
+  else {
+    GST_INFO ("%p: source error notification", client);
+
+    g_signal_emit (client,
+        gst_rtsp_client_wfd_signals[SIGNAL_WFD_KEEP_ALIVE_FAIL], 0,
+        NULL);
+    return FALSE;
+  }
+}
+
+/*Sending keep_alive (M16) message.
+  Without calling prepare_request function.*/
+static GstRTSPResult
+handle_M16_message (GstRTSPWFDClient * client)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GstRTSPMessage request = { 0 };
+  gchar *url_str = NULL;
+
+  url_str = g_strdup("rtsp://localhost/wfd1.0");
+
+  res = gst_rtsp_message_init_request (&request, GST_RTSP_GET_PARAMETER, url_str);
+  if (res < 0) {
+    GST_ERROR ("init request failed");
+    return FALSE;
+  }
+
+  send_request (client, NULL, &request);
+  return GST_RTSP_OK;
+}
+
+/*CHecking whether source has got response of any request.
+ * If yes, keep alive message is sent otherwise error message
+ * will be displayed.*/
+static gboolean
+keep_alive_condition(gpointer userdata)
+{
+  GstRTSPWFDClient *client;
+  GstRTSPWFDClientPrivate *priv;
+  GstRTSPResult res;
+  client = (GstRTSPWFDClient *)userdata;
+  if (!client) {
+    return FALSE;
+  }
+  priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+
+  g_return_val_if_fail (priv != NULL, FALSE);
+
+  g_mutex_lock(&priv->keep_alive_lock);
+  if(!priv->keep_alive_flag) {
+    g_timeout_add(5000, wfd_ckeck_keep_alive_response, client);
+  }
+  else {
+    GST_DEBUG_OBJECT (client, "have received last keep alive message response");
+  }
+
+  GST_DEBUG("sending keep alive message");
+  res = handle_M16_message(client);
+  if(res == GST_RTSP_OK) {
+    priv->keep_alive_flag = FALSE;
+  } else {
+    GST_ERROR_OBJECT (client, "Failed to send Keep Alive Message");
+    g_mutex_unlock(&priv->keep_alive_lock);
+    return FALSE;
+  }
+
+  g_mutex_unlock(&priv->keep_alive_lock);
+  return TRUE;
+}
+
+static
+void wfd_set_keep_alive_condition(GstRTSPWFDClient * client)
+{
+  g_timeout_add((DEFAULT_WFD_TIMEOUT-5)*1000, keep_alive_condition, client);
+}
+
+void
+gst_rtsp_wfd_client_set_host_address (GstRTSPWFDClient *client, const gchar * address)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+
+  g_return_if_fail (priv != NULL);
+
+  if (priv->host_address) {
+    g_free (priv->host_address);
+  }
+
+  priv->host_address = g_strdup (address);
+}
+
+guint
+gst_rtsp_wfd_client_get_audio_codec(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->caCodec;
+}
+
+guint
+gst_rtsp_wfd_client_get_audio_freq(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->cFreq;
+}
+
+guint
+gst_rtsp_wfd_client_get_audio_channels(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->cChanels;
+}
+
+guint
+gst_rtsp_wfd_client_get_audio_bit_width(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->cBitwidth;
+}
+
+guint
+gst_rtsp_wfd_client_get_audio_latency(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->caLatency;
+}
+
+guint
+gst_rtsp_wfd_client_get_video_codec(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->cvCodec;
+}
+
+guint
+gst_rtsp_wfd_client_get_video_native(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->cNative;
+}
+
+guint64
+gst_rtsp_wfd_client_get_video_native_resolution(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->cNativeResolution;
+}
+
+guint64
+gst_rtsp_wfd_client_get_video_cea_resolution(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->cCEAResolution;
+}
+
+guint64
+gst_rtsp_wfd_client_get_video_vesa_resolution(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->cVESAResolution;
+}
+
+guint64
+gst_rtsp_wfd_client_get_video_hh_resolution(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->cHHResolution;
+}
+
+guint
+gst_rtsp_wfd_client_get_video_profile(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->cProfile;
+}
+
+guint
+gst_rtsp_wfd_client_get_video_level(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->cLevel;
+}
+
+guint
+gst_rtsp_wfd_client_get_video_latency(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->cvLatency;
+}
+
+guint32
+gst_rtsp_wfd_client_get_video_max_height(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->cMaxHeight;
+}
+
+guint32
+gst_rtsp_wfd_client_get_video_max_width(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->cMaxWidth;
+}
+
+guint32
+gst_rtsp_wfd_client_get_video_framerate(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->cFramerate;
+}
+
+guint32
+gst_rtsp_wfd_client_get_video_min_slice_size(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->cmin_slice_size;
+}
+
+guint32
+gst_rtsp_wfd_client_get_video_slice_enc_params(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->cslice_enc_params;
+}
+
+guint
+gst_rtsp_wfd_client_get_video_framerate_control(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->cframe_rate_control;
+}
+
+guint32
+gst_rtsp_wfd_client_get_rtp_port0(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->crtp_port0;
+}
+
+guint32
+gst_rtsp_wfd_client_get_rtp_port1(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->crtp_port1;
+}
+
+gboolean
+gst_rtsp_wfd_client_get_edid_supported(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->edid_supported;
+}
+
+guint32
+gst_rtsp_wfd_client_get_edid_hresolution(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->edid_hres;
+}
+
+guint32
+gst_rtsp_wfd_client_get_edid_vresolution(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->edid_vres;
+}
+
+gboolean
+gst_rtsp_wfd_client_get_protection_enabled(GstRTSPWFDClient *client)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  return priv->protection_enabled;
+}
+
+void
+gst_rtsp_wfd_client_set_audio_freq(GstRTSPWFDClient *client, guint freq)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  priv->cFreq = freq;
+}
+
+void
+gst_rtsp_wfd_client_set_edid_supported(GstRTSPWFDClient *client, gboolean supported)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  priv->edid_supported = supported;
+}
+
+void
+gst_rtsp_wfd_client_set_edid_hresolution(GstRTSPWFDClient *client, guint32 reso)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  priv->edid_hres = reso;
+}
+
+void
+gst_rtsp_wfd_client_set_edid_vresolution(GstRTSPWFDClient *client, guint32 reso)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  priv->edid_vres = reso;
+}
+
+void
+gst_rtsp_wfd_client_set_protection_enabled(GstRTSPWFDClient *client, gboolean enable)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  priv->protection_enabled = enable;
+}
+
+void gst_rtsp_wfd_client_set_keep_alive_flag(GstRTSPWFDClient *client, gboolean flag)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_val_if_fail (priv != NULL, 0);
+
+  g_mutex_lock(&priv->keep_alive_lock);
+  if (priv->keep_alive_flag == !(flag))
+    priv->keep_alive_flag = flag;
+  g_mutex_unlock(&priv->keep_alive_lock);
+}
+
+void
+gst_rtsp_wfd_client_set_aud_codec (GstRTSPWFDClient *client, guint acodec)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->caCodec = acodec;
+}
+
+void
+gst_rtsp_wfd_client_set_audio_channels(GstRTSPWFDClient *client, guint channels)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->cChanels = channels;
+}
+
+void
+gst_rtsp_wfd_client_set_audio_bit_width(GstRTSPWFDClient *client, guint bwidth)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->cBitwidth = bwidth;
+}
+
+void
+gst_rtsp_wfd_client_set_audio_latency(GstRTSPWFDClient *client, guint latency)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->caLatency = latency;
+}
+
+void
+gst_rtsp_wfd_client_set_video_codec(GstRTSPWFDClient *client, guint vcodec)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->cvCodec = vcodec;
+}
+
+void
+gst_rtsp_wfd_client_set_video_native(GstRTSPWFDClient *client, guint native)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->cNative = native;
+}
+
+void
+gst_rtsp_wfd_client_set_vid_native_resolution(GstRTSPWFDClient *client, guint64 res)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->cNativeResolution = res;
+}
+
+void
+gst_rtsp_wfd_client_set_video_cea_resolution(GstRTSPWFDClient *client, guint64 res)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->cCEAResolution = res;
+}
+
+void
+gst_rtsp_wfd_client_set_video_vesa_resolution(GstRTSPWFDClient *client, guint64 res)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->cVESAResolution = res;
+}
+
+void
+gst_rtsp_wfd_client_set_video_hh_resolution(GstRTSPWFDClient *client, guint64 res)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->cHHResolution = res;
+}
+
+void
+gst_rtsp_wfd_client_set_video_profile(GstRTSPWFDClient *client, guint profile)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->cProfile = profile;
+}
+
+void
+gst_rtsp_wfd_client_set_video_level(GstRTSPWFDClient *client, guint level)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->cLevel = level;
+}
+
+void
+gst_rtsp_wfd_client_set_video_latency(GstRTSPWFDClient *client, guint latency)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->cvLatency = latency;
+}
+
+void
+gst_rtsp_wfd_client_set_video_max_height(GstRTSPWFDClient *client, guint32 height)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->cMaxHeight = height;
+}
+
+void
+gst_rtsp_wfd_client_set_video_max_width(GstRTSPWFDClient *client, guint32 width)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->cMaxWidth = width;
+}
+
+void
+gst_rtsp_wfd_client_set_video_framerate(GstRTSPWFDClient *client, guint32 framerate)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->cFramerate = framerate;
+}
+
+void
+gst_rtsp_wfd_client_set_video_min_slice_size(GstRTSPWFDClient *client, guint32 slice_size)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->cmin_slice_size = slice_size;
+}
+
+void
+gst_rtsp_wfd_client_set_video_slice_enc_params(GstRTSPWFDClient *client, guint32 enc_params)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->cslice_enc_params = enc_params;
+}
+
+void
+gst_rtsp_wfd_client_set_video_framerate_control(GstRTSPWFDClient *client, guint framerate)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->cframe_rate_control = framerate;
+}
+
+void
+gst_rtsp_wfd_client_set_rtp_port0(GstRTSPWFDClient *client, guint32 port)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->crtp_port0 = port;
+}
+
+void
+gst_rtsp_wfd_client_set_rtp_port1(GstRTSPWFDClient *client, guint32 port)
+{
+  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
+  g_return_if_fail (priv != NULL);
+
+  priv->crtp_port1 = port;
+}
diff --git a/gst/rtsp-server/rtsp-client-wfd.h b/gst/rtsp-server/rtsp-client-wfd.h
new file mode 100644 (file)
index 0000000..baf54b9
--- /dev/null
@@ -0,0 +1,221 @@
+/* GStreamer
+ * Copyright (C) 2015 Samsung Electronics Hyunjun Ko <zzoon.ko@samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/gst.h>
+#include <gst/rtsp/gstrtspconnection.h>
+
+#ifndef __GST_RTSP_WFD_CLIENT_H__
+#define __GST_RTSP_WFD_CLIENT_H__
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTSPWFDClient GstRTSPWFDClient;
+typedef struct _GstRTSPWFDClientClass GstRTSPWFDClientClass;
+typedef struct _GstRTSPWFDClientPrivate GstRTSPWFDClientPrivate;
+
+#include "rtsp-context.h"
+#include "rtsp-mount-points.h"
+#include "rtsp-sdp.h"
+#include "rtsp-auth.h"
+#include "rtsp-client.h"
+#include "gstwfdmessage.h"
+
+#define GST_TYPE_RTSP_WFD_CLIENT              (gst_rtsp_wfd_client_get_type ())
+#define GST_IS_RTSP_WFD_CLIENT(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_WFD_CLIENT))
+#define GST_IS_RTSP_WFD_CLIENT_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_WFD_CLIENT))
+#define GST_RTSP_WFD_CLIENT_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_WFD_CLIENT, GstRTSPWFDClientClass))
+#define GST_RTSP_WFD_CLIENT(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_WFD_CLIENT, GstRTSPWFDClient))
+#define GST_RTSP_WFD_CLIENT_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_WFD_CLIENT, GstRTSPWFDClientClass))
+#define GST_RTSP_WFD_CLIENT_CAST(obj)         ((GstRTSPWFDClient*)(obj))
+#define GST_RTSP_WFD_CLIENT_CLASS_CAST(klass) ((GstRTSPWFDClientClass*)(klass))
+
+
+/**
+ *
+ */
+typedef enum {
+  WFD_TRIGGER_SETUP,
+  WFD_TRIGGER_PAUSE,
+  WFD_TRIGGER_TEARDOWN,
+  WFD_TRIGGER_PLAY
+} GstWFDTriggerType;
+
+/**
+ * GstRTSPWFDClientSendFunc:
+ * @client: a #GstRTSPWFDClient
+ * @message: a #GstRTSPMessage
+ * @close: close the connection
+ * @user_data: user data when registering the callback
+ *
+ * This callback is called when @client wants to send @message. When @close is
+ * %TRUE, the connection should be closed when the message has been sent.
+ *
+ * Returns: %TRUE on success.
+ */
+typedef gboolean (*GstRTSPWFDClientSendFunc)      (GstRTSPWFDClient *client,
+                                                GstRTSPMessage *message,
+                                                gboolean close,
+                                                gpointer user_data);
+
+/**
+ * GstRTSPWFDClient:
+ *
+ * The client object represents the connection and its state with a client.
+ */
+struct _GstRTSPWFDClient {
+  GstRTSPClient  parent;
+
+  gint           supported_methods;
+  /*< private >*/
+  GstRTSPWFDClientPrivate *priv;
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+/**
+ * GstRTSPWFDClientClass:
+ * @create_sdp: called when the SDP needs to be created for media.
+ * @configure_client_media: called when the stream in media needs to be configured.
+ *    The default implementation will configure the blocksize on the payloader when
+ *    spcified in the request headers.
+ * @configure_client_transport: called when the client transport needs to be
+ *    configured.
+ * @params_set: set parameters. This function should also initialize the
+ *    RTSP response(ctx->response) via a call to gst_rtsp_message_init_response()
+ * @params_get: get parameters. This function should also initialize the
+ *    RTSP response(ctx->response) via a call to gst_rtsp_message_init_response()
+ *
+ * The client class structure.
+ */
+struct _GstRTSPWFDClientClass {
+  GstRTSPClientClass  parent_class;
+
+  GstRTSPResult       (*prepare_resource) (GstRTSPWFDClient *client, GstRTSPContext *ctx);
+  GstRTSPResult       (*confirm_resource) (GstRTSPWFDClient *client, GstRTSPContext *ctx);
+
+  /* signals */
+  void     (*wfd_options_request)         (GstRTSPWFDClient *client, GstRTSPContext *ctx);
+  void     (*wfd_get_param_request)       (GstRTSPWFDClient *client, GstRTSPContext *ctx);
+  void     (*wfd_keep_alive_fail)         (GstRTSPWFDClient *client);
+
+  /*< private >*/
+  gpointer _gst_reserved[GST_PADDING_LARGE];
+};
+
+GType                 gst_rtsp_wfd_client_get_type          (void);
+
+GstRTSPWFDClient *    gst_rtsp_wfd_client_new               (void);
+
+void                  gst_rtsp_wfd_client_set_host_address  (
+                          GstRTSPWFDClient *client, const gchar * address);
+
+void                  gst_rtsp_wfd_client_start_wfd(GstRTSPWFDClient *client);
+GstRTSPResult         gst_rtsp_wfd_client_trigger_request (
+                          GstRTSPWFDClient * client, GstWFDTriggerType type);
+
+GstRTSPResult         gst_rtsp_wfd_client_set_video_supported_resolution (
+                          GstRTSPWFDClient * client, guint64 supported_reso);
+GstRTSPResult         gst_rtsp_wfd_client_set_video_native_resolution (
+                                     GstRTSPWFDClient * client, guint64 native_reso);
+GstRTSPResult         gst_rtsp_wfd_client_set_audio_codec (
+                                     GstRTSPWFDClient * client, guint8 audio_codec);
+
+guint     gst_rtsp_wfd_client_get_audio_codec(GstRTSPWFDClient *client);
+guint     gst_rtsp_wfd_client_get_audio_freq(GstRTSPWFDClient *client);
+guint     gst_rtsp_wfd_client_get_audio_channels(GstRTSPWFDClient *client);
+guint     gst_rtsp_wfd_client_get_audio_bit_width(GstRTSPWFDClient *client);
+guint     gst_rtsp_wfd_client_get_audio_latency(GstRTSPWFDClient *client);
+guint     gst_rtsp_wfd_client_get_video_codec(GstRTSPWFDClient *client);
+guint     gst_rtsp_wfd_client_get_video_native(GstRTSPWFDClient *client);
+guint64   gst_rtsp_wfd_client_get_video_native_resolution(GstRTSPWFDClient *client);
+guint64   gst_rtsp_wfd_client_get_video_cea_resolution(GstRTSPWFDClient *client);
+guint64   gst_rtsp_wfd_client_get_video_vesa_resolution(GstRTSPWFDClient *client);
+guint64   gst_rtsp_wfd_client_get_video_hh_resolution(GstRTSPWFDClient *client);
+guint     gst_rtsp_wfd_client_get_video_profile(GstRTSPWFDClient *client);
+guint     gst_rtsp_wfd_client_get_video_level(GstRTSPWFDClient *client);
+guint     gst_rtsp_wfd_client_get_video_latency(GstRTSPWFDClient *client);
+guint32   gst_rtsp_wfd_client_get_video_max_height(GstRTSPWFDClient *client);
+guint32   gst_rtsp_wfd_client_get_video_max_width(GstRTSPWFDClient *client);
+guint32   gst_rtsp_wfd_client_get_video_framerate(GstRTSPWFDClient *client);
+guint32   gst_rtsp_wfd_client_get_video_min_slice_size(GstRTSPWFDClient *client);
+guint32   gst_rtsp_wfd_client_get_video_slice_enc_params(GstRTSPWFDClient *client);
+guint     gst_rtsp_wfd_client_get_video_framerate_control(GstRTSPWFDClient *client);
+guint32   gst_rtsp_wfd_client_get_rtp_port0(GstRTSPWFDClient *client);
+guint32   gst_rtsp_wfd_client_get_rtp_port1(GstRTSPWFDClient *client);
+gboolean  gst_rtsp_wfd_client_get_edid_supported(GstRTSPWFDClient *client);
+guint32   gst_rtsp_wfd_client_get_edid_hresolution(GstRTSPWFDClient *client);
+guint32   gst_rtsp_wfd_client_get_edid_vresolution(GstRTSPWFDClient *client);
+gboolean  gst_rtsp_wfd_client_get_protection_enabled(GstRTSPWFDClient *client);
+
+void gst_rtsp_wfd_client_set_audio_freq(GstRTSPWFDClient *client, guint freq);
+void gst_rtsp_wfd_client_set_edid_supported(GstRTSPWFDClient *client, gboolean supported);
+void gst_rtsp_wfd_client_set_edid_hresolution(GstRTSPWFDClient *client, guint32 reso);
+void gst_rtsp_wfd_client_set_edid_vresolution(GstRTSPWFDClient *client, guint32 reso);
+void gst_rtsp_wfd_client_set_protection_enabled(GstRTSPWFDClient *client, gboolean enable);
+void gst_rtsp_wfd_client_set_keep_alive_flag(GstRTSPWFDClient *client, gboolean flag);
+void gst_rtsp_wfd_client_set_aud_codec(GstRTSPWFDClient *client, guint acodec);
+void gst_rtsp_wfd_client_set_audio_channels(GstRTSPWFDClient *client, guint channels);
+void gst_rtsp_wfd_client_set_audio_bit_width(GstRTSPWFDClient *client, guint bwidth);
+void gst_rtsp_wfd_client_set_audio_latency(GstRTSPWFDClient *client, guint latency);
+void gst_rtsp_wfd_client_set_video_codec(GstRTSPWFDClient *client, guint vcodec);
+void gst_rtsp_wfd_client_set_video_native(GstRTSPWFDClient *client, guint native);
+void gst_rtsp_wfd_client_set_vid_native_resolution(GstRTSPWFDClient *client, guint64 res);
+void gst_rtsp_wfd_client_set_video_cea_resolution(GstRTSPWFDClient *client, guint64 res);
+void gst_rtsp_wfd_client_set_video_vesa_resolution(GstRTSPWFDClient *client, guint64 res);
+void gst_rtsp_wfd_client_set_video_hh_resolution(GstRTSPWFDClient *client, guint64 res);
+void gst_rtsp_wfd_client_set_video_profile(GstRTSPWFDClient *client, guint profile);
+void gst_rtsp_wfd_client_set_video_level(GstRTSPWFDClient *client, guint level);
+void gst_rtsp_wfd_client_set_video_latency(GstRTSPWFDClient *client, guint latency);
+void gst_rtsp_wfd_client_set_video_max_height(GstRTSPWFDClient *client, guint32 height);
+void gst_rtsp_wfd_client_set_video_max_width(GstRTSPWFDClient *client, guint32 width);
+void gst_rtsp_wfd_client_set_video_framerate(GstRTSPWFDClient *client, guint32 framerate);
+void gst_rtsp_wfd_client_set_video_min_slice_size(GstRTSPWFDClient *client, guint32 slice_size);
+void gst_rtsp_wfd_client_set_video_slice_enc_params(GstRTSPWFDClient *client, guint32 enc_params);
+void gst_rtsp_wfd_client_set_video_framerate_control(GstRTSPWFDClient *client, guint framerate);
+void gst_rtsp_wfd_client_set_rtp_port0(GstRTSPWFDClient *client, guint32 port);
+void gst_rtsp_wfd_client_set_rtp_port1(GstRTSPWFDClient *client, guint32 port);
+
+/**
+ * GstRTSPWFDClientSessionFilterFunc:
+ * @client: a #GstRTSPWFDClient object
+ * @sess: a #GstRTSPSession in @client
+ * @user_data: user data that has been given to gst_rtsp_wfd_client_session_filter()
+ *
+ * This function will be called by the gst_rtsp_wfd_client_session_filter(). An
+ * implementation should return a value of #GstRTSPFilterResult.
+ *
+ * When this function returns #GST_RTSP_FILTER_REMOVE, @sess will be removed
+ * from @client.
+ *
+ * A return value of #GST_RTSP_FILTER_KEEP will leave @sess untouched in
+ * @client.
+ *
+ * A value of #GST_RTSP_FILTER_REF will add @sess to the result #GList of
+ * gst_rtsp_wfd_client_session_filter().
+ *
+ * Returns: a #GstRTSPFilterResult.
+ */
+typedef GstRTSPFilterResult (*GstRTSPWFDClientSessionFilterFunc)  (GstRTSPWFDClient *client,
+                                                                GstRTSPSession *sess,
+                                                                gpointer user_data);
+
+
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_WFD_CLIENT_H__ */
index 55f6259..13ccf36 100644 (file)
@@ -155,6 +155,12 @@ static GstRTSPResult default_params_get (GstRTSPClient * client,
     GstRTSPContext * ctx);
 static gchar *default_make_path_from_uri (GstRTSPClient * client,
     const GstRTSPUrl * uri);
+static gboolean default_handle_options_request (GstRTSPClient * client,
+    GstRTSPContext * ctx);
+static gboolean default_handle_set_param_request (GstRTSPClient * client,
+    GstRTSPContext * ctx);
+static gboolean default_handle_get_param_request (GstRTSPClient * client,
+    GstRTSPContext * ctx);
 static void client_session_removed (GstRTSPSessionPool * pool,
     GstRTSPSession * session, GstRTSPClient * client);
 
@@ -180,6 +186,9 @@ gst_rtsp_client_class_init (GstRTSPClientClass * klass)
   klass->params_set = default_params_set;
   klass->params_get = default_params_get;
   klass->make_path_from_uri = default_make_path_from_uri;
+  klass->handle_options_request = default_handle_options_request;
+  klass->handle_set_param_request = default_handle_set_param_request;
+  klass->handle_get_param_request = default_handle_get_param_request;
 
   g_object_class_install_property (gobject_class, PROP_SESSION_POOL,
       g_param_spec_object ("session-pool", "Session Pool",
@@ -929,7 +938,7 @@ default_params_get (GstRTSPClient * client, GstRTSPContext * ctx)
 }
 
 static gboolean
-handle_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
+default_handle_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
 {
   GstRTSPResult res;
   guint8 *data;
@@ -966,7 +975,7 @@ bad_request:
 }
 
 static gboolean
-handle_set_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
+default_handle_set_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
 {
   GstRTSPResult res;
   guint8 *data;
@@ -1833,6 +1842,8 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
   if (media == NULL)
     goto media_not_found_no_reply;
 
+  /* FIXME-WFD : wfd url problem */
+#if 0
   if (path[matched] == '\0') {
     if (gst_rtsp_media_n_streams (media) == 1) {
       stream = gst_rtsp_media_get_stream (media, 0);
@@ -1848,6 +1859,12 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
     /* find the stream now using the control part */
     stream = gst_rtsp_media_find_stream (media, control);
   }
+#else
+  control = g_strdup ("stream=0");
+
+  /* find the stream now using the control part */
+  stream = gst_rtsp_media_find_stream (media, control);
+#endif
 
   if (stream == NULL)
     goto stream_not_found;
@@ -1944,6 +1961,10 @@ handle_setup_request (GstRTSPClient * client, GstRTSPContext * ctx)
   /* create and serialize the server transport */
   st = make_server_transport (client, media, ctx, ct);
   trans_str = gst_rtsp_transport_as_text (st);
+
+  /* FIXME-WFD : Temporarily force to set profile string */
+  trans_str = g_strjoinv ("RTP/AVP/UDP", g_strsplit (trans_str, "RTP/AVP", -1));
+
   gst_rtsp_transport_free (st);
 
   /* construct the response now */
@@ -2548,7 +2569,7 @@ unsuspend_failed:
 }
 
 static gboolean
-handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx)
+default_handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx)
 {
   GstRTSPMethod options;
   gchar *str;
@@ -2704,6 +2725,9 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request)
   GstRTSPMessage response = { 0 };
   gchar *unsupported_reqs = NULL;
   gchar *sessid;
+  GstRTSPClientClass *klass;
+
+  klass = GST_RTSP_CLIENT_GET_CLASS (client);
 
   if (!(ctx = gst_rtsp_context_get_current ())) {
     ctx = &sctx;
@@ -2828,7 +2852,7 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request)
   /* now see what is asked and dispatch to a dedicated handler */
   switch (method) {
     case GST_RTSP_OPTIONS:
-      handle_options_request (client, ctx);
+      klass->handle_options_request (client, ctx);
       break;
     case GST_RTSP_DESCRIBE:
       handle_describe_request (client, ctx);
@@ -2846,10 +2870,10 @@ handle_request (GstRTSPClient * client, GstRTSPMessage * request)
       handle_teardown_request (client, ctx);
       break;
     case GST_RTSP_SET_PARAMETER:
-      handle_set_param_request (client, ctx);
+      klass->handle_set_param_request (client, ctx);
       break;
     case GST_RTSP_GET_PARAMETER:
-      handle_get_param_request (client, ctx);
+      klass->handle_get_param_request (client, ctx);
       break;
     case GST_RTSP_ANNOUNCE:
       handle_announce_request (client, ctx);
index 6b05448..9b6d879 100644 (file)
@@ -103,6 +103,9 @@ struct _GstRTSPClientClass {
   GstRTSPResult   (*params_set) (GstRTSPClient *client, GstRTSPContext *ctx);
   GstRTSPResult   (*params_get) (GstRTSPClient *client, GstRTSPContext *ctx);
   gchar *         (*make_path_from_uri) (GstRTSPClient *client, const GstRTSPUrl *uri);
+  gboolean        (*handle_options_request) (GstRTSPClient * client, GstRTSPContext * ctx);
+  gboolean        (*handle_set_param_request) (GstRTSPClient * client, GstRTSPContext * ctx);
+  gboolean        (*handle_get_param_request) (GstRTSPClient * client, GstRTSPContext * ctx);
 
   /* signals */
   void     (*closed)                  (GstRTSPClient *client);
@@ -129,7 +132,7 @@ struct _GstRTSPClientClass {
   gchar*   (*check_requirements)      (GstRTSPClient *client, GstRTSPContext *ctx, gchar ** arr);
 
   /*< private >*/
-  gpointer _gst_reserved[GST_PADDING_LARGE-6];
+  gpointer _gst_reserved[GST_PADDING_LARGE-9];
 };
 
 GType                 gst_rtsp_client_get_type          (void);
diff --git a/gst/rtsp-server/rtsp-media-factory-wfd.c b/gst/rtsp-server/rtsp-media-factory-wfd.c
new file mode 100644 (file)
index 0000000..f08a5c2
--- /dev/null
@@ -0,0 +1,1200 @@
+/* GStreamer
+ * Copyright (C) 2015 Samsung Electronics Hyunjun Ko <zzoon.ko@samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:rtsp-media-factory
+ * @short_description: A factory for media pipelines
+ * @see_also: #GstRTSPMountPoints, #GstRTSPMedia
+ *
+ * The #GstRTSPMediaFactoryWFD is responsible for creating or recycling
+ * #GstRTSPMedia objects based on the passed URL.
+ *
+ * The default implementation of the object can create #GstRTSPMedia objects
+ * containing a pipeline created from a launch description set with
+ * gst_rtsp_media_factory_wfd_set_launch().
+ *
+ * Media from a factory can be shared by setting the shared flag with
+ * gst_rtsp_media_factory_wfd_set_shared(). When a factory is shared,
+ * gst_rtsp_media_factory_wfd_construct() will return the same #GstRTSPMedia when
+ * the url matches.
+ *
+ * Last reviewed on 2013-07-11 (1.0.0)
+ */
+
+#include <stdio.h>
+#include "rtsp-media-factory-wfd.h"
+#include "gstwfdmessage.h"
+
+#define GST_RTSP_MEDIA_FACTORY_WFD_GET_PRIVATE(obj)  \
+       (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA_FACTORY_WFD, GstRTSPMediaFactoryWFDPrivate))
+
+#define GST_RTSP_MEDIA_FACTORY_WFD_GET_LOCK(f)       (&(GST_RTSP_MEDIA_FACTORY_WFD_CAST(f)->priv->lock))
+#define GST_RTSP_MEDIA_FACTORY_WFD_LOCK(f)           (g_mutex_lock(GST_RTSP_MEDIA_FACTORY_WFD_GET_LOCK(f)))
+#define GST_RTSP_MEDIA_FACTORY_WFD_UNLOCK(f)         (g_mutex_unlock(GST_RTSP_MEDIA_FACTORY_WFD_GET_LOCK(f)))
+
+struct _GstRTSPMediaFactoryWFDPrivate
+{
+  GMutex lock;
+  GstRTSPPermissions *permissions;
+  gchar *launch;
+  gboolean shared;
+  GstRTSPLowerTrans protocols;
+  guint buffer_size;
+  guint mtu_size;
+
+  guint8 videosrc_type;
+  guint8 video_codec;
+  gchar *video_encoder;
+  guint video_bitrate;
+  guint video_width;
+  guint video_height;
+  guint video_framerate;
+  guint video_enc_skip_inbuf_value;
+  GstElement *video_queue;
+
+  gchar *audio_device;
+  gchar *audio_encoder_aac;
+  gchar *audio_encoder_ac3;
+  guint8 audio_codec;
+  guint64 audio_latency_time;
+  guint64 audio_buffer_time;
+  gboolean audio_do_timestamp;
+  guint8 audio_channels;
+  guint8 audio_freq;
+  guint8 audio_bitrate;
+  GstElement *audio_queue;
+
+  guint64 video_resolution_supported;
+
+  gboolean dump_ts;
+};
+
+#define DEFAULT_LAUNCH          NULL
+#define DEFAULT_SHARED          FALSE
+#define DEFAULT_PROTOCOLS       GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST | \
+                                        GST_RTSP_LOWER_TRANS_TCP
+#define DEFAULT_BUFFER_SIZE     0x80000
+
+enum
+{
+  PROP_0,
+  PROP_LAUNCH,
+  PROP_SHARED,
+  PROP_SUSPEND_MODE,
+  PROP_EOS_SHUTDOWN,
+  PROP_PROTOCOLS,
+  PROP_BUFFER_SIZE,
+  PROP_LAST
+};
+
+enum
+{
+  SIGNAL_MEDIA_CONSTRUCTED,
+  SIGNAL_MEDIA_CONFIGURE,
+  SIGNAL_LAST
+};
+
+GST_DEBUG_CATEGORY_STATIC (rtsp_media_wfd_debug);
+#define GST_CAT_DEFAULT rtsp_media_wfd_debug
+
+static void gst_rtsp_media_factory_wfd_get_property (GObject * object,
+    guint propid, GValue * value, GParamSpec * pspec);
+static void gst_rtsp_media_factory_wfd_set_property (GObject * object,
+    guint propid, const GValue * value, GParamSpec * pspec);
+
+static void gst_rtsp_media_factory_wfd_finalize (GObject * obj);
+
+
+static GstElement *rtsp_media_factory_wfd_create_element (GstRTSPMediaFactory *
+    factory, const GstRTSPUrl * url);
+static GstRTSPMedia *rtsp_media_factory_wfd_construct (GstRTSPMediaFactory *
+    factory, const GstRTSPUrl * url);
+
+G_DEFINE_TYPE (GstRTSPMediaFactoryWFD, gst_rtsp_media_factory_wfd,
+    GST_TYPE_RTSP_MEDIA_FACTORY);
+
+static void
+gst_rtsp_media_factory_wfd_class_init (GstRTSPMediaFactoryWFDClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstRTSPMediaFactoryClass *factory_class;
+
+  g_type_class_add_private (klass, sizeof (GstRTSPMediaFactoryWFDPrivate));
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  factory_class = GST_RTSP_MEDIA_FACTORY_CLASS (klass);
+
+  gobject_class->get_property = gst_rtsp_media_factory_wfd_get_property;
+  gobject_class->set_property = gst_rtsp_media_factory_wfd_set_property;
+  gobject_class->finalize = gst_rtsp_media_factory_wfd_finalize;
+
+  factory_class->construct = rtsp_media_factory_wfd_construct;
+  factory_class->create_element = rtsp_media_factory_wfd_create_element;
+
+  GST_DEBUG_CATEGORY_INIT (rtsp_media_wfd_debug, "rtspmediafactorywfd", 0,
+      "GstRTSPMediaFactoryWFD");
+}
+
+void  gst_rtsp_media_factory_wfd_set (GstRTSPMediaFactoryWFD * factory,
+    guint8 videosrc_type, gchar *audio_device, guint64 audio_latency_time,
+    guint64 audio_buffer_time, gboolean audio_do_timestamp, guint mtu_size)
+{
+  GstRTSPMediaFactoryWFDPrivate *priv =
+      GST_RTSP_MEDIA_FACTORY_WFD_GET_PRIVATE (factory);
+  factory->priv = priv;
+
+  priv->videosrc_type = videosrc_type;
+  priv->audio_device = audio_device;
+  priv->audio_latency_time = audio_latency_time;
+  priv->audio_buffer_time = audio_buffer_time;
+  priv->audio_do_timestamp = audio_do_timestamp;
+  priv->mtu_size = mtu_size;
+}
+
+void  gst_rtsp_media_factory_wfd_set_encoders (GstRTSPMediaFactoryWFD * factory,
+    gchar *video_encoder, gchar *audio_encoder_aac, gchar *audio_encoder_ac3)
+{
+  GstRTSPMediaFactoryWFDPrivate *priv =
+      GST_RTSP_MEDIA_FACTORY_WFD_GET_PRIVATE (factory);
+  factory->priv = priv;
+
+  priv->video_encoder = video_encoder;
+  priv->audio_encoder_aac = audio_encoder_aac;
+  priv->audio_encoder_ac3 = audio_encoder_ac3;
+}
+
+void  gst_rtsp_media_factory_wfd_set_dump_ts (GstRTSPMediaFactoryWFD * factory,
+    gboolean dump_ts)
+{
+  GstRTSPMediaFactoryWFDPrivate *priv =
+      GST_RTSP_MEDIA_FACTORY_WFD_GET_PRIVATE (factory);
+  factory->priv = priv;
+
+  priv->dump_ts = dump_ts;
+}
+void gst_rtsp_media_factory_wfd_set_negotiated_resolution (GstRTSPMediaFactory *factory,
+   guint32 width, guint32 height)
+{
+  GstRTSPMediaFactoryWFD *factory_wfd = GST_RTSP_MEDIA_FACTORY_WFD (factory);
+  GstRTSPMediaFactoryWFDPrivate *priv = factory_wfd->priv;
+
+  priv->video_width = width;
+  priv->video_height = height;
+}
+void gst_rtsp_media_factory_wfd_set_audio_codec (GstRTSPMediaFactory *factory,
+   guint audio_codec)
+{
+  GstRTSPMediaFactoryWFD *factory_wfd = GST_RTSP_MEDIA_FACTORY_WFD (factory);
+  GstRTSPMediaFactoryWFDPrivate *priv = factory_wfd->priv;
+
+  priv->audio_codec = audio_codec;
+}
+
+static void
+gst_rtsp_media_factory_wfd_init (GstRTSPMediaFactoryWFD * factory)
+{
+  GstRTSPMediaFactoryWFDPrivate *priv =
+      GST_RTSP_MEDIA_FACTORY_WFD_GET_PRIVATE (factory);
+  factory->priv = priv;
+
+  priv->launch = g_strdup (DEFAULT_LAUNCH);
+  priv->shared = DEFAULT_SHARED;
+  priv->protocols = DEFAULT_PROTOCOLS;
+  priv->buffer_size = DEFAULT_BUFFER_SIZE;
+
+  //priv->videosrc_type = GST_WFD_VSRC_XIMAGESRC;
+  //priv->videosrc_type = GST_WFD_VSRC_XVIMAGESRC;
+  //priv->videosrc_type = GST_WFD_VSRC_CAMERASRC;
+  priv->videosrc_type = GST_WFD_VSRC_VIDEOTESTSRC;
+  priv->video_codec = GST_WFD_VIDEO_H264;
+  priv->video_encoder = g_strdup ("omxh264enc");
+  priv->video_bitrate = 200000;
+  priv->video_width = 640;
+  priv->video_height = 480;
+  priv->video_framerate = 30;
+  priv->video_enc_skip_inbuf_value = 5;
+
+  priv->audio_device = g_strdup ("alsa_output.1.analog-stereo.monitor");
+  priv->audio_codec = GST_WFD_AUDIO_AAC;
+  priv->audio_encoder_aac = g_strdup ("avenc_aac");
+  priv->audio_encoder_ac3 = g_strdup ("avenc_ac3");
+  priv->audio_latency_time = 10000;
+  priv->audio_buffer_time = 200000;
+  priv->audio_do_timestamp = FALSE;
+  priv->audio_channels = GST_WFD_CHANNEL_2;
+  priv->audio_freq = GST_WFD_FREQ_48000;
+
+  g_mutex_init (&priv->lock);
+}
+
+static void
+gst_rtsp_media_factory_wfd_finalize (GObject * obj)
+{
+  GstRTSPMediaFactoryWFD *factory = GST_RTSP_MEDIA_FACTORY_WFD (obj);
+  GstRTSPMediaFactoryWFDPrivate *priv = factory->priv;
+
+  if (priv->permissions)
+    gst_rtsp_permissions_unref (priv->permissions);
+  g_free (priv->launch);
+  g_mutex_clear (&priv->lock);
+
+  if (priv->audio_device)
+    g_free (priv->audio_device);
+  if (priv->audio_encoder_aac)
+    g_free (priv->audio_encoder_aac);
+  if (priv->audio_encoder_ac3)
+    g_free (priv->audio_encoder_ac3);
+
+  if (priv->video_encoder)
+    g_free (priv->video_encoder);
+
+  G_OBJECT_CLASS (gst_rtsp_media_factory_wfd_parent_class)->finalize (obj);
+}
+
+GstRTSPMediaFactoryWFD *
+gst_rtsp_media_factory_wfd_new (void)
+{
+  GstRTSPMediaFactoryWFD *result;
+
+  result = g_object_new (GST_TYPE_RTSP_MEDIA_FACTORY_WFD, NULL);
+
+  return result;
+}
+
+static void
+gst_rtsp_media_factory_wfd_get_property (GObject * object,
+    guint propid, GValue * value, GParamSpec * pspec)
+{
+  //GstRTSPMediaFactoryWFD *factory = GST_RTSP_MEDIA_FACTORY_WFD (object);
+
+  switch (propid) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
+  }
+}
+
+static void
+gst_rtsp_media_factory_wfd_set_property (GObject * object,
+    guint propid, const GValue * value, GParamSpec * pspec)
+{
+  //GstRTSPMediaFactoryWFD *factory = GST_RTSP_MEDIA_FACTORY_WFD (object);
+
+  switch (propid) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
+  }
+}
+
+static GstPadProbeReturn
+rtsp_media_wfd_dump_data (GstPad * pad, GstPadProbeInfo *info, gpointer u_data)
+{
+  guint8 *data;
+  gsize size;
+  FILE *f;
+  GstMapInfo mapinfo;
+
+  if (info->type == (GST_PAD_PROBE_TYPE_BUFFER | GST_PAD_PROBE_TYPE_PUSH)) {
+    GstBuffer *buffer = gst_pad_probe_info_get_buffer (info);
+
+    gst_buffer_map (buffer, &mapinfo, GST_MAP_READ);
+    data = mapinfo.data;
+    size = gst_buffer_get_size (buffer);
+
+    f = fopen ("/root/probe.ts", "a");
+    if (f != NULL) {
+      fwrite (data, size, 1, f);
+      fclose (f);
+    }
+    gst_buffer_unmap (buffer, &mapinfo);
+  }
+
+  return GST_PAD_PROBE_OK;
+}
+
+static gboolean
+_rtsp_media_factory_wfd_create_audio_capture_bin (GstRTSPMediaFactoryWFD *
+    factory, GstBin * srcbin)
+{
+  GstElement *audiosrc = NULL;
+  GstElement *acaps = NULL;
+  GstElement *acaps2 = NULL;
+  GstElement *aenc = NULL;
+  GstElement *audio_convert = NULL;
+  GstElement *aqueue = NULL;
+  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
+
+  guint channels = 0;
+  gboolean is_enc_req = TRUE;
+  guint freq = 0;
+  gchar *acodec = NULL;
+
+  priv = factory->priv;
+
+  /* create audio src element */
+  audiosrc = gst_element_factory_make ("pulsesrc", "audiosrc");
+  if (!audiosrc) {
+    GST_ERROR_OBJECT (factory, "failed to create audiosrc element");
+    goto create_error;
+  }
+
+  GST_INFO_OBJECT (factory, "audio device : %s", priv->audio_device);
+  GST_INFO_OBJECT (factory, "audio latency time  : %"G_GUINT64_FORMAT,
+      priv->audio_latency_time);
+  GST_INFO_OBJECT (factory, "audio_buffer_time  : %"G_GUINT64_FORMAT,
+      priv->audio_buffer_time);
+  GST_INFO_OBJECT (factory, "audio_do_timestamp  : %d",
+      priv->audio_do_timestamp);
+
+  g_object_set (audiosrc, "device", priv->audio_device, NULL);
+  g_object_set (audiosrc, "buffer-time", (gint64) priv->audio_buffer_time,
+      NULL);
+  g_object_set (audiosrc, "latency-time", (gint64) priv->audio_latency_time,
+      NULL);
+  g_object_set (audiosrc, "do-timestamp", (gboolean) priv->audio_do_timestamp,
+      NULL);
+  g_object_set (audiosrc, "provide-clock", (gboolean) FALSE, NULL);
+  g_object_set (audiosrc, "is-live", (gboolean) TRUE, NULL);
+
+  if (priv->audio_codec == GST_WFD_AUDIO_LPCM) {
+    /* To meet miracast certification */
+    gint64 block_size = 1920;
+    g_object_set (audiosrc, "blocksize", (gint64) block_size, NULL);
+
+    audio_convert = gst_element_factory_make ("capssetter", "audio_convert");
+    if (NULL == audio_convert) {
+      GST_ERROR_OBJECT (factory, "failed to create audio convert element");
+      goto create_error;
+    }
+    g_object_set (audio_convert, "caps", gst_caps_new_simple("audio/x-lpcm",
+              "width", G_TYPE_INT, 16,
+              "rate", G_TYPE_INT, 48000,
+              "channels", G_TYPE_INT, 2,
+              "dynamic_range", G_TYPE_INT, 0,
+              "emphasis", G_TYPE_BOOLEAN, FALSE,
+              "mute", G_TYPE_BOOLEAN, FALSE, NULL), NULL);
+    g_object_set (audio_convert, "join", (gboolean)FALSE, NULL);
+    g_object_set (audio_convert, "replace", (gboolean)TRUE, NULL);
+
+    acaps2 = gst_element_factory_make ("capsfilter", "audiocaps2");
+    if (NULL == acaps2) {
+      GST_ERROR_OBJECT (factory, "failed to create audio capsilfter element");
+      goto create_error;
+    }
+    /* In case of LPCM, uses big endian */
+        g_object_set (G_OBJECT (acaps2), "caps",
+            gst_caps_new_simple ("audio/x-raw", "format", G_TYPE_STRING, "S16BE",
+                /* In case of LPCM, uses big endian */
+                "rate", G_TYPE_INT, 48000,
+                "channels", G_TYPE_INT, 2, NULL), NULL);
+  }
+
+  /* create audio caps element */
+  acaps = gst_element_factory_make ("capsfilter", "audiocaps");
+  if (NULL == acaps) {
+    GST_ERROR_OBJECT (factory, "failed to create audio capsilfter element");
+    goto create_error;
+  }
+
+  if (priv->audio_channels == GST_WFD_CHANNEL_2)
+    channels = 2;
+  else if (priv->audio_channels == GST_WFD_CHANNEL_4)
+    channels = 4;
+  else if (priv->audio_channels == GST_WFD_CHANNEL_6)
+    channels = 6;
+  else if (priv->audio_channels == GST_WFD_CHANNEL_8)
+    channels = 8;
+  else
+    channels = 2;
+
+  if (priv->audio_freq == GST_WFD_FREQ_44100)
+    freq = 44100;
+  else if (priv->audio_freq == GST_WFD_FREQ_48000)
+    freq = 48000;
+  else
+    freq = 44100;
+
+  if (priv->audio_codec == GST_WFD_AUDIO_LPCM) {
+    g_object_set (G_OBJECT (acaps), "caps",
+        gst_caps_new_simple ("audio/x-lpcm", "width", G_TYPE_INT, 16,
+            "rate", G_TYPE_INT, 48000,
+            "channels", G_TYPE_INT, 2,
+            "dynamic_range", G_TYPE_INT, 0,
+            "emphasis", G_TYPE_BOOLEAN, FALSE,
+            "mute", G_TYPE_BOOLEAN, FALSE, NULL), NULL);
+  } else if ((priv->audio_codec == GST_WFD_AUDIO_AAC)
+      || (priv->audio_codec == GST_WFD_AUDIO_AC3)) {
+    g_object_set (G_OBJECT (acaps), "caps", gst_caps_new_simple ("audio/x-raw",
+            "endianness", G_TYPE_INT, 1234, "signed", G_TYPE_BOOLEAN, TRUE,
+            "depth", G_TYPE_INT, 16, "rate", G_TYPE_INT, freq, "channels",
+            G_TYPE_INT, channels, NULL), NULL);
+  }
+
+  if (priv->audio_codec == GST_WFD_AUDIO_AAC) {
+    acodec = g_strdup (priv->audio_encoder_aac);
+    is_enc_req = TRUE;
+  } else if (priv->audio_codec == GST_WFD_AUDIO_AC3) {
+    acodec = g_strdup (priv->audio_encoder_ac3);
+    is_enc_req = TRUE;
+  } else if (priv->audio_codec == GST_WFD_AUDIO_LPCM) {
+    GST_DEBUG_OBJECT (factory, "No codec required, raw data will be sent");
+    is_enc_req = FALSE;
+  } else {
+    GST_ERROR_OBJECT (factory, "Yet to support other than H264 format");
+    goto create_error;
+  }
+
+  if (is_enc_req) {
+    aenc = gst_element_factory_make (acodec, "audioenc");
+    if (NULL == aenc) {
+      GST_ERROR_OBJECT (factory, "failed to create audio encoder element");
+      goto create_error;
+    }
+
+    g_object_set (aenc, "compliance", -2, NULL);
+    g_object_set (aenc, "tolerance", 400000000, NULL);
+    g_object_set (aenc, "bitrate", (guint) 128000, NULL);
+    g_object_set (aenc, "rate-control", 2, NULL);
+
+    aqueue = gst_element_factory_make ("queue", "audio-queue");
+    if (!aqueue) {
+      GST_ERROR_OBJECT (factory, "failed to create audio queue element");
+      goto create_error;
+    }
+
+    gst_bin_add_many (srcbin, audiosrc, acaps, aenc, aqueue, NULL);
+
+    if (!gst_element_link_many (audiosrc, acaps, aenc, aqueue, NULL)) {
+      GST_ERROR_OBJECT (factory, "Failed to link audio src elements...");
+      goto create_error;
+    }
+  } else {
+    aqueue = gst_element_factory_make ("queue", "audio-queue");
+    if (!aqueue) {
+      GST_ERROR_OBJECT (factory, "failed to create audio queue element");
+      goto create_error;
+    }
+
+    gst_bin_add_many (srcbin, audiosrc, acaps2, audio_convert, acaps, aqueue, NULL);
+
+    if (!gst_element_link_many (audiosrc, acaps2, audio_convert, acaps, aqueue, NULL)) {
+      GST_ERROR_OBJECT (factory, "Failed to link audio src elements...");
+      goto create_error;
+    }
+  }
+
+  priv->audio_queue = aqueue;
+  if (acodec) g_free (acodec);
+
+  return TRUE;
+
+create_error:
+  if (acodec) g_free (acodec);
+  return FALSE;
+}
+
+static gboolean
+_rtsp_media_factory_wfd_create_videotest_bin (GstRTSPMediaFactoryWFD * factory,
+    GstBin * srcbin)
+{
+  GstElement *videosrc = NULL;
+  GstElement *vcaps = NULL;
+  GstElement *videoconvert = NULL;
+  GstElement *venc_caps = NULL;
+  gchar *vcodec = NULL;
+  GstElement *venc = NULL;
+  GstElement *vparse = NULL;
+  GstElement *vqueue = NULL;
+  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
+
+  priv = factory->priv;
+
+  GST_INFO_OBJECT (factory, "picked videotestsrc as video source");
+
+  videosrc = gst_element_factory_make ("videotestsrc", "videosrc");
+  if (NULL == videosrc) {
+    GST_ERROR_OBJECT (factory, "failed to create ximagesrc element");
+    goto create_error;
+  }
+
+  /* create video caps element */
+  vcaps = gst_element_factory_make ("capsfilter", "videocaps");
+  if (NULL == vcaps) {
+    GST_ERROR_OBJECT (factory, "failed to create video capsilfter element");
+    goto create_error;
+  }
+
+  g_object_set (G_OBJECT (vcaps), "caps",
+      gst_caps_new_simple ("video/x-raw",
+          "format", G_TYPE_STRING, "I420",
+          "width", G_TYPE_INT, priv->video_width,
+          "height", G_TYPE_INT, priv->video_height,
+          "framerate", GST_TYPE_FRACTION, priv->video_framerate, 1, NULL),
+      NULL);
+
+  /* create video convert element */
+  videoconvert = gst_element_factory_make ("videoconvert", "videoconvert");
+  if (NULL == videoconvert) {
+    GST_ERROR_OBJECT (factory, "failed to create video videoconvert element");
+    goto create_error;
+  }
+
+  venc_caps = gst_element_factory_make ("capsfilter", "venc_caps");
+  if (NULL == venc_caps) {
+    GST_ERROR_OBJECT (factory, "failed to create video capsilfter element");
+    goto create_error;
+  }
+
+  g_object_set (G_OBJECT (venc_caps), "caps",
+      gst_caps_new_simple ("video/x-raw",
+          "format", G_TYPE_STRING, "SN12",
+          "width", G_TYPE_INT, priv->video_width,
+          "height", G_TYPE_INT, priv->video_height,
+          "framerate", GST_TYPE_FRACTION, priv->video_framerate, 1, NULL),
+      NULL);
+
+  if (priv->video_codec == GST_WFD_VIDEO_H264)
+    vcodec = g_strdup (priv->video_encoder);
+  else {
+    GST_ERROR_OBJECT (factory, "Yet to support other than H264 format");
+    goto create_error;
+  }
+
+  venc = gst_element_factory_make (vcodec, "videoenc");
+  if (vcodec) g_free (vcodec);
+
+  if (!venc) {
+    GST_ERROR_OBJECT (factory, "failed to create video encoder element");
+    goto create_error;
+  }
+
+  g_object_set (venc, "aud", 0, NULL);
+  g_object_set (venc, "byte-stream", 1, NULL);
+  g_object_set (venc, "bitrate", 512, NULL);
+
+  vparse = gst_element_factory_make ("h264parse", "videoparse");
+  if (NULL == vparse) {
+    GST_ERROR_OBJECT (factory, "failed to create h264 parse element");
+    goto create_error;
+  }
+  g_object_set (vparse, "config-interval", 1, NULL);
+
+  vqueue = gst_element_factory_make ("queue", "video-queue");
+  if (!vqueue) {
+    GST_ERROR_OBJECT (factory, "failed to create video queue element");
+    goto create_error;
+  }
+
+  gst_bin_add_many (srcbin, videosrc, vcaps, videoconvert, venc_caps, venc, vparse, vqueue, NULL);
+  if (!gst_element_link_many (videosrc, vcaps, videoconvert, venc_caps, venc, vparse, vqueue, NULL)) {
+    GST_ERROR_OBJECT (factory, "Failed to link video src elements...");
+    goto create_error;
+  }
+
+  priv->video_queue = vqueue;
+
+  return TRUE;
+
+create_error:
+  return FALSE;
+}
+
+static gboolean
+_rtsp_media_factory_wfd_create_waylandsrc_bin (GstRTSPMediaFactoryWFD * factory,
+    GstBin * srcbin)
+{
+  GstElement *videosrc = NULL;
+  GstElement *vcaps = NULL;
+  gchar *vcodec = NULL;
+  GstElement *venc = NULL;
+  GstElement *vparse = NULL;
+  GstElement *vqueue = NULL;
+  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
+
+  priv = factory->priv;
+
+  GST_INFO_OBJECT (factory, "picked waylandsrc as video source");
+
+  videosrc = gst_element_factory_make ("waylandsrc", "videosrc");
+  if (NULL == videosrc) {
+    GST_ERROR_OBJECT (factory, "failed to create ximagesrc element");
+    goto create_error;
+  }
+
+  /* create video caps element */
+  vcaps = gst_element_factory_make ("capsfilter", "videocaps");
+  if (NULL == vcaps) {
+    GST_ERROR_OBJECT (factory, "failed to create video capsilfter element");
+    goto create_error;
+  }
+
+  g_object_set (G_OBJECT (vcaps), "caps",
+      gst_caps_new_simple ("video/x-raw",
+          "format", G_TYPE_STRING, "SN12",
+          "width", G_TYPE_INT, priv->video_width,
+          "height", G_TYPE_INT, priv->video_height,
+          "framerate", GST_TYPE_FRACTION, priv->video_framerate, 1, NULL),
+      NULL);
+
+  if (priv->video_codec == GST_WFD_VIDEO_H264)
+    vcodec = g_strdup (priv->video_encoder);
+  else {
+    GST_ERROR_OBJECT (factory, "Yet to support other than H264 format");
+    goto create_error;
+  }
+
+  venc = gst_element_factory_make (vcodec, "videoenc");
+  if (vcodec) g_free (vcodec);
+
+  if (!venc) {
+    GST_ERROR_OBJECT (factory, "failed to create video encoder element");
+    goto create_error;
+  }
+
+  g_object_set (venc, "aud", 0, NULL);
+  g_object_set (venc, "byte-stream", 1, NULL);
+  g_object_set (venc, "bitrate", 512, NULL);
+
+  vparse = gst_element_factory_make ("h264parse", "videoparse");
+  if (NULL == vparse) {
+    GST_ERROR_OBJECT (factory, "failed to create h264 parse element");
+    goto create_error;
+  }
+  g_object_set (vparse, "config-interval", 1, NULL);
+
+  vqueue = gst_element_factory_make ("queue", "video-queue");
+  if (!vqueue) {
+    GST_ERROR_OBJECT (factory, "failed to create video queue element");
+    goto create_error;
+  }
+
+  gst_bin_add_many (srcbin, videosrc, vcaps, venc, vparse, vqueue, NULL);
+  if (!gst_element_link_many (videosrc, vcaps, venc, vparse, vqueue, NULL)) {
+    GST_ERROR_OBJECT (factory, "Failed to link video src elements...");
+    goto create_error;
+  }
+
+  priv->video_queue = vqueue;
+
+  return TRUE;
+
+create_error:
+  return FALSE;
+}
+
+static gboolean
+_rtsp_media_factory_wfd_create_camera_capture_bin (GstRTSPMediaFactoryWFD *
+    factory, GstBin * srcbin)
+{
+  GstElement *videosrc = NULL;
+  GstElement *vcaps = NULL;
+  GstElement *venc = NULL;
+  GstElement *vparse = NULL;
+  GstElement *vqueue = NULL;
+  gchar *vcodec = NULL;
+  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
+
+  priv = factory->priv;
+
+  videosrc = gst_element_factory_make ("camerasrc", "videosrc");
+  if (NULL == videosrc) {
+    GST_ERROR_OBJECT (factory, "failed to create camerasrc element");
+    goto create_error;
+  }
+
+  /* create video caps element */
+  vcaps = gst_element_factory_make ("capsfilter", "videocaps");
+  if (NULL == vcaps) {
+    GST_ERROR_OBJECT (factory, "failed to create video capsilfter element");
+    goto create_error;
+  }
+
+  GST_INFO_OBJECT (factory, "picked camerasrc as video source");
+  g_object_set (G_OBJECT (vcaps), "caps",
+      gst_caps_new_simple ("video/x-raw",
+          "width", G_TYPE_INT, priv->video_width,
+          "height", G_TYPE_INT, priv->video_height,
+          "format", G_TYPE_STRING, "SN12",
+          "framerate", GST_TYPE_FRACTION, priv->video_framerate, 1, NULL),
+      NULL);
+
+  if (priv->video_codec == GST_WFD_VIDEO_H264)
+    vcodec = g_strdup (priv->video_encoder);
+  else {
+    GST_ERROR_OBJECT (factory, "Yet to support other than H264 format");
+    goto create_error;
+  }
+
+  venc = gst_element_factory_make (vcodec, "videoenc");
+  if (!venc) {
+    GST_ERROR_OBJECT (factory, "failed to create video encoder element");
+    goto create_error;
+  }
+  if (vcodec) g_free (vcodec);
+
+  g_object_set (venc, "bitrate", priv->video_bitrate, NULL);
+  g_object_set (venc, "byte-stream", 1, NULL);
+  g_object_set (venc, "append-dci", 1, NULL);
+
+  vparse = gst_element_factory_make ("h264parse", "videoparse");
+  if (NULL == vparse) {
+    GST_ERROR_OBJECT (factory, "failed to create h264 parse element");
+    goto create_error;
+  }
+  g_object_set (vparse, "config-interval", 1, NULL);
+
+  vqueue = gst_element_factory_make ("queue", "video-queue");
+  if (!vqueue) {
+    GST_ERROR_OBJECT (factory, "failed to create video queue element");
+    goto create_error;
+  }
+
+  gst_bin_add_many (srcbin, videosrc, vcaps, venc, vparse, vqueue, NULL);
+
+  if (!gst_element_link_many (videosrc, vcaps, venc, vparse, vqueue, NULL)) {
+    GST_ERROR_OBJECT (factory, "Failed to link video src elements...");
+    goto create_error;
+  }
+
+  priv->video_queue = vqueue;
+
+  return TRUE;
+
+create_error:
+  return FALSE;
+}
+
+static gboolean
+_rtsp_media_factory_wfd_create_xcapture_bin (GstRTSPMediaFactoryWFD * factory,
+    GstBin * srcbin)
+{
+  GstElement *videosrc = NULL;
+  GstElement *vcaps = NULL;
+  GstElement *venc_caps = NULL;
+  GstElement *videoconvert = NULL, *videoscale = NULL;
+  gchar *vcodec = NULL;
+  GstElement *venc = NULL;
+  GstElement *vparse = NULL;
+  GstElement *vqueue = NULL;
+  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
+
+  priv = factory->priv;
+
+  GST_INFO_OBJECT (factory, "picked ximagesrc as video source");
+
+  videosrc = gst_element_factory_make ("ximagesrc", "videosrc");
+  if (NULL == videosrc) {
+    GST_ERROR_OBJECT (factory, "failed to create ximagesrc element");
+    goto create_error;
+  }
+
+  videoscale = gst_element_factory_make ("videoscale", "videoscale");
+  if (NULL == videoscale) {
+    GST_ERROR_OBJECT (factory, "failed to create videoscale element");
+    goto create_error;
+  }
+
+  videoconvert = gst_element_factory_make ("videoconvert", "videoconvert");
+  if (NULL == videoconvert) {
+    GST_ERROR_OBJECT (factory, "failed to create videoconvert element");
+    goto create_error;
+  }
+
+  /* create video caps element */
+  vcaps = gst_element_factory_make ("capsfilter", "videocaps");
+  if (NULL == vcaps) {
+    GST_ERROR_OBJECT (factory, "failed to create video capsilfter element");
+    goto create_error;
+  }
+
+  g_object_set (G_OBJECT (vcaps), "caps",
+      gst_caps_new_simple ("video/x-raw",
+          "width", G_TYPE_INT, priv->video_width,
+          "height", G_TYPE_INT, priv->video_height,
+          "framerate", GST_TYPE_FRACTION, priv->video_framerate, 1, NULL),
+      NULL);
+
+  if (priv->video_codec == GST_WFD_VIDEO_H264)
+    vcodec = g_strdup (priv->video_encoder);
+  else {
+    GST_ERROR_OBJECT (factory, "Yet to support other than H264 format");
+    goto create_error;
+  }
+
+  venc = gst_element_factory_make (vcodec, "videoenc");
+  if (vcodec) g_free (vcodec);
+
+  if (!venc) {
+    GST_ERROR_OBJECT (factory, "failed to create video encoder element");
+    goto create_error;
+  }
+
+  g_object_set (venc, "aud", 0, NULL);
+  g_object_set (venc, "byte-stream", 1, NULL);
+  g_object_set (venc, "bitrate", 512, NULL);
+
+  venc_caps = gst_element_factory_make ("capsfilter", "venc_caps");
+  if (NULL == venc_caps) {
+    GST_ERROR_OBJECT (factory, "failed to create video capsilfter element");
+    goto create_error;
+  }
+
+  g_object_set (G_OBJECT (venc_caps), "caps",
+      gst_caps_new_simple ("video/x-h264",
+          "profile", G_TYPE_STRING, "baseline", NULL), NULL);
+
+  vparse = gst_element_factory_make ("h264parse", "videoparse");
+  if (NULL == vparse) {
+    GST_ERROR_OBJECT (factory, "failed to create h264 parse element");
+    goto create_error;
+  }
+  g_object_set (vparse, "config-interval", 1, NULL);
+
+  vqueue = gst_element_factory_make ("queue", "video-queue");
+  if (!vqueue) {
+    GST_ERROR_OBJECT (factory, "failed to create video queue element");
+    goto create_error;
+  }
+
+  gst_bin_add_many (srcbin, videosrc, videoscale, videoconvert, vcaps, venc,
+      venc_caps, vparse, vqueue, NULL);
+  if (!gst_element_link_many (videosrc, videoscale, videoconvert, vcaps, venc,
+          venc_caps, vparse, vqueue, NULL)) {
+    GST_ERROR_OBJECT (factory, "Failed to link video src elements...");
+    goto create_error;
+  }
+
+  priv->video_queue = vqueue;
+
+  return TRUE;
+
+create_error:
+  return FALSE;
+}
+
+static gboolean
+_rtsp_media_factory_wfd_create_xvcapture_bin (GstRTSPMediaFactoryWFD * factory,
+    GstBin * srcbin)
+{
+  GstElement *videosrc = NULL;
+  GstElement *vcaps = NULL;
+  gchar *vcodec = NULL;
+  GstElement *venc = NULL;
+  GstElement *vparse = NULL;
+  GstElement *vqueue = NULL;
+  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
+
+  priv = factory->priv;
+
+  GST_INFO_OBJECT (factory, "picked xvimagesrc as video source");
+
+  videosrc = gst_element_factory_make ("xvimagesrc", "videosrc");
+  if (NULL == videosrc) {
+    GST_ERROR_OBJECT (factory, "failed to create xvimagesrc element");
+    goto create_error;
+  }
+
+  /* create video caps element */
+  vcaps = gst_element_factory_make ("capsfilter", "videocaps");
+  if (NULL == vcaps) {
+    GST_ERROR_OBJECT (factory, "failed to create video capsilfter element");
+    goto create_error;
+  }
+
+  g_object_set (G_OBJECT (vcaps), "caps",
+      gst_caps_new_simple ("video/x-raw",
+          "width", G_TYPE_INT, priv->video_width,
+          "height", G_TYPE_INT, priv->video_height,
+          "format", G_TYPE_STRING, "SN12",
+          "framerate", GST_TYPE_FRACTION, priv->video_framerate, 1, NULL),
+      NULL);
+
+  if (priv->video_codec == GST_WFD_VIDEO_H264) {
+    vcodec = g_strdup (priv->video_encoder);
+  } else {
+    GST_ERROR_OBJECT (factory, "Yet to support other than H264 format");
+    goto create_error;
+  }
+
+  venc = gst_element_factory_make (vcodec, "videoenc");
+  if (!venc) {
+    GST_ERROR_OBJECT (factory, "failed to create video encoder element");
+    goto create_error;
+  }
+  g_object_set (venc, "bitrate", priv->video_bitrate, NULL);
+  g_object_set (venc, "byte-stream", 1, NULL);
+  g_object_set (venc, "append-dci", 1, NULL);
+  g_object_set (venc, "idr-period", 120, NULL);
+  g_object_set (venc, "skip-inbuf", priv->video_enc_skip_inbuf_value, NULL);
+
+  vparse = gst_element_factory_make ("h264parse", "videoparse");
+  if (NULL == vparse) {
+    GST_ERROR_OBJECT (factory, "failed to create h264 parse element");
+    goto create_error;
+  }
+  g_object_set (vparse, "config-interval", 1, NULL);
+
+  vqueue = gst_element_factory_make ("queue", "video-queue");
+  if (!vqueue) {
+    GST_ERROR_OBJECT (factory, "failed to create video queue element");
+    goto create_error;
+  }
+
+  gst_bin_add_many (srcbin, videosrc, vcaps, venc, vparse, vqueue, NULL);
+  if (!gst_element_link_many (videosrc, vcaps, venc, vparse, vqueue, NULL)) {
+    GST_ERROR_OBJECT (factory, "Failed to link video src elements...");
+    goto create_error;
+  }
+
+  priv->video_queue = vqueue;
+  if (vcodec) g_free (vcodec);
+
+  return TRUE;
+
+create_error:
+  if (vcodec) g_free (vcodec);
+  return FALSE;
+}
+
+static GstElement *
+_rtsp_media_factory_wfd_create_srcbin (GstRTSPMediaFactoryWFD * factory)
+{
+  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
+
+  GstBin *srcbin = NULL;
+  GstElement *mux = NULL;
+  GstElement *mux_queue = NULL;
+  GstElement *payload = NULL;
+  GstPad *srcpad = NULL;
+  GstPad *mux_vsinkpad = NULL;
+  GstPad *mux_asinkpad = NULL;
+
+  priv = factory->priv;
+
+  /* create source bin */
+  srcbin = GST_BIN (gst_bin_new ("srcbin"));
+  if (!srcbin) {
+    GST_ERROR_OBJECT (factory, "failed to create source bin...");
+    goto create_error;
+  }
+
+  /* create video src element */
+  switch (priv->videosrc_type) {
+    case GST_WFD_VSRC_XIMAGESRC:
+      if (!_rtsp_media_factory_wfd_create_xcapture_bin (factory, srcbin)) {
+        GST_ERROR_OBJECT (factory, "failed to create xcapture bin...");
+        goto create_error;
+      }
+      break;
+    case GST_WFD_VSRC_XVIMAGESRC:
+      if (!_rtsp_media_factory_wfd_create_xvcapture_bin (factory, srcbin)) {
+        GST_ERROR_OBJECT (factory, "failed to create xvcapture bin...");
+        goto create_error;
+      }
+      break;
+    case GST_WFD_VSRC_CAMERASRC:
+      if (!_rtsp_media_factory_wfd_create_camera_capture_bin (factory, srcbin)) {
+        GST_ERROR_OBJECT (factory, "failed to create camera capture bin...");
+        goto create_error;
+      }
+      break;
+    case GST_WFD_VSRC_VIDEOTESTSRC:
+      if (!_rtsp_media_factory_wfd_create_videotest_bin (factory, srcbin)) {
+        GST_ERROR_OBJECT (factory, "failed to create videotestsrc bin...");
+        goto create_error;
+      }
+      break;
+    case GST_WFD_VSRC_WAYLANDSRC:
+      if (!_rtsp_media_factory_wfd_create_waylandsrc_bin (factory, srcbin)) {
+        GST_ERROR_OBJECT (factory, "failed to create videotestsrc bin...");
+        goto create_error;
+      }
+      break;
+    default:
+      GST_ERROR_OBJECT (factory, "unknow mode selected...");
+      goto create_error;
+  }
+
+  mux = gst_element_factory_make ("mpegtsmux", "tsmux");
+  if (!mux) {
+    GST_ERROR_OBJECT (factory, "failed to create muxer element");
+    goto create_error;
+  }
+
+  g_object_set (mux, "wfd-mode", TRUE, NULL);
+
+  mux_queue = gst_element_factory_make ("queue", "muxer-queue");
+  if (!mux_queue) {
+    GST_ERROR_OBJECT (factory, "failed to create muxer-queue element");
+    goto create_error;
+  }
+
+  g_object_set (mux_queue, "max-size-buffers", 20000, NULL);
+
+  payload = gst_element_factory_make ("rtpmp2tpay", "pay0");
+  if (!payload) {
+    GST_ERROR_OBJECT (factory, "failed to create payload element");
+    goto create_error;
+  }
+
+  g_object_set (payload, "pt", 33, NULL);
+  g_object_set (payload, "mtu", priv->mtu_size, NULL);
+  g_object_set (payload, "rtp-flush", (gboolean) TRUE, NULL);
+
+  gst_bin_add_many (srcbin, mux, mux_queue, payload, NULL);
+
+  if (!gst_element_link_many (mux, mux_queue, payload, NULL)) {
+    GST_ERROR_OBJECT (factory, "Failed to link muxer & payload...");
+    goto create_error;
+  }
+
+  /* request video sink pad from muxer, which has elementary pid 0x1011 */
+  mux_vsinkpad = gst_element_get_request_pad (mux, "sink_4113");
+  if (!mux_vsinkpad) {
+    GST_ERROR_OBJECT (factory, "Failed to get sink pad from muxer...");
+    goto create_error;
+  }
+
+  /* request srcpad from video queue */
+  srcpad = gst_element_get_static_pad (priv->video_queue, "src");
+  if (!srcpad) {
+    GST_ERROR_OBJECT (factory, "Failed to get srcpad from video queue...");
+    goto create_error;
+  }
+
+  if (gst_pad_link (srcpad, mux_vsinkpad) != GST_PAD_LINK_OK) {
+    GST_ERROR_OBJECT (factory,
+        "Failed to link video queue src pad & muxer video sink pad...");
+    goto create_error;
+  }
+
+  gst_object_unref (mux_vsinkpad);
+  gst_object_unref (srcpad);
+  srcpad = NULL;
+
+  /* create audio source elements & add to pipeline */
+  if (!_rtsp_media_factory_wfd_create_audio_capture_bin (factory, srcbin))
+    goto create_error;
+
+  /* request audio sink pad from muxer, which has elementary pid 0x1100 */
+  mux_asinkpad = gst_element_get_request_pad (mux, "sink_4352");
+  if (!mux_asinkpad) {
+    GST_ERROR_OBJECT (factory, "Failed to get sinkpad from muxer...");
+    goto create_error;
+  }
+
+  /* request srcpad from audio queue */
+  srcpad = gst_element_get_static_pad (priv->audio_queue, "src");
+  if (!srcpad) {
+    GST_ERROR_OBJECT (factory, "Failed to get srcpad from audio queue...");
+    goto create_error;
+  }
+
+  /* link audio queue's srcpad & muxer sink pad */
+  if (gst_pad_link (srcpad, mux_asinkpad) != GST_PAD_LINK_OK) {
+    GST_ERROR_OBJECT (factory,
+        "Failed to link audio queue src pad & muxer audio sink pad...");
+    goto create_error;
+  }
+  gst_object_unref (mux_asinkpad);
+  gst_object_unref (srcpad);
+
+  if (priv->dump_ts)
+  {
+    GstPad *pad_probe = NULL;
+    pad_probe = gst_element_get_static_pad (mux, "src");
+
+    if (NULL == pad_probe) {
+      GST_INFO_OBJECT (factory, "pad for probe not created");
+    } else {
+      GST_INFO_OBJECT (factory, "pad for probe SUCCESSFUL");
+    }
+    gst_pad_add_probe (pad_probe, GST_PAD_PROBE_TYPE_BUFFER,
+        rtsp_media_wfd_dump_data, factory, NULL);
+  }
+
+  GST_DEBUG_OBJECT (factory, "successfully created source bin...");
+
+  return GST_ELEMENT_CAST (srcbin);
+
+create_error:
+  GST_ERROR_OBJECT (factory, "Failed to create pipeline");
+  return NULL;
+}
+
+static GstElement *
+rtsp_media_factory_wfd_create_element (GstRTSPMediaFactory * factory,
+    const GstRTSPUrl * url)
+{
+  GstRTSPMediaFactoryWFD *_factory = GST_RTSP_MEDIA_FACTORY_WFD_CAST (factory);
+  GstElement *element = NULL;
+
+  GST_RTSP_MEDIA_FACTORY_WFD_LOCK (factory);
+
+  element = _rtsp_media_factory_wfd_create_srcbin (_factory);
+
+  GST_RTSP_MEDIA_FACTORY_WFD_UNLOCK (factory);
+
+  return element;
+}
+
+static GstRTSPMedia *
+rtsp_media_factory_wfd_construct (GstRTSPMediaFactory * factory,
+    const GstRTSPUrl * url)
+{
+  GstRTSPMedia *media;
+  GstElement *element, *pipeline;
+  GstRTSPMediaFactoryClass *klass;
+
+  klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
+
+  if (!klass->create_pipeline)
+    goto no_create;
+
+  element = gst_rtsp_media_factory_create_element (factory, url);
+  if (element == NULL)
+    goto no_element;
+
+  /* create a new empty media */
+  media = gst_rtsp_media_new (element);
+
+  gst_rtsp_media_collect_streams (media);
+
+  pipeline = klass->create_pipeline (factory, media);
+  if (pipeline == NULL)
+    goto no_pipeline;
+
+  return media;
+
+  /* ERRORS */
+no_create:
+  {
+    g_critical ("no create_pipeline function");
+    return NULL;
+  }
+no_element:
+  {
+    g_critical ("could not create element");
+    return NULL;
+  }
+no_pipeline:
+  {
+    g_critical ("can't create pipeline");
+    g_object_unref (media);
+    return NULL;
+  }
+}
diff --git a/gst/rtsp-server/rtsp-media-factory-wfd.h b/gst/rtsp-server/rtsp-media-factory-wfd.h
new file mode 100644 (file)
index 0000000..1751a22
--- /dev/null
@@ -0,0 +1,131 @@
+/* GStreamer
+ * Copyright (C) 2015 Samsung Electronics Hyunjun Ko <zzoon.ko@samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <gst/gst.h>
+
+#include "rtsp-media-factory.h"
+
+#ifndef __GST_RTSP_MEDIA_FACTORY_WFD_H__
+#define __GST_RTSP_MEDIA_FACTORY_WFD_H__
+
+G_BEGIN_DECLS
+/* types for the media factory */
+#define GST_TYPE_RTSP_MEDIA_FACTORY_WFD              (gst_rtsp_media_factory_wfd_get_type ())
+#define GST_IS_RTSP_MEDIA_FACTORY_WFD(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_MEDIA_FACTORY_WFD))
+#define GST_IS_RTSP_MEDIA_FACTORY_WFD_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_MEDIA_FACTORY_WFD))
+#define GST_RTSP_MEDIA_FACTORY_WFD_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_MEDIA_FACTORY_WFD, GstRTSPMediaFactoryWFDClass))
+#define GST_RTSP_MEDIA_FACTORY_WFD(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_MEDIA_FACTORY_WFD, GstRTSPMediaFactoryWFD))
+#define GST_RTSP_MEDIA_FACTORY_WFD_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_MEDIA_FACTORY_WFD, GstRTSPMediaFactoryWFDClass))
+#define GST_RTSP_MEDIA_FACTORY_WFD_CAST(obj)         ((GstRTSPMediaFactoryWFD*)(obj))
+#define GST_RTSP_MEDIA_FACTORY_WFD_CLASS_CAST(klass) ((GstRTSPMediaFactoryWFDClass*)(klass))
+    enum
+{
+  GST_WFD_VSRC_XIMAGESRC,
+  GST_WFD_VSRC_XVIMAGESRC,
+  GST_WFD_VSRC_CAMERASRC,
+  GST_WFD_VSRC_VIDEOTESTSRC,
+  GST_WFD_VSRC_WAYLANDSRC
+};
+
+typedef struct _GstRTSPMediaFactoryWFD GstRTSPMediaFactoryWFD;
+typedef struct _GstRTSPMediaFactoryWFDClass GstRTSPMediaFactoryWFDClass;
+typedef struct _GstRTSPMediaFactoryWFDPrivate GstRTSPMediaFactoryWFDPrivate;
+
+/**
+ * GstRTSPMediaFactoryWFD:
+ *
+ * The definition and logic for constructing the pipeline for a media. The media
+ * can contain multiple streams like audio and video.
+ */
+struct _GstRTSPMediaFactoryWFD
+{
+  GstRTSPMediaFactory parent;
+
+  /*< private > */
+  GstRTSPMediaFactoryWFDPrivate *priv;
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+/**
+ * GstRTSPMediaFactoryWFDClass:
+ * @gen_key: convert @url to a key for caching shared #GstRTSPMedia objects.
+ *       The default implementation of this function will use the complete URL
+ *       including the query parameters to return a key.
+ * @create_element: Construct and return a #GstElement that is a #GstBin containing
+ *       the elements to use for streaming the media. The bin should contain
+ *       payloaders pay\%d for each stream. The default implementation of this
+ *       function returns the bin created from the launch parameter.
+ * @construct: the vmethod that will be called when the factory has to create the
+ *       #GstRTSPMedia for @url. The default implementation of this
+ *       function calls create_element to retrieve an element and then looks for
+ *       pay\%d to create the streams.
+ * @create_pipeline: create a new pipeline or re-use an existing one and
+ *       add the #GstRTSPMedia's element created by @construct to the pipeline.
+ * @configure: configure the media created with @construct. The default
+ *       implementation will configure the 'shared' property of the media.
+ * @media_constructed: signal emited when a media was constructed
+ * @media_configure: signal emited when a media should be configured
+ *
+ * The #GstRTSPMediaFactoryWFD class structure.
+ */
+struct _GstRTSPMediaFactoryWFDClass
+{
+  GstRTSPMediaFactoryClass parent_class;
+
+  gchar *(*gen_key) (GstRTSPMediaFactoryWFD * factory, const GstRTSPUrl * url);
+
+  GstElement *(*create_element) (GstRTSPMediaFactoryWFD * factory,
+      const GstRTSPUrl * url);
+  GstRTSPMedia *(*construct) (GstRTSPMediaFactoryWFD * factory,
+      const GstRTSPUrl * url);
+  GstElement *(*create_pipeline) (GstRTSPMediaFactoryWFD * factory,
+      GstRTSPMedia * media);
+  void (*configure) (GstRTSPMediaFactoryWFD * factory, GstRTSPMedia * media);
+
+  /* signals */
+  void (*media_constructed) (GstRTSPMediaFactoryWFD * factory,
+      GstRTSPMedia * media);
+  void (*media_configure) (GstRTSPMediaFactoryWFD * factory,
+      GstRTSPMedia * media);
+
+  /*< private > */
+  gpointer _gst_reserved[GST_PADDING_LARGE];
+};
+
+GType gst_rtsp_media_factory_wfd_get_type (void);
+
+/* creating the factory */
+GstRTSPMediaFactoryWFD *gst_rtsp_media_factory_wfd_new (void);
+GstElement *gst_rtsp_media_factory_wfd_create_element (GstRTSPMediaFactoryWFD *
+    factory, const GstRTSPUrl * url);
+
+void  gst_rtsp_media_factory_wfd_set (GstRTSPMediaFactoryWFD * factory,
+    guint8 videosrc_type, gchar *audio_device, guint64 audio_latency_time,
+    guint64 audio_buffer_time, gboolean audio_do_timestamp, guint mtu_size);
+void  gst_rtsp_media_factory_wfd_set_encoders (GstRTSPMediaFactoryWFD * factory,
+    gchar *video_encoder, gchar *audio_encoder_aac, gchar *audio_encoder_ac3);
+void  gst_rtsp_media_factory_wfd_set_dump_ts (GstRTSPMediaFactoryWFD * factory,
+    gboolean dump_ts);
+void gst_rtsp_media_factory_wfd_set_negotiated_resolution (GstRTSPMediaFactory *factory,
+   guint32 width, guint32 height);
+void gst_rtsp_media_factory_wfd_set_audio_codec (GstRTSPMediaFactory *factory,
+    guint audio_codec);
+
+G_END_DECLS
+#endif /* __GST_RTSP_MEDIA_FACTORY_WFD_H__ */
diff --git a/gst/rtsp-server/rtsp-server-wfd.c b/gst/rtsp-server/rtsp-server-wfd.c
new file mode 100644 (file)
index 0000000..4e72093
--- /dev/null
@@ -0,0 +1,332 @@
+/* GStreamer
+ * Copyright (C) 2015 Samsung Electronics Hyunjun Ko <zzoon.ko@samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+/**
+ * SECTION:rtsp-server
+ * @short_description: The main server object
+ * @see_also: #GstRTSPClient, #GstRTSPThreadPool
+ *
+ * The server object is the object listening for connections on a port and
+ * creating #GstRTSPClient objects to handle those connections.
+ *
+ * The server will listen on the address set with gst_rtsp_server_set_address()
+ * and the port or service configured with gst_rtsp_server_set_service().
+ * Use gst_rtsp_server_set_backlog() to configure the amount of pending requests
+ * that the server will keep. By default the server listens on the current
+ * network (0.0.0.0) and port 8554.
+ *
+ * The server will require an SSL connection when a TLS certificate has been
+ * set in the auth object with gst_rtsp_auth_set_tls_certificate().
+ *
+ * To start the server, use gst_rtsp_server_attach() to attach it to a
+ * #GMainContext. For more control, gst_rtsp_server_create_source() and
+ * gst_rtsp_server_create_socket() can be used to get a #GSource and #GSocket
+ * respectively.
+ *
+ * gst_rtsp_server_transfer_connection() can be used to transfer an existing
+ * socket to the RTSP server, for example from an HTTP server.
+ *
+ * Once the server socket is attached to a mainloop, it will start accepting
+ * connections. When a new connection is received, a new #GstRTSPClient object
+ * is created to handle the connection. The new client will be configured with
+ * the server #GstRTSPAuth, #GstRTSPMountPoints, #GstRTSPSessionPool and
+ * #GstRTSPThreadPool.
+ *
+ * The server uses the configured #GstRTSPThreadPool object to handle the
+ * remainder of the communication with this client.
+ *
+ * Last reviewed on 2013-07-11 (1.0.0)
+ */
+#include <stdlib.h>
+#include <string.h>
+
+#include "rtsp-server-wfd.h"
+#include "rtsp-client-wfd.h"
+
+#define GST_RTSP_WFD_SERVER_GET_PRIVATE(obj)  \
+       (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_WFD_SERVER, GstRTSPWFDServerPrivate))
+
+#define GST_RTSP_WFD_SERVER_GET_LOCK(server)  (&(GST_RTSP_WFD_SERVER_CAST(server)->priv->lock))
+#define GST_RTSP_WFD_SERVER_LOCK(server)      (g_mutex_lock(GST_RTSP_WFD_SERVER_GET_LOCK(server)))
+#define GST_RTSP_WFD_SERVER_UNLOCK(server)    (g_mutex_unlock(GST_RTSP_WFD_SERVER_GET_LOCK(server)))
+
+struct _GstRTSPWFDServerPrivate
+{
+  GMutex lock;                  /* protects everything in this struct */
+
+  /* the clients that are connected */
+  GList *clients;
+  guint64 native_resolution;
+  guint64 supported_resolution;
+  guint8 audio_codec;
+};
+
+G_DEFINE_TYPE (GstRTSPWFDServer, gst_rtsp_wfd_server, GST_TYPE_RTSP_SERVER);
+
+GST_DEBUG_CATEGORY_STATIC (rtsp_wfd_server_debug);
+#define GST_CAT_DEFAULT rtsp_wfd_server_debug
+
+static void gst_rtsp_wfd_server_get_property (GObject * object, guint propid,
+    GValue * value, GParamSpec * pspec);
+static void gst_rtsp_wfd_server_set_property (GObject * object, guint propid,
+    const GValue * value, GParamSpec * pspec);
+static void gst_rtsp_wfd_server_finalize (GObject * object);
+
+static GstRTSPClient *create_client_wfd (GstRTSPServer * server);
+static void client_connected_wfd (GstRTSPServer * server,
+    GstRTSPClient * client);
+
+static void
+gst_rtsp_wfd_server_class_init (GstRTSPWFDServerClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstRTSPServerClass *rtsp_server_class;
+
+  g_type_class_add_private (klass, sizeof (GstRTSPWFDServerPrivate));
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  rtsp_server_class = GST_RTSP_SERVER_CLASS (klass);
+
+  gobject_class->get_property = gst_rtsp_wfd_server_get_property;
+  gobject_class->set_property = gst_rtsp_wfd_server_set_property;
+  gobject_class->finalize = gst_rtsp_wfd_server_finalize;
+
+  rtsp_server_class->create_client = create_client_wfd;
+  rtsp_server_class->client_connected = client_connected_wfd;
+
+
+  GST_DEBUG_CATEGORY_INIT (rtsp_wfd_server_debug, "rtspwfdserver", 0,
+      "GstRTSPWFDServer");
+}
+
+static void
+gst_rtsp_wfd_server_init (GstRTSPWFDServer * server)
+{
+  GstRTSPWFDServerPrivate *priv = GST_RTSP_WFD_SERVER_GET_PRIVATE (server);
+
+  g_return_if_fail (priv != NULL);
+
+  server->priv = priv;
+  server->priv->native_resolution = 0;
+  server->priv->supported_resolution = 1;
+  server->priv->audio_codec = 2;
+  GST_INFO_OBJECT (server, "New server is initialized");
+}
+
+static void
+gst_rtsp_wfd_server_finalize (GObject * object)
+{
+  GstRTSPWFDServer *server = GST_RTSP_WFD_SERVER (object);
+  //GstRTSPWFDServerPrivate *priv = server->priv;
+
+  GST_DEBUG_OBJECT (server, "finalize server");
+
+  G_OBJECT_CLASS (gst_rtsp_wfd_server_parent_class)->finalize (object);
+}
+
+/**
+ * gst_rtsp_server_new:
+ *
+ * Create a new #GstRTSPWFDServer instance.
+ */
+GstRTSPWFDServer *
+gst_rtsp_wfd_server_new (void)
+{
+  GstRTSPWFDServer *result;
+
+  result = g_object_new (GST_TYPE_RTSP_WFD_SERVER, NULL);
+
+  return result;
+}
+
+static void
+gst_rtsp_wfd_server_get_property (GObject * object, guint propid,
+    GValue * value, GParamSpec * pspec)
+{
+  //GstRTSPWFDServer *server = GST_RTSP_WFD_SERVER (object);
+
+  switch (propid) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
+  }
+}
+
+static void
+gst_rtsp_wfd_server_set_property (GObject * object, guint propid,
+    const GValue * value, GParamSpec * pspec)
+{
+  //GstRTSPWFDServer *server = GST_RTSP_WFD_SERVER (object);
+
+  switch (propid) {
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
+  }
+}
+
+static gboolean
+_start_wfd (gpointer data)
+{
+  GstRTSPWFDClient *client = (GstRTSPWFDClient *) data;
+
+  GST_INFO_OBJECT (client, "WFD client is STARTing");
+
+  gst_rtsp_wfd_client_start_wfd (client);
+  return FALSE;
+}
+
+static void
+client_connected_wfd (GstRTSPServer * server, GstRTSPClient * client)
+{
+  GST_INFO_OBJECT (server, "Client is connected");
+
+  gst_rtsp_wfd_client_set_host_address (GST_RTSP_WFD_CLIENT_CAST (client),
+      gst_rtsp_server_get_address (server));
+  g_idle_add (_start_wfd, client);
+  return;
+}
+
+static GstRTSPClient *
+create_client_wfd (GstRTSPServer * server)
+{
+  GstRTSPWFDClient *client;
+  GstRTSPThreadPool *thread_pool = NULL;
+  GstRTSPSessionPool *session_pool = NULL;
+  GstRTSPMountPoints *mount_points = NULL;
+  GstRTSPAuth *auth = NULL;
+  GstRTSPWFDServerPrivate *priv = GST_RTSP_WFD_SERVER_GET_PRIVATE(server);
+
+  g_return_val_if_fail (priv != NULL, NULL);
+
+  GST_INFO_OBJECT (server, "New Client is being created");
+
+  /* a new client connected, create a session to handle the client. */
+  client = gst_rtsp_wfd_client_new ();
+
+  thread_pool = gst_rtsp_server_get_thread_pool (server);
+  session_pool = gst_rtsp_server_get_session_pool (server);
+  mount_points = gst_rtsp_server_get_mount_points (server);
+  auth = gst_rtsp_server_get_auth (server);
+
+  /* set the session pool that this client should use */
+  GST_RTSP_WFD_SERVER_LOCK (server);
+  gst_rtsp_client_set_session_pool (GST_RTSP_CLIENT_CAST (client),
+      session_pool);
+  /* set the mount points that this client should use */
+  gst_rtsp_client_set_mount_points (GST_RTSP_CLIENT_CAST (client),
+      mount_points);
+  /* set authentication manager */
+  gst_rtsp_client_set_auth (GST_RTSP_CLIENT_CAST (client), auth);
+  /* set threadpool */
+  gst_rtsp_client_set_thread_pool (GST_RTSP_CLIENT_CAST (client), thread_pool);
+
+  gst_rtsp_wfd_client_set_video_supported_resolution (client,
+        priv->supported_resolution);
+
+  gst_rtsp_wfd_client_set_video_native_resolution (client,
+        priv->native_resolution);
+
+  gst_rtsp_wfd_client_set_audio_codec (client,
+        priv->audio_codec);
+
+  GST_RTSP_WFD_SERVER_UNLOCK (server);
+
+  return GST_RTSP_CLIENT (client);
+}
+
+GstRTSPResult
+gst_rtsp_wfd_server_trigger_request (GstRTSPServer * server,
+    GstWFDTriggerType type)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GList *clients, *walk, *next;
+
+  g_return_val_if_fail (GST_IS_RTSP_SERVER (server), GST_RTSP_ERROR);
+
+  clients = gst_rtsp_server_client_filter (server, NULL, NULL);
+  if (clients == NULL) {
+    GST_ERROR_OBJECT (server, "There is no client in this server");
+  }
+
+  for (walk = clients; walk; walk = next) {
+    GstRTSPClient *client = walk->data;
+
+    next = g_list_next (walk);
+
+    res =
+        gst_rtsp_wfd_client_trigger_request (GST_RTSP_WFD_CLIENT (client),
+        type);
+    if (res != GST_RTSP_OK) {
+      GST_ERROR_OBJECT (server, "Failed to send trigger request %d", type);
+    }
+    g_object_unref (client);
+  }
+
+  return res;
+
+}
+
+GstRTSPResult
+gst_rtsp_wfd_server_set_supported_reso(GstRTSPWFDServer *server, guint64 supported_reso)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GstRTSPWFDServerPrivate *priv = GST_RTSP_WFD_SERVER_GET_PRIVATE(server);
+
+  g_return_val_if_fail (GST_IS_RTSP_WFD_SERVER (server), GST_RTSP_ERROR);
+  g_return_val_if_fail (priv != NULL, GST_RTSP_ERROR);
+
+  GST_RTSP_WFD_SERVER_LOCK (server);
+
+  priv->supported_resolution = supported_reso;
+
+  GST_RTSP_WFD_SERVER_UNLOCK (server);
+  return res;
+}
+
+GstRTSPResult
+gst_rtsp_wfd_server_set_video_native_reso (GstRTSPWFDServer *server, guint64 native_reso)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GstRTSPWFDServerPrivate *priv = GST_RTSP_WFD_SERVER_GET_PRIVATE(server);
+
+  g_return_val_if_fail (GST_IS_RTSP_WFD_SERVER (server), GST_RTSP_ERROR);
+  g_return_val_if_fail (priv != NULL, GST_RTSP_ERROR);
+
+  GST_RTSP_WFD_SERVER_LOCK (server);
+
+  priv->native_resolution = native_reso;
+
+  GST_RTSP_WFD_SERVER_UNLOCK (server);
+  return res;
+}
+
+GstRTSPResult
+gst_rtsp_wfd_server_set_audio_codec (GstRTSPWFDServer *server, guint8 audio_codec)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  GstRTSPWFDServerPrivate *priv = GST_RTSP_WFD_SERVER_GET_PRIVATE(server);
+
+  g_return_val_if_fail (GST_IS_RTSP_WFD_SERVER (server), GST_RTSP_ERROR);
+  g_return_val_if_fail (priv != NULL, GST_RTSP_ERROR);
+
+  GST_RTSP_WFD_SERVER_LOCK (server);
+
+  priv->audio_codec = audio_codec;
+
+  GST_RTSP_WFD_SERVER_UNLOCK (server);
+  return res;
+}
diff --git a/gst/rtsp-server/rtsp-server-wfd.h b/gst/rtsp-server/rtsp-server-wfd.h
new file mode 100644 (file)
index 0000000..e718e62
--- /dev/null
@@ -0,0 +1,155 @@
+/* GStreamer
+ * Copyright (C) 2015 Samsung Electronics Hyunjun Ko <zzoon.ko@samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_RTSP_SERVER_WFD_H__
+#define __GST_RTSP_SERVER_WFD_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTSPWFDServer GstRTSPWFDServer;
+typedef struct _GstRTSPWFDServerClass GstRTSPWFDServerClass;
+typedef struct _GstRTSPWFDServerPrivate GstRTSPWFDServerPrivate;
+
+#include "rtsp-session-pool.h"
+#include "rtsp-mount-points.h"
+#include "rtsp-server.h"
+#include "rtsp-client-wfd.h"
+#include "rtsp-auth.h"
+
+#define GST_TYPE_RTSP_WFD_SERVER              (gst_rtsp_wfd_server_get_type ())
+#define GST_IS_RTSP_WFD_SERVER(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_WFD_SERVER))
+#define GST_IS_RTSP_WFD_SERVER_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_WFD_SERVER))
+#define GST_RTSP_WFD_SERVER_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_WFD_SERVER, GstRTSPWFDServerClass))
+#define GST_RTSP_WFD_SERVER(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_WFD_SERVER, GstRTSPWFDServer))
+#define GST_RTSP_WFD_SERVER_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_WFD_SERVER, GstRTSPWFDServerClass))
+#define GST_RTSP_WFD_SERVER_CAST(obj)         ((GstRTSPWFDServer*)(obj))
+#define GST_RTSP_WFD_SERVER_CLASS_CAST(klass) ((GstRTSPWFDServerClass*)(klass))
+
+/**
+ * GstRTSPWFDServer:
+ *
+ * This object listens on a port, creates and manages the clients connected to
+ * it.
+ */
+struct _GstRTSPWFDServer {
+  GstRTSPServer parent;
+
+  /*< private >*/
+  GstRTSPWFDServerPrivate *priv;
+  gpointer _gst_reserved[GST_PADDING];
+};
+
+/**
+ * GstRTSPServerClass:
+ * @create_client: Create, configure a new GstRTSPClient
+ *          object that handles the new connection on @socket. The default
+ *          implementation will create a GstRTSPClient and will configure the
+ *          mount-points, auth, session-pool and thread-pool on the client.
+ * @client_connected: emited when a new client connected.
+ *
+ * The RTSP server class structure
+ */
+struct _GstRTSPWFDServerClass {
+  GstRTSPServerClass  parent_class;
+
+  /*< private >*/
+  gpointer         _gst_reserved[GST_PADDING_LARGE];
+};
+
+GType                 gst_rtsp_wfd_server_get_type             (void);
+GstRTSPWFDServer *    gst_rtsp_wfd_server_new                  (void);
+GstRTSPResult         gst_rtsp_wfd_server_trigger_request      (GstRTSPServer *server, GstWFDTriggerType type);
+
+GstRTSPResult         gst_rtsp_wfd_server_set_supported_reso (GstRTSPWFDServer *server, guint64 supported_reso);
+GstRTSPResult         gst_rtsp_wfd_server_set_video_native_reso    (GstRTSPWFDServer *server, guint64 native_reso);
+GstRTSPResult         gst_rtsp_wfd_server_set_audio_codec    (GstRTSPWFDServer *server, guint8 audio_codec);
+
+#if 0
+void                  gst_rtsp_server_set_address          (GstRTSPServer *server, const gchar *address);
+gchar *               gst_rtsp_server_get_address          (GstRTSPServer *server);
+
+void                  gst_rtsp_server_set_service          (GstRTSPServer *server, const gchar *service);
+gchar *               gst_rtsp_server_get_service          (GstRTSPServer *server);
+
+void                  gst_rtsp_server_set_backlog          (GstRTSPServer *server, gint backlog);
+gint                  gst_rtsp_server_get_backlog          (GstRTSPServer *server);
+
+int                   gst_rtsp_server_get_bound_port       (GstRTSPServer *server);
+
+void                  gst_rtsp_server_set_session_pool     (GstRTSPServer *server, GstRTSPSessionPool *pool);
+GstRTSPSessionPool *  gst_rtsp_server_get_session_pool     (GstRTSPServer *server);
+
+void                  gst_rtsp_server_set_mount_points     (GstRTSPServer *server, GstRTSPMountPoints *mounts);
+GstRTSPMountPoints *  gst_rtsp_server_get_mount_points     (GstRTSPServer *server);
+
+void                  gst_rtsp_server_set_auth             (GstRTSPServer *server, GstRTSPAuth *auth);
+GstRTSPAuth *         gst_rtsp_server_get_auth             (GstRTSPServer *server);
+
+void                  gst_rtsp_server_set_thread_pool      (GstRTSPServer *server, GstRTSPThreadPool *pool);
+GstRTSPThreadPool *   gst_rtsp_server_get_thread_pool      (GstRTSPServer *server);
+
+gboolean              gst_rtsp_server_transfer_connection  (GstRTSPServer * server, GSocket *socket,
+                                                            const gchar * ip, gint port,
+                                                            const gchar *initial_buffer);
+
+gboolean              gst_rtsp_server_io_func              (GSocket *socket, GIOCondition condition,
+                                                            GstRTSPServer *server);
+
+GSocket *             gst_rtsp_server_create_socket        (GstRTSPServer *server,
+                                                            GCancellable  *cancellable,
+                                                            GError **error);
+GSource *             gst_rtsp_server_create_source        (GstRTSPServer *server,
+                                                            GCancellable * cancellable,
+                                                            GError **error);
+guint                 gst_rtsp_server_attach               (GstRTSPServer *server,
+                                                            GMainContext *context);
+/**
+ * GstRTSPServerClientFilterFunc:
+ * @server: a #GstRTSPServer object
+ * @client: a #GstRTSPClient in @server
+ * @user_data: user data that has been given to gst_rtsp_server_client_filter()
+ *
+ * This function will be called by the gst_rtsp_server_client_filter(). An
+ * implementation should return a value of #GstRTSPFilterResult.
+ *
+ * When this function returns #GST_RTSP_FILTER_REMOVE, @client will be removed
+ * from @server.
+ *
+ * A return value of #GST_RTSP_FILTER_KEEP will leave @client untouched in
+ * @server.
+ *
+ * A value of #GST_RTSP_FILTER_REF will add @client to the result #GList of
+ * gst_rtsp_server_client_filter().
+ *
+ * Returns: a #GstRTSPFilterResult.
+ */
+typedef GstRTSPFilterResult (*GstRTSPServerClientFilterFunc)  (GstRTSPServer *server,
+                                                               GstRTSPClient *client,
+                                                               gpointer user_data);
+
+GList *                gst_rtsp_server_client_filter    (GstRTSPServer *server,
+                                                         GstRTSPServerClientFilterFunc func,
+                                                         gpointer user_data);
+#endif
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_SERVER_WFD_H__ */
index 1c4366e..4c1f3b7 100644 (file)
@@ -1103,6 +1103,9 @@ again:
       inetaddr = g_inet_address_new_any (family);
   }
 
+  /* FIXME-WFD : Force to set 19000 as port number */
+  tmp_rtp = 19000;
+
   rtp_sockaddr = g_inet_socket_address_new (inetaddr, tmp_rtp);
   if (!g_socket_bind (rtp_socket, rtp_sockaddr, FALSE, NULL)) {
     g_object_unref (rtp_sockaddr);
@@ -1280,10 +1283,15 @@ alloc_ports (GstRTSPStream * stream)
       G_SOCKET_FAMILY_IPV4, priv->udpsrc_v4, priv->udpsink,
       &priv->server_port_v4, &priv->server_addr_v4);
 
+  /* FIXME-WFD : force to disable ipv6 mode in WFD mode */
+#if 0
   priv->have_ipv6 =
       alloc_ports_one_family (stream, priv->pool, priv->buffer_size,
       G_SOCKET_FAMILY_IPV6, priv->udpsrc_v6, priv->udpsink,
       &priv->server_port_v6, &priv->server_addr_v6);
+#else
+  priv->have_ipv6 = FALSE;
+#endif
 
   return priv->have_ipv4 || priv->have_ipv6;
 }
@@ -3154,6 +3162,21 @@ gst_rtsp_stream_get_current_seqnum (GstRTSPStream * stream)
   return seqnum;
 }
 
+guint64
+gst_rtsp_stream_get_udp_sent_bytes (GstRTSPStream *stream)
+{
+  GstRTSPStreamPrivate *priv;
+  guint64 bytes = 0;
+
+  g_return_val_if_fail (GST_IS_RTSP_STREAM (stream), 0);
+
+  priv = stream->priv;
+
+  g_object_get (G_OBJECT (priv->udpsink[0]), "bytes-to-serve", &bytes, NULL);
+
+  return bytes;
+}
+
 /**
  * gst_rtsp_stream_transport_filter:
  * @stream: a #GstRTSPStream
index 0042f67..eca190c 100644 (file)
@@ -155,6 +155,7 @@ gboolean          gst_rtsp_stream_query_stop       (GstRTSPStream * stream,
 
 void              gst_rtsp_stream_set_seqnum_offset          (GstRTSPStream *stream, guint16 seqnum);
 guint16           gst_rtsp_stream_get_current_seqnum          (GstRTSPStream *stream);
+guint64           gst_rtsp_stream_get_udp_sent_bytes          (GstRTSPStream *stream);
 void              gst_rtsp_stream_set_retransmission_time     (GstRTSPStream *stream, GstClockTime time);
 GstClockTime      gst_rtsp_stream_get_retransmission_time     (GstRTSPStream *stream);
 guint             gst_rtsp_stream_get_retransmission_pt       (GstRTSPStream * stream);
diff --git a/packaging/common.tar.bz2 b/packaging/common.tar.bz2
new file mode 100644 (file)
index 0000000..9f0dd3f
Binary files /dev/null and b/packaging/common.tar.bz2 differ
diff --git a/packaging/gst-rtsp-server.spec b/packaging/gst-rtsp-server.spec
new file mode 100644 (file)
index 0000000..0474352
--- /dev/null
@@ -0,0 +1,76 @@
+Name:       gst-rtsp-server
+Summary:    Multimedia Framework Library
+Version:    1.6.1
+Release:    0
+Url:        http://gstreamer.freedesktop.org/
+Group:      System/Libraries
+License:    LGPL-2.0+
+Source:     http://gstreamer.freedesktop.org/src/gst-rtsp-server/gst-rtsp-server-%{version}.tar.xz
+Source100:  common.tar.bz2
+Requires(post):  /sbin/ldconfig
+Requires(postun):  /sbin/ldconfig
+BuildRequires:  pkgconfig(gstreamer-1.0)
+BuildRequires:  pkgconfig(gstreamer-plugins-base-1.0)
+
+BuildRoot:  %{_tmppath}/%{name}-%{version}-build
+
+%description
+
+%package devel
+Summary:    Multimedia Framework RTSP server library (DEV)
+Group:      Development/Libraries
+Requires:   %{name} = %{version}-%{release}
+
+%description devel
+
+%package factory
+Summary:    Multimedia Framework RTSP server Library (Factory)
+Group:      Development/Libraries
+Requires:   %{name} = %{version}-%{release}
+
+%description factory
+
+%prep
+%setup -q -n gst-rtsp-server-%{version}
+%setup -q -T -D -a 100 
+
+%build
+
+NOCONFIGURE=1 ./autogen.sh
+
+CFLAGS+=" -DEXPORT_API=\"__attribute__((visibility(\\\"default\\\")))\" "; export CFLAGS
+LDFLAGS+="-Wl,--rpath=%{_prefix}/lib -Wl,--hash-style=both -Wl,--as-needed"; export LDFLAGS
+
+# always enable sdk build. This option should go away
+%configure --disable-static
+
+# Call make instruction with smp support
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+mkdir -p %{buildroot}/%{_datadir}/license
+cp -rf %{_builddir}/%{name}-%{version}/COPYING %{buildroot}%{_datadir}/license/%{name}
+
+%clean
+rm -rf %{buildroot}
+
+%post
+/sbin/ldconfig
+
+%postun
+/sbin/ldconfig
+
+%files
+%manifest gst-rtsp-server.manifest
+%defattr(-,root,root,-)
+%{_datadir}/license/%{name}
+%{_libdir}/*.so.*
+
+%files devel
+%defattr(-,root,root,-)
+%{_libdir}/*.so
+%{_includedir}/gstreamer-1.0/gst/rtsp-server/rtsp-*.h
+%{_includedir}/gstreamer-1.0/gst/rtsp-server/gstwfd*.h
+%{_libdir}/pkgconfig/*