Merge branch 'move_subdir_rtsp-server' into tizen_gst_1.19.2_mono
authorGilbok Lee <gilbok.lee@samsung.com>
Tue, 25 Jan 2022 04:34:47 +0000 (13:34 +0900)
committerGilbok Lee <gilbok.lee@samsung.com>
Tue, 25 Jan 2022 04:34:47 +0000 (13:34 +0900)
Change-Id: I15c0ddc678464e2c8b225170f51f9c0ff3aa10d0

28 files changed:
1  2 
subprojects/gst-rtsp-server/.gitlab-ci.yml
subprojects/gst-rtsp-server/NEWS
subprojects/gst-rtsp-server/gst-rtsp-server.doap
subprojects/gst-rtsp-server/gst/rtsp-server/gstwfdmessage-ext.c
subprojects/gst-rtsp-server/gst/rtsp-server/gstwfdmessage-ext.h
subprojects/gst-rtsp-server/gst/rtsp-server/gstwfdmessage.c
subprojects/gst-rtsp-server/gst/rtsp-server/gstwfdmessage.h
subprojects/gst-rtsp-server/gst/rtsp-server/meson.build
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-client-ext.c
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-client-ext.h
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-client-wfd.c
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-client-wfd.h
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-client.c
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-client.h
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-ext.c
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-ext.h
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory-uri.c
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory-wfd.c
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media-factory-wfd.h
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.c
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-media.h
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-server-object.h
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-server-wfd.c
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-server-wfd.h
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-server.c
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-stream.c
subprojects/gst-rtsp-server/gst/rtsp-server/rtsp-stream.h
subprojects/gst-rtsp-server/gst/rtsp-sink/gstrtspclientsink.c

@@@ -1,1 -1,1 +1,1 @@@
 -include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/master/gitlab/ci_template.yml"
 +include: "https://gitlab.freedesktop.org/gstreamer/gst-ci/raw/1.16/gitlab/ci_template.yml"
@@@ -197,26 -197,6 +197,26 @@@ RTSP server library based on GStreame
     <name></name>
     <created>2017-07-14</created>
     <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-rtsp-server/gst-rtsp-server-1.12.2.tar.xz" />
 +  </Version>
 + </release>
 +
 + <release>
 +  <Version>
 +   <revision>1.12.1</revision>
 +   <branch>1.12</branch>
 +   <name></name>
 +   <created>2017-06-20</created>
 +   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-rtsp-server/gst-rtsp-server-1.12.1.tar.xz" />
 +  </Version>
 + </release>
 +
 + <release>
 +  <Version>
 +   <revision>1.12.2</revision>
 +   <branch>1.12</branch>
 +   <name></name>
 +   <created>2017-07-14</created>
 +   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gst-rtsp-server/gst-rtsp-server-1.12.2.tar.xz" />
    </Version>
   </release>
  
index 73ce8b1,0000000..73ce8b1
mode 100644,000000..100644
--- /dev/null
@@@ -1,520 -1,0 +1,520 @@@
 +/* GStreamer
 + * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.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-ext.h"
 +
 +#define FREE_STRING(field)              do { g_free (field); (field) = NULL; } while(0)
 +
 +G_DEFINE_BOXED_TYPE (GstWFDExtMessage, gst_wfd_ext_message, NULL, NULL);
 +
 +/**
 + * gst_wfd_ext_message_new:
 + * @msg: (out) (transfer full): pointer to new #GstWFDExtMessage
 + *
 + * Allocate a new GstWFDExtMessage and store the result in @msg.
 + *
 + * Returns: a #GstWFDResult.
 + */
 +GstWFDResult
 +gst_wfd_ext_message_new (GstWFDExtMessage ** msg)
 +{
 +  GstWFDExtMessage *newmsg;
 +
 +  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
 +
 +  newmsg = g_new0 (GstWFDExtMessage, 1);
 +
 +  *msg = newmsg;
 +
 +  return gst_wfd_ext_message_init (newmsg);
 +}
 +
 +/**
 + * gst_wfd_ext_message_init:
 + * @msg: a #GstWFDExtMessage
 + *
 + * Initialize @msg so that its contents are as if it was freshly allocated
 + * with gst_wfd_ext_message_new(). This function is mostly used to initialize a message
 + * allocated on the stack. gst_wfd_ext_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_ext_message_init (GstWFDExtMessage * msg)
 +{
 +  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
 +
 +  return GST_WFD_OK;
 +}
 +
 +/**
 + * gst_wfd_ext_message_uninit:
 + * @msg: a #GstWFDExtMessage
 + *
 + * 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_ext_message_init().
 + *
 + * Returns: a #GstWFDResult.
 + */
 +GstWFDResult
 +gst_wfd_ext_message_uninit (GstWFDExtMessage * msg)
 +{
 +  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
 +
 +  if (msg->tizen_retransmission)
 +    FREE_STRING (msg->tizen_retransmission);
 +
 +  if (msg->tizen_fec)
 +    FREE_STRING (msg->tizen_fec);
 +
 +  if (msg->tizen_latency_mode)
 +    FREE_STRING (msg->tizen_latency_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, GstWFDExtMessage * 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_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_TIZEN_WFD_RESTRANSMISSION)) {
 +    msg->tizen_retransmission = g_new0 (GstWFDTizenRetransmission, 1);
 +    if (strlen (v)) {
 +      if (!strstr (v, "none")) {
 +        WFD_SKIP_SPACE (v);
 +        WFD_READ_UINT32_DIGIT (msg->tizen_retransmission->rtp_port);
 +        WFD_SKIP_SPACE (v);
 +        WFD_READ_UINT32_DIGIT (msg->tizen_retransmission->rtcp_port);
 +      }
 +    }
 +  }
 +  else if (!g_strcmp0 (attr, GST_STRING_TIZEN_WFD_FEC)) {
 +    msg->tizen_fec = g_new0 (GstWFDTizenFec, 1);
 +    if (strlen (v)) {
 +      if (!strstr (v, "none")) {
 +        WFD_SKIP_SPACE (v);
 +        WFD_READ_UINT32_DIGIT (msg->tizen_fec->t_max);
 +        WFD_SKIP_SPACE (v);
 +        WFD_READ_UINT32_DIGIT (msg->tizen_fec->p_max);
 +      }
 +    }
 +  } else if (!g_strcmp0 (attr, GST_STRING_TIZEN_WFD_LATENCY_MODE)) {
 +    msg->tizen_latency_mode = g_new0 (GstWFDTizenLatencyMode, 1);
 +    if (strlen (v)) {
 +      if (strstr (v, GST_STRING_TIZEN_WFD_LATENCY_LOW)) {
 +        msg->tizen_latency_mode->latency_mode = GST_WFD_TIZEN_LATENCY_LOW;
 +      } else if (strstr (v, GST_STRING_TIZEN_WFD_LATENCY_MID)) {
 +        msg->tizen_latency_mode->latency_mode = GST_WFD_TIZEN_LATENCY_MID;
 +      } else if (strstr (v, GST_STRING_TIZEN_WFD_LATENCY_HIGH)) {
 +        msg->tizen_latency_mode->latency_mode = GST_WFD_TIZEN_LATENCY_HIGH;
 +      } else {
 +        msg->tizen_latency_mode->latency_mode = GST_WFD_TIZEN_LATENCY_NONE;
 +      }
 +    }
 +  }
 +
 +  return;
 +}
 +
 +/**
 + * gst_wfd_ext_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_ext_message_parse_buffer (const guint8 * data, guint size,
 +    GstWFDExtMessage * 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_ext_message_free:
 + * @msg: a #GstWFDExtMessage
 + *
 + * 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_ext_message_new().
 + *
 + * Returns: a #GstWFDResult.
 + */
 +GstWFDResult
 +gst_wfd_ext_message_free (GstWFDExtMessage * msg)
 +{
 +  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
 +
 +  gst_wfd_ext_message_uninit (msg);
 +  g_free (msg);
 +
 +  return GST_WFD_OK;
 +}
 +
 +/**
 + * gst_wfd_ext_message_as_text:
 + * @msg: a #GstWFDExtMessage
 + *
 + * Convert the contents of @msg to a text string.
 + *
 + * Returns: A dynamically allocated string representing the WFD description.
 + */
 +gchar *
 +gst_wfd_ext_message_as_text (const GstWFDExtMessage * msg)
 +{
 +  /* change all vars so they match rfc? */
 +  GString *lines;
 +
 +  g_return_val_if_fail (msg != NULL, NULL);
 +
 +  lines = g_string_new ("");
 +
 +  if (msg->tizen_retransmission) {
 +    g_string_append_printf (lines, GST_STRING_TIZEN_WFD_RESTRANSMISSION);
 +    g_string_append_printf (lines, ":");
 +    g_string_append_printf (lines, " %d", msg->tizen_retransmission->rtp_port);
 +    g_string_append_printf (lines, " %d", msg->tizen_retransmission->rtcp_port);
 +    g_string_append_printf (lines, "\r\n");
 +  }
 +
 +  if (msg->tizen_fec) {
 +    g_string_append_printf (lines, GST_STRING_TIZEN_WFD_FEC);
 +    g_string_append_printf (lines, ":");
 +    g_string_append_printf (lines, " %d", msg->tizen_fec->t_max);
 +    g_string_append_printf (lines, " %d", msg->tizen_fec->p_max);
 +    g_string_append_printf (lines, "\r\n");
 +  }
 +
 +  if (msg->tizen_latency_mode) {
 +    g_string_append_printf (lines, GST_STRING_TIZEN_WFD_LATENCY_MODE);
 +    g_string_append_printf (lines, ":");
 +
 +    if (msg->tizen_latency_mode->latency_mode == GST_WFD_TIZEN_LATENCY_LOW)
 +      g_string_append_printf (lines, " " GST_STRING_TIZEN_WFD_LATENCY_LOW);
 +    else if (msg->tizen_latency_mode->latency_mode == GST_WFD_TIZEN_LATENCY_MID)
 +      g_string_append_printf (lines, " " GST_STRING_TIZEN_WFD_LATENCY_MID);
 +    else if (msg->tizen_latency_mode->latency_mode ==
 +        GST_WFD_TIZEN_LATENCY_HIGH)
 +      g_string_append_printf (lines, " " GST_STRING_TIZEN_WFD_LATENCY_HIGH);
 +    else
 +      g_string_append_printf (lines, " none");
 +
 +    g_string_append_printf (lines, "\r\n");
 +  }
 +
 +  return g_string_free (lines, FALSE);
 +}
 +
 +gchar *
 +gst_wfd_ext_message_param_names_as_text (const GstWFDExtMessage * msg)
 +{
 +  /* change all vars so they match rfc? */
 +  GString *lines;
 +  g_return_val_if_fail (msg != NULL, NULL);
 +
 +  lines = g_string_new ("");
 +
 +  if (msg->tizen_retransmission) {
 +    g_string_append_printf (lines, GST_STRING_TIZEN_WFD_RESTRANSMISSION);
 +    g_string_append_printf (lines, "\r\n");
 +  }
 +  if (msg->tizen_fec) {
 +    g_string_append_printf (lines, GST_STRING_TIZEN_WFD_FEC);
 +    g_string_append_printf (lines, "\r\n");
 +  }
 +  if (msg->tizen_latency_mode) {
 +    g_string_append_printf (lines, GST_STRING_TIZEN_WFD_LATENCY_MODE);
 +    g_string_append_printf (lines, "\r\n");
 +  }
 +
 +  return g_string_free (lines, FALSE);
 +}
 +
 +/**
 + * gst_wfd_ext_message_dump:
 + * @msg: a #GstWFDExtMessage
 + *
 + * Dump the parsed contents of @msg to stdout.
 + *
 + * Returns: a #GstWFDResult.
 + */
 +GstWFDResult
 +gst_wfd_ext_message_dump (const GstWFDExtMessage * msg)
 +{
 +  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
 +
 +  if (msg->tizen_retransmission) {
 +    g_print ("tizen_wfd_retransmission: %d %d",
 +        msg->tizen_retransmission->rtp_port,
 +        msg->tizen_retransmission->rtcp_port);
 +    g_print ("\r\n");
 +  }
 +
 +  if (msg->tizen_fec) {
 +    g_print ("tizen_wfd_fec: %d %d", msg->tizen_fec->t_max, msg->tizen_fec->p_max);
 +    g_print ("\r\n");
 +  }
 +
 +  if (msg->tizen_latency_mode) {
 +    g_print ("tizen_wfd_latency_mode:");
 +
 +    if (msg->tizen_latency_mode->latency_mode == GST_WFD_TIZEN_LATENCY_LOW)
 +      g_print (" low");
 +    else if (msg->tizen_latency_mode->latency_mode == GST_WFD_TIZEN_LATENCY_MID)
 +      g_print (" mid");
 +    else if (msg->tizen_latency_mode->latency_mode == GST_WFD_TIZEN_LATENCY_HIGH)
 +      g_print (" high");
 +    else
 +      g_print (" none");
 +
 +    g_print ("\r\n");
 +  }
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_ext_message_set_tizen_retransmission (GstWFDExtMessage * msg,
 +    guint rtp_port, guint rtcp_port)
 +{
 +  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
 +
 +  if (!msg->tizen_retransmission)
 +    msg->tizen_retransmission = g_new0 (GstWFDTizenRetransmission, 1);
 +
 +  msg->tizen_retransmission->rtp_port = rtp_port;
 +  msg->tizen_retransmission->rtcp_port = rtcp_port;
 +
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_ext_message_get_tizen_retransmission (GstWFDExtMessage * msg,
 +    guint * rtp_port, guint * rtcp_port)
 +{
 +  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
 +  g_return_val_if_fail (msg->tizen_retransmission != NULL, GST_WFD_EINVAL);
 +  g_return_val_if_fail (rtp_port != NULL, GST_WFD_EINVAL);
 +  g_return_val_if_fail (rtcp_port != NULL, GST_WFD_EINVAL);
 +
 +  *rtp_port = msg->tizen_retransmission->rtp_port;
 +  *rtcp_port = msg->tizen_retransmission->rtcp_port;
 +
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_ext_message_set_tizen_fec (GstWFDExtMessage * msg, guint t_max,
 +    guint p_max)
 +{
 +  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
 +
 +  if (!msg->tizen_fec)
 +    msg->tizen_fec = g_new0 (GstWFDTizenFec, 1);
 +
 +  msg->tizen_fec->t_max = t_max;
 +  msg->tizen_fec->p_max = p_max;
 +
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_ext_message_get_tizen_fec (GstWFDExtMessage * msg, guint * t_max,
 +    guint * p_max)
 +{
 +  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
 +  g_return_val_if_fail (msg->tizen_fec != NULL, GST_WFD_EINVAL);
 +  g_return_val_if_fail (t_max != NULL, GST_WFD_EINVAL);
 +  g_return_val_if_fail (p_max != NULL, GST_WFD_EINVAL);
 +
 +  *t_max = msg->tizen_fec->t_max;
 +  *p_max = msg->tizen_fec->p_max;
 +
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_ext_message_set_tizen_latency_mode (GstWFDExtMessage * msg,
 +    guint latency_mode)
 +{
 +  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
 +
 +  if (!msg->tizen_latency_mode)
 +    msg->tizen_latency_mode = g_new0 (GstWFDTizenLatencyMode, 1);
 +
 +  msg->tizen_latency_mode->latency_mode = latency_mode;
 +
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_ext_message_get_tizen_latency_mode (GstWFDExtMessage * msg,
 +    guint * latency_mode)
 +{
 +  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
 +  g_return_val_if_fail (msg->tizen_latency_mode != NULL, GST_WFD_EINVAL);
 +  g_return_val_if_fail (latency_mode != NULL, GST_WFD_EINVAL);
 +
 +  *latency_mode = msg->tizen_latency_mode->latency_mode;
 +
 +  return GST_WFD_OK;
 +}
index 02f323c,0000000..02f323c
mode 100755,000000..100755
--- /dev/null
@@@ -1,153 -1,0 +1,153 @@@
 +/* GStreamer
 + * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.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_EXT_MESSAGE_H__
 +#define __GST_WFD_EXT_MESSAGE_H__
 +
 +#include <glib.h>
 +#include "gstwfdmessage.h"
 +
 +G_BEGIN_DECLS
 +
 +#define GST_STRING_TIZEN_WFD_RESTRANSMISSION "tizen_wfd_retransmission"
 +#define GST_STRING_TIZEN_WFD_FEC             "tizen_wfd_fec"
 +#define GST_STRING_TIZEN_WFD_LATENCY_MODE    "tizen_wfd_latency_mode"
 +#define GST_STRING_TIZEN_WFD_LATENCY_LOW     "low"
 +#define GST_STRING_TIZEN_WFD_LATENCY_MID     "mid"
 +#define GST_STRING_TIZEN_WFD_LATENCY_HIGH    "high"
 +
 +typedef enum {
 +  GST_WFD_TIZEN_LATENCY_NONE,
 +  GST_WFD_TIZEN_LATENCY_LOW,
 +  GST_WFD_TIZEN_LATENCY_MID,
 +  GST_WFD_TIZEN_LATENCY_HIGH
 +} GstWFDTizenLatencyEnum;
 +
 +typedef struct {
 +  guint rtp_port;
 +  guint rtcp_port;
 +} GstWFDTizenRetransmission;
 +
 +typedef struct {
 +  guint t_max;        /*TMAX is the maximum number of source symbols in a block*/
 +  guint p_max;        /*PMAX is the maximum number of parity symbols in a block*/
 +} GstWFDTizenFec;
 +
 +typedef struct {
 +  guint latency_mode;
 +} GstWFDTizenLatencyMode;
 +
 +typedef struct {
 +  GstWFDTizenRetransmission *tizen_retransmission;
 +  GstWFDTizenFec            *tizen_fec;
 +  GstWFDTizenLatencyMode    *tizen_latency_mode;
 +} GstWFDExtMessage;
 +
 +
 +GST_RTSP_SERVER_API
 +GType                   gst_wfd_ext_message_get_type            (void);
 +
 +#define GST_TYPE_WFD_EXT_MESSAGE           (gst_wfd_ext_message_get_type())
 +#define GST_WFD_EXT_MESSAGE_CAST(object)   ((GstWFDExtMessage *)(object))
 +#define GST_WFD_EXT_MESSAGE(object)        (GST_WFD_EXT_MESSAGE_CAST(object))
 +
 +/* Session descriptions */
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_ext_message_new                 (GstWFDExtMessage **msg);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_ext_message_init                (GstWFDExtMessage *msg);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_ext_message_uninit              (GstWFDExtMessage *msg);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_ext_message_free                (GstWFDExtMessage *msg);
 +
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_ext_message_parse_buffer        (const guint8 *data, guint size, GstWFDExtMessage *msg);
 +
 +GST_RTSP_SERVER_API
 +gchar*                  gst_wfd_ext_message_as_text             (const GstWFDExtMessage *msg);
 +
 +GST_RTSP_SERVER_API
 +gchar*                  gst_wfd_ext_message_param_names_as_text (const GstWFDExtMessage *msg);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_ext_message_dump                (const GstWFDExtMessage *msg);
 +
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_ext_message_set_tizen_retransmission (GstWFDExtMessage *msg,
 +                                                                  guint rtp_port,
 +                                                                  guint rtcp_port);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_ext_message_get_tizen_retransmission (GstWFDExtMessage *msg,
 +                                                                  guint *rtp_port,
 +                                                                  guint *rtcp_port);
 +
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_ext_message_set_tizen_fec (GstWFDExtMessage *msg,
 +                                                       guint t_max,
 +                                                       guint p_max);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_ext_message_get_tizen_fec (GstWFDExtMessage *msg,
 +                                                       guint *t_max,
 +                                                       guint *p_max);
 +
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_ext_message_set_tizen_latency_mode (GstWFDExtMessage *msg,
 +                                                                guint latency_mode);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_ext_message_get_tizen_latency_mode (GstWFDExtMessage *msg,
 +                                                                guint *latency_mode);
 +
 +G_END_DECLS
 +
 +#endif /* __GST_WFD_EXT_MESSAGE_H__ */
index ee8ccce,0000000..ee8ccce
mode 100755,000000..100755
--- /dev/null
@@@ -1,2955 -1,0 +1,2955 @@@
 +/* 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)              do { g_free (field); (field) = NULL; } while(0)
 +#define REPLACE_STRING(field, val)      do { FREE_STRING(field); (field) = g_strdup (val); } while(0)
 +
 +#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->wfd2_audio_codecs) {
 +    guint i = 0;
 +    if (msg->wfd2_audio_codecs->list) {
 +      for (; i < msg->wfd2_audio_codecs->count; i++) {
 +        FREE_STRING(msg->wfd2_audio_codecs->list[i].audio_format);
 +        msg->wfd2_audio_codecs->list[i].modes = 0;
 +        msg->wfd2_audio_codecs->list[i].latency = 0;
 +      }
 +      FREE_STRING(msg->wfd2_audio_codecs->list);
 +    }
 +    FREE_STRING(msg->wfd2_audio_codecs);
 +  }
 +
 +  if (msg->direct_video_formats) {
 +    FREE_STRING(msg->direct_video_formats->list);
 +    FREE_STRING(msg->direct_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);
 +
 +  if (msg->direct_mode)
 +    FREE_STRING(msg->direct_mode);
 +
 +  if (msg->tcp_ports)
 +    FREE_STRING(msg->tcp_ports);
 +
 +  if (msg->buf_len)
 +    FREE_STRING(msg->buf_len);
 +
 +  if (msg->audio_status)
 +    FREE_STRING(msg->audio_status);
 +
 +  if (msg->video_status)
 +    FREE_STRING(msg->video_status);
 +
 +  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)
 +#define WFD_READ_UINT64_DIGIT(field) _read_string_space_ended (temp, sizeof (temp), v); v+=strlen(temp); field = strtoull (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)) {
 +      WFD_SKIP_SPACE (v);
 +      if (strncmp (v, "none", 4)) {
 +        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 {
 +        msg->audio_codecs->count = 0;
 +        msg->audio_codecs->list = NULL;
 +      }
 +    }
 +  } else if (!g_strcmp0 (attr, GST_STRING_WFD_VIDEO_FORMATS)) {
 +    msg->video_formats = g_new0 (GstWFDVideoCodeclist, 1);
 +    if (strlen (v)) {
 +      WFD_SKIP_SPACE (v);
 +      if (strncmp (v, "none", 4)) {
 +        msg->video_formats->count = 1;
 +        msg->video_formats->list = g_new0 (GstWFDVideoCodec, 1);
 +        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 {
 +        msg->video_formats->count = 0;
 +        msg->video_formats->list = NULL;
 +      }
 +    }
 +  } else if (!g_strcmp0 (attr, GST_STRING_WFD2_AUDIO_CODECS)) {
 +    msg->wfd2_audio_codecs = g_new0 (GstWFD2AudioCodeclist, 1);
 +    if (strlen (v)) {
 +      guint i = 0;
 +      msg->wfd2_audio_codecs->count = strlen (v) / 16;
 +      msg->wfd2_audio_codecs->list =
 +          g_new0 (GstWFDAudioCodec, msg->wfd2_audio_codecs->count);
 +      for (; i < msg->wfd2_audio_codecs->count; i++) {
 +        WFD_SKIP_SPACE (v);
 +        WFD_READ_STRING (msg->wfd2_audio_codecs->list[i].audio_format);
 +        WFD_SKIP_SPACE (v);
 +        WFD_READ_UINT32 (msg->wfd2_audio_codecs->list[i].modes);
 +        WFD_SKIP_SPACE (v);
 +        WFD_READ_UINT32 (msg->wfd2_audio_codecs->list[i].latency);
 +        WFD_SKIP_COMMA (v);
 +      }
 +    }
 +  } else if (!g_strcmp0 (attr, GST_STRING_WFD2_VIDEO_FORMATS)) {
 +    msg->direct_video_formats = g_new0 (GstWFD2VideoCodeclist, 1);
 +    if (strlen (v)) {
 +      msg->direct_video_formats->count = 1;
 +      msg->direct_video_formats->list = g_new0 (GstWFDVideoCodec, 1);
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_UINT32 (msg->direct_video_formats->list->native);
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_UINT32 (msg->direct_video_formats->
 +          list->preferred_display_mode_supported);
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_UINT32 (msg->direct_video_formats->list->H264_codec.profile);
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_UINT32 (msg->direct_video_formats->list->H264_codec.level);
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_UINT32 (msg->direct_video_formats->list->H264_codec.
 +          misc_params.CEA_Support);
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_UINT32 (msg->direct_video_formats->list->H264_codec.
 +          misc_params.VESA_Support);
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_UINT32 (msg->direct_video_formats->list->H264_codec.
 +          misc_params.HH_Support);
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_UINT32 (msg->direct_video_formats->list->H264_codec.
 +          misc_params.latency);
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_UINT32 (msg->direct_video_formats->list->H264_codec.
 +          misc_params.min_slice_size);
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_UINT32 (msg->direct_video_formats->list->H264_codec.
 +          misc_params.slice_enc_params);
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_UINT32 (msg->direct_video_formats->list->H264_codec.
 +          misc_params.frame_rate_control_support);
 +      WFD_SKIP_SPACE (v);
 +      if (msg->direct_video_formats->list->preferred_display_mode_supported == 1) {
 +        WFD_READ_UINT32 (msg->direct_video_formats->list->H264_codec.max_hres);
 +        WFD_SKIP_SPACE (v);
 +        WFD_READ_UINT32 (msg->direct_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 (GstWFDCoupledSinkCap, 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;
 +  } else if (!g_strcmp0 (attr, GST_STRING_WFD2_DIRECT_STREAMING_MODE)) {
 +    msg->direct_mode = g_new0 (GstWFD2DirectStreamingMode, 1);
 +    if (strlen (v)) {
 +      WFD_SKIP_SPACE (v);
 +      if (!g_strcmp0 (v, "active"))
 +        msg->direct_mode->direct_mode = TRUE;
 +      else
 +        msg->direct_mode->direct_mode = FALSE;
 +    }
 +  } else if (!g_strcmp0 (attr, GST_STRING_WFD2_TRANSPORT_SWITCH)) {
 +    msg->tcp_ports = g_new0 (GstWFDTCPPorts, 1);
 +    if (strlen (v)) {
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_STRING (msg->tcp_ports->profile);
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_UINT32_DIGIT (msg->tcp_ports->rtp_port0);
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_UINT32_DIGIT (msg->tcp_ports->rtp_port1);
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_STRING (msg->tcp_ports->mode);
 +    }
 +  } else if (!g_strcmp0 (attr, GST_STRING_WFD2_BUFFER_LEN)) {
 +    msg->buf_len = g_new0 (GstWFDBufferLen, 1);
 +    if (strlen (v)) {
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_UINT32_DIGIT (msg->buf_len->buf_len);
 +    }
 +  } else if (!g_strcmp0 (attr, GST_STRING_WFD2_AUDIO_STATUS)) {
 +    msg->audio_status = g_new0 (GstWFDAudioReport, 1);
 +    if (strlen (v)) {
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_UINT32_DIGIT (msg->audio_status->aud_bufsize);
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_UINT64_DIGIT (msg->audio_status->aud_pts);
 +    }
 +  } else if (!g_strcmp0 (attr, GST_STRING_WFD2_VIDEO_STATUS)) {
 +    msg->video_status = g_new0 (GstWFDVideoReport, 1);
 +    if (strlen (v)) {
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_UINT32_DIGIT (msg->video_status->vid_bufsize);
 +      WFD_SKIP_SPACE (v);
 +      WFD_READ_UINT64_DIGIT (msg->video_status->vid_pts);
 +    }
 +  }
 +  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);
 +  msg = NULL;
 +
 +  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);
 +    g_string_append_printf (lines, ":");
 +    if (msg->audio_codecs->list) {
 +      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, ",");
 +      }
 +    } else {
 +      g_string_append_printf (lines, " none");
 +    }
 +    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, ":");
 +    if (msg->video_formats->list) {
 +      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");
 +    } else {
 +      g_string_append_printf (lines, " none");
 +    }
 +    g_string_append_printf (lines, "\r\n");
 +  }
 +
 +  /* list of wfd2 audio codecs */
 +  if (msg->wfd2_audio_codecs) {
 +    g_string_append_printf (lines, GST_STRING_WFD2_AUDIO_CODECS);
 +    if (msg->wfd2_audio_codecs->list) {
 +      g_string_append_printf (lines, ":");
 +      for (i = 0; i < msg->wfd2_audio_codecs->count; i++) {
 +        g_string_append_printf (lines, " %s",
 +            msg->wfd2_audio_codecs->list[i].audio_format);
 +        g_string_append_printf (lines, " %08x",
 +            msg->wfd2_audio_codecs->list[i].modes);
 +        g_string_append_printf (lines, " %02x",
 +            msg->wfd2_audio_codecs->list[i].latency);
 +        if ((i + 1) < msg->wfd2_audio_codecs->count)
 +          g_string_append_printf (lines, ",");
 +      }
 +    }
 +    g_string_append_printf (lines, "\r\n");
 +  }
 +
 +  /* list of direct video codecs */
 +  if (msg->direct_video_formats) {
 +    g_string_append_printf (lines, GST_STRING_WFD2_VIDEO_FORMATS);
 +    if (msg->direct_video_formats->list) {
 +      g_string_append_printf (lines, ":");
 +      g_string_append_printf (lines, " %02x", msg->direct_video_formats->list->native);
 +      g_string_append_printf (lines, " %02x",
 +          msg->direct_video_formats->list->preferred_display_mode_supported);
 +      g_string_append_printf (lines, " %02x",
 +          msg->direct_video_formats->list->H264_codec.profile);
 +      g_string_append_printf (lines, " %02x",
 +          msg->direct_video_formats->list->H264_codec.level);
 +      g_string_append_printf (lines, " %08x",
 +          msg->direct_video_formats->list->H264_codec.misc_params.CEA_Support);
 +      g_string_append_printf (lines, " %08x",
 +          msg->direct_video_formats->list->H264_codec.misc_params.VESA_Support);
 +      g_string_append_printf (lines, " %08x",
 +          msg->direct_video_formats->list->H264_codec.misc_params.HH_Support);
 +      g_string_append_printf (lines, " %02x",
 +          msg->direct_video_formats->list->H264_codec.misc_params.latency);
 +      g_string_append_printf (lines, " %04x",
 +          msg->direct_video_formats->list->H264_codec.misc_params.min_slice_size);
 +      g_string_append_printf (lines, " %04x",
 +          msg->direct_video_formats->list->H264_codec.misc_params.slice_enc_params);
 +      g_string_append_printf (lines, " %02x",
 +          msg->direct_video_formats->list->H264_codec.
 +          misc_params.frame_rate_control_support);
 +
 +      if (msg->direct_video_formats->list->H264_codec.max_hres)
 +        g_string_append_printf (lines, " %04x",
 +            msg->direct_video_formats->list->H264_codec.max_hres);
 +      else
 +        g_string_append_printf (lines, " none");
 +
 +      if (msg->direct_video_formats->list->H264_codec.max_vres)
 +        g_string_append_printf (lines, " %04x",
 +            msg->direct_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 &&
 +      (gboolean)msg->coupled_sink->coupled_sink_cap->sink_supported == TRUE) {
 +      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");
 +  }
 +
 +  if (msg->direct_mode && msg->direct_mode->direct_mode) {
 +    g_string_append_printf (lines, GST_STRING_WFD2_DIRECT_STREAMING_MODE);
 +    g_string_append_printf (lines, ":");
 +    g_string_append_printf (lines, " active");
 +    g_string_append_printf (lines, "\r\n");
 +  }
 +
 +  if (msg->tcp_ports) {
 +    g_string_append_printf (lines, GST_STRING_WFD2_TRANSPORT_SWITCH);
 +    if (msg->tcp_ports->profile) {
 +      g_string_append_printf (lines, ":");
 +      g_string_append_printf (lines, " %s", msg->tcp_ports->profile);
 +      g_string_append_printf (lines, " %d", msg->tcp_ports->rtp_port0);
 +      g_string_append_printf (lines, " %d", msg->tcp_ports->rtp_port1);
 +      g_string_append_printf (lines, " %s", msg->tcp_ports->mode);
 +    }
 +    g_string_append_printf (lines, "\r\n");
 +  }
 +
 +  if (msg->buf_len) {
 +    g_string_append_printf (lines, GST_STRING_WFD2_BUFFER_LEN);
 +    g_string_append_printf (lines, ":");
 +    g_string_append_printf (lines, " %d", msg->buf_len->buf_len);
 +    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 wfd2 audio codecs */
 +  if (msg->wfd2_audio_codecs) {
 +    g_string_append_printf (lines, GST_STRING_WFD2_AUDIO_CODECS);
 +    g_string_append_printf (lines, "\r\n");
 +  }
 +  /* list of direct video codecs */
 +  if (msg->direct_video_formats) {
 +    g_string_append_printf (lines, GST_STRING_WFD2_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");
 +  }
 +  if (msg->tcp_ports) {
 +    g_string_append_printf (lines, GST_STRING_WFD2_TRANSPORT_SWITCH);
 +    g_string_append_printf (lines, "\r\n");
 +  }
 +  if (msg->buf_len) {
 +    g_string_append_printf (lines, GST_STRING_WFD2_BUFFER_LEN);
 +    g_string_append_printf (lines, "\r\n");
 +  }
 +  if (msg->audio_status) {
 +    g_string_append_printf (lines, GST_STRING_WFD2_AUDIO_STATUS);
 +    g_string_append_printf (lines, "\r\n");
 +  }
 +  if (msg->video_status) {
 +    g_string_append_printf (lines, GST_STRING_WFD2_VIDEO_STATUS);
 +    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 Width(horizontal resolution): %04d\n",
 +            msg->video_formats->list->H264_codec.max_hres);
 +      }
 +      if (msg->video_formats->list->H264_codec.max_vres) {
 +        g_print ("    Max Height(vertical resolution): %04d\n",
 +            msg->video_formats->list->H264_codec.max_vres);
 +      }
 +    }
 +  }
 +
 +  if (msg->wfd2_audio_codecs) {
 +    guint i = 0;
 +    g_print ("Audio supported codecs for R2 : \n");
 +    for (; i < msg->wfd2_audio_codecs->count; i++) {
 +      g_print ("Codec: %s\n", msg->wfd2_audio_codecs->list[i].audio_format);
 +      if (!strcmp (msg->wfd2_audio_codecs->list[i].audio_format, "LPCM")) {
 +        if (msg->wfd2_audio_codecs->list[i].modes & GST_WFD_FREQ_44100)
 +          g_print ("  Freq: %d\n", 44100);
 +        if (msg->wfd2_audio_codecs->list[i].modes & GST_WFD_FREQ_48000)
 +          g_print ("  Freq: %d\n", 48000);
 +        g_print ("    Channels: %d\n", 2);
 +      }
 +      if (!strcmp (msg->wfd2_audio_codecs->list[i].audio_format, "AAC")) {
 +        g_print ("    Freq: %d\n", 48000);
 +        if (msg->wfd2_audio_codecs->list[i].modes & GST_WFD_CHANNEL_2)
 +          g_print ("  Channels: %d\n", 2);
 +        if (msg->wfd2_audio_codecs->list[i].modes & GST_WFD_CHANNEL_4)
 +          g_print ("  Channels: %d\n", 4);
 +        if (msg->wfd2_audio_codecs->list[i].modes & GST_WFD_CHANNEL_6)
 +          g_print ("  Channels: %d\n", 6);
 +        if (msg->wfd2_audio_codecs->list[i].modes & GST_WFD_CHANNEL_8)
 +          g_print ("  Channels: %d\n", 8);
 +      }
 +      if (!strcmp (msg->wfd2_audio_codecs->list[i].audio_format, "AC3")) {
 +        g_print ("    Freq: %d\n", 48000);
 +        if (msg->wfd2_audio_codecs->list[i].modes & GST_WFD_CHANNEL_2)
 +          g_print ("  Channels: %d\n", 2);
 +        if (msg->wfd2_audio_codecs->list[i].modes & GST_WFD_CHANNEL_4)
 +          g_print ("  Channels: %d\n", 4);
 +        if (msg->wfd2_audio_codecs->list[i].modes & GST_WFD_CHANNEL_6)
 +          g_print ("  Channels: %d\n", 6);
 +      }
 +      if (!strcmp (msg->wfd2_audio_codecs->list[i].audio_format, "CTA")) {
 +        g_print ("    Freq: %d\n", 48000);
 +        if (msg->wfd2_audio_codecs->list[i].modes & GST_WFD_CHANNEL_2)
 +          g_print ("  Channels: %d\n", 2);
 +        if (msg->wfd2_audio_codecs->list[i].modes & GST_WFD_CHANNEL_4)
 +          g_print ("  Channels: %d\n", 4);
 +        if (msg->wfd2_audio_codecs->list[i].modes & GST_WFD_CHANNEL_6)
 +          g_print ("  Channels: %d\n", 6);
 +      }
 +      if (!strcmp (msg->wfd2_audio_codecs->list[i].audio_format, "AAC-ELDv2")) {
 +        g_print ("    Freq: %d\n", 48000);
 +        if (msg->wfd2_audio_codecs->list[i].modes & GST_WFD_CHANNEL_2)
 +          g_print ("  Channels: %d\n", 2);
 +        if (msg->wfd2_audio_codecs->list[i].modes & GST_WFD_CHANNEL_4)
 +          g_print ("  Channels: %d\n", 4);
 +        if (msg->wfd2_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->wfd2_audio_codecs->list[i].latency);
 +    }
 +  }
 +
 +
 +  if (msg->direct_video_formats) {
 +    g_print ("Video supported formats for direct streaming : \n");
 +    if (msg->direct_video_formats->list) {
 +      guint nativeindex = 0;
 +      g_print ("Codec: H264\n");
 +      if ((msg->direct_video_formats->list->native & 0x7) ==
 +          GST_WFD_VIDEO_CEA_RESOLUTION) {
 +        g_print ("    Native type: CEA\n");
 +      } else if ((msg->direct_video_formats->list->native & 0x7) ==
 +          GST_WFD_VIDEO_VESA_RESOLUTION) {
 +        g_print ("    Native type: VESA\n");
 +      } else if ((msg->direct_video_formats->list->native & 0x7) ==
 +          GST_WFD_VIDEO_HH_RESOLUTION) {
 +        g_print ("    Native type: HH\n");
 +      }
 +      nativeindex = msg->direct_video_formats->list->native >> 3;
 +      g_print ("      Resolution: %d\n", (1 << nativeindex));
 +
 +      if (msg->direct_video_formats->list->
 +          H264_codec.profile & GST_WFD_H264_BASE_PROFILE) {
 +        g_print ("    Profile: BASE\n");
 +      } else if (msg->direct_video_formats->list->
 +          H264_codec.profile & GST_WFD_H264_HIGH_PROFILE) {
 +        g_print ("    Profile: HIGH\n");
 +      }
 +      if (msg->direct_video_formats->list->H264_codec.level & GST_WFD_H264_LEVEL_3_1) {
 +        g_print ("    Level: 3.1\n");
 +      } else if (msg->direct_video_formats->list->
 +          H264_codec.level & GST_WFD_H264_LEVEL_3_2) {
 +        g_print ("    Level: 3.2\n");
 +      } else if (msg->direct_video_formats->list->
 +          H264_codec.level & GST_WFD_H264_LEVEL_4) {
 +        g_print ("    Level: 4\n");
 +      } else if (msg->direct_video_formats->list->
 +          H264_codec.level & GST_WFD_H264_LEVEL_4_1) {
 +        g_print ("    Level: 4.1\n");
 +      } else if (msg->direct_video_formats->list->
 +          H264_codec.level & GST_WFD_H264_LEVEL_4_2) {
 +        g_print ("    Level: 4.2\n");
 +      }
 +      g_print ("      Latency: %d\n",
 +          msg->direct_video_formats->list->H264_codec.misc_params.latency);
 +      g_print ("      min_slice_size: %x\n",
 +          msg->direct_video_formats->list->H264_codec.misc_params.min_slice_size);
 +      g_print ("      slice_enc_params: %x\n",
 +          msg->direct_video_formats->list->H264_codec.misc_params.slice_enc_params);
 +      g_print ("      frame_rate_control_support: %x\n",
 +          msg->direct_video_formats->list->H264_codec.
 +          misc_params.frame_rate_control_support);
 +      if (msg->direct_video_formats->list->H264_codec.max_hres) {
 +        g_print ("    Max Width(horizontal resolution): %04d\n",
 +            msg->direct_video_formats->list->H264_codec.max_hres);
 +      }
 +      if (msg->direct_video_formats->list->H264_codec.max_vres) {
 +        g_print ("    Max height(vertical resolution): %04d\n",
 +            msg->direct_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");
 +  }
 +
 +  if (msg->direct_mode) {
 +    g_print (GST_STRING_WFD2_DIRECT_STREAMING_MODE);
 +    g_print ("\r\n");
 +  }
 +
 +  if (msg->tcp_ports) {
 +    g_print (" TCP Ports : \n");
 +    if (msg->tcp_ports->profile) {
 +      g_print ("%s\n", msg->tcp_ports->profile);
 +      g_print ("      %d\n", msg->tcp_ports->rtp_port0);
 +      g_print ("      %d\n", msg->tcp_ports->rtp_port1);
 +      g_print ("      %s\n", msg->tcp_ports->mode);
 +    }
 +    g_print ("\r\n");
 +  }
 +
 +  if (msg->buf_len) {
 +    g_print (" Buffer Length : %d\n", msg->buf_len->buf_len);
 +    g_print ("\r\n");
 +  }
 +
 +  if (msg->audio_status) {
 +    g_print ("Audio Playback Status : \n");
 +    g_print ("  Current audio buffer size : %d\n", msg->audio_status->aud_bufsize);
 +    g_print ("  Current audio decoded PTS : %lld\n", msg->audio_status->aud_pts);
 +    g_print ("\r\n");
 +  }
 +
 +  if (msg->video_status) {
 +    g_print ("Video Playback Status : \n");
 +    g_print ("  Current video buffer size : %d\n", msg->video_status->vid_bufsize);
 +    g_print ("  Current video decoded PTS : %lld\n", msg->video_status->vid_pts);
 +    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 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) {
 +
 +    if (a_codec & GST_WFD_AUDIO_LPCM)
 +      msg->audio_codecs->count++;
 +    if (a_codec & GST_WFD_AUDIO_AAC)
 +      msg->audio_codecs->count++;
 +    if (a_codec & GST_WFD_AUDIO_AC3)
 +      msg->audio_codecs->count++;
 +
 +    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_preferred_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);
 +
 +  if (a_codec == GST_WFD_AUDIO_UNKNOWN) {
 +    msg->audio_codecs->list = NULL;
 +    msg->audio_codecs->count = 0;
 +    return GST_WFD_OK;
 +  }
 +  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_preferred_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);
 +
 +    temp >>= 1;
 +    while (temp) {
 +      nativeindex++;
 +      temp >>= 1;
 +    }
 +
 +    msg->video_formats->list->native = nativeindex;
 +    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_width;
 +    msg->video_formats->list->H264_codec.max_vres = v_max_height;
 +    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_preferred_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);
 +
 +  if (v_codec == GST_WFD_VIDEO_UNKNOWN) {
 +    msg->video_formats->list = NULL;
 +    msg->video_formats->count = 0;
 +    return GST_WFD_OK;
 +  }
 +
 +  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_width;
 +  msg->video_formats->list->H264_codec.max_vres = v_max_height;
 +  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_width = msg->video_formats->list->H264_codec.max_hres;
 +  *v_max_height = 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_preferred_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_width = msg->video_formats->list->H264_codec.max_hres;
 +  *v_max_height = 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_supported_wfd2_audio_codec (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, cta = 0, aac_eldv2 = 0;
 +
 +  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
 +
 +  if (!msg->wfd2_audio_codecs)
 +    msg->wfd2_audio_codecs = g_new0 (GstWFD2AudioCodeclist, 1);
 +
 +  if (a_codec != GST_WFD_AUDIO_UNKNOWN) {
 +    while (temp) {
 +      msg->wfd2_audio_codecs->count++;
 +      temp >>= 1;
 +    }
 +    msg->wfd2_audio_codecs->list =
 +        g_new0 (GstWFDAudioCodec, msg->wfd2_audio_codecs->count);
 +    for (; i < msg->wfd2_audio_codecs->count; i++) {
 +      if ((a_codec & GST_WFD_AUDIO_LPCM) && (!pcm)) {
 +        msg->wfd2_audio_codecs->list[i].audio_format = g_strdup ("LPCM");
 +        msg->wfd2_audio_codecs->list[i].modes = a_freq;
 +        msg->wfd2_audio_codecs->list[i].latency = a_latency;
 +        pcm = 1;
 +      } else if ((a_codec & GST_WFD_AUDIO_AAC) && (!aac)) {
 +        msg->wfd2_audio_codecs->list[i].audio_format = g_strdup ("AAC");
 +        msg->wfd2_audio_codecs->list[i].modes = a_channels;
 +        msg->wfd2_audio_codecs->list[i].latency = a_latency;
 +        aac = 1;
 +      } else if ((a_codec & GST_WFD_AUDIO_AC3) && (!ac3)) {
 +        msg->wfd2_audio_codecs->list[i].audio_format = g_strdup ("AC3");
 +        msg->wfd2_audio_codecs->list[i].modes = a_channels;
 +        msg->wfd2_audio_codecs->list[i].latency = a_latency;
 +        ac3 = 1;
 +      } else if ((a_codec & GST_WFD_AUDIO_CTA) && (!cta)) {
 +        msg->wfd2_audio_codecs->list[i].audio_format = g_strdup ("CTA");
 +        msg->wfd2_audio_codecs->list[i].modes = a_channels;
 +        msg->wfd2_audio_codecs->list[i].latency = a_latency;
 +        cta = 1;
 +      } else if ((a_codec & GST_WFD_AUDIO_AAC_ELDV2) && (!aac_eldv2)) {
 +        msg->wfd2_audio_codecs->list[i].audio_format = g_strdup ("AAC-ELDv2");
 +        msg->wfd2_audio_codecs->list[i].modes = a_channels;
 +        msg->wfd2_audio_codecs->list[i].latency = a_latency;
 +        aac_eldv2 = 1;
 +      }
 +    }
 +  }
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_message_set_preferred_wfd2_audio_codec (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->wfd2_audio_codecs)
 +    msg->wfd2_audio_codecs = g_new0 (GstWFD2AudioCodeclist, 1);
 +
 +  msg->wfd2_audio_codecs->list = g_new0 (GstWFDAudioCodec, 1);
 +  msg->wfd2_audio_codecs->count = 1;
 +  if (a_codec == GST_WFD_AUDIO_LPCM) {
 +    msg->wfd2_audio_codecs->list->audio_format = g_strdup ("LPCM");
 +    msg->wfd2_audio_codecs->list->modes = a_freq;
 +    msg->wfd2_audio_codecs->list->latency = a_latency;
 +  } else if (a_codec == GST_WFD_AUDIO_AAC) {
 +    msg->wfd2_audio_codecs->list->audio_format = g_strdup ("AAC");
 +    msg->wfd2_audio_codecs->list->modes = a_channels;
 +    msg->wfd2_audio_codecs->list->latency = a_latency;
 +  } else if (a_codec == GST_WFD_AUDIO_AC3) {
 +    msg->wfd2_audio_codecs->list->audio_format = g_strdup ("AC3");
 +    msg->wfd2_audio_codecs->list->modes = a_channels;
 +    msg->wfd2_audio_codecs->list->latency = a_latency;
 +  } else if (a_codec == GST_WFD_AUDIO_CTA) {
 +    msg->wfd2_audio_codecs->list->audio_format = g_strdup ("CTA");
 +    msg->wfd2_audio_codecs->list->modes = a_channels;
 +    msg->wfd2_audio_codecs->list->latency = a_latency;
 +  } else if (a_codec == GST_WFD_AUDIO_AAC_ELDV2) {
 +    msg->wfd2_audio_codecs->list->audio_format = g_strdup ("AAC-ELDv2");
 +    msg->wfd2_audio_codecs->list->modes = a_channels;
 +    msg->wfd2_audio_codecs->list->latency = a_latency;
 +  }
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_message_get_supported_wfd2_audio_codec (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->wfd2_audio_codecs != NULL, GST_WFD_EINVAL);
 +
 +  for (; i < msg->wfd2_audio_codecs->count; i++) {
 +    if (!g_strcmp0 (msg->wfd2_audio_codecs->list[i].audio_format, "LPCM")) {
 +      *a_codec |= GST_WFD_AUDIO_LPCM;
 +      *a_freq |= msg->wfd2_audio_codecs->list[i].modes;
 +      *a_channels |= GST_WFD_CHANNEL_2;
 +      *a_bitwidth = 16;
 +      *a_latency = msg->wfd2_audio_codecs->list[i].latency;
 +    } else if (!g_strcmp0 (msg->wfd2_audio_codecs->list[i].audio_format, "AAC")) {
 +      *a_codec |= GST_WFD_AUDIO_AAC;
 +      *a_freq |= GST_WFD_FREQ_48000;
 +      *a_channels |= msg->wfd2_audio_codecs->list[i].modes;
 +      *a_bitwidth = 16;
 +      *a_latency = msg->wfd2_audio_codecs->list[i].latency;
 +    } else if (!g_strcmp0 (msg->wfd2_audio_codecs->list[i].audio_format, "AC3")) {
 +      *a_codec |= GST_WFD_AUDIO_AC3;
 +      *a_freq |= GST_WFD_FREQ_48000;
 +      *a_channels |= msg->wfd2_audio_codecs->list[i].modes;
 +      *a_bitwidth = 16;
 +      *a_latency = msg->wfd2_audio_codecs->list[i].latency;
 +    } else if (!g_strcmp0 (msg->wfd2_audio_codecs->list[i].audio_format, "CTA")) {
 +      *a_codec |= GST_WFD_AUDIO_CTA;
 +      *a_freq |= GST_WFD_FREQ_48000;
 +      *a_channels |= msg->wfd2_audio_codecs->list[i].modes;
 +      *a_bitwidth = 16;
 +      *a_latency = msg->wfd2_audio_codecs->list[i].latency;
 +    } else if (!g_strcmp0 (msg->wfd2_audio_codecs->list[i].audio_format, "AAC-ELDv2")) {
 +      *a_codec |= GST_WFD_AUDIO_AAC_ELDV2;
 +      *a_freq |= GST_WFD_FREQ_48000;
 +      *a_channels |= msg->wfd2_audio_codecs->list[i].modes;
 +      *a_bitwidth = 16;
 +      *a_latency = msg->wfd2_audio_codecs->list[i].latency;
 +    }
 +  }
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_message_get_preferred_wfd2_audio_codec (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->wfd2_audio_codecs->list->audio_format, "LPCM")) {
 +    *a_codec = GST_WFD_AUDIO_LPCM;
 +    *a_freq = msg->wfd2_audio_codecs->list->modes;
 +    *a_channels = GST_WFD_CHANNEL_2;
 +    *a_bitwidth = 16;
 +    *a_latency = msg->wfd2_audio_codecs->list->latency;
 +  } else if (!g_strcmp0 (msg->wfd2_audio_codecs->list->audio_format, "AAC")) {
 +    *a_codec = GST_WFD_AUDIO_AAC;
 +    *a_freq = GST_WFD_FREQ_48000;
 +    *a_channels = msg->wfd2_audio_codecs->list->modes;
 +    *a_bitwidth = 16;
 +    *a_latency = msg->wfd2_audio_codecs->list->latency;
 +  } else if (!g_strcmp0 (msg->wfd2_audio_codecs->list->audio_format, "AC3")) {
 +    *a_codec = GST_WFD_AUDIO_AC3;
 +    *a_freq = GST_WFD_FREQ_48000;
 +    *a_channels = msg->wfd2_audio_codecs->list->modes;
 +    *a_bitwidth = 16;
 +    *a_latency = msg->wfd2_audio_codecs->list->latency;
 +  } else if (!g_strcmp0 (msg->wfd2_audio_codecs->list->audio_format, "CTA")) {
 +    *a_codec = GST_WFD_AUDIO_CTA;
 +    *a_freq = GST_WFD_FREQ_48000;
 +    *a_channels = msg->wfd2_audio_codecs->list->modes;
 +    *a_bitwidth = 16;
 +    *a_latency = msg->wfd2_audio_codecs->list->latency;
 +  } else if (!g_strcmp0 (msg->wfd2_audio_codecs->list->audio_format, "AAC-ELDv2")) {
 +    *a_codec = GST_WFD_AUDIO_AAC_ELDV2;
 +    *a_freq = GST_WFD_FREQ_48000;
 +    *a_channels = msg->wfd2_audio_codecs->list->modes;
 +    *a_bitwidth = 16;
 +    *a_latency = msg->wfd2_audio_codecs->list->latency;
 +  }
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_message_set_supported_direct_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->direct_video_formats)
 +    msg->direct_video_formats = g_new0 (GstWFD2VideoCodeclist, 1);
 +
 +  if (v_codec != GST_WFD_VIDEO_UNKNOWN) {
 +    msg->direct_video_formats->list = g_new0 (GstWFDVideoCodec, 1);
 +    while (temp) {
 +      nativeindex++;
 +      temp >>= 1;
 +    }
 +
 +    if (nativeindex) msg->direct_video_formats->list->native = nativeindex - 1;
 +    msg->direct_video_formats->list->native <<= 3;
 +
 +    if (v_native == GST_WFD_VIDEO_VESA_RESOLUTION)
 +      msg->direct_video_formats->list->native |= 1;
 +    else if (v_native == GST_WFD_VIDEO_HH_RESOLUTION)
 +      msg->direct_video_formats->list->native |= 2;
 +
 +    msg->direct_video_formats->list->preferred_display_mode_supported = 1;
 +    msg->direct_video_formats->list->H264_codec.profile = v_profile;
 +    msg->direct_video_formats->list->H264_codec.level = v_level;
 +    msg->direct_video_formats->list->H264_codec.max_hres = v_max_width;
 +    msg->direct_video_formats->list->H264_codec.max_vres = v_max_height;
 +    msg->direct_video_formats->list->H264_codec.misc_params.CEA_Support =
 +        v_cea_resolution;
 +    msg->direct_video_formats->list->H264_codec.misc_params.VESA_Support =
 +        v_vesa_resolution;
 +    msg->direct_video_formats->list->H264_codec.misc_params.HH_Support =
 +        v_hh_resolution;
 +    msg->direct_video_formats->list->H264_codec.misc_params.latency = v_latency;
 +    msg->direct_video_formats->list->H264_codec.misc_params.min_slice_size =
 +        min_slice_size;
 +    msg->direct_video_formats->list->H264_codec.misc_params.slice_enc_params =
 +        slice_enc_params;
 +    msg->direct_video_formats->list->H264_codec.
 +        misc_params.frame_rate_control_support = frame_rate_control;
 +  }
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_message_set_preferred_direct_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,
 +    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->direct_video_formats)
 +    msg->direct_video_formats = g_new0 (GstWFD2VideoCodeclist, 1);
 +  msg->direct_video_formats->list = g_new0 (GstWFDVideoCodec, 1);
 +
 +  while (temp) {
 +    nativeindex++;
 +    temp >>= 1;
 +  }
 +
 +  if (nativeindex)
 +    msg->direct_video_formats->list->native = nativeindex - 1;
 +  msg->direct_video_formats->list->native <<= 3;
 +
 +  if (v_native == GST_WFD_VIDEO_VESA_RESOLUTION)
 +    msg->direct_video_formats->list->native |= 1;
 +  else if (v_native == GST_WFD_VIDEO_HH_RESOLUTION)
 +    msg->direct_video_formats->list->native |= 2;
 +
 +  msg->direct_video_formats->list->preferred_display_mode_supported = 0;
 +  msg->direct_video_formats->list->H264_codec.profile = v_profile;
 +  msg->direct_video_formats->list->H264_codec.level = v_level;
 +  msg->direct_video_formats->list->H264_codec.max_hres = v_max_width;
 +  msg->direct_video_formats->list->H264_codec.max_vres = v_max_height;
 +  msg->direct_video_formats->list->H264_codec.misc_params.CEA_Support =
 +      v_cea_resolution;
 +  msg->direct_video_formats->list->H264_codec.misc_params.VESA_Support =
 +      v_vesa_resolution;
 +  msg->direct_video_formats->list->H264_codec.misc_params.HH_Support = v_hh_resolution;
 +  msg->direct_video_formats->list->H264_codec.misc_params.latency = v_latency;
 +  msg->direct_video_formats->list->H264_codec.misc_params.min_slice_size =
 +      min_slice_size;
 +  msg->direct_video_formats->list->H264_codec.misc_params.slice_enc_params =
 +      slice_enc_params;
 +  msg->direct_video_formats->list->H264_codec.misc_params.frame_rate_control_support =
 +      frame_rate_control;
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_message_get_supported_direct_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->direct_video_formats->list->native & 0x7;
 +  nativeindex = msg->direct_video_formats->list->native >> 3;
 +  *v_native_resolution = ((guint64) 1) << nativeindex;
 +  *v_profile = msg->direct_video_formats->list->H264_codec.profile;
 +  *v_level = msg->direct_video_formats->list->H264_codec.level;
 +  *v_max_width = msg->direct_video_formats->list->H264_codec.max_hres;
 +  *v_max_height = msg->direct_video_formats->list->H264_codec.max_vres;
 +  *v_cea_resolution =
 +      msg->direct_video_formats->list->H264_codec.misc_params.CEA_Support;
 +  *v_vesa_resolution =
 +      msg->direct_video_formats->list->H264_codec.misc_params.VESA_Support;
 +  *v_hh_resolution =
 +      msg->direct_video_formats->list->H264_codec.misc_params.HH_Support;
 +  *v_latency = msg->direct_video_formats->list->H264_codec.misc_params.latency;
 +  *min_slice_size =
 +      msg->direct_video_formats->list->H264_codec.misc_params.min_slice_size;
 +  *slice_enc_params =
 +      msg->direct_video_formats->list->H264_codec.misc_params.slice_enc_params;
 +  *frame_rate_control =
 +      msg->direct_video_formats->list->H264_codec.
 +      misc_params.frame_rate_control_support;
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_message_get_preferred_direct_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,
 +    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->direct_video_formats->list->native & 0x7;
 +  nativeindex = msg->direct_video_formats->list->native >> 3;
 +  *v_native_resolution = ((guint64) 1) << nativeindex;
 +  *v_profile = msg->direct_video_formats->list->H264_codec.profile;
 +  *v_level = msg->direct_video_formats->list->H264_codec.level;
 +  *v_max_width = msg->direct_video_formats->list->H264_codec.max_hres;
 +  *v_max_height = msg->direct_video_formats->list->H264_codec.max_vres;
 +  *v_cea_resolution =
 +      msg->direct_video_formats->list->H264_codec.misc_params.CEA_Support;
 +  *v_vesa_resolution =
 +      msg->direct_video_formats->list->H264_codec.misc_params.VESA_Support;
 +  *v_hh_resolution =
 +      msg->direct_video_formats->list->H264_codec.misc_params.HH_Support;
 +  *v_latency = msg->direct_video_formats->list->H264_codec.misc_params.latency;
 +  *min_slice_size =
 +      msg->direct_video_formats->list->H264_codec.misc_params.min_slice_size;
 +  *slice_enc_params =
 +      msg->direct_video_formats->list->H264_codec.misc_params.slice_enc_params;
 +  *frame_rate_control =
 +      msg->direct_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_coupled_sink(GstWFDMessage *msg,
 +    GstWFDCoupledSinkStatus status, gchar *sink_address, gboolean sink_supported)
 +{
 +  g_return_val_if_fail(msg != NULL, GST_WFD_EINVAL);
 +  if (!msg->coupled_sink) msg->coupled_sink = g_new0(GstWFDCoupledSink, 1);
 +  if (!sink_supported) return GST_WFD_OK;
 +  msg->coupled_sink->coupled_sink_cap = g_new0(GstWFDCoupledSinkCap, 1);
 +  msg->coupled_sink->coupled_sink_cap->status = status;
 +  msg->coupled_sink->coupled_sink_cap->sink_address = g_strdup(sink_address);
 +  msg->coupled_sink->coupled_sink_cap->sink_supported = sink_supported;
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult gst_wfd_message_get_coupled_sink(GstWFDMessage *msg,
 +    GstWFDCoupledSinkStatus *status, gchar **sink_address, gboolean *sink_supported)
 +{
 +  g_return_val_if_fail(msg != NULL, GST_WFD_EINVAL);
 +  if (msg->coupled_sink
 +      && msg->coupled_sink->coupled_sink_cap->sink_supported) {
 +    *status = msg->coupled_sink->coupled_sink_cap->status;
 +    *sink_address = g_strdup(msg->coupled_sink->coupled_sink_cap->sink_address);
 +    *sink_supported = (gboolean)msg->coupled_sink->coupled_sink_cap->sink_supported;
 +  }
 +  else {
 +    *status = GST_WFD_SINK_NOT_COUPLED;
 +  }
 +  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);
 +  *hdcpversion = GST_WFD_HDCP_NONE;
 +  *TCPPort = 0;
 +
 +  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"))
 +      return GST_WFD_OK;
 +    else 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
 +      return GST_WFD_OK;
 +
 +    if (!msg->content_protection->hdcp2_spec->TCPPort)
 +      return GST_WFD_OK;
 +
 +    result = strtok_r (msg->content_protection->hdcp2_spec->TCPPort, "=", &ptr);
 +    if (result == NULL || ptr == NULL)
 +      return GST_WFD_OK;
 +
 +    result = strtok_r (NULL, "=", &ptr);
 +    if (result)
 +      *TCPPort = atoi(result);
 +  }
 +  return GST_WFD_OK;
 +}
 +
 +
 +GstWFDResult
 +gst_wfd_messge_set_preferred_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_preferred_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;
 +}
 +
 +GstWFDResult
 +gst_wfd_message_set_direct_streaming_mode(GstWFDMessage *msg, gboolean enable)
 +{
 +  g_return_val_if_fail(msg != NULL, GST_WFD_EINVAL);
 +
 +  if (!msg->direct_mode)
 +    msg->direct_mode = g_new0(GstWFD2DirectStreamingMode, 1);
 +
 +  msg->direct_mode->direct_mode = enable;
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_messge_set_preferred_tcp_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->tcp_ports)
 +    msg->tcp_ports = g_new0 (GstWFDTCPPorts, 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->tcp_ports->profile = g_string_free (lines, FALSE);
 +    msg->tcp_ports->rtp_port0 = rtp_port0;
 +    msg->tcp_ports->rtp_port1 = rtp_port1;
 +    msg->tcp_ports->mode = g_strdup ("mode=play");
 +  }
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_message_get_preferred_tcp_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->tcp_ports != NULL, GST_WFD_EINVAL);
 +
 +  if (g_strrstr (msg->tcp_ports->profile, "RTP"))
 +    *trans = GST_WFD_RTSP_TRANS_RTP;
 +  if (g_strrstr (msg->tcp_ports->profile, "RDT"))
 +    *trans = GST_WFD_RTSP_TRANS_RDT;
 +  if (g_strrstr (msg->tcp_ports->profile, "AVP"))
 +    *profile = GST_WFD_RTSP_PROFILE_AVP;
 +  if (g_strrstr (msg->tcp_ports->profile, "SAVP"))
 +    *profile = GST_WFD_RTSP_PROFILE_SAVP;
 +  if (g_strrstr (msg->tcp_ports->profile, "UDP;unicast"))
 +    *lowertrans = GST_WFD_RTSP_LOWER_TRANS_UDP;
 +  if (g_strrstr (msg->tcp_ports->profile, "UDP;multicast"))
 +    *lowertrans = GST_WFD_RTSP_LOWER_TRANS_UDP_MCAST;
 +  if (g_strrstr (msg->tcp_ports->profile, "TCP;unicast"))
 +    *lowertrans = GST_WFD_RTSP_LOWER_TRANS_TCP;
 +  if (g_strrstr (msg->tcp_ports->profile, "HTTP"))
 +    *lowertrans = GST_WFD_RTSP_LOWER_TRANS_HTTP;
 +
 +  *rtp_port0 = msg->tcp_ports->rtp_port0;
 +  *rtp_port1 = msg->tcp_ports->rtp_port1;
 +
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_message_set_buffer_length (GstWFDMessage *msg, guint buf_len)
 +{
 +  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
 +
 +  if (!msg->buf_len)
 +    msg->buf_len = g_new0 (GstWFDBufferLen, 1);
 +  msg->buf_len->buf_len = buf_len;
 +
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_message_get_buffer_length (GstWFDMessage *msg, guint *buf_len)
 +{
 +  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
 +  g_return_val_if_fail (msg->buf_len != NULL, GST_WFD_EINVAL);
 +
 +  *buf_len = msg->buf_len->buf_len;
 +
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_message_get_audio_playback_status (GstWFDMessage *msg,
 +    guint *bufsize,
 +    guint64 *pts)
 +{
 +  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
 +  g_return_val_if_fail (msg->audio_status != NULL, GST_WFD_EINVAL);
 +
 +  *bufsize = msg->audio_status->aud_bufsize;
 +  *pts = msg->audio_status->aud_pts;
 +
 +  return GST_WFD_OK;
 +}
 +
 +GstWFDResult
 +gst_wfd_message_get_video_playback_status (GstWFDMessage *msg,
 +    guint *bufsize,
 +    guint64 *pts)
 +{
 +  g_return_val_if_fail (msg != NULL, GST_WFD_EINVAL);
 +  g_return_val_if_fail (msg->video_status != NULL, GST_WFD_EINVAL);
 +
 +  *bufsize = msg->video_status->vid_bufsize;
 +  *pts = msg->video_status->vid_pts;
 +
 +  return GST_WFD_OK;
 +}
index 48d587a,0000000..48d587a
mode 100755,000000..100755
--- /dev/null
@@@ -1,852 -1,0 +1,852 @@@
 +/* 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>
 +
 +#include "rtsp-server-prelude.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"
 +
 +#define GST_STRING_WFD2_AUDIO_CODECS              "wfd2_audio_codecs"
 +#define GST_STRING_WFD2_VIDEO_FORMATS             "wfd2_video_formats"
 +#define GST_STRING_WFD2_DIRECT_STREAMING_MODE     "wfd2_direct_streaming_mode"
 +
 +#define GST_STRING_WFD2_TRANSPORT_SWITCH          "wfd2_transport_switch"
 +#define GST_STRING_WFD2_BUFFER_LEN                "wfd2_buffer_len"
 +#define GST_STRING_WFD2_AUDIO_STATUS              "wfd2_audio_playback_status"
 +#define GST_STRING_WFD2_VIDEO_STATUS              "wfd2_video_playback_status"
 +
 +/**
 + * 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),
 +  GST_WFD_AUDIO_CTA       = (1 << 3),
 +  GST_WFD_AUDIO_AAC_ELDV2 = (1 << 4)
 +} 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_NOT_COUPLED         = 0,
 +  GST_WFD_SINK_COUPLED           = (1 << 0),
 +  GST_WFD_SINK_TEARDOWN_COUPLING = (1 << 1)
 +} 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 count;
 +  GstWFDAudioCodec *list;
 +} GstWFD2AudioCodeclist;
 +
 +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 count;
 +  GstWFDVideoCodec *list;
 +} GstWFD2VideoCodeclist;
 +
 +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;
 +  gboolean sink_supported;
 +} GstWFDCoupledSinkCap;
 +
 +typedef struct {
 +  GstWFDCoupledSinkCap *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;
 +
 +typedef struct {
 +  gboolean direct_mode;
 +} GstWFD2DirectStreamingMode;
 +
 +typedef struct {
 +  gchar *profile;
 +  guint32 rtp_port0;
 +  guint32 rtp_port1;
 +  gchar *mode;
 +} GstWFDTCPPorts;
 +
 +typedef struct {
 +  guint buf_len;
 +} GstWFDBufferLen;
 +
 +typedef struct {
 +  guint aud_bufsize;
 +  guint64 aud_pts;
 +} GstWFDAudioReport;
 +
 +typedef struct {
 +  guint vid_bufsize;
 +  guint64 vid_pts;
 +} GstWFDVideoReport;
 +
 +/**
 + * 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;
 +  GstWFD2AudioCodeclist *wfd2_audio_codecs;
 +  GstWFD2VideoCodeclist *direct_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;
 +  GstWFD2DirectStreamingMode *direct_mode;
 +  GstWFDTCPPorts *tcp_ports;
 +  GstWFDBufferLen *buf_len;
 +  GstWFDAudioReport *audio_status;
 +  GstWFDVideoReport *video_status;
 +} GstWFDMessage;
 +
 +GST_RTSP_SERVER_API
 +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 */
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_message_new                 (GstWFDMessage **msg);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_message_init                (GstWFDMessage *msg);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_message_uninit              (GstWFDMessage *msg);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_message_free                (GstWFDMessage *msg);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_message_copy                (const GstWFDMessage *msg, GstWFDMessage **copy);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_message_parse_buffer        (const guint8 *data, guint size, GstWFDMessage *msg);
 +
 +GST_RTSP_SERVER_API
 +gchar*                  gst_wfd_message_as_text             (const GstWFDMessage *msg);
 +
 +GST_RTSP_SERVER_API
 +gchar*                  gst_wfd_message_param_names_as_text (const GstWFDMessage *msg);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult            gst_wfd_message_dump                (const GstWFDMessage *msg);
 +
 +GST_RTSP_SERVER_API
 +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);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_set_preferred_audio_format(GstWFDMessage *msg,
 +                                        GstWFDAudioFormats a_codec,
 +                                        GstWFDAudioFreq a_freq,
 +                                        GstWFDAudioChannels a_channels,
 +                                        guint a_bitwidth, guint32 a_latency);
 +
 +GST_RTSP_SERVER_API
 +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);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_get_preferred_audio_format (GstWFDMessage *msg,
 +                                        GstWFDAudioFormats *a_codec,
 +                                        GstWFDAudioFreq *a_freq,
 +                                        GstWFDAudioChannels *a_channels,
 +                                        guint *a_bitwidth, guint32 *a_latency);
 +
 +GST_RTSP_SERVER_API
 +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);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_set_preferred_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);
 +
 +GST_RTSP_SERVER_API
 +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);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_get_preferred_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);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_set_supported_wfd2_audio_codec(GstWFDMessage *msg,
 +                                        GstWFDAudioFormats a_codec,
 +                                        guint a_freq, guint a_channels,
 +                                        guint a_bitwidth, guint32 a_latency);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_set_preferred_wfd2_audio_codec(GstWFDMessage *msg,
 +                                        GstWFDAudioFormats a_codec,
 +                                        GstWFDAudioFreq a_freq,
 +                                        GstWFDAudioChannels a_channels,
 +                                        guint a_bitwidth, guint32 a_latency);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_get_supported_wfd2_audio_codec (GstWFDMessage *msg,
 +                                        guint *a_codec,
 +                                        guint *a_freq,
 +                                        guint *a_channels,
 +                                        guint *a_bitwidth,
 +                                        guint32 *a_latency);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_get_preferred_wfd2_audio_codec (GstWFDMessage *msg,
 +                                        GstWFDAudioFormats *a_codec,
 +                                        GstWFDAudioFreq *a_freq,
 +                                        GstWFDAudioChannels *a_channels,
 +                                        guint *a_bitwidth, guint32 *a_latency);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_set_supported_direct_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);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_set_preferred_direct_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,
 +                                        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);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_get_supported_direct_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);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_get_preferred_direct_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,
 +                                        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);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_set_display_edid (GstWFDMessage *msg,
 +                                        gboolean edid_supported,
 +                                        guint32 edid_blockcount,
 +                                        gchar *edid_playload);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_get_display_edid (GstWFDMessage *msg,
 +                                        gboolean *edid_supported,
 +                                        guint32 *edid_blockcount,
 +                                        gchar **edid_playload);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_set_coupled_sink(GstWFDMessage *msg,
 +                                        GstWFDCoupledSinkStatus status,
 +                                        gchar *sink_address,
 +                                        gboolean sink_supported);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_get_coupled_sink(GstWFDMessage *msg,
 +                                        GstWFDCoupledSinkStatus *status,
 +                                        gchar **sink_address,
 +                                        gboolean *sink_supported);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_set_contentprotection_type (GstWFDMessage *msg,
 +                                        GstWFDHDCPProtection hdcpversion,
 +                                        guint32 TCPPort);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_get_contentprotection_type (GstWFDMessage *msg,
 +                                        GstWFDHDCPProtection *hdcpversion,
 +                                        guint32 *TCPPort);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_messge_set_preferred_rtp_ports (GstWFDMessage *msg,
 +                                        GstWFDRTSPTransMode trans,
 +                                        GstWFDRTSPProfile profile,
 +                                        GstWFDRTSPLowerTrans lowertrans,
 +                                        guint32 rtp_port0,
 +                                        guint32 rtp_port1);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_get_preferred_rtp_ports (GstWFDMessage *msg,
 +                                        GstWFDRTSPTransMode *trans,
 +                                        GstWFDRTSPProfile *profile,
 +                                        GstWFDRTSPLowerTrans *lowertrans,
 +                                        guint32 *rtp_port0,
 +                                        guint32 *rtp_port1);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_set_presentation_url(GstWFDMessage *msg,
 +                                        gchar *wfd_url0, gchar *wfd_url1);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_get_presentation_url(GstWFDMessage *msg, gchar **wfd_url0,
 +                                        gchar **wfd_url1);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_set_av_format_change_timing(GstWFDMessage *msg,
 +                                        guint64 PTS,
 +                                        guint64 DTS);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_get_av_format_change_timing(GstWFDMessage *msg,
 +                                        guint64 *PTS,
 +                                        guint64 *DTS);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_set_direct_streaming_mode(GstWFDMessage *msg,
 +                                        gboolean enable);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_messge_set_preferred_tcp_ports (GstWFDMessage *msg,
 +                                        GstWFDRTSPTransMode trans,
 +                                        GstWFDRTSPProfile profile,
 +                                        GstWFDRTSPLowerTrans lowertrans,
 +                                        guint32 rtp_port0,
 +                                        guint32 rtp_port1);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_get_preferred_tcp_ports (GstWFDMessage *msg,
 +                                        GstWFDRTSPTransMode *trans,
 +                                        GstWFDRTSPProfile *profile,
 +                                        GstWFDRTSPLowerTrans *lowertrans,
 +                                        guint32 *rtp_port0,
 +                                        guint32 *rtp_port1);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_set_buffer_length (GstWFDMessage *msg,
 +                                        guint buf_len);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_get_buffer_length (GstWFDMessage *msg,
 +                                        guint *buf_len);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_get_audio_playback_status (GstWFDMessage *msg,
 +                                        guint *bufsize,
 +                                        guint64 *pts);
 +
 +GST_RTSP_SERVER_API
 +GstWFDResult gst_wfd_message_get_video_playback_status (GstWFDMessage *msg,
 +                                        guint *bufsize,
 +                                        guint64 *pts);
 +G_END_DECLS
 +
 +#endif /* __GST_WFD_MESSAGE_H__ */
@@@ -23,13 -23,6 +23,13 @@@ rtsp_server_sources = 
    'rtsp-onvif-client.c',
    'rtsp-onvif-media-factory.c',
    'rtsp-onvif-media.c',
 +  'rtsp-media-ext.c',
 +  'rtsp-media-factory-wfd.c',
 +  'gstwfdmessage-ext.c',
 +  'gstwfdmessage.c',
 +  'rtsp-client-ext.c',
 +  'rtsp-client-wfd.c',
 +  'rtsp-server-wfd.c',
  ]
  
  rtsp_server_headers = [
    'rtsp-onvif-client.h',
    'rtsp-onvif-media-factory.h',
    'rtsp-onvif-media.h',
 +  'rtsp-media-ext.h',
 +  'rtsp-media-factory-wfd.h',
 +  'gstwfdmessage-ext.h',
 +  'gstwfdmessage.h',
 +  'rtsp-client-ext.h',
 +  'rtsp-client-wfd.h',
 +  'rtsp-server-wfd.h',
  ]
  
  install_headers(rtsp_server_headers, subdir : 'gstreamer-1.0/gst/rtsp-server')
index 3f43973,0000000..3f43973
mode 100644,000000..100644
--- /dev/null
@@@ -1,917 -1,0 +1,917 @@@
 +/* GStreamer
 + * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.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)
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include "config.h"
 +#endif
 +
 +#include <stdio.h>
 +#include <string.h>
 +
 +#include "rtsp-client-ext.h"
 +#include "rtsp-media-factory-wfd.h"
 +#include "rtsp-sdp.h"
 +#include "rtsp-params.h"
 +#include "rtsp-media-ext.h"
 +#include "gstwfdmessage-ext.h"
 +
 +#define GST_RTSP_EXT_CLIENT_GET_PRIVATE(obj)  \
 +   (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_EXT_CLIENT, GstRTSPExtClientPrivate))
 +
 +struct _GstRTSPExtClientPrivate
 +{
 +  GstRTSPMediaExt *media;
 +  guint resend_packets;
 +  guint prev_max_seqnum;
 +  guint prev_fraction_lost;
 +  guint32 prev_max_packets_lost;
 +  gboolean first_rtcp;
 +  guint consecutive_low_bitrate_count;
 +
 +  guint tizen_retransmission_rtp_port;
 +  guint tizen_retransmission_rtcp_port;
 +  guint tizen_fec_t_max;
 +  guint tizen_fec_p_max;
 +  guint tizen_latency_mode;
 +};
 +
 +#define WFD_MOUNT_POINT "/wfd1.0/streamid=0"
 +#define UNSTABLE_NETWORK_INTERVAL 15
 +#define MIN_PORT_NUM 1024
 +#define MAX_PORT_NUM 65535
 +#define TIZEN_RETRANSMISSION_RTP_PORT_NONE 0
 +#define TIZEN_RETRANSMISSION_RTCP_PORT_NONE 0
 +#define MIN_FEC_T_NUM 2
 +#define MAX_FEC_T_NUM 100
 +#define MIN_FEC_P_NUM 2
 +#define MAX_FEC_P_NUM 100
 +#define TIZEN_T_MAX_NONE 0
 +#define TIZEN_P_MAX_NONE 0
 +#define TIZEN_USER_AGENT "TIZEN"
 +#define DEFAULT_WFD_TIMEOUT 60
 +
 +GST_DEBUG_CATEGORY_STATIC (rtsp_ext_client_debug);
 +#define GST_CAT_DEFAULT rtsp_ext_client_debug
 +
 +static gboolean ext_configure_client_media (GstRTSPClient * client,
 +    GstRTSPMedia * media, GstRTSPStream * stream, GstRTSPContext * ctx);
 +static void handle_ext_stats (GstRTSPWFDClient * client, GstStructure * stats);
 +static gchar* handle_ext_m3_req_msg (GstRTSPWFDClient * client, gchar * data);
 +static void handle_ext_set_param_msg (GstRTSPWFDClient * client, gchar * data);
 +
 +static void handle_ext_m3_res_msg (GstRTSPWFDClient * client, gchar * data);
 +static gchar* handle_ext_m4_req_msg (GstRTSPWFDClient * client, gchar * data);
 +
 +static void gst_rtsp_ext_client_finalize (GObject * obj);
 +
 +G_DEFINE_TYPE (GstRTSPExtClient, gst_rtsp_ext_client, GST_TYPE_RTSP_WFD_CLIENT);
 +
 +static void
 +gst_rtsp_ext_client_class_init (GstRTSPExtClientClass * klass)
 +{
 +  GObjectClass *gobject_class;
 +  GstRTSPClientClass *rtsp_client_class;
 +  GstRTSPWFDClientClass *wfd_client_class;
 +
 +  g_type_class_add_private (klass, sizeof (GstRTSPExtClientPrivate));
 +
 +  gobject_class = G_OBJECT_CLASS (klass);
 +  rtsp_client_class = GST_RTSP_CLIENT_CLASS (klass);
 +  wfd_client_class = GST_RTSP_WFD_CLIENT_CLASS (klass);
 +
 +  gobject_class->finalize = gst_rtsp_ext_client_finalize;
 +
 +  rtsp_client_class->configure_client_media = ext_configure_client_media;
 +  wfd_client_class->wfd_rtp_stats = handle_ext_stats;
 +  wfd_client_class->wfd_handle_m3_req_msg = handle_ext_m3_req_msg;
 +  wfd_client_class->wfd_handle_m3_res_msg = handle_ext_m3_res_msg;
 +  wfd_client_class->wfd_handle_m4_req_msg = handle_ext_m4_req_msg;
 +  wfd_client_class->wfd_handle_set_param_msg = handle_ext_set_param_msg;
 +
 +  GST_DEBUG_CATEGORY_INIT (rtsp_ext_client_debug, "rtspextclient", 0,
 +      "GstRTSPExtClient");
 +}
 +
 +static void
 +gst_rtsp_ext_client_init (GstRTSPExtClient * client)
 +{
 +  GstRTSPExtClientPrivate *priv = GST_RTSP_EXT_CLIENT_GET_PRIVATE (client);
 +
 +  client->priv = priv;
 +  priv->resend_packets = 0;
 +  priv->prev_max_seqnum = 0;
 +  priv->prev_fraction_lost = 0;
 +  priv->prev_max_packets_lost = 0;
 +  priv->first_rtcp = FALSE;
 +  priv->consecutive_low_bitrate_count = 0;
 +  priv->tizen_retransmission_rtp_port = TIZEN_RETRANSMISSION_RTP_PORT_NONE;
 +  priv->tizen_retransmission_rtcp_port = TIZEN_RETRANSMISSION_RTCP_PORT_NONE;
 +  priv->tizen_fec_t_max = TIZEN_T_MAX_NONE;
 +  priv->tizen_fec_p_max = TIZEN_P_MAX_NONE;
 +  priv->tizen_latency_mode = GST_WFD_TIZEN_LATENCY_NONE;
 +
 +  GST_INFO_OBJECT (client, "Client is initialized");
 +
 +  return;
 +}
 +
 +/* A client is finalized when the connection is broken */
 +static void
 +gst_rtsp_ext_client_finalize (GObject * obj)
 +{
 +  GstRTSPExtClient *client = GST_RTSP_EXT_CLIENT (obj);
 +//  GstRTSPExtClientPrivate *priv = GST_RTSP_EXT_CLIENT_GET_PRIVATE (client);
 +
 +  GST_INFO ("finalize client %p", client);
 +
 +  G_OBJECT_CLASS (gst_rtsp_ext_client_parent_class)->finalize (obj);
 +}
 +
 +/**
 + * gst_rtsp_ext_client_new:
 + *
 + * Create a new #GstRTSPExtClient instance.
 + *
 + * Returns: a new #GstRTSPExtClient
 + */
 +GstRTSPExtClient *
 +gst_rtsp_ext_client_new (void)
 +{
 +  GstRTSPExtClient *result;
 +
 +  result = g_object_new (GST_TYPE_RTSP_EXT_CLIENT, NULL);
 +
 +  return result;
 +}
 +
 +static gboolean
 +ext_configure_client_media (GstRTSPClient * client, GstRTSPMedia * media,
 +    GstRTSPStream * stream, GstRTSPContext * ctx)
 +{
 +  GstRTSPMediaExt* _media = NULL;
 +  GstRTSPExtClient *_client = GST_RTSP_EXT_CLIENT (client);
 +  GstRTSPExtClientPrivate *priv = GST_RTSP_EXT_CLIENT_GET_PRIVATE (_client);
 +
 +  _media = GST_RTSP_MEDIA_EXT (media);
 +
 +  if (GST_IS_RTSP_MEDIA_EXT (_media)) {
 +    if (_media != priv->media) {
 +      GST_ERROR_OBJECT (client, "Different media!");
 +      priv->media = _media;
 +    }
 +  }
 +
 +  return GST_RTSP_WFD_CLIENT_CLASS (gst_rtsp_ext_client_parent_class)->
 +      configure_client_media (client, media, stream, ctx);
 +}
 +
 +static gboolean
 +_set_venc_bitrate (GstRTSPWFDClient * client, gint bitrate)
 +{
 +  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_venc_bitrate (factory, bitrate);
 +  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
 +_get_venc_bitrate (GstRTSPWFDClient * client, gint * bitrate)
 +{
 +  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_get_venc_bitrate (factory, bitrate);
 +  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
 +_get_config_bitrate (GstRTSPWFDClient * client, guint32 * min, guint32 * max)
 +{
 +  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_get_config_bitrate (factory, min, max);
 +  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
 +_bitrate_config (GstRTSPWFDClient * client, gint bitrate, guint32 min_bitrate)
 +{
 +  GstRTSPExtClient *_client = GST_RTSP_EXT_CLIENT (client);
 +  GstRTSPExtClientPrivate *priv = GST_RTSP_EXT_CLIENT_GET_PRIVATE (_client);
 +  gint prev_bitrate;
 +
 +  _get_venc_bitrate (client, &prev_bitrate);
 +
 +  if (prev_bitrate != bitrate) {
 +    _set_venc_bitrate (client, bitrate);
 +    GST_INFO_OBJECT (client, "[UDP] New Bitrate value [%d]", bitrate);
 +  }
 +
 +  if (prev_bitrate == min_bitrate && prev_bitrate == bitrate)
 +    priv->consecutive_low_bitrate_count++;
 +  else
 +    priv->consecutive_low_bitrate_count = 0;
 +
 +  if (priv->consecutive_low_bitrate_count >= UNSTABLE_NETWORK_INTERVAL) {
 +    /* Network congestion happens. Add logic for popup warning or something else */
 +    GST_WARNING_OBJECT (client, "Network unstable");
 +    priv->consecutive_low_bitrate_count = 0;
 +  }
 +
 +  return TRUE;
 +}
 +
 +static void
 +handle_ext_stats (GstRTSPWFDClient * client, GstStructure * stats)
 +{
 +  GstRTSPExtClient *_client = GST_RTSP_EXT_CLIENT (client);
 +  GstRTSPExtClientPrivate *priv = GST_RTSP_EXT_CLIENT_GET_PRIVATE (_client);
 +  guint latest_resend_packets = 0;
 +
 +  g_return_if_fail (priv != NULL);
 +
 +  latest_resend_packets = gst_rtsp_media_ext_get_resent_packets (priv->media);
 +
 +  GST_INFO_OBJECT (client, "Re-sent RTP packets : %d", latest_resend_packets);
 +
 +  /* calculation to decide bitrate */
 +  {
 +    static gint32 next_k = 40;
 +    static gint32 next_p = 0;
 +    guint32 min_bitrate = 0;
 +    guint32 max_bitrate = 0;
 +    guint fraction_lost = 0;
 +    guint max_seqnum = 0;
 +    gint packetslost;
 +    gint bitrate = 0;
 +    gint temp_fraction_lost = 0;
 +    gint statistics_fraction_lost = 0;
 +    gfloat thretholdValue = 0;
 +    static gint fraction_lost_MA = 0;
 +
 +    gst_structure_get_uint (stats, "rb-fractionlost", &fraction_lost);
 +    gst_structure_get_uint (stats, "rb-exthighestseq", &max_seqnum);
 +    gst_structure_get_int (stats, "rb-packetslost", &packetslost);
 +
 +    _get_venc_bitrate (client, &bitrate);
 +    GST_INFO_OBJECT (client, "[UDP] Current Bitrate value [%d]", bitrate);
 +
 +    _get_config_bitrate (client, &min_bitrate, &max_bitrate);
 +    GST_INFO_OBJECT (client, "[UDP] min [%d], max [%d]", min_bitrate,
 +        max_bitrate);
 +
 +    if (priv->resend_packets == latest_resend_packets)
 +      fraction_lost = 0;
 +    priv->resend_packets = latest_resend_packets;
 +
 +    if (priv->prev_max_seqnum == max_seqnum)
 +      goto config;
 +
 +    if (priv->first_rtcp == FALSE) {
 +      GST_DEBUG_OBJECT (client, "Ignoring first receiver report");
 +      priv->prev_fraction_lost = 0;
 +      priv->prev_max_packets_lost = packetslost;
 +      priv->prev_max_seqnum = max_seqnum;
 +      fraction_lost_MA = 0;
 +      priv->first_rtcp = TRUE;
 +      return;
 +    }
 +
 +    if (priv->prev_fraction_lost == 0)
 +      thretholdValue = 1.0;
 +    else
 +      thretholdValue = 0.8;
 +
 +    if (fraction_lost > 0) {
 +      temp_fraction_lost = fraction_lost * 100 / 256;
 +      GST_DEBUG_OBJECT (client, "fraction lost from sink RR [%d]",
 +          temp_fraction_lost);
 +    } else {
 +      if ((max_seqnum > priv->prev_max_seqnum)
 +          && (packetslost > priv->prev_max_packets_lost))
 +        temp_fraction_lost =
 +            (((packetslost - priv->prev_max_packets_lost) * 100) / (max_seqnum -
 +                priv->prev_max_seqnum));
 +      GST_DEBUG_OBJECT (client, "fraction lost calculated [%d]",
 +          temp_fraction_lost);
 +    }
 +    statistics_fraction_lost =
 +        (gint) (temp_fraction_lost * thretholdValue +
 +        priv->prev_fraction_lost * (1 - thretholdValue));
 +    fraction_lost_MA =
 +        (fraction_lost_MA * 7 + statistics_fraction_lost * 5) / 8;
 +
 +    if (fraction_lost_MA > 100)
 +      fraction_lost_MA = 100;
 +
 +    GST_DEBUG_OBJECT (client,
 +        "statistics fraction lost = %d, fraction lost MA = %d",
 +        statistics_fraction_lost, fraction_lost_MA);
 +
 +    if (temp_fraction_lost > 0) {
 +      guint32 temp_change_bandwith_amount = 0;
 +      gint32 fec_step = 0;
 +
 +      if (statistics_fraction_lost >= 5) {
 +        temp_change_bandwith_amount = max_bitrate - min_bitrate;
 +        fec_step = 10;
 +      } else if (temp_fraction_lost >= 3) {
 +        temp_change_bandwith_amount = (max_bitrate - min_bitrate) / 2;
 +        fec_step = 5;
 +      } else {
 +        temp_change_bandwith_amount = (max_bitrate - min_bitrate) / 4;
 +        fec_step = 3;
 +      }
 +
 +      GST_DEBUG_OBJECT (client,
 +          "LOSS case, statistics fraction lost = %d percent, temp change"
 +          "bandwith amount = %d bit", statistics_fraction_lost,
 +          temp_change_bandwith_amount);
 +
 +      if (next_p >= 100)
 +        next_k -= fec_step;
 +      else
 +        next_p += fec_step;
 +
 +      if (next_k < 10)
 +        next_k = 10;
 +
 +      if (next_p > 100)
 +        next_p = 100;
 +
 +      if (bitrate <= min_bitrate) {
 +        bitrate = min_bitrate;
 +        priv->prev_fraction_lost = statistics_fraction_lost;
 +        priv->prev_max_packets_lost = packetslost;
 +        goto config;
 +      }
 +
 +      bitrate -= temp_change_bandwith_amount;
 +
 +      if (bitrate < min_bitrate)
 +        bitrate = min_bitrate;
 +
 +    } else if (0 == temp_fraction_lost && fraction_lost_MA < 1) {
 +      gint32 fec_step = 0;
 +
 +      if (0 == priv->prev_fraction_lost) {
 +        bitrate += 512 * 1024;
 +        fec_step = 10;
 +      } else {
 +        bitrate += 100 * 1024;
 +        fec_step = 5;
 +      }
 +
 +      if (bitrate > max_bitrate)
 +        bitrate = max_bitrate;
 +
 +      if (next_p <= 0)
 +        next_k += fec_step;
 +      else
 +        next_p -= fec_step;
 +
 +      if (next_k > 100)
 +        next_k = 100;
 +
 +      if (next_p < 0)
 +        next_p = 0;
 +
 +      if (bitrate >= max_bitrate) {
 +        GST_DEBUG_OBJECT (client, "bitrate can not be increased");
 +        bitrate = max_bitrate;
 +        priv->prev_fraction_lost = statistics_fraction_lost;
 +        priv->prev_max_seqnum = max_seqnum;
 +        priv->prev_max_packets_lost = packetslost;
 +        goto config;
 +      }
 +
 +    }
 +
 +    priv->prev_fraction_lost = statistics_fraction_lost;
 +    priv->prev_max_seqnum = max_seqnum;
 +    priv->prev_max_packets_lost = packetslost;
 +
 +    GST_INFO_OBJECT (client, "final bitrate is %d", bitrate);
 +
 +  config:
 +    _bitrate_config (client, bitrate, min_bitrate);
 +    gst_rtsp_media_ext_set_next_param (priv->media, next_k, next_p);
 +  }
 +}
 +
 +static gchar *
 +handle_ext_m3_req_msg (GstRTSPWFDClient * client, gchar * data)
 +{
 +  gchar *tmp = NULL;
 +  gchar *sink_user_agent = NULL;
 +  GstWFDExtMessage *msg = NULL;
 +  GstWFDResult wfd_res = GST_WFD_EINVAL;
 +  gboolean is_appended = FALSE;
 +
 +  g_return_val_if_fail (client != NULL, NULL);
 +  g_return_val_if_fail (data != NULL, NULL);
 +
 +  sink_user_agent = gst_rtsp_wfd_client_get_sink_user_agent (client);
 +
 +  if (sink_user_agent && strstr (sink_user_agent, TIZEN_USER_AGENT)) {
 +
 +    GST_INFO_OBJECT (client,
 +        "Setting tizen extended features on wfd message...");
 +
 +    wfd_res = gst_wfd_ext_message_new (&msg);
 +    if (wfd_res != GST_WFD_OK) {
 +      GST_ERROR_OBJECT (client, "Failed to create wfd message...");
 +      goto error;
 +    }
 +
 +    wfd_res = gst_wfd_ext_message_init (msg);
 +    if (wfd_res != GST_WFD_OK) {
 +      GST_ERROR_OBJECT (client, "Failed to init wfd message...");
 +      goto error;
 +    }
 +
 +    GST_INFO_OBJECT (client,
 +        "Setting tizen extended features on wfd message...");
 +
 +    wfd_res = gst_wfd_ext_message_set_tizen_retransmission (msg, 0, 0);
 +    if (wfd_res != GST_WFD_OK) {
 +      GST_ERROR_OBJECT (client,
 +          "Failed to set tizen retransmission on wfd message...");
 +      goto error;
 +    }
 +
 +    wfd_res = gst_wfd_ext_message_set_tizen_fec (msg, 0, 0);
 +    if (wfd_res != GST_WFD_OK) {
 +      GST_ERROR_OBJECT (client, "Failed to set tizen fec on wfd message...");
 +      goto error;
 +    }
 +
 +    wfd_res = gst_wfd_ext_message_set_tizen_latency_mode (msg, 0);
 +    if (wfd_res != GST_WFD_OK) {
 +      GST_ERROR_OBJECT (client,
 +          "Failed to set tizen latency mode on wfd message...");
 +      goto error;
 +    }
 +
 +    tmp = gst_wfd_ext_message_param_names_as_text (msg);
 +    if (tmp) {
 +      data = g_strconcat (data, tmp, NULL);
 +      g_free (tmp);
 +      is_appended = TRUE;
 +    } else {
 +      GST_ERROR_OBJECT (client,
 +          "Failed to gst_wfd_ext_message_param_names_as_text");
 +      goto error;
 +    }
 +  }
 +  if (msg != NULL)
 +    gst_wfd_ext_message_free (msg);
 +
 +  if (sink_user_agent != NULL)
 +    g_free (sink_user_agent);
 +
 +  if (is_appended == FALSE)
 +    return NULL;
 +  else
 +    return data;
 +
 +error:
 +  if (msg != NULL)
 +    gst_wfd_ext_message_free (msg);
 +
 +  if (sink_user_agent != NULL)
 +    g_free (sink_user_agent);
 +
 +  return NULL;
 +}
 +
 +static void
 +handle_ext_m3_res_msg (GstRTSPWFDClient * client, gchar * data)
 +{
 +  GstWFDExtMessage *msg = NULL;
 +  GstRTSPExtClientPrivate *ext_priv = GST_RTSP_EXT_CLIENT_GET_PRIVATE (client);
 +  GstWFDResult wfd_res = GST_WFD_EINVAL;
 +
 +  g_return_if_fail (ext_priv != NULL);
 +  g_return_if_fail (data != NULL);
 +
 +  wfd_res = gst_wfd_ext_message_new (&msg);
 +  if (wfd_res != GST_WFD_OK) {
 +    GST_ERROR_OBJECT (client, "Failed to create wfd message...");
 +    goto error;
 +  }
 +
 +  wfd_res = gst_wfd_ext_message_init (msg);
 +  if (wfd_res != GST_WFD_OK) {
 +    GST_ERROR_OBJECT (client, "Failed to init wfd message...");
 +    goto error;
 +  }
 +
 +  wfd_res =
 +      gst_wfd_ext_message_parse_buffer ((const guint8 *) data, strlen (data),
 +      msg);
 +  if (wfd_res != GST_WFD_OK) {
 +    GST_ERROR_OBJECT (client, "Failed to parse buffer...");
 +    goto error;
 +  }
 +
 +  /* Get tizen extended features from WFD message. */
 +  if (msg->tizen_retransmission) {
 +
 +    guint rtp_port = TIZEN_RETRANSMISSION_RTP_PORT_NONE;
 +    guint rtcp_port = TIZEN_RETRANSMISSION_RTCP_PORT_NONE;
 +    wfd_res =
 +        gst_wfd_ext_message_get_tizen_retransmission (msg, &rtp_port,
 +        &rtcp_port);
 +    if (wfd_res != GST_WFD_OK) {
 +      GST_ERROR_OBJECT (client,
 +          "Failed to get tizen retransmission from wfd message...");
 +      goto error;
 +    }
 +
 +    if (rtp_port >= MIN_PORT_NUM && rtp_port <= MAX_PORT_NUM)
 +      ext_priv->tizen_retransmission_rtp_port = rtp_port;
 +
 +    if (rtcp_port >= MIN_PORT_NUM && rtcp_port <= MAX_PORT_NUM)
 +      ext_priv->tizen_retransmission_rtcp_port = rtcp_port;
 +
 +    GST_DEBUG_OBJECT (client, "Tizen retransmission rtp_port[%d] rtcp_port[%d]",
 +        ext_priv->tizen_retransmission_rtp_port,
 +        ext_priv->tizen_retransmission_rtcp_port);
 +  }
 +
 +  if (msg->tizen_fec) {
 +
 +    guint fec_t_max = TIZEN_T_MAX_NONE;
 +    guint fec_p_max = TIZEN_P_MAX_NONE;
 +
 +    wfd_res = gst_wfd_ext_message_get_tizen_fec (msg, &fec_t_max, &fec_p_max);
 +    if (wfd_res != GST_WFD_OK) {
 +      GST_ERROR_OBJECT (client, "Failed to get tizen fec from wfd message...");
 +      goto error;
 +    }
 +
 +    if (fec_t_max >= MIN_FEC_T_NUM && fec_t_max <= MAX_FEC_T_NUM)
 +      ext_priv->tizen_fec_t_max = fec_t_max;
 +
 +    if (fec_p_max >= MIN_FEC_P_NUM && fec_p_max <= MAX_FEC_P_NUM)
 +      ext_priv->tizen_fec_p_max = fec_p_max;
 +
 +    GST_DEBUG_OBJECT (client, "Tizen fec t_max[%d] p_max[%d]",
 +        ext_priv->tizen_fec_t_max, ext_priv->tizen_fec_p_max);
 +  }
 +
 +  if (msg->tizen_latency_mode) {
 +    wfd_res =
 +        gst_wfd_ext_message_get_tizen_latency_mode (msg,
 +        &ext_priv->tizen_latency_mode);
 +    if (wfd_res != GST_WFD_OK) {
 +      GST_ERROR_OBJECT (client,
 +          "Failed to get tizen latency mode on wfd message...");
 +      goto error;
 +    }
 +    GST_DEBUG_OBJECT (client, "Tizen latency mode[%d]",
 +        ext_priv->tizen_latency_mode);
 +  }
 +
 +  if (msg != NULL)
 +    gst_wfd_ext_message_free (msg);
 +
 +  return;
 +error:
 +
 +  if (msg != NULL)
 +    gst_wfd_ext_message_free (msg);
 +
 +  return;
 +}
 +
 +static void
 +media_ext_constructed (GstRTSPMediaFactory * factory, GstRTSPMedia * media,
 +    GstRTSPExtClient * client)
 +{
 +  GstRTSPExtClientPrivate *priv = GST_RTSP_EXT_CLIENT_GET_PRIVATE (client);
 +  g_return_if_fail (priv != NULL);
 +
 +  priv->media = GST_RTSP_MEDIA_EXT (media);
 +
 +  if (priv->tizen_retransmission_rtp_port != TIZEN_RETRANSMISSION_RTP_PORT_NONE
 +      && priv->tizen_retransmission_rtcp_port !=
 +      TIZEN_RETRANSMISSION_RTCP_PORT_NONE) {
 +    GST_DEBUG_OBJECT (client, "Tizen retransmission rtp_port[%d] rtcp_port[%d]",
 +        priv->tizen_retransmission_rtp_port,
 +        priv->tizen_retransmission_rtcp_port);
 +    gst_rtsp_media_ext_set_extended_mode (priv->media, MEDIA_EXT_MODE_RESEND);
 +    gst_rtsp_media_ext_set_retrans_port (priv->media,
 +        priv->tizen_retransmission_rtp_port);
 +  }
 +  if (priv->tizen_fec_t_max != TIZEN_T_MAX_NONE
 +      && priv->tizen_fec_p_max != TIZEN_P_MAX_NONE) {
 +    GST_DEBUG_OBJECT (client, "Tizen fec t_max[%d] p_max[%d]",
 +        priv->tizen_fec_t_max, priv->tizen_fec_p_max);
 +    gst_rtsp_media_ext_set_extended_mode (priv->media, MEDIA_EXT_MODE_FEC);
 +    gst_rtsp_media_ext_set_fec_value (priv->media, priv->tizen_fec_t_max,
 +        priv->tizen_fec_p_max);
 +  }
 +  if (priv->tizen_latency_mode != GST_WFD_TIZEN_LATENCY_NONE) {
 +    GST_DEBUG_OBJECT (client, "Tizen latency mode[%d]",
 +        priv->tizen_latency_mode);
 +    gst_rtsp_media_ext_set_latency_mode (priv->media, priv->tizen_latency_mode);
 +  }
 +}
 +
 +static void
 +gst_wfd_ext_listen_media_constructed (GstRTSPWFDClient * client)
 +{
 +  GstRTSPMediaFactory *factory = NULL;
 +  GstRTSPMountPoints *mount_points = NULL;
 +  gchar *path = NULL;
 +  gint matched = 0;
 +  GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
 +
 +  GstRTSPExtClient *_client = GST_RTSP_EXT_CLIENT (client);
 +
 +  if (!(mount_points = gst_rtsp_client_get_mount_points (parent_client))) {
 +    GST_ERROR_OBJECT (client,
 +        "Failed to set negotiated resolution: no mount points...");
 +    goto no_mount_points;
 +  }
 +
 +  path = g_strdup (WFD_MOUNT_POINT);
 +  if (!path) {
 +    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...");
 +    goto no_factory;
 +  }
 +
 +  g_signal_connect (factory, "media-constructed",
 +      (GCallback) media_ext_constructed, _client);
 +
 +no_factory:
 +  g_free (path);
 +no_path:
 +  g_object_unref (mount_points);
 +no_mount_points:
 +  return;
 +}
 +
 +static void
 +handle_ext_set_param_msg (GstRTSPWFDClient * client, gchar * data)
 +{
 +  GstRTSPExtClientPrivate *priv = GST_RTSP_EXT_CLIENT_GET_PRIVATE (client);
 +
 +  g_return_if_fail (priv != NULL);
 +  g_return_if_fail (data != NULL);
 +
 +  return;
 +}
 +
 +static gchar *
 +handle_ext_m4_req_msg (GstRTSPWFDClient * client, gchar * data)
 +{
 +  GstWFDExtMessage *msg = NULL;
 +  gchar *tmp = NULL;
 +  GstRTSPExtClientPrivate *ext_priv = GST_RTSP_EXT_CLIENT_GET_PRIVATE (client);
 +  GstWFDResult wfd_res = GST_WFD_EINVAL;
 +
 +  g_return_val_if_fail (ext_priv != NULL, NULL);
 +  g_return_val_if_fail (data != NULL, NULL);
 +
 +  wfd_res = gst_wfd_ext_message_new (&msg);
 +  if (wfd_res != GST_WFD_OK) {
 +    GST_ERROR_OBJECT (client, "Failed to create wfd message...");
 +    goto error;
 +  }
 +
 +  wfd_res = gst_wfd_ext_message_init (msg);
 +  if (wfd_res != GST_WFD_OK) {
 +    GST_ERROR_OBJECT (client, "Failed to init wfd message...");
 +    goto error;
 +  }
 +
 +  GST_INFO_OBJECT (client, "Setting extended features on wfd message...");
 +
 +  if (ext_priv->tizen_retransmission_rtp_port !=
 +      TIZEN_RETRANSMISSION_RTP_PORT_NONE
 +      && ext_priv->tizen_retransmission_rtcp_port !=
 +      TIZEN_RETRANSMISSION_RTCP_PORT_NONE) {
 +
 +    wfd_res =
 +        gst_wfd_ext_message_set_tizen_retransmission (msg,
 +        ext_priv->tizen_retransmission_rtp_port,
 +        ext_priv->tizen_retransmission_rtcp_port);
 +    if (wfd_res != GST_WFD_OK) {
 +      GST_ERROR_OBJECT (client,
 +          "Failed to set tizen retransmission on wfd message...");
 +      goto error;
 +    }
 +    GST_DEBUG_OBJECT (client, "Tizen retransmission rtp_port[%d] rtcp_port[%d]",
 +        ext_priv->tizen_retransmission_rtp_port,
 +        ext_priv->tizen_retransmission_rtcp_port);
 +  }
 +
 +  if (ext_priv->tizen_fec_t_max != TIZEN_T_MAX_NONE
 +      && ext_priv->tizen_fec_p_max != TIZEN_P_MAX_NONE) {
 +
 +    wfd_res =
 +        gst_wfd_ext_message_set_tizen_fec (msg, ext_priv->tizen_fec_t_max,
 +        ext_priv->tizen_fec_p_max);
 +    if (wfd_res != GST_WFD_OK) {
 +      GST_ERROR_OBJECT (client, "Failed to set tizen fec on wfd message...");
 +      goto error;
 +    }
 +    GST_DEBUG_OBJECT (client, "Tizen fec t_max[%d] p_max[%d]",
 +        ext_priv->tizen_fec_t_max, ext_priv->tizen_fec_p_max);
 +  }
 +
 +  if (ext_priv->tizen_latency_mode != GST_WFD_TIZEN_LATENCY_NONE) {
 +
 +    wfd_res =
 +        gst_wfd_ext_message_set_tizen_latency_mode (msg,
 +        ext_priv->tizen_latency_mode);
 +    if (wfd_res != GST_WFD_OK) {
 +      GST_ERROR_OBJECT (client,
 +          "Failed to set tizen latency mode on wfd message...");
 +      goto error;
 +    }
 +    GST_DEBUG_OBJECT (client, "Tizen latency mode[%d]",
 +        ext_priv->tizen_latency_mode);
 +  }
 +
 +  tmp = gst_wfd_ext_message_as_text (msg);
 +  if (tmp) {
 +    data = g_strconcat (data, tmp, NULL);
 +    g_free (tmp);
 +  } else {
 +    GST_ERROR_OBJECT (client, "Failed to gst_wfd_ext_message_as_text");
 +    goto error;
 +  }
 +
 +  if (msg != NULL)
 +    gst_wfd_ext_message_free (msg);
 +
 +  gst_wfd_ext_listen_media_constructed (client);
 +
 +  return data;
 +
 +error:
 +
 +  if (msg != NULL)
 +    gst_wfd_ext_message_free (msg);
 +
 +  return NULL;
 +}
index eb73154,0000000..eb73154
mode 100755,000000..100755
--- /dev/null
@@@ -1,75 -1,0 +1,75 @@@
 +/* GStreamer
 + * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.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_EXT_CLIENT_H__
 +#define __GST_RTSP_EXT_CLIENT_H__
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _GstRTSPExtClient GstRTSPExtClient;
 +typedef struct _GstRTSPExtClientClass GstRTSPExtClientClass;
 +typedef struct _GstRTSPExtClientPrivate GstRTSPExtClientPrivate;
 +
 +#include "rtsp-mount-points.h"
 +#include "rtsp-client-wfd.h"
 +
 +#define GST_TYPE_RTSP_EXT_CLIENT              (gst_rtsp_ext_client_get_type ())
 +#define GST_IS_RTSP_EXT_CLIENT(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_EXT_CLIENT))
 +#define GST_IS_RTSP_EXT_CLIENT_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_EXT_CLIENT))
 +#define GST_RTSP_EXT_CLIENT_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_EXT_CLIENT, GstRTSPExtClientClass))
 +#define GST_RTSP_EXT_CLIENT(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_EXT_CLIENT, GstRTSPExtClient))
 +#define GST_RTSP_EXT_CLIENT_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_EXT_CLIENT, GstRTSPExtClientClass))
 +#define GST_RTSP_EXT_CLIENT_CAST(obj)         ((GstRTSPExtClient*)(obj))
 +#define GST_RTSP_EXT_CLIENT_CLASS_CAST(klass) ((GstRTSPExtClientClass*)(klass))
 +
 +/**
 + * GstRTSPExtClient:
 + *
 + * The client object represents the connection and its state with a client.
 + */
 +struct _GstRTSPExtClient {
 +  GstRTSPWFDClient  parent;
 +
 +  /*< private >*/
 +  GstRTSPExtClientPrivate *priv;
 +  gpointer _gst_reserved[GST_PADDING];
 +};
 +
 +/**
 + * GstRTSPExtClientClass:
 + *
 + * The client class structure.
 + */
 +struct _GstRTSPExtClientClass {
 +  GstRTSPWFDClientClass  parent_class;
 +  gpointer _gst_reserved[GST_PADDING];
 +};
 +
 +GST_RTSP_SERVER_API
 +GType                 gst_rtsp_ext_client_get_type          (void);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPExtClient *    gst_rtsp_ext_client_new               (void);
 +
 +G_END_DECLS
 +
 +#endif /* __GST_RTSP_EXT_CLIENT_H__ */
index a7e492b,0000000..a7e492b
mode 100644,000000..100644
--- /dev/null
@@@ -1,4373 -1,0 +1,4373 @@@
 +/* 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)
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include "config.h"
 +#endif
 +
 +#include <stdio.h>
 +#include <string.h>
 +#include <unistd.h>
 +#include <sys/ioctl.h>
 +#include <netinet/in.h>
 +#include <netinet/tcp.h>
 +#include <arpa/inet.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;
 +};
 +
 +typedef enum {
 +  WFD_TS_UDP,
 +  WFD_TS_TCP
 +} WFDTSMode;
 +
 +typedef enum {
 +  WFD_TS_REP_AUDIO,
 +  WFD_TS_REP_VIDEO
 +} WFDTSReportType;
 +
 +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;
 +  guint8 video_codec;
 +  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 direct_streaming_supported;
 +  gint direct_streaming_state;
 +  guint8 direct_detected_video_codec;
 +  guint8 direct_detected_audio_codec;
 +
 +  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;
 +
 +  gchar *sink_user_agent;
 +  guint ctrans_tcp;
 +  guint cprofile_tcp;
 +  guint clowertrans_tcp;
 +  guint32 crtp_port0_tcp;
 +  guint32 crtp_port1_tcp;
 +  guint buf_len;
 +  WFDTSMode ts_mode;
 +  WFDTSReportType report_type;
 +  GstRTSPWatch *datawatch;
 +  guint datawatchid;
 +  GstRTSPConnection *data_conn;
 +  gchar *uristr;
 +  GMutex tcp_send_lock;
 +
 +  /* enable or disable R2 features */
 +  gboolean wfd2_mode;
 +  gint wfd2_supported;
 +  gboolean coupling_mode;
 +
 +  guint coupled_sink_status;
 +  gchar *coupled_sink_address;
 +  gboolean coupled_sink_supported;
 +};
 +
 +#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_PLAYING_DONE,
 +  SIGNAL_WFD_RTP_STATS,
 +  SIGNAL_WFD_M3_REQ_MSG,
 +  SIGNAL_WFD_M3_RES_MSG,
 +  SIGNAL_WFD_M4_REQ_MSG,
 +  SIGNAL_WFD_SET_PARAM_MSG,
 +  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, GstRTSPVersion version);
 +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_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);
 +
 +static GstRTSPResult handle_M4_direct_streaming_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);
 +
 +  gst_rtsp_client_wfd_signals[SIGNAL_WFD_PLAYING_DONE] =
 +      g_signal_new ("wfd-playing-done", G_TYPE_FROM_CLASS (klass),
 +      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPWFDClientClass,
 +          wfd_playing_done), NULL, NULL, g_cclosure_marshal_generic,
 +      G_TYPE_NONE, 0, G_TYPE_NONE);
 +
 +  gst_rtsp_client_wfd_signals[SIGNAL_WFD_RTP_STATS] =
 +      g_signal_new ("wfd-rtp-stats", G_TYPE_FROM_CLASS (klass),
 +      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPWFDClientClass,
 +          wfd_rtp_stats), NULL, NULL, g_cclosure_marshal_generic,
 +      G_TYPE_NONE, 1, GST_TYPE_STRUCTURE);
 +
 +  gst_rtsp_client_wfd_signals[SIGNAL_WFD_M3_REQ_MSG] =
 +      g_signal_new ("wfd-m3-request-msg", G_TYPE_FROM_CLASS (klass),
 +      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPWFDClientClass,
 +          wfd_handle_m3_req_msg), NULL, NULL, g_cclosure_marshal_generic,
 +      G_TYPE_STRING, 1, G_TYPE_STRING);
 +
 +  gst_rtsp_client_wfd_signals[SIGNAL_WFD_M3_RES_MSG] =
 +      g_signal_new ("wfd-m3-response-msg", G_TYPE_FROM_CLASS (klass),
 +      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPWFDClientClass,
 +          wfd_handle_m3_res_msg), NULL, NULL, g_cclosure_marshal_generic,
 +      G_TYPE_NONE, 1, G_TYPE_STRING);
 +
 +  gst_rtsp_client_wfd_signals[SIGNAL_WFD_M4_REQ_MSG] =
 +      g_signal_new ("wfd-m4-request-msg", G_TYPE_FROM_CLASS (klass),
 +      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPWFDClientClass,
 +          wfd_handle_m4_req_msg), NULL, NULL, g_cclosure_marshal_generic,
 +      G_TYPE_STRING, 1, G_TYPE_STRING);
 +
 +  gst_rtsp_client_wfd_signals[SIGNAL_WFD_SET_PARAM_MSG] =
 +      g_signal_new ("wfd-set-param-msg", G_TYPE_FROM_CLASS (klass),
 +      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPWFDClientClass,
 +          wfd_handle_set_param_msg), NULL, NULL, g_cclosure_marshal_generic,
 +      G_TYPE_NONE, 1, G_TYPE_STRING);
 +
 +  klass->wfd_options_request = wfd_options_request_done;
 +  klass->wfd_get_param_request = wfd_get_param_request_done;
 +  klass->configure_client_media = wfd_configure_client_media;
 +
 +  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));
 +
 +  priv->direct_streaming_supported = FALSE;
 +  priv->direct_streaming_state = 0;
 +
 +  priv->sink_user_agent = NULL;
 +
 +  priv->ts_mode = WFD_TS_UDP;
 +  priv->report_type = WFD_TS_REP_AUDIO;
 +
 +  priv->wfd2_supported = 0;
 +  priv->coupled_sink_address = NULL;
 +
 +  g_mutex_init (&priv->tcp_send_lock);
 +  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);
 +
 +  if (priv->sink_user_agent) {
 +    g_free (priv->sink_user_agent);
 +    priv->sink_user_agent = NULL;
 +  }
 +
 +  g_mutex_clear (&priv->keep_alive_lock);
 +  g_mutex_clear (&priv->stats_lock);
 +  g_mutex_clear (&priv->tcp_send_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);
 +  g_signal_emit (client, gst_rtsp_client_wfd_signals[SIGNAL_WFD_RTP_STATS], 0,
 +      stats);
 +}
 +
 +static gboolean
 +wfd_configure_client_media (GstRTSPClient * client, GstRTSPMedia * media,
 +    GstRTSPStream * stream, GstRTSPContext * ctx)
 +{
 +  if (media) {
 +    GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
 +    priv->media = media;
 +  }
 +  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_preferred_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 guint
 +wfd_get_preferred_video_codec (guint8 srcVideoCodec, guint sinkVideoCodec)
 +{
 +  int i = 0;
 +  guint codec = 0;
 +  for (i = 0; i < 8; i++) {
 +    if (((sinkVideoCodec << i) & 0x80)
 +        && ((srcVideoCodec << i) & 0x80)) {
 +      codec = (0x01 << (7 - i));
 +      break;
 +    }
 +  }
 +  return codec;
 +}
 +
 +static guint64
 +wfd_get_preferred_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);
 +
 +  g_signal_emit (client,
 +      gst_rtsp_client_wfd_signals[SIGNAL_WFD_PLAYING_DONE], 0, NULL);
 +}
 +
 +static gboolean
 +do_send_data (GstBuffer * buffer, guint8 channel, GstRTSPClient * client)
 +{
 +  GstRTSPMessage message = { 0 };
 +  GstRTSPResult res = GST_RTSP_OK;
 +  GstMapInfo map_info;
 +  guint8 *data;
 +  guint usize;
 +
 +  gst_rtsp_message_init_data (&message, channel);
 +
 +  /* FIXME, need some sort of iovec RTSPMessage here */
 +  if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ))
 +    return FALSE;
 +
 +  gst_rtsp_message_take_body (&message, map_info.data, map_info.size);
 +
 +  g_mutex_lock (&(GST_RTSP_WFD_CLIENT (client)->priv->tcp_send_lock));
 +
 +  gst_rtsp_watch_send_message (GST_RTSP_WFD_CLIENT (client)->priv->datawatch, &message, NULL);
 +
 +  g_mutex_unlock (&(GST_RTSP_WFD_CLIENT (client)->priv->tcp_send_lock));
 +
 +  gst_rtsp_message_steal_body (&message, &data, &usize);
 +  gst_buffer_unmap (buffer, &map_info);
 +
 +  gst_rtsp_message_unset (&message);
 +
 +  return res == GST_RTSP_OK;
 +}
 +static GstRTSPResult
 +message_received (GstRTSPWatch * watch, GstRTSPMessage * message,
 +    gpointer user_data)
 +{
 +  return gst_rtsp_client_handle_message (GST_RTSP_CLIENT (user_data), message);
 +}
 +
 +static GstRTSPResult
 +message_sent (GstRTSPWatch * watch, guint cseq, gpointer user_data)
 +{
 +  GstRTSPClient *client;
 +
 +  client = GST_RTSP_CLIENT (user_data);
 +  if(client == NULL)
 +    return GST_RTSP_ERROR;
 +  return GST_RTSP_OK;
 +}
 +
 +static GstRTSPResult
 +error (GstRTSPWatch * watch, GstRTSPResult result, gpointer user_data)
 +{
 +  GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
 +  gchar *str;
 +
 +  str = gst_rtsp_strresult (result);
 +  GST_INFO ("client %p: received an error %s", client, str);
 +  g_free (str);
 +
 +  return GST_RTSP_OK;
 +}
 +static GstRTSPResult
 +closed_tcp (GstRTSPWatch * watch, gpointer user_data)
 +{
 +  GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
 +
 +  GST_INFO ("client %p: connection closed", client);
 +
 +  return GST_RTSP_OK;
 +}
 +
 +static GstRTSPResult
 +error_full_tcp (GstRTSPWatch * watch, GstRTSPResult result,
 +    GstRTSPMessage * message, guint id, gpointer user_data)
 +{
 +  GstRTSPClient *client = GST_RTSP_CLIENT (user_data);
 +  gchar *str;
 +
 +  str = gst_rtsp_strresult (result);
 +  GST_INFO
 +    ("client %p: received an error %s when handling message %p with id %d",
 +     client, str, message, id);
 +  g_free (str);
 +
 +  return GST_RTSP_OK;
 +}
 +
 +static GstRTSPWatchFuncs watch_funcs_tcp = {
 +  message_received,
 +  message_sent,
 +  closed_tcp,
 +  error,
 +  NULL,
 +  NULL,
 +  error_full_tcp,
 +  NULL
 +};
 +static void
 +client_watch_notify_tcp (GstRTSPClient * client)
 +{
 +  GST_INFO ("client %p: watch destroyed", client);
 +  GST_RTSP_WFD_CLIENT (client)->priv->datawatch = NULL;
 +  GST_RTSP_WFD_CLIENT (client)->priv->data_conn = NULL;
 +}
 +
 +static GstRTSPResult
 +new_tcp (GstRTSPWFDClient * client)
 +{
 +  GstRTSPResult res = GST_RTSP_OK;
 +  GstRTSPConnection *conn = NULL;
 +  GstRTSPConnection *parent_conn = NULL;
 +  GstRTSPUrl *url;
 +  GSource *source;
 +  GMainContext *context;
 +  int conn_retry_remained = 10;
 +  int bsize = -1;
 +  GError *err = NULL;
 +
 +  /* client's address */
 +  int ret;
 +  GSocket *tcp_socket = NULL;
 +  GSocketAddress *tcp_socket_addr = NULL;
 +
 +  /* Get the client connection details */
 +  parent_conn = gst_rtsp_client_get_connection (GST_RTSP_CLIENT (client));
 +  url = gst_rtsp_connection_get_url (parent_conn);
 +  if(!url)
 +    return GST_RTSP_ERROR;
 +
 +  gst_rtsp_url_set_port (url, client->priv->crtp_port0_tcp);
 +
 +  GST_INFO ("create new connection %p ip %s:%d", client, url->host, url->port);
 +
 +  /* create a TCP/IP socket */
 +  if ((tcp_socket = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, NULL)) == NULL) {
 +    GST_ERROR ("cannot create socket");
 +    return GST_RTSP_ERROR;
 +  }
 +
 +  /* allow immediate reuse of the port */
 +  ret = g_socket_set_option (tcp_socket, SOL_SOCKET, SO_REUSEADDR, TRUE, NULL);
 +  if (ret == 0) {
 +    GST_ERROR ("cannot change socket options");
 +    goto failed;
 +  }
 +
 +  /* bind the socket to our source address */
 +  tcp_socket_addr = g_inet_socket_address_new_from_string (url->host, url->port);
 +  if (!tcp_socket_addr) {
 +    GST_ERROR ("tcp_socket_addr is failed");
 +    goto failed;
 +  }
 +
 +  g_socket_set_blocking (tcp_socket, FALSE);
 +
 +  while (!g_socket_connect (tcp_socket, tcp_socket_addr, NULL, &err)) {
 +    GST_ERROR ("Connection failed... Try again...");
 +    if (err) {
 +      GST_ERROR ("         error: [%s]", err->message);
 +      g_error_free (err);
 +      err = NULL;
 +    }
 +
 +    if (conn_retry_remained-- == 0) {
 +      GST_ERROR ("Failed to connection finally.");
 +      goto failed;
 +    }
 +
 +    usleep (100000);
 +  }
 +
 +  res = gst_rtsp_connection_create_from_socket (tcp_socket, url->host, url->port, NULL, &conn);
 +  if (res < 0) {
 +    GST_ERROR ("gst_rtsp_connection_create_from_socket function is failed");
 +    goto failed;
 +  }
 +
 +  /* Set send buffer size to 1024000 */
 +  if (g_socket_set_option (tcp_socket , SOL_SOCKET, SO_SNDBUF, 1024000, NULL))
 +    GST_DEBUG_OBJECT (client, "Set send buf size : %d\n", bsize);
 +  else
 +    GST_ERROR_OBJECT (client, "SO_SNDBUF setsockopt failed");
 +
 +  /* Get send buffer size */
 +  if (g_socket_get_option (tcp_socket , SOL_SOCKET, SO_SNDBUF, &bsize, &err)) {
 +    GST_DEBUG_OBJECT (client, "Get send buf size : %d\n", bsize);
 +  } else {
 +    GST_ERROR_OBJECT (client, "SO_SNDBUF getsockopt failed");
 +    if (err) {
 +      GST_ERROR_OBJECT (client,"         error: [%s]", err->message);
 +      g_error_free (err);
 +      err = NULL;
 +    }
 +  }
 +
 +  /* Set TCP no delay */
 +  if (g_socket_set_option (tcp_socket , IPPROTO_TCP, TCP_NODELAY, TRUE, NULL))
 +    GST_DEBUG_OBJECT (client, "TCP NO DELAY");
 +  else
 +    GST_ERROR_OBJECT (client, "TCP_NODELAY setsockopt failed");
 +
 +  client->priv->data_conn = conn;
 +
 +  /* create watch for the connection and attach */
 +  client->priv->datawatch = gst_rtsp_watch_new (client->priv->data_conn, &watch_funcs_tcp, client, (GDestroyNotify) client_watch_notify_tcp);
 +  GST_DEBUG_OBJECT (client, "data watch : %p", client->priv->datawatch);
 +  /* find the context to add the watch */
 +  if ((source = g_main_current_source ()))
 +    context = g_source_get_context (source);
 +  else
 +    context = NULL;
 +
 +  GST_DEBUG (" source = %p", source);
 +  GST_INFO ("attaching to context %p", context);
 +  client->priv->datawatchid = gst_rtsp_watch_attach (client->priv->datawatch, context);
 +  gst_rtsp_watch_unref (client->priv->datawatch);
 +  g_object_unref (tcp_socket_addr);
 +  return res;
 +
 +failed:
 +  g_object_unref (tcp_socket_addr);
 +  g_object_unref (tcp_socket);
 +
 +  return GST_RTSP_ERROR;
 +}
 +
 +static void
 +do_keepalive (GstRTSPSession * session)
 +{
 +  GST_INFO ("keep session %p alive", session);
 +  gst_rtsp_session_touch (session);
 +}
 +static void
 +map_transport (GstRTSPWFDClient * client, GstRTSPTransport  * ct)
 +{
 +  switch(client->priv->ctrans) {
 +    case GST_WFD_RTSP_TRANS_RTP:
 +      ct->trans = GST_RTSP_TRANS_RTP;
 +      break;
 +    case GST_WFD_RTSP_TRANS_RDT:
 +      ct->trans = GST_RTSP_TRANS_RDT;
 +      break;
 +    default:
 +      ct->trans = GST_RTSP_TRANS_UNKNOWN;
 +      break;
 +  }
 +  switch(client->priv->cprofile) {
 +    case GST_WFD_RTSP_PROFILE_AVP:
 +      ct->profile = GST_RTSP_PROFILE_AVP;
 +      break;
 +    case GST_WFD_RTSP_PROFILE_SAVP:
 +      ct->profile = GST_RTSP_PROFILE_SAVP;
 +      break;
 +    default:
 +      ct->profile = GST_RTSP_PROFILE_UNKNOWN;
 +      break;
 +  }
 +  switch(client->priv->clowertrans) {
 +    case GST_WFD_RTSP_LOWER_TRANS_UDP:
 +      ct->lower_transport = GST_RTSP_LOWER_TRANS_UDP;
 +      break;
 +    case GST_WFD_RTSP_LOWER_TRANS_UDP_MCAST:
 +      ct->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST;
 +      break;
 +    case GST_WFD_RTSP_LOWER_TRANS_TCP:
 +      ct->lower_transport = GST_RTSP_LOWER_TRANS_TCP;
 +      break;
 +    case GST_WFD_RTSP_LOWER_TRANS_HTTP:
 +      ct->lower_transport = GST_RTSP_LOWER_TRANS_HTTP;
 +      break;
 +    default:
 +      ct->lower_transport = GST_RTSP_LOWER_TRANS_UNKNOWN;
 +      break;
 +  }
 +
 +  if (client->priv->ts_mode == WFD_TS_TCP)
 +    ct->lower_transport = GST_RTSP_LOWER_TRANS_TCP;
 +}
 +
 +static GstRTSPResult
 +handle_ts_response (GstRTSPWFDClient * client, GstRTSPContext * ctx)
 +{
 +  GstRTSPResult res = GST_RTSP_OK;
 +  GstRTSPTransport *ct;
 +  GstRTSPConnection *conn;
 +  GstRTSPUrl *url = NULL;
 +  GList *t = NULL;
 +  GstRTSPStreamTransport *tr = NULL;
 +  GPtrArray *ta = NULL;
 +
 +  ta = g_ptr_array_new();
 +
 +  t = client->priv->transports;
 +  tr = GST_RTSP_STREAM_TRANSPORT (t->data);
 +  g_ptr_array_add (ta, t->data);
 +
 +  gst_rtsp_stream_transport_set_callbacks (tr, NULL, NULL, NULL, NULL);
 +  gst_rtsp_stream_transport_set_keepalive (tr, NULL, ctx->session, NULL);
 +
 +  gst_rtsp_transport_new (&ct);
 +
 +  map_transport (client, ct);
 +
 +  if (ct->trans != GST_RTSP_TRANS_RTP || ct->profile != GST_RTSP_PROFILE_AVP) {
 +    GST_WARNING_OBJECT (client, "Trans or profile is wrong");
 +    goto error;
 +  }
 +  if (ct->lower_transport == GST_RTSP_LOWER_TRANS_HTTP ||
 +      ct->lower_transport == GST_RTSP_LOWER_TRANS_UNKNOWN) {
 +    GST_WARNING_OBJECT (client, "Lowertrans is wrong");
 +    goto error;
 +  }
 +
 +  if (client->priv->ts_mode == WFD_TS_UDP) {
 +    g_print ("\nSwitched to UDP !!!\n");
 +    /* Free any previous TCP connection */
 +    if(client->priv->data_conn)
 +    {
 +      gst_rtsp_connection_close (client->priv->data_conn);
 +      gst_rtsp_connection_free(client->priv->data_conn);
 +      if (client->priv->datawatch) {
 +        g_source_destroy ((GSource *)client->priv->datawatch);
 +      }
 +    }
 +    conn = gst_rtsp_client_get_connection (GST_RTSP_CLIENT (client));
 +    url = gst_rtsp_connection_get_url (conn);
 +    gst_rtsp_url_set_port (url, client->priv->crtp_port0);
 +    ct->destination = g_strdup (url->host);
 +    ct->client_port.min = client->priv->crtp_port0;
 +    if(client->priv->crtp_port1 == 0)
 +      ct->client_port.max = client->priv->crtp_port0 + 1;
 +    else ct->client_port.max = client->priv->crtp_port1;
 +  } else if (client->priv->ts_mode == WFD_TS_TCP) {
 +    res = new_tcp(client);
 +    if(res != GST_RTSP_OK)
 +      goto error;
 +
 +    conn = gst_rtsp_client_get_connection (GST_RTSP_CLIENT (client));
 +    url = gst_rtsp_connection_get_url (conn);
 +    ct->destination = g_strdup (url->host);
 +    ct->client_port.min = client->priv->crtp_port0_tcp;
 +    if(client->priv->crtp_port1_tcp == 0)
 +      ct->client_port.max = client->priv->crtp_port0_tcp + 1;
 +    else ct->client_port.max = client->priv->crtp_port1_tcp;
 +  }
 +
 +  gst_rtsp_stream_transport_set_transport (tr, ct);
 +
 +  GST_DEBUG ("client %p: linking transport", client);
 +  if (client->priv->ts_mode == WFD_TS_TCP) {
 +    g_print ("\nSwitched to TCP !!!\n");
 +    gst_rtsp_stream_transport_set_callbacks (tr, (GstRTSPSendFunc) do_send_data,
 +        (GstRTSPSendFunc) do_send_data, client, NULL);
 +  }
 +  else if(client->priv->ts_mode == WFD_TS_UDP ) {
 +    g_print ("\nSwitched to UDP !!!\n");
 +    /* configure keepalive for this transport */
 +    gst_rtsp_stream_transport_set_keepalive (tr, (GstRTSPKeepAliveFunc) do_keepalive, ctx->session, NULL);
 +    gst_rtsp_stream_transport_set_callbacks (tr, NULL, NULL, client, NULL);
 +  }
 +
 +  gst_rtsp_media_set_state (client->priv->media, GST_STATE_PLAYING, ta);
 +
 +  g_ptr_array_free (ta, FALSE);
 +
 +  return res;
 +
 +error:
 +  gst_rtsp_transport_free (ct);
 +  g_ptr_array_free (ta, FALSE);
 +  return GST_RTSP_ERROR;
 +}
 +
 +static void
 +handle_wfd_response (GstRTSPClient * client, GstRTSPContext * ctx)
 +{
 +  GstRTSPResult res = GST_RTSP_OK;
 +  guint8 *data = NULL;
 +  guint size = 0;
 +  GstWFDResult wfd_res;
 +  GstWFDMessage *msg = NULL;
 +
 +  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;
 +  }
 +
 +  if (priv->sink_user_agent == NULL) {
 +    gchar *user_agent = NULL;
 +    res = gst_rtsp_message_get_header (ctx->response, GST_RTSP_HDR_USER_AGENT,
 +        &user_agent, 0);
 +      if (res == GST_RTSP_OK) {
 +      priv->sink_user_agent = g_strdup (user_agent);
 +      GST_INFO_OBJECT (_client, "sink user_agent : %s", priv->sink_user_agent);
 +    } else {
 +      GST_INFO_OBJECT (_client, "user_agent is NULL and user_agent is optional.");
 +    }
 +  }
 +
 +  /* 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) {
 +      /* 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_ERROR_OBJECT (client, "M3 response server side message body: %s",
 +          gst_wfd_message_as_text (msg));
 +
 +      /* Get the audio formats supported by WFDSink */
 +      if (msg->wfd2_audio_codecs && msg->wfd2_audio_codecs->count > 0) {
 +        priv->wfd2_mode = TRUE;
 +        wfd_res =
 +            gst_wfd_message_get_supported_wfd2_audio_codec (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;
 +        }
 +      } else if (msg->audio_codecs && msg->audio_codecs->count > 0) {
 +        priv->wfd2_mode = FALSE;
 +        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;
 +        }
 +      }
 +
 +      if (msg->direct_video_formats) {
 +        priv->direct_streaming_supported = TRUE;
 +      }
 +
 +      /* Get the Video formats supported by WFDSink */
 +      if (msg->video_formats && msg->video_formats->count > 0) {
 +        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_preferred_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 preferred RTP ports...");
 +          goto error;
 +        }
 +      }
 +      if (msg->tcp_ports) {
 +        /* Get the TCP ports preferred by WFDSink */
 +        wfd_res =
 +            gst_wfd_message_get_preferred_tcp_ports (msg, &priv->ctrans_tcp,
 +            &priv->cprofile_tcp, &priv->clowertrans_tcp, &priv->crtp_port0_tcp,
 +            &priv->crtp_port1_tcp);
 +        if (wfd_res != GST_WFD_OK) {
 +          GST_WARNING_OBJECT (client,
 +              "Failed to get wfd preferred RTP ports...");
 +          goto error;
 +        }
 +      }
 +
 +      if (msg->buf_len) {
 +        wfd_res =
 +          gst_wfd_message_get_buffer_length (msg, &priv->buf_len);
 +        if (wfd_res != GST_WFD_OK) {
 +          GST_WARNING_OBJECT (client,
 +              "Failed to get wfd preferred 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");
 +          }
 +        }
 +        /* Release allocated memory */
 +        g_free (edid_payload);
 +      }
 +
 +      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_M3_RES_MSG], 0, data);
 +
 +      g_signal_emit (_client,
 +          gst_rtsp_client_wfd_signals[SIGNAL_WFD_GET_PARAMETER_REQUEST], 0,
 +          ctx);
 +    } else {
 +      if (g_strrstr((char *)data, "wfd2_buffer_len")) {
 +        GST_DEBUG_OBJECT (_client, "Get TS message responce");
 +
 +        /* Parse TS 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);
 +        if (wfd_res != GST_WFD_OK) {
 +          GST_ERROR_OBJECT (client, "Failed to parse wfd message...");
 +          goto error;
 +        }
 +
 +        wfd_res = gst_wfd_message_get_buffer_length (msg, &_client->priv->buf_len);
 +        if (wfd_res != GST_WFD_OK) {
 +          GST_ERROR_OBJECT (client, "Failed to parse wfd message...");
 +          goto error;
 +        }
 +
 +        if (GST_RTSP_OK != handle_ts_response (_client, ctx)) {
 +          GST_ERROR_OBJECT (client, "Failed to handle transport switch response");
 +          goto error;
 +        }
 +      }
 +      /* 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;
 +      /* Checks whether server is 'coupling mode' or not */
 +      GST_DEBUG_OBJECT (client, "server coupling mode [%d]",priv->coupling_mode );
 +      if (priv->coupling_mode) {
 +        gst_rtsp_wfd_client_trigger_request (_client, WFD_TRIGGER_TEARDOWN_COUPLING);
 +      } else {
 +        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);
 +    }
 +  }
 +
 +  if (msg != NULL)
 +    gst_wfd_message_free(msg);
 +
 +  return;
 +
 +error:
 +
 +  if (msg != NULL)
 +    gst_wfd_message_free(msg);
 +
 +  return;
 +}
 +
 +static gboolean
 +handle_wfd_options_request (GstRTSPClient * client, GstRTSPContext * ctx, GstRTSPVersion version)
 +{
 +  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;
 +
 +  if (version < GST_RTSP_VERSION_2_0) {
 +    options |= GST_RTSP_RECORD;
 +    options |= GST_RTSP_ANNOUNCE;
 +  }
 +
 +  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);
 +  g_free (tmp);
 +
 +  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 {
 +    GST_INFO_OBJECT (_client, "user_agent is NULL and user_agent is optional.");
 +  }
 +
 +  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);
 +      else {
 +        send_generic_wfd_response (_client, GST_RTSP_STS_OK, ctx);
 +        g_signal_emit (client,
 +            gst_rtsp_client_wfd_signals[SIGNAL_WFD_SET_PARAM_MSG], 0, data);
 +      }
 +    } 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_DS_REQ_MSG,
 +  M4_RES_MSG,
 +  M5_REQ_MSG,
 +  TEARDOWN_TRIGGER,
 +  TEARDOWN_COUPLING_TRIGGER,
 +  PLAY_TRIGGER,
 +  PAUSE_TRIGGER,
 +  TS_REQ_MSG,
 +  TS_REP_REQ_MSG,
 +} 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_video_codec (GstRTSPWFDClient * client, guint video_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 video 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 vidoe 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 vidoe codec: no factory...");
 +    ret = FALSE;
 +    goto no_factory;
 +  }
 +
 +  gst_rtsp_media_factory_wfd_set_video_codec (factory, video_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);
 +
 +  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;
 +    }
 +
 +    /* set wfd2_audio_codecs & wfd2_video_formats if it is supported */
 +    if (priv->wfd2_supported == 1) {
 +      /* set the supported audio formats by the WFD server for direct streaming */
 +      wfd_res =
 +          gst_wfd_message_set_supported_wfd2_audio_codec (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 for direct streaming on wfd message...");
 +        goto error;
 +      }
 +
 +      /* set the supported Video formats by the WFD server for direct streaming */
 +      wfd_res =
 +          gst_wfd_message_set_supported_direct_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 for direct streaming 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_preferred_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;
 +    }
 +
 +    /* set the preffered TCP ports for the WFD server */
 +    wfd_res =
 +        gst_wfd_messge_set_preferred_tcp_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 tcp ports parameter on wfd message...");
 +      goto error;
 +    }
 +
 +    /* set the buffer length for the WFD server */
 +    wfd_res =
 +        gst_wfd_message_set_buffer_length (msg, 0);
 +    if (wfd_res != GST_WFD_OK) {
 +      GST_ERROR_OBJECT (client,
 +          "Failed to set tcp ports parameter on wfd message...");
 +      goto error;
 +    }
 +
 +    /* set the coupled sink for the WFD server */
 +    wfd_res =
 +        gst_wfd_message_set_coupled_sink (msg, GST_WFD_SINK_NOT_COUPLED, NULL, TRUE);
 +
 +    if (wfd_res != GST_WFD_OK) {
 +      GST_ERROR_OBJECT (client,
 +        "Failed to set coupled sink parameter 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 {
 +      gchar *append_data = NULL;
 +
 +      g_signal_emit (client, gst_rtsp_client_wfd_signals[SIGNAL_WFD_M3_REQ_MSG],
 +          0, *data, &append_data);
 +
 +      if (append_data) {
 +        g_free (*data);
 +        *data = append_data;
 +      }
 +
 +      *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 */
 +    GstWFDVideoCodecs tvideocodec = GST_WFD_VIDEO_UNKNOWN;
 +    guint64 tcCEAResolution = GST_WFD_CEA_UNKNOWN;
 +    guint64 tcVESAResolution = GST_WFD_VESA_UNKNOWN;
 +    guint64 tcHHResolution = GST_WFD_HH_UNKNOWN;
 +    GstWFDVideoH264Profile tcProfile = GST_WFD_H264_UNKNOWN_PROFILE;
 +    GstWFDVideoH264Level tcLevel = GST_WFD_H264_LEVEL_UNKNOWN;
 +    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;
 +    }
 +
 +    buf = g_string_new ("");
 +    if (buf == NULL)
 +      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");
 +      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;
 +    }
 +
 +    if (priv->caCodec != GST_WFD_AUDIO_UNKNOWN) {
 +      taudiocodec = wfd_get_preferred_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->caCodec != GST_WFD_AUDIO_UNKNOWN) {
 +      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;
 +    }
 +
 +    if(priv->wfd2_mode)
 +      wfd_res =
 +        gst_wfd_message_set_preferred_wfd2_audio_codec (msg, taudiocodec, taudiofreq,
 +        taudiochannels, priv->cBitwidth, priv->caLatency);
 +    else
 +      wfd_res =
 +        gst_wfd_message_set_preferred_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 */
 +    tvideocodec = wfd_get_preferred_video_codec (priv->video_codec, priv->cvCodec);
 +    GST_INFO_OBJECT (priv, "Set the video formats. source codec %d, sink codec %d, Negotiated code %d",
 +                       priv->video_codec, priv->cvCodec, tvideocodec);
 +    priv->cvCodec = tvideocodec;
 +
 +    if (priv->cvCodec != GST_WFD_VIDEO_UNKNOWN) {
 +      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_preferred_resolution (resolution_supported,
 +            priv->cCEAResolution, priv->video_native_resolution, &priv->cMaxWidth,
 +            &priv->cMaxHeight, &priv->cFramerate, &priv->cInterleaved);
 +        GST_DEBUG
 +            ("wfd negotiated resolution: %" G_GUINT64_FORMAT ", 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_preferred_resolution (resolution_supported,
 +            priv->cVESAResolution, priv->video_native_resolution,
 +            &priv->cMaxWidth, &priv->cMaxHeight, &priv->cFramerate,
 +            &priv->cInterleaved);
 +        GST_DEBUG
 +            ("wfd negotiated resolution: %" G_GUINT64_FORMAT ", 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_preferred_resolution (resolution_supported,
 +            priv->cHHResolution, priv->video_native_resolution, &priv->cMaxWidth,
 +            &priv->cMaxHeight, &priv->cFramerate, &priv->cInterleaved);
 +        GST_DEBUG
 +            ("wfd negotiated resolution: %" G_GUINT64_FORMAT ", 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...");
 +      }
 +    }
 +
 +    if (!_set_negotiated_video_codec (client, priv->cvCodec)) {
 +      GST_ERROR_OBJECT (client, "Failed to set negotiated "
 +          "video format to media factory...");
 +    }
 +
 +    wfd_res =
 +        gst_wfd_message_set_preferred_video_format (msg, priv->cvCodec,
 +        priv->video_native_resolution, GST_WFD_CEA_UNKNOWN, tcCEAResolution,
 +        tcVESAResolution, tcHHResolution, tcProfile, tcLevel, 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_ERROR_OBJECT (client, "Failed to set preffered video formats...");
 +      goto error;
 +    }
 +
 +    if (priv->direct_streaming_supported) {
 +      wfd_res =
 +        gst_wfd_message_set_preferred_direct_video_format (msg, priv->cvCodec,
 +            priv->video_native_resolution, GST_WFD_CEA_UNKNOWN, tcCEAResolution,
 +            tcVESAResolution, tcHHResolution, tcProfile, tcLevel, 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_ERROR_OBJECT (client, "Failed to set preffered video formats for direct streaming...");
 +        goto error;
 +      }
 +    }
 +
 +    /* set the preffered RTP ports for the WFD server */
 +    wfd_res =
 +        gst_wfd_messge_set_preferred_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 == M4_DS_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 */
 +    GstWFDAudioFreq taudiofreq = GST_WFD_FREQ_UNKNOWN;
 +    GstWFDAudioChannels taudiochannels = GST_WFD_CHANNEL_UNKNOWN;
 +
 +    /* Parameters for the preffered video formats */
 +    guint64 tcCEAResolution = GST_WFD_CEA_UNKNOWN;
 +    guint64 tcVESAResolution = GST_WFD_VESA_UNKNOWN;
 +    guint64 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;
 +    }
 +
 +    /* create M4 for direct streaming 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;
 +    }
 +
 +    buf = g_string_new ("");
 +    if (buf == NULL)
 +      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;
 +    }
 +
 +    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_preferred_wfd2_audio_codec (msg,
 +          priv->direct_detected_audio_codec, taudiofreq,
 +          taudiochannels, priv->cBitwidth, priv->caLatency);
 +    if (wfd_res != GST_WFD_OK) {
 +      GST_ERROR_OBJECT (priv, "Failed to set preffered audio formats for direct streaming...");
 +      goto error;
 +    }
 +
 +    /* Set the preffered video formats */
 +    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_preferred_resolution (resolution_supported,
 +          priv->cCEAResolution, priv->video_native_resolution, &priv->cMaxWidth,
 +          &priv->cMaxHeight, &priv->cFramerate, &priv->cInterleaved);
 +      GST_DEBUG
 +          ("wfd negotiated resolution: %" G_GUINT64_FORMAT ", 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_preferred_resolution (resolution_supported,
 +          priv->cVESAResolution, priv->video_native_resolution,
 +          &priv->cMaxWidth, &priv->cMaxHeight, &priv->cFramerate,
 +          &priv->cInterleaved);
 +      GST_DEBUG
 +          ("wfd negotiated resolution: %" G_GUINT64_FORMAT ", 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_preferred_resolution (resolution_supported,
 +          priv->cHHResolution, priv->video_native_resolution, &priv->cMaxWidth,
 +          &priv->cMaxHeight, &priv->cFramerate, &priv->cInterleaved);
 +      GST_DEBUG
 +          ("wfd negotiated resolution: %" G_GUINT64_FORMAT ", width: %d, height: %d, framerate: %d, interleaved: %d",
 +          tcHHResolution, priv->cMaxWidth, priv->cMaxHeight, priv->cFramerate,
 +          priv->cInterleaved);
 +    }
 +
 +    wfd_res =
 +      gst_wfd_message_set_preferred_direct_video_format (msg,
 +          priv->direct_detected_video_codec,
 +          priv->video_native_resolution, GST_WFD_CEA_UNKNOWN, tcCEAResolution,
 +          tcVESAResolution, tcHHResolution, tcProfile, tcLevel, 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_ERROR_OBJECT (client, "Failed to set preffered video formats for direct streaming...");
 +      goto error;
 +    }
 +
 +    wfd_res =
 +      gst_wfd_message_set_direct_streaming_mode (msg, TRUE);
 +
 +    if (wfd_res != GST_WFD_OK) {
 +      GST_ERROR_OBJECT (client, "Failed to set preffered video formats for direct streaming...");
 +      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 == TS_REQ_MSG) {
 +    /* create transport switch 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 preffered TCP ports for the WFD server */
 +    if (priv->ts_mode == WFD_TS_UDP) {
 +      wfd_res =
 +        gst_wfd_messge_set_preferred_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 preferred RTP ports on wfd message...");
 +        goto error;
 +      }
 +    } else {
 +      wfd_res =
 +        gst_wfd_messge_set_preferred_tcp_ports (msg, GST_WFD_RTSP_TRANS_RTP,
 +            GST_WFD_RTSP_PROFILE_AVP, GST_WFD_RTSP_LOWER_TRANS_TCP, priv->crtp_port0_tcp, priv->crtp_port1_tcp);
 +      if (wfd_res != GST_WFD_OK) {
 +        GST_ERROR_OBJECT (client,
 +            "Failed to set preferred TCP ports on wfd message...");
 +        goto error;
 +      }
 +    }
 +
 +    wfd_res =
 +      gst_wfd_message_set_buffer_length (msg, 200);
 +    if (wfd_res != GST_WFD_OK) {
 +      GST_ERROR_OBJECT (client,
 +          "Failed to set preferred buffer length 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 {
 +      gchar *append_data = NULL;
 +
 +      g_signal_emit (client,
 +          gst_rtsp_client_wfd_signals[SIGNAL_WFD_M4_REQ_MSG], 0, *data,
 +          &append_data);
 +
 +      if (append_data) {
 +        g_free (*data);
 +        *data = append_data;
 +      }
 +      *len = strlen (*data);
 +    }
 +  } else if (msg_type == M5_REQ_MSG) {
 +    buf = g_string_new ("wfd_trigger_method: SETUP\r\n");
 +    if (buf == NULL)
 +      goto error;
 +    *len = buf->len;
 +    *data = g_string_free (buf, FALSE);
 +  } else if (msg_type == TEARDOWN_TRIGGER) {
 +    buf = g_string_new ("wfd_trigger_method: TEARDOWN\r\n");
 +    if (buf == NULL)
 +      goto error;
 +    *len = buf->len;
 +    *data = g_string_free (buf, FALSE);
 +  } else if (msg_type == TEARDOWN_COUPLING_TRIGGER) {
 +    buf = g_string_new ("wfd_trigger_method: TEARDOWN_COUPLING\r\n");
 +    if (buf == NULL)
 +      goto error;
 +    *len = buf->len;
 +    *data = g_string_free (buf, FALSE);
 +  } else if (msg_type == PLAY_TRIGGER) {
 +    buf = g_string_new ("wfd_trigger_method: PLAY\r\n");
 +    if (buf == NULL)
 +      goto error;
 +    *len = buf->len;
 +    *data = g_string_free (buf, FALSE);
 +  } else if (msg_type == PAUSE_TRIGGER) {
 +    buf = g_string_new ("wfd_trigger_method: PAUSE\r\n");
 +    if (buf == NULL)
 +      goto error;
 +    *len = buf->len;
 +    *data = g_string_free (buf, FALSE);
 +  }
 +
 +  if (msg != NULL)
 +    gst_wfd_message_free(msg);
 +
 +  return;
 +
 +error:
 +
 +  if (msg != NULL)
 +    gst_wfd_message_free(msg);
 +
 +  *data = NULL;
 +  *len = 0;
 +
 +  return;
 +}
 +
 +/**
 +* gst_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
 +gst_prepare_request (GstRTSPWFDClient * client, GstRTSPMessage * request,
 +    GstRTSPMethod method, gchar * url)
 +{
 +  GstRTSPResult res = GST_RTSP_OK;
 +  gchar *str = NULL;
 +
 +  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;
 +
 +      /* 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);
 +      GST_DEBUG ("M3 server side message body: %s", msg);
 +
 +      res = gst_rtsp_message_set_body (request, (guint8 *) msg, msglen);
 +      if (res != GST_RTSP_OK) {
 +        GST_ERROR_OBJECT (client, "Failed to set body data to rtsp message...");
 +        goto error;
 +      }
 +
 +      g_free (msg);
 +      break;
 +    }
 +
 +      /* Prepare SET_PARAMETER request */
 +    case GST_RTSP_SET_PARAMETER:{
 +      gchar *msg = NULL;
 +      guint msglen = 0;
 +
 +      /* 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);
 +      GST_DEBUG ("M4 server side message body: %s", msg);
 +
 +      res = gst_rtsp_message_set_body (request, (guint8 *) msg, msglen);
 +      if (res != GST_RTSP_OK) {
 +        GST_ERROR_OBJECT (client, "Failed to set body data 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_TEARDOWN_COUPLING:{
 +      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_COUPLING_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
 +gst_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);
 +      g_free (tmp);
 +      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 = gst_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)");
 +
 +  gst_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 };
 +
 +  res = gst_prepare_request (client, &request, GST_RTSP_GET_PARAMETER,
 +                            (gchar *) "rtsp://localhost/wfd1.0");
 +
 +  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)...");
 +
 +  gst_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 };
 +
 +  res = gst_prepare_request (client, &request, GST_RTSP_SET_PARAMETER,
 +                            (gchar *) "rtsp://localhost/wfd1.0");
 +
 +  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)...");
 +
 +  gst_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 };
 +
 +  res = prepare_trigger_request (client, &request, type, (gchar *) "rtsp://localhost/wfd1.0");
 +
 +  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);
 +
 +  gst_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_video_codec (GstRTSPWFDClient * client,
 +    guint8 video_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->video_codec = video_codec;
 +  GST_DEBUG ("Video codec : %d", video_codec);
 +
 +  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;
 +}
 +
 +GstRTSPResult
 +gst_rtsp_wfd_client_set_coupling_mode (GstRTSPWFDClient * client,
 +    gboolean coupling_mode)
 +{
 +  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->coupling_mode = coupling_mode;
 +
 +  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 gst_prepare_request function.*/
 +static GstRTSPResult
 +handle_M16_message (GstRTSPWFDClient * client)
 +{
 +  GstRTSPResult res = GST_RTSP_OK;
 +  GstRTSPMessage request = { 0 };
 +
 +  res = gst_rtsp_message_init_request (&request, GST_RTSP_GET_PARAMETER,
 +                                    (gchar *) "rtsp://localhost/wfd1.0");
 +
 +  if (res < 0) {
 +    GST_ERROR ("init request failed");
 +    return FALSE;
 +  }
 +
 +  gst_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;
 +}
 +
 +gboolean
 +gst_rtsp_wfd_client_get_coupling_mode (GstRTSPWFDClient * client)
 +{
 +  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
 +  g_return_val_if_fail (priv != NULL, 0);
 +
 +  return priv->coupling_mode;
 +}
 +
 +void
 +gst_rtsp_wfd_client_set_audio_freq (GstRTSPWFDClient * client, guint freq)
 +{
 +  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
 +  g_return_if_fail (priv != NULL);
 +
 +  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_if_fail (priv != NULL);
 +
 +  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_if_fail (priv != NULL);
 +
 +  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_if_fail (priv != NULL);
 +
 +  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_if_fail (priv != NULL);
 +
 +  priv->protection_enabled = enable;
 +}
 +
 +void
 +gst_rtsp_wfd_client_set_hdcp_version (GstRTSPWFDClient * client,
 +    GstWFDHDCPProtection version)
 +{
 +  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
 +  g_return_if_fail (priv != NULL);
 +
 +  priv->hdcp_version = version;
 +}
 +
 +void
 +gst_rtsp_wfd_client_set_hdcp_port (GstRTSPWFDClient * client, guint32 port)
 +{
 +  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
 +  g_return_if_fail (priv != NULL);
 +
 +  priv->hdcp_tcpport = port;
 +}
 +
 +void
 +gst_rtsp_wfd_client_set_keep_alive_flag (GstRTSPWFDClient * client,
 +    gboolean flag)
 +{
 +  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
 +  g_return_if_fail (priv != NULL);
 +
 +  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_vid_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;
 +}
 +
 +void
 +gst_rtsp_wfd_client_set_wfd2_supported (GstRTSPWFDClient *client,
 +    gint flag)
 +{
 +  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
 +  g_return_if_fail (priv != NULL);
 +
 +  priv->wfd2_supported = flag;
 +}
 +
 +static void
 +direct_stream_end_cb (GstRTSPMediaFactoryWFD *factory, void *user_data)
 +{
 +  GstRTSPWFDClient *client = GST_RTSP_WFD_CLIENT_CAST (user_data);
 +  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
 +  GstRTSPResult res = GST_RTSP_OK;
 +
 +  priv->direct_streaming_state = 0;
 +  res = handle_M4_message (client);
 +
 +  if (res != GST_RTSP_OK) {
 +    GST_ERROR_OBJECT (client, "Failed to send message for direct streaming");
 +  }
 +}
 +
 +GstRTSPResult
 +gst_rtsp_wfd_client_set_direct_streaming(GstRTSPWFDClient * client,
 +    gint direct_streaming, gchar *urisrc)
 +{
 +  GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
 +  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
 +  GstRTSPResult res = GST_RTSP_OK;
 +
 +  GstRTSPMediaFactory *factory = NULL;
 +  GstRTSPMountPoints *mount_points = NULL;
 +  gchar *path = NULL;
 +  gint matched = 0;
 +
 +  if (priv->direct_streaming_supported == FALSE) {
 +    GST_ERROR_OBJECT (client, "Direct streaming not supported by client");
 +    return GST_RTSP_ERROR;
 +  }
 +
 +  if (priv->direct_streaming_state == direct_streaming) {
 +    GST_DEBUG_OBJECT (client, "Direct streaming state not changed");
 +    return res;
 +  }
 +
 +  if (!(mount_points = gst_rtsp_client_get_mount_points (parent_client))) {
 +    res = GST_RTSP_ERROR;
 +    GST_ERROR_OBJECT (client, "Failed to set direct streaing: no mount points...");
 +    goto no_mount_points;
 +  }
 +
 +  path = g_strdup(WFD_MOUNT_POINT);
 +  if (!path) {
 +    res = GST_RTSP_ERROR;
 +    GST_ERROR_OBJECT (client, "Failed to set direct streaing: no path...");
 +    goto no_path;
 +  }
 +
 +  if (!(factory = gst_rtsp_mount_points_match (mount_points,
 +          path, &matched))) {
 +    GST_ERROR_OBJECT (client, "Failed to set direct streaing: no factory...");
 +    res = GST_RTSP_ERROR;
 +    goto no_factory;
 +  }
 +
 +  if (direct_streaming) {
 +    res = gst_rtsp_media_factory_wfd_uri_type_find (factory,
 +        urisrc, &priv->direct_detected_video_codec,
 +        &priv->direct_detected_audio_codec);
 +
 +    if (res != GST_RTSP_OK) {
 +      GST_ERROR_OBJECT (client, "Failed to create direct streaming pipeline");
 +      goto no_pipe;
 +    }
 +  }
 +
 +  if (!(priv->direct_detected_video_codec & GST_WFD_VIDEO_H264)) {
 +    GST_ERROR_OBJECT (client, "Detected video codec not supported");
 +    res = GST_RTSP_ERROR;
 +    goto no_pipe;
 +  }
 +
 +  if (!(priv->direct_detected_audio_codec & GST_WFD_AUDIO_AAC ||
 +      priv->direct_detected_audio_codec & GST_WFD_AUDIO_LPCM ||
 +      priv->direct_detected_audio_codec & GST_WFD_AUDIO_AC3)) {
 +    GST_ERROR_OBJECT (client, "Detected audio codec not supported");
 +    res = GST_RTSP_ERROR;
 +    goto no_pipe;
 +  }
 +
 +  g_signal_connect_object (GST_RTSP_MEDIA_FACTORY_WFD_CAST (factory), "direct-stream-end",
 +      G_CALLBACK (direct_stream_end_cb), client, 0);
 +
 +  res = gst_rtsp_media_factory_wfd_set_direct_streaming (factory,
 +      direct_streaming, urisrc);
 +
 +  if (res != GST_RTSP_OK) {
 +    GST_ERROR_OBJECT (client, "Failed to create direct streaming pipeline");
 +    goto no_pipe;
 +  }
 +
 +  if (direct_streaming) {
 +    res = handle_M4_direct_streaming_message (client);
 +
 +    if (res != GST_RTSP_OK) {
 +      GST_ERROR_OBJECT (client, "Failed to send message for direct streaming");
 +      goto no_pipe;
 +    }
 +  }
 +
 +  priv->direct_streaming_state = direct_streaming;
 +
 +no_pipe:
 +  g_object_unref(factory);
 +no_factory:
 +  g_free(path);
 +no_path:
 +  g_object_unref(mount_points);
 +no_mount_points:
 +  return res;
 +}
 +
 +/**
 +* prepare_direct_streaming_request:
 +* @client: client object
 +* @request : requst message to be prepared
 +* @url : url need to be in the request
 +*
 +* Prepares request based on @method & @message_type
 +*
 +* Returns: a #GstRTSPResult.
 +*/
 +static GstRTSPResult
 +prepare_direct_streaming_request (GstRTSPWFDClient * client, GstRTSPMessage * request)
 +{
 +  GstRTSPResult res = GST_RTSP_OK;
 +  gchar *msg = NULL;
 +  guint msglen = 0;
 +  GString *msglength;
 +
 +  GST_DEBUG_OBJECT (client, "Preparing request for direct streaming");
 +
 +  /* initialize the request */
 +  res = gst_rtsp_message_init_request (request, GST_RTSP_SET_PARAMETER,
 +                                    (gchar *) "rtsp://localhost/wfd1.0");
 +  if (res < 0) {
 +    GST_ERROR ("init request failed");
 +    return res;
 +  }
 +
 +  /* 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_DS_REQ_MSG, &msg, &msglen);
 +  msglength = g_string_new ("");
 +  g_string_append_printf (msglength, "%d", msglen);
 +  GST_DEBUG ("M4 for direct streaming 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);
 +
 +  return res;
 +
 +error:
 +  return GST_RTSP_ERROR;
 +}
 +
 +static GstRTSPResult
 +handle_M4_direct_streaming_message (GstRTSPWFDClient * client)
 +{
 +  GstRTSPResult res = GST_RTSP_OK;
 +  GstRTSPMessage request = { 0 };
 +
 +  res = prepare_direct_streaming_request (client, &request);
 +  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 for direct streaming (M4)...");
 +
 +  gst_send_request (client, NULL, &request);
 +
 +  return res;
 +
 +error:
 +  return res;
 +}
 +
 +/**
 +* prepare_transport_switch_request:
 +* @client: client object
 +* @request : requst message to be prepared
 +* @url : url need to be in the request
 +*
 +* Prepares request based on @method & @message_type
 +*
 +* Returns: a #GstRTSPResult.
 +*/
 +static GstRTSPResult
 +prepare_transport_switch_request (GstRTSPWFDClient * client, GstRTSPMessage * request)
 +{
 +  GstRTSPResult res = GST_RTSP_OK;
 +  gchar *url = NULL;
 +  gchar *msg = NULL;
 +  guint msglen = 0;
 +  GString *msglength;
 +
 +  GstRTSPMethod method = GST_RTSP_SET_PARAMETER;
 +
 +  url = g_strdup ("rtsp://localhost/wfd1.0");
 +  if (!url)
 +    return GST_RTSP_ERROR;
 +
 +  GST_DEBUG_OBJECT (client, "Preparing request for transport switch");
 +
 +  /* initialize the request */
 +  res = gst_rtsp_message_init_request (request, method, url);
 +  g_free (url);
 +  if (res < 0) {
 +    GST_ERROR ("init request failed");
 +    return res;
 +  }
 +
 +  /* 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, TS_REQ_MSG, &msg, &msglen);
 +  msglength = g_string_new ("");
 +  g_string_append_printf (msglength, "%d", msglen);
 +  GST_DEBUG ("Transport switch 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);
 +
 +  return res;
 +
 +error:
 +  return GST_RTSP_ERROR;
 +}
 +
 +GstRTSPResult
 +gst_rtsp_wfd_client_switch_to_udp (GstRTSPWFDClient * client)
 +{
 +  GstRTSPResult res = GST_RTSP_OK;
 +  GstRTSPMessage request = { 0 };
 +  GList *tl = NULL;
 +  GPtrArray *ta = NULL;
 +
 +  if (client->priv->ts_mode == WFD_TS_UDP) {
 +    GST_ERROR_OBJECT (client, "Transport already UDP");
 +    return res;
 +  }
 +
 +  ta = g_ptr_array_new();
 +
 +  tl = gst_rtsp_stream_transport_filter (client->priv->stats.stream, NULL, NULL);
 +  client->priv->transports = tl;
 +  g_ptr_array_add (ta, tl->data);
 +
 +  client->priv->ts_mode = WFD_TS_UDP;
 +  res = prepare_transport_switch_request (client, &request);
 +  if (GST_RTSP_OK != res) {
 +    GST_ERROR_OBJECT (client, "Failed to prepare transport switch request....\n");
 +    goto error;
 +  }
 +
 +  GST_DEBUG_OBJECT (client, "Sending SET_PARAMETER request message for transport switch...");
 +
 +  gst_send_request (client, NULL, &request);
 +
 +  gst_rtsp_media_set_state (client->priv->media, GST_STATE_PAUSED, ta);
 +
 +  g_ptr_array_free (ta, FALSE);
 +
 +  return res;
 +
 +error:
 +  g_ptr_array_free (ta, FALSE);
 +  return res;
 +}
 +
 +GstRTSPResult
 +gst_rtsp_wfd_client_switch_to_tcp (GstRTSPWFDClient * client)
 +{
 +  GstRTSPResult res = GST_RTSP_OK;
 +  GstRTSPMessage request = { 0 };
 +  GList *tl = NULL;
 +  GPtrArray *ta = NULL;
 +
 +  ta = g_ptr_array_new();
 +
 +  tl = gst_rtsp_stream_transport_filter (client->priv->stats.stream, NULL, NULL);
 +  client->priv->transports = tl;
 +  g_ptr_array_add (ta, tl->data);
 +
 +  if (client->priv->ts_mode == WFD_TS_TCP) {
 +    GST_ERROR_OBJECT (client, "Transport already TCP");
 +    return res;
 +  }
 +
 +  client->priv->ts_mode = WFD_TS_TCP;
 +  res = prepare_transport_switch_request (client, &request);
 +  if (GST_RTSP_OK != res) {
 +    GST_ERROR_OBJECT (client, "Failed to prepare transport switch request....\n");
 +    goto error;
 +  }
 +
 +  GST_DEBUG_OBJECT (client, "Sending SET_PARAMETER request message for transport switch...");
 +
 +  gst_send_request (client, NULL, &request);
 +
 +  gst_rtsp_media_set_state (client->priv->media, GST_STATE_PAUSED, ta);
 +
 +  g_ptr_array_free (ta, FALSE);
 +
 +  return res;
 +
 +error:
 +  g_ptr_array_free (ta, FALSE);
 +  return res;
 +}
 +gchar * gst_rtsp_wfd_client_get_sink_user_agent (GstRTSPWFDClient * client)
 +{
 +  char *str = NULL;
 +  GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
 +  g_return_val_if_fail (priv != NULL, NULL);
 +
 +  if (priv->sink_user_agent != NULL)
 +    str = g_strdup (priv->sink_user_agent);
 +
 +  return str;
 +}
index dd3c049,0000000..dd3c049
mode 100644,000000..100644
--- /dev/null
@@@ -1,396 -1,0 +1,396 @@@
 +/* 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_TEARDOWN_COUPLING,
 +  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;
 +
 +#if 0 /* unused variable */
 +  gint           supported_methods;
 +#endif
 +  /*< 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);
 +  gboolean            (*configure_client_media) (GstRTSPClient * client,
 +                                                 GstRTSPMedia * media, GstRTSPStream * stream,
 +                                                 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);
 +  void     (*wfd_playing_done)            (GstRTSPWFDClient *client);
 +  void     (*wfd_rtp_stats)               (GstRTSPWFDClient *client, GstStructure *stats);
 +  gchar*   (*wfd_handle_m3_req_msg)       (GstRTSPWFDClient *client, gchar *data);
 +  void     (*wfd_handle_m3_res_msg)       (GstRTSPWFDClient *client, gchar *data);
 +  gchar*   (*wfd_handle_m4_req_msg)       (GstRTSPWFDClient *client, gchar *data);
 +  void     (*wfd_handle_set_param_msg)    (GstRTSPWFDClient *client, gchar *data);
 +
 +  /*< private >*/
 +  gpointer _gst_reserved[GST_PADDING_LARGE];
 +};
 +
 +GST_RTSP_SERVER_API
 +GType                 gst_rtsp_wfd_client_get_type          (void);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPWFDClient *    gst_rtsp_wfd_client_new               (void);
 +
 +
 +GST_RTSP_SERVER_API
 +void                  gst_rtsp_wfd_client_set_host_address  (
 +                          GstRTSPWFDClient *client, const gchar * address);
 +
 +
 +GST_RTSP_SERVER_API
 +void                  gst_rtsp_wfd_client_start_wfd(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_client_trigger_request (
 +                          GstRTSPWFDClient * client, GstWFDTriggerType type);
 +
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_client_set_video_supported_resolution (
 +                          GstRTSPWFDClient * client, guint64 supported_reso);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_client_set_video_native_resolution (
 +                                    GstRTSPWFDClient * client, guint64 native_reso);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_client_set_video_codec (
 +                                    GstRTSPWFDClient * client, guint8 video_codec);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_client_set_audio_codec (
 +                                    GstRTSPWFDClient * client, guint8 audio_codec);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_client_set_direct_streaming(
 +                          GstRTSPWFDClient * client, gint direct_streaming, gchar *urisrc);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_client_set_coupling_mode(
 +                          GstRTSPWFDClient * client, gboolean coupling_mode);
 +
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_prepare_request (GstRTSPWFDClient * client,
 +                          GstRTSPMessage * request, GstRTSPMethod method, gchar * url);
 +
 +GST_RTSP_SERVER_API
 +void                  gst_send_request (GstRTSPWFDClient * client,
 +                          GstRTSPSession * session, GstRTSPMessage * request);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_client_switch_to_udp (GstRTSPWFDClient * client);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_client_switch_to_tcp (GstRTSPWFDClient * client);
 +
 +
 +GST_RTSP_SERVER_API
 +guint     gst_rtsp_wfd_client_get_audio_codec(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint     gst_rtsp_wfd_client_get_audio_freq(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint     gst_rtsp_wfd_client_get_audio_channels(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint     gst_rtsp_wfd_client_get_audio_bit_width(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint     gst_rtsp_wfd_client_get_audio_latency(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint     gst_rtsp_wfd_client_get_video_codec(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint     gst_rtsp_wfd_client_get_video_native(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint64   gst_rtsp_wfd_client_get_video_native_resolution(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint64   gst_rtsp_wfd_client_get_video_cea_resolution(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint64   gst_rtsp_wfd_client_get_video_vesa_resolution(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint64   gst_rtsp_wfd_client_get_video_hh_resolution(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint     gst_rtsp_wfd_client_get_video_profile(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint     gst_rtsp_wfd_client_get_video_level(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint     gst_rtsp_wfd_client_get_video_latency(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint32   gst_rtsp_wfd_client_get_video_max_height(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint32   gst_rtsp_wfd_client_get_video_max_width(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint32   gst_rtsp_wfd_client_get_video_framerate(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint32   gst_rtsp_wfd_client_get_video_min_slice_size(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint32   gst_rtsp_wfd_client_get_video_slice_enc_params(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint     gst_rtsp_wfd_client_get_video_framerate_control(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint32   gst_rtsp_wfd_client_get_rtp_port0(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint32   gst_rtsp_wfd_client_get_rtp_port1(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +gboolean  gst_rtsp_wfd_client_get_edid_supported(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint32   gst_rtsp_wfd_client_get_edid_hresolution(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +guint32   gst_rtsp_wfd_client_get_edid_vresolution(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +gboolean  gst_rtsp_wfd_client_get_protection_enabled(GstRTSPWFDClient *client);
 +
 +GST_RTSP_SERVER_API
 +gboolean  gst_rtsp_wfd_client_get_coupling_mode(GstRTSPWFDClient *client);
 +
 +
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_audio_freq(GstRTSPWFDClient *client, guint freq);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_edid_supported(GstRTSPWFDClient *client, gboolean supported);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_edid_hresolution(GstRTSPWFDClient *client, guint32 reso);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_edid_vresolution(GstRTSPWFDClient *client, guint32 reso);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_protection_enabled(GstRTSPWFDClient *client, gboolean enable);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_hdcp_version(GstRTSPWFDClient *client, GstWFDHDCPProtection version);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_hdcp_port(GstRTSPWFDClient *client, guint32 port);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_keep_alive_flag(GstRTSPWFDClient *client, gboolean flag);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_aud_codec(GstRTSPWFDClient *client, guint acodec);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_audio_channels(GstRTSPWFDClient *client, guint channels);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_audio_bit_width(GstRTSPWFDClient *client, guint bwidth);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_audio_latency(GstRTSPWFDClient *client, guint latency);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_vid_codec(GstRTSPWFDClient *client, guint vcodec);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_video_native(GstRTSPWFDClient *client, guint native);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_vid_native_resolution(GstRTSPWFDClient *client, guint64 res);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_video_cea_resolution(GstRTSPWFDClient *client, guint64 res);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_video_vesa_resolution(GstRTSPWFDClient *client, guint64 res);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_video_hh_resolution(GstRTSPWFDClient *client, guint64 res);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_video_profile(GstRTSPWFDClient *client, guint profile);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_video_level(GstRTSPWFDClient *client, guint level);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_video_latency(GstRTSPWFDClient *client, guint latency);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_video_max_height(GstRTSPWFDClient *client, guint32 height);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_video_max_width(GstRTSPWFDClient *client, guint32 width);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_video_framerate(GstRTSPWFDClient *client, guint32 framerate);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_video_min_slice_size(GstRTSPWFDClient *client, guint32 slice_size);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_video_slice_enc_params(GstRTSPWFDClient *client, guint32 enc_params);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_video_framerate_control(GstRTSPWFDClient *client, guint framerate);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_rtp_port0(GstRTSPWFDClient *client, guint32 port);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_rtp_port1(GstRTSPWFDClient *client, guint32 port);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_wfd_client_set_wfd2_supported (GstRTSPWFDClient *client, gint flag);
 +
 +GST_RTSP_SERVER_API
 +gchar *gst_rtsp_wfd_client_get_sink_user_agent(GstRTSPWFDClient *client);
 +
 +/**
 + * 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__ */
@@@ -202,22 -202,12 +202,22 @@@ static GstRTSPResult default_params_ge
      GstRTSPContext * ctx);
  static gchar *default_make_path_from_uri (GstRTSPClient * client,
      const GstRTSPUrl * uri);
 +static gboolean default_handle_options_request (GstRTSPClient * client,
 +    GstRTSPContext * ctx, GstRTSPVersion version);
 +static gboolean default_handle_set_param_request (GstRTSPClient * client,
 +    GstRTSPContext * ctx);
 +static gboolean default_handle_get_param_request (GstRTSPClient * client,
 +    GstRTSPContext * ctx);
 +static gboolean default_handle_play_request (GstRTSPClient * client,
 +    GstRTSPContext * ctx);
 +
  static void client_session_removed (GstRTSPSessionPool * pool,
      GstRTSPSession * session, GstRTSPClient * client);
  static GstRTSPStatusCode default_pre_signal_handler (GstRTSPClient * client,
      GstRTSPContext * ctx);
  static gboolean pre_signal_accumulator (GSignalInvocationHint * ihint,
      GValue * return_accu, const GValue * handler_return, gpointer data);
 +gboolean gst_rtsp_media_has_completed_sender (GstRTSPMedia * media);
  
  G_DEFINE_TYPE_WITH_PRIVATE (GstRTSPClient, gst_rtsp_client, G_TYPE_OBJECT);
  
@@@ -239,10 -229,6 +239,10 @@@ gst_rtsp_client_class_init (GstRTSPClie
    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;
 +  klass->handle_play_request = default_handle_play_request;
  
    klass->pre_options_request = default_pre_signal_handler;
    klass->pre_describe_request = default_pre_signal_handler;
@@@ -1580,7 -1566,7 +1580,7 @@@ default_params_get (GstRTSPClient * cli
  }
  
  static gboolean
 -handle_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
 +default_handle_get_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
  {
    GstRTSPResult res;
    guint8 *data;
@@@ -1638,7 -1624,7 +1638,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;
@@@ -2052,7 -2038,7 +2052,7 @@@ seek_failed
  }
  
  static gboolean
 -handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx)
 +default_handle_play_request (GstRTSPClient * client, GstRTSPContext * ctx)
  {
    GstRTSPSession *session;
    GstRTSPClientClass *klass;
@@@ -3000,10 -2986,6 +3000,10 @@@ handle_setup_request (GstRTSPClient * c
    /* 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 */
@@@ -3758,7 -3740,7 +3758,7 @@@ unsuspend_failed
  }
  
  static gboolean
 -handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx,
 +default_handle_options_request (GstRTSPClient * client, GstRTSPContext * ctx,
      GstRTSPVersion version)
  {
    GstRTSPMethod options;
@@@ -3957,9 -3939,7 +3957,9 @@@ handle_request (GstRTSPClient * client
    GstRTSPMessage response = { 0 };
    gchar *unsupported_reqs = NULL;
    gchar *sessid = NULL, *pipelined_request_id = NULL;
 +  GstRTSPClientClass *klass;
  
 +  klass = GST_RTSP_CLIENT_GET_CLASS (client);
    if (!(ctx = gst_rtsp_context_get_current ())) {
      ctx = &sctx;
      ctx->auth = priv->auth;
    switch (method) {
      case GST_RTSP_OPTIONS:
        priv->version = version;
 -      handle_options_request (client, ctx, version);
 +      klass->handle_options_request (client, ctx, version);
        break;
      case GST_RTSP_DESCRIBE:
        handle_describe_request (client, ctx);
        handle_setup_request (client, ctx);
        break;
      case GST_RTSP_PLAY:
 -      handle_play_request (client, ctx);
 +      klass->handle_play_request (client, ctx);
        break;
      case GST_RTSP_PAUSE:
        handle_pause_request (client, ctx);
        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:
        if (version >= GST_RTSP_VERSION_2_0)
@@@ -4652,7 -4632,6 +4652,7 @@@ gst_rtsp_client_set_connection (GstRTSP
    } else {
      priv->is_ipv6 = g_socket_get_family (read_socket) == G_SOCKET_FAMILY_IPV6;
      priv->server_ip = g_strdup ("unknown");
 +    g_object_unref (address);
    }
  
    GST_INFO ("client %p connected to server ip %s, ipv6 = %d", client,
@@@ -5423,25 -5402,3 +5423,25 @@@ restart
  
    return result;
  }
 +
 +/**
 + * gst_rtsp_client_set_watch_flushing:
 + * @client: a #GstRTSPClient
 + * @val: a boolean value
 + *
 + * sets watch flushing to @val on watch to accet/ignore new messages.
 + */
 +void
 +gst_rtsp_client_set_watch_flushing (GstRTSPClient * client, gboolean val)
 +{
 +  GstRTSPClientPrivate *priv = NULL;
 +  g_return_if_fail (GST_IS_RTSP_CLIENT (client));
 +
 +  priv = gst_rtsp_client_get_instance_private (client);
 +
 +  /* make sure we unblock/block the backlog and accept/don't accept new messages on the watch */
 +  if (priv->watch != NULL) {
 +    GST_INFO ("Set watch flushing as %d", val);
 +    gst_rtsp_watch_set_flushing (priv->watch, val);
 +  }
 +}
@@@ -131,10 -131,6 +131,10 @@@ 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, GstRTSPVersion version);
 +  gboolean        (*handle_set_param_request) (GstRTSPClient * client, GstRTSPContext * ctx);
 +  gboolean        (*handle_get_param_request) (GstRTSPClient * client, GstRTSPContext * ctx);
 +  gboolean        (*handle_play_request) (GstRTSPClient * client, GstRTSPContext * ctx);
    GstRTSPStatusCode (*adjust_play_mode) (GstRTSPClient * client,
                                           GstRTSPContext * context,
                                           GstRTSPTimeRange ** range,
@@@ -255,9 -251,6 +255,9 @@@ GST_RTSP_SERVER_AP
  GstRTSPResult         gst_rtsp_client_send_message      (GstRTSPClient * client,
                                                           GstRTSPSession *session,
                                                           GstRTSPMessage *message);
 +
 +GST_RTSP_SERVER_API
 +void                  gst_rtsp_client_set_watch_flushing (GstRTSPClient * client, gboolean val);
  /**
   * GstRTSPClientSessionFilterFunc:
   * @client: a #GstRTSPClient object
index a5d60d0,0000000..a5d60d0
mode 100644,000000..100644
--- /dev/null
@@@ -1,780 -1,0 +1,780 @@@
 +/* GStreamer
 + * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.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
 + * @short_description: The media pipeline
 + * @see_also: #GstRTSPMediaFactory, #GstRTSPStream, #GstRTSPSession,
 + *     #GstRTSPSessionMedia
 + *
 + * a #GstRTSPMedia contains the complete GStreamer pipeline to manage the
 + * streaming to the clients. The actual data transfer is done by the
 + * #GstRTSPStream objects that are created and exposed by the #GstRTSPMedia.
 + *
 + * The #GstRTSPMedia is usually created from a #GstRTSPMediaFactory when the
 + * client does a DESCRIBE or SETUP of a resource.
 + *
 + * A media is created with gst_rtsp_media_new() that takes the element that will
 + * provide the streaming elements. For each of the streams, a new #GstRTSPStream
 + * object needs to be made with the gst_rtsp_media_create_stream() which takes
 + * the payloader element and the source pad that produces the RTP stream.
 + *
 + * The pipeline of the media is set to PAUSED with gst_rtsp_media_prepare(). The
 + * prepare method will add rtpbin and sinks and sources to send and receive RTP
 + * and RTCP packets from the clients. Each stream srcpad is connected to an
 + * input into the internal rtpbin.
 + *
 + * It is also possible to dynamically create #GstRTSPStream objects during the
 + * prepare phase. With gst_rtsp_media_get_status() you can check the status of
 + * the prepare phase.
 + *
 + * After the media is prepared, it is ready for streaming. It will usually be
 + * managed in a session with gst_rtsp_session_manage_media(). See
 + * #GstRTSPSession and #GstRTSPSessionMedia.
 + *
 + * The state of the media can be controlled with gst_rtsp_media_set_state ().
 + * Seeking can be done with gst_rtsp_media_seek().
 + *
 + * With gst_rtsp_media_unprepare() the pipeline is stopped and shut down. When
 + * gst_rtsp_media_set_eos_shutdown() an EOS will be sent to the pipeline to
 + * cleanly shut down.
 + *
 + * With gst_rtsp_media_set_shared(), the media can be shared between multiple
 + * clients. With gst_rtsp_media_set_reusable() you can control if the pipeline
 + * can be prepared again after an unprepare.
 + *
 + * Last reviewed on 2013-07-11 (1.0.0)
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include "config.h"
 +#endif
 +
 +#include <string.h>
 +#include <stdlib.h>
 +
 +#include <gst/app/gstappsrc.h>
 +#include <gst/app/gstappsink.h>
 +
 +#include "rtsp-media-ext.h"
 +
 +#define GST_RTSP_MEDIA_EXT_GET_PRIVATE(obj)  \
 +     (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_MEDIA_EXT, GstRTSPMediaExtPrivate))
 +
 +#define RTP_RETRANS_PORT 19120
 +
 +typedef struct _GstRTSPMediaExtRTPResender GstRTSPMediaExtRTPResender;
 +
 +struct _GstRTSPMediaExtRTPResender
 +{
 +  /* sinks used for sending and receiving RTP and RTCP over ipv4, they share
 +   * sockets */
 +  GstElement *udpsrc_v4;
 +
 +  /* for TCP transport */
 +  GstElement *appsrc;
 +  GstElement *funnel;
 +  GstElement *resender;
 +  GstElement *resend_sink;
 +};
 +
 +struct _GstRTSPMediaExtPrivate
 +{
 +  GMutex lock;
 +  GstRTSPMediaExtMode mode;
 +
 +  GstRTSPMediaExtRTPResender rtp_resender;
 +  GstElement *fecenc;
 +  gboolean is_joined;
 +
 +  /* pads on the rtpbin */
 +  GstPad *send_src;
 +
 +  guint retransmit_port;
 +  guint max_size_k;
 +  guint max_size_p;
 +  GstRTSPMediaExtLatency latency_mode;
 +#ifdef FORCE_DROP
 +  GstElement *identity;
 +#endif
 +};
 +
 +GST_DEBUG_CATEGORY_STATIC (rtsp_media_ext_debug);
 +#define GST_CAT_DEFAULT rtsp_media_ext_debug
 +
 +static void gst_rtsp_media_ext_get_property (GObject * object, guint propid,
 +    GValue * value, GParamSpec * pspec);
 +static void gst_rtsp_media_ext_set_property (GObject * object, guint propid,
 +    const GValue * value, GParamSpec * pspec);
 +static void gst_rtsp_media_ext_finalize (GObject * obj);
 +
 +static void ext_preparing (GstRTSPMedia * media, GstRTSPStream * stream,
 +    guint idx);
 +static void ext_unpreparing (GstRTSPMedia * media, GstRTSPStream * stream,
 +    guint idx);
 +
 +G_DEFINE_TYPE (GstRTSPMediaExt, gst_rtsp_media_ext, GST_TYPE_RTSP_MEDIA);
 +
 +static void
 +gst_rtsp_media_ext_class_init (GstRTSPMediaExtClass * klass)
 +{
 +  GObjectClass *gobject_class;
 +  GstRTSPMediaClass *rtsp_media_class;
 +
 +  g_type_class_add_private (klass, sizeof (GstRTSPMediaExtPrivate));
 +
 +  gobject_class = G_OBJECT_CLASS (klass);
 +  rtsp_media_class = GST_RTSP_MEDIA_CLASS (klass);
 +
 +  gobject_class->get_property = gst_rtsp_media_ext_get_property;
 +  gobject_class->set_property = gst_rtsp_media_ext_set_property;
 +  gobject_class->finalize = gst_rtsp_media_ext_finalize;
 +
 +  GST_DEBUG_CATEGORY_INIT (rtsp_media_ext_debug, "rtspmediaext", 0,
 +      "GstRTSPMediaExt");
 +
 +  rtsp_media_class->preparing = ext_preparing;
 +  rtsp_media_class->unpreparing = ext_unpreparing;
 +}
 +
 +static void
 +gst_rtsp_media_ext_init (GstRTSPMediaExt * media)
 +{
 +  GstRTSPMediaExtPrivate *priv = GST_RTSP_MEDIA_EXT_GET_PRIVATE (media);
 +
 +  media->priv = priv;
 +  priv->is_joined = FALSE;
 +  priv->mode = MEDIA_EXT_MODE_RESEND;
 +  priv->retransmit_port = RTP_RETRANS_PORT;
 +  priv->max_size_k = 10;
 +  priv->max_size_p = 10;
 +  priv->latency_mode = MEDIA_EXT_LATENCY_LOW;
 +  memset (&priv->rtp_resender, 0x00, sizeof (GstRTSPMediaExtRTPResender));
 +  g_mutex_init (&priv->lock);
 +}
 +
 +static void
 +gst_rtsp_media_ext_finalize (GObject * obj)
 +{
 +  GstRTSPMediaExtPrivate *priv;
 +  GstRTSPMediaExt *media;
 +
 +  media = GST_RTSP_MEDIA_EXT (obj);
 +  priv = media->priv;
 +  g_mutex_clear (&priv->lock);
 +
 +  G_OBJECT_CLASS (gst_rtsp_media_ext_parent_class)->finalize (obj);
 +}
 +
 +static void
 +gst_rtsp_media_ext_get_property (GObject * object, guint propid, GValue * value,
 +    GParamSpec * pspec)
 +{
 +}
 +
 +static void
 +gst_rtsp_media_ext_set_property (GObject * object, guint propid,
 +    const GValue * value, GParamSpec * pspec)
 +{
 +}
 +
 +GstRTSPMediaExt *
 +gst_rtsp_media_ext_new (GstElement * element)
 +{
 +  GstRTSPMediaExt *result;
 +
 +  g_return_val_if_fail (GST_IS_ELEMENT (element), NULL);
 +
 +  result = g_object_new (GST_TYPE_RTSP_MEDIA_EXT, "element", element, NULL);
 +
 +  return result;
 +}
 +
 +static gint in_idle_probe = FALSE;
 +
 +static gboolean
 +alloc_ports (GstRTSPMediaExt * media)
 +{
 +  GstStateChangeReturn ret;
 +  GstElement *udpsrc;
 +  GstElement *udpsink;
 +
 +  gint tmp_feedback_rtcp;
 +  gint feedback_rtcpport;
 +
 +  GInetAddress *inetaddr = NULL;
 +  GSocketAddress *feedback_rtcp_sockaddr = NULL;
 +  GSocket *feedback_rtp_socket;
 +  GSocketFamily family = G_SOCKET_FAMILY_IPV4;
 +  const gchar *sink_socket = "socket";
 +  gchar *resend_uri = NULL;
 +
 +  GstRTSPMediaExtPrivate *priv;
 +  priv = media->priv;
 +
 +  g_return_val_if_fail (priv != NULL, GST_PAD_PROBE_REMOVE);
 +
 +  udpsrc = NULL;
 +  udpsink = NULL;
 +
 +  /* Start with random port */
 +  tmp_feedback_rtcp = priv->retransmit_port + 1;
 +
 +  feedback_rtp_socket =
 +      g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, G_SOCKET_PROTOCOL_UDP,
 +      NULL);
 +
 +  if (!feedback_rtp_socket)
 +    goto no_udp_protocol;
 +
 +  inetaddr = g_inet_address_new_any (family);
 +
 +  feedback_rtcp_sockaddr =
 +      g_inet_socket_address_new (inetaddr, tmp_feedback_rtcp);
 +
 +  g_object_unref (inetaddr);
 +  inetaddr = NULL;
 +
 +  if (!g_socket_bind (feedback_rtp_socket, feedback_rtcp_sockaddr, FALSE, NULL)) {
 +    g_object_unref (feedback_rtcp_sockaddr);
 +    goto port_error;
 +  }
 +  g_object_unref (feedback_rtcp_sockaddr);
 +
 +  udpsrc = gst_element_factory_make ("udpsrc", NULL);
 +
 +  if (udpsrc == NULL)
 +    goto no_udp_protocol;
 +
 +  g_object_set (G_OBJECT (udpsrc), "socket", feedback_rtp_socket, NULL);
 +
 +  ret = gst_element_set_state (udpsrc, GST_STATE_READY);
 +  if (ret == GST_STATE_CHANGE_FAILURE)
 +    goto element_error;
 +
 +  /* all fine, do port check */
 +  g_object_get (G_OBJECT (udpsrc), "port", &feedback_rtcpport, NULL);
 +
 +  /* this should not happen... */
 +  if (feedback_rtcpport != tmp_feedback_rtcp)
 +    goto port_error;
 +
 +  resend_uri = g_strdup_printf ("udp://localhost:%d", priv->retransmit_port);
 +  if (resend_uri) {
 +    udpsink = gst_element_make_from_uri (GST_URI_SINK, resend_uri, NULL, NULL);
 +    g_free (resend_uri);
 +  }
 +
 +  if (!udpsink)
 +    goto no_udp_protocol;
 +
 +  g_object_set (G_OBJECT (udpsink), "close-socket", FALSE, NULL);
 +  g_object_set (G_OBJECT (udpsink), sink_socket, feedback_rtp_socket, NULL);
 +  g_object_set (G_OBJECT (udpsink), "sync", FALSE, NULL);
 +  g_object_set (G_OBJECT (udpsink), "async", FALSE, NULL);
 +  g_object_set (G_OBJECT (udpsink), "send-duplicates", FALSE, NULL);
 +  g_object_set (G_OBJECT (udpsink), "auto-multicast", FALSE, NULL);
 +  g_object_set (G_OBJECT (udpsink), "loop", FALSE, NULL);
 +
 +  priv->rtp_resender.resend_sink = udpsink;
 +  priv->rtp_resender.udpsrc_v4 = udpsrc;
 +
 +  return TRUE;
 +
 +  /* ERRORS */
 +no_udp_protocol:
 +  {
 +    goto cleanup;
 +  }
 +port_error:
 +  {
 +    goto cleanup;
 +  }
 +element_error:
 +  {
 +    goto cleanup;
 +  }
 +cleanup:
 +  {
 +    if (udpsrc) {
 +      gst_element_set_state (udpsrc, GST_STATE_NULL);
 +      gst_object_unref (udpsrc);
 +    }
 +    if (udpsink) {
 +      gst_element_set_state (udpsink, GST_STATE_NULL);
 +      gst_object_unref (udpsink);
 +    }
 +    if (inetaddr)
 +      g_object_unref (inetaddr);
 +    return FALSE;
 +  }
 +}
 +
 +static GstPadProbeReturn
 +pad_probe_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
 +{
 +  GstPad *sinkpad, *resend_pad, *fecpad;
 +  GstRTSPMediaExt *media = NULL;
 +  GstRTSPMediaExtPrivate *priv;
 +
 +  if (!g_atomic_int_compare_and_exchange (&in_idle_probe, FALSE, TRUE))
 +    return GST_PAD_PROBE_OK;
 +
 +  media = (GstRTSPMediaExt *) user_data;
 +
 +  priv = media->priv;
 +
 +  g_return_val_if_fail (priv != NULL, GST_PAD_PROBE_REMOVE);
 +
 +  sinkpad = gst_pad_get_peer (priv->send_src);
 +  gst_pad_unlink (priv->send_src, sinkpad);
 +
 +  if (priv->mode & MEDIA_EXT_MODE_RESEND) {
 +    GST_INFO_OBJECT (media, "joining resender");
 +    resend_pad =
 +        gst_element_get_static_pad (priv->rtp_resender.resender, "rtp_sink");
 +    gst_pad_link (priv->send_src, resend_pad);
 +    gst_object_unref (resend_pad);
 +
 +#ifdef FORCE_DROP
 +    {
 +      GstPad *identity_src, *identity_sink;
 +      identity_src = gst_element_get_static_pad (priv->identity, "src");
 +      identity_sink = gst_element_get_static_pad (priv->identity, "sink");
 +      resend_pad =
 +          gst_element_get_static_pad (priv->rtp_resender.resender, "send_src");
 +      gst_pad_link (resend_pad, identity_sink);
 +      gst_pad_link (identity_src, sinkpad);
 +      gst_object_unref (identity_sink);
 +      gst_object_unref (identity_src);
 +    }
 +#else
 +    resend_pad =
 +        gst_element_get_static_pad (priv->rtp_resender.resender, "send_src");
 +    gst_pad_link (resend_pad, sinkpad);
 +#endif
 +    gst_object_unref (resend_pad);
 +  } else if (priv->mode & MEDIA_EXT_MODE_FEC) {
 +    GST_INFO_OBJECT (media, "joining fec encoder");
 +    fecpad = gst_element_get_static_pad (priv->fecenc, "sink");
 +    gst_pad_link (priv->send_src, fecpad);
 +    gst_object_unref (fecpad);
 +
 +#ifdef FORCE_DROP
 +    {
 +      GstPad *identity_src, *identity_sink;
 +      identity_src = gst_element_get_static_pad (priv->identity, "src");
 +      identity_sink = gst_element_get_static_pad (priv->identity, "sink");
 +
 +      fecpad = gst_element_get_static_pad (priv->fecenc, "src");
 +
 +      gst_pad_link (fecpad, identity_sink);
 +      gst_pad_link (identity_src, sinkpad);
 +      gst_object_unref (identity_sink);
 +      gst_object_unref (identity_src);
 +    }
 +#else
 +    fecpad = gst_element_get_static_pad (priv->fecenc, "src");
 +    gst_pad_link (fecpad, sinkpad);
 +#endif
 +    gst_object_unref (fecpad);
 +  }
 +
 +  gst_object_unref (sinkpad);
 +
 +  return GST_PAD_PROBE_REMOVE;
 +}
 +
 +static gboolean
 +gst_rtsp_media_ext_join_extended_plugin (GstRTSPMediaExt * media, GstBin * bin,
 +    GstElement * rtpbin, GstState state, guint idx)
 +{
 +  GstRTSPMediaExtPrivate *priv;
 +  gchar *name;
 +  GstPad *pad, *sinkpad, *selpad;
 +  GstPad *resenderpad;
 +
 +  g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
 +  g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE);
 +
 +  priv = media->priv;
 +  g_return_val_if_fail (priv != NULL, FALSE);
 +
 +  g_mutex_lock (&priv->lock);
 +  if (priv->is_joined)
 +    goto was_joined;
 +
 +  GST_INFO ("media %p joining rtp resender %u", media, idx);
 +
 +  /* get pads from the RTP session element for sending and receiving
 +   * RTP/RTCP*/
 +  name = g_strdup_printf ("send_rtp_src_%u", idx);
 +  priv->send_src = gst_element_get_static_pad (rtpbin, name);
 +  g_free (name);
 +
 +  /* make resender for RTP and link to stream */
 +  priv->rtp_resender.resender = gst_element_factory_make ("rtpresender", NULL);
 +  gst_bin_add (bin, priv->rtp_resender.resender);
 +
 +  gst_element_sync_state_with_parent (priv->rtp_resender.resender);
 +
 +  if (!alloc_ports (media))
 +    goto no_ports;
 +
 +  /* For the sender we create this bit of pipeline for both
 +   * RTP and RTCP. Sync and preroll are enabled on udpsink so
 +   * we need to add a queue before appsink to make the pipeline
 +   * not block. For the TCP case, we want to pump data to the
 +   * client as fast as possible anyway.
 +   *
 +   * .--------.      .-----.    .---------.
 +   * | rtpbin |      | tee |    | udpsink |
 +   * |       send->sink   src->sink       |
 +   * '--------'      |     |    '---------'
 +   *                 |     |    .---------.    .---------.
 +   *                 |     |    |  queue  |    | appsink |
 +   *                 |    src->sink      src->sink       |
 +   *                 '-----'    '---------'    '---------'
 +   *
 +   * When only UDP is allowed, we skip the tee, queue and appsink and link the
 +   * udpsink directly to the session.
 +   */
 +  /* add udpsink */
 +  gst_bin_add (bin, priv->rtp_resender.resend_sink);
 +  sinkpad = gst_element_get_static_pad (priv->rtp_resender.resend_sink, "sink");
 +  resenderpad =
 +      gst_element_get_static_pad (priv->rtp_resender.resender, "resend_src");
 +
 +  gst_pad_link (resenderpad, sinkpad);
 +  gst_object_unref (resenderpad);
 +  gst_object_unref (sinkpad);
 +
 +  /* For the receiver we create this bit of pipeline for both
 +   * RTP and RTCP. We receive RTP/RTCP on appsrc and udpsrc
 +   * and it is all funneled into the rtpbin receive pad.
 +   *
 +   * .--------.     .--------.    .--------.
 +   * | udpsrc |     | funnel |    | rtpbin |
 +   * |       src->sink      src->sink      |
 +   * '--------'     |        |    '--------'
 +   * .--------.     |        |
 +   * | appsrc |     |        |
 +   * |       src->sink       |
 +   * '--------'     '--------'
 +   */
 +  /* make funnel for the RTP/RTCP receivers */
 +  priv->rtp_resender.funnel = gst_element_factory_make ("funnel", NULL);
 +  gst_bin_add (bin, priv->rtp_resender.funnel);
 +
 +  resenderpad =
 +      gst_element_get_static_pad (priv->rtp_resender.resender, "rtcp_sink");
 +  pad = gst_element_get_static_pad (priv->rtp_resender.funnel, "src");
 +  gst_pad_link (pad, resenderpad);
 +  gst_object_unref (resenderpad);
 +  gst_object_unref (pad);
 +
 +  if (priv->rtp_resender.udpsrc_v4) {
 +    /* we set and keep these to playing so that they don't cause NO_PREROLL return
 +     * values */
 +    gst_element_set_state (priv->rtp_resender.udpsrc_v4, GST_STATE_PLAYING);
 +    gst_element_set_locked_state (priv->rtp_resender.udpsrc_v4, TRUE);
 +    /* add udpsrc */
 +    gst_bin_add (bin, priv->rtp_resender.udpsrc_v4);
 +
 +    /* and link to the funnel v4 */
 +    selpad = gst_element_get_request_pad (priv->rtp_resender.funnel, "sink_%u");
 +    pad = gst_element_get_static_pad (priv->rtp_resender.udpsrc_v4, "src");
 +    gst_pad_link (pad, selpad);
 +    gst_object_unref (pad);
 +    gst_object_unref (selpad);
 +  }
 +
 +  /* make and add appsrc */
 +  priv->rtp_resender.appsrc = gst_element_factory_make ("appsrc", NULL);
 +  gst_bin_add (bin, priv->rtp_resender.appsrc);
 +  /* and link to the funnel */
 +  selpad = gst_element_get_request_pad (priv->rtp_resender.funnel, "sink_%u");
 +  pad = gst_element_get_static_pad (priv->rtp_resender.appsrc, "src");
 +  gst_pad_link (pad, selpad);
 +  gst_object_unref (pad);
 +  gst_object_unref (selpad);
 +
 +  /* check if we need to set to a special state */
 +  if (state != GST_STATE_NULL) {
 +    if (priv->rtp_resender.resend_sink)
 +      gst_element_set_state (priv->rtp_resender.resend_sink, state);
 +    if (priv->rtp_resender.funnel)
 +      gst_element_set_state (priv->rtp_resender.funnel, state);
 +    if (priv->rtp_resender.appsrc)
 +      gst_element_set_state (priv->rtp_resender.appsrc, state);
 +  }
 +
 +  /* make alfec encoder for RTP and link to stream */
 +  priv->fecenc = gst_element_factory_make ("alfecencoder", NULL);
 +  g_object_set (G_OBJECT (priv->fecenc), "max-size-k", priv->max_size_k, NULL);
 +  g_object_set (G_OBJECT (priv->fecenc), "max-size-p", priv->max_size_p, NULL);
 +  GST_DEBUG ("k:%d, p:%d", priv->max_size_k, priv->max_size_p);
 +  g_object_set (G_OBJECT (priv->fecenc), "next-k", priv->max_size_k, NULL);
 +  g_object_set (G_OBJECT (priv->fecenc), "next-p", priv->max_size_p, NULL);
 +  g_object_set (G_OBJECT (priv->fecenc), "symbol-length", 1500, NULL);
 +  gst_bin_add (bin, priv->fecenc);
 +
 +  gst_element_sync_state_with_parent (priv->fecenc);
 +
 +#ifdef FORCE_DROP
 +  priv->identity = gst_element_factory_make ("identity", NULL);
 +  g_object_set (G_OBJECT (priv->identity), "drop-probability", 0.05, NULL);
 +  gst_bin_add (bin, priv->identity);
 +
 +  gst_element_sync_state_with_parent(priv->identity);
 +#endif
 +
 +  in_idle_probe = FALSE;
 +  gst_pad_add_probe (priv->send_src, GST_PAD_PROBE_TYPE_IDLE, pad_probe_cb,
 +      media, NULL);
 +
 +  priv->is_joined = TRUE;
 +  g_mutex_unlock (&priv->lock);
 +
 +  return TRUE;
 +
 +  /* ERRORS */
 +was_joined:
 +  {
 +    g_mutex_unlock (&priv->lock);
 +    return TRUE;
 +  }
 +no_ports:
 +  {
 +    g_mutex_unlock (&priv->lock);
 +    GST_WARNING ("failed to allocate ports %u", idx);
 +    return FALSE;
 +  }
 +}
 +
 +
 +static void
 +ext_preparing (GstRTSPMedia * media, GstRTSPStream * stream, guint idx)
 +{
 +  gboolean ret = FALSE;
 +  GstElement *rtpbin = NULL;
 +  GstElement *pipeline = NULL;
 +  GstRTSPMediaExt *_media = GST_RTSP_MEDIA_EXT (media);
 +  GstRTSPMediaExtPrivate *priv;
 +
 +  priv = _media->priv;
 +  g_return_if_fail (priv != NULL);
 +
 +  pipeline = gst_rtsp_media_get_pipeline (media);
 +  rtpbin = gst_rtsp_media_get_rtpbin (media);
 +
 +  ret =
 +      gst_rtsp_media_ext_join_extended_plugin (_media, GST_BIN (pipeline),
 +      rtpbin, GST_STATE_NULL, idx);
 +  if (!ret)
 +    GST_ERROR_OBJECT (_media, "Fatal error to join resender");
 +
 +  g_object_unref (pipeline);
 +  g_object_unref (rtpbin);
 +
 +  return;
 +}
 +
 +static gboolean
 +gst_rtsp_media_ext_leave_extended_plugin (GstRTSPMediaExt * media, GstBin * bin,
 +    GstElement * rtpbin)
 +{
 +  GstRTSPMediaExtPrivate *priv;
 +
 +  g_return_val_if_fail (GST_IS_BIN (bin), FALSE);
 +  g_return_val_if_fail (GST_IS_ELEMENT (rtpbin), FALSE);
 +
 +  priv = media->priv;
 +  g_return_val_if_fail (priv != NULL, FALSE);
 +
 +  g_mutex_lock (&priv->lock);
 +  if (!priv->is_joined)
 +    goto was_not_joined;
 +
 +  GST_INFO ("media %p leaving rtp resender", media);
 +
 +  if (priv->rtp_resender.resend_sink)
 +    gst_element_set_state (priv->rtp_resender.resend_sink, GST_STATE_NULL);
 +  if (priv->rtp_resender.funnel)
 +    gst_element_set_state (priv->rtp_resender.funnel, GST_STATE_NULL);
 +  if (priv->rtp_resender.appsrc)
 +    gst_element_set_state (priv->rtp_resender.appsrc, GST_STATE_NULL);
 +
 +  if (priv->rtp_resender.udpsrc_v4) {
 +    /* and set udpsrc to NULL now before removing */
 +    gst_element_set_locked_state (priv->rtp_resender.udpsrc_v4, FALSE);
 +    gst_element_set_state (priv->rtp_resender.udpsrc_v4, GST_STATE_NULL);
 +    /* removing them should also nicely release the request
 +     * pads when they finalize */
 +    gst_bin_remove (bin, priv->rtp_resender.udpsrc_v4);
 +  }
 +
 +  if (priv->rtp_resender.resend_sink)
 +    gst_bin_remove (bin, priv->rtp_resender.resend_sink);
 +  if (priv->rtp_resender.appsrc)
 +    gst_bin_remove (bin, priv->rtp_resender.appsrc);
 +  if (priv->rtp_resender.funnel)
 +    gst_bin_remove (bin, priv->rtp_resender.funnel);
 +
 +  priv->rtp_resender.udpsrc_v4 = NULL;
 +  priv->rtp_resender.resend_sink = NULL;
 +  priv->rtp_resender.appsrc = NULL;
 +  priv->rtp_resender.funnel = NULL;
 +
 +  GST_INFO ("media %p leaving fec encoder", media);
 +
 +  if (priv->fecenc) {
 +    gst_element_set_state (priv->fecenc, GST_STATE_NULL);
 +    priv->fecenc = NULL;
 +  }
 +
 +  gst_object_unref (priv->send_src);
 +  priv->send_src = NULL;
 +  priv->is_joined = FALSE;
 +  g_mutex_unlock (&priv->lock);
 +
 +  return TRUE;
 +
 +was_not_joined:
 +  {
 +    g_mutex_unlock (&priv->lock);
 +    return TRUE;
 +  }
 +}
 +
 +
 +static void
 +ext_unpreparing (GstRTSPMedia * media, GstRTSPStream * stream, guint idx)
 +{
 +  gboolean ret = FALSE;
 +  GstElement *rtpbin = NULL;
 +  GstElement *pipeline = NULL;
 +  GstRTSPMediaExt *_media = GST_RTSP_MEDIA_EXT (media);
 +  GstRTSPMediaExtPrivate *priv;
 +
 +  priv = _media->priv;
 +  g_return_if_fail (priv != NULL);
 +
 +  pipeline = gst_rtsp_media_get_pipeline (media);
 +  rtpbin = gst_rtsp_media_get_rtpbin (media);
 +
 +  ret =
 +      gst_rtsp_media_ext_leave_extended_plugin (_media, GST_BIN (pipeline),
 +      rtpbin);
 +
 +  if (!ret)
 +    GST_ERROR_OBJECT (_media, "Fatal error to leave resender");
 +
 +  g_object_unref (pipeline);
 +  g_object_unref (rtpbin);
 +
 +  return;
 +}
 +
 +guint
 +gst_rtsp_media_ext_get_resent_packets (GstRTSPMediaExt * media)
 +{
 +  guint resent_packets = 0;
 +  GstRTSPMediaExtPrivate *priv;
 +
 +  g_return_val_if_fail (GST_IS_RTSP_MEDIA_EXT (media), 0);
 +
 +  priv = media->priv;
 +  g_return_val_if_fail (priv != NULL, 0);
 +
 +  g_object_get (G_OBJECT (priv->rtp_resender.resender), "rtp-packets-resend",
 +      &resent_packets, NULL);
 +
 +  return resent_packets;
 +}
 +
 +void
 +gst_rtsp_media_ext_set_extended_mode (GstRTSPMediaExt * media,
 +    GstRTSPMediaExtMode mode)
 +{
 +  GstRTSPMediaExtPrivate *priv;
 +
 +  g_return_if_fail (GST_IS_RTSP_MEDIA_EXT (media));
 +
 +  priv = media->priv;
 +  g_return_if_fail (priv != NULL);
 +
 +  priv->mode = mode;
 +}
 +
 +void
 +gst_rtsp_media_ext_set_retrans_port (GstRTSPMediaExt * media, guint port)
 +{
 +  GstRTSPMediaExtPrivate *priv;
 +
 +  g_return_if_fail (GST_IS_RTSP_MEDIA_EXT (media));
 +
 +  priv = media->priv;
 +  g_return_if_fail (priv != NULL);
 +
 +  priv->retransmit_port = port;
 +}
 +
 +void
 +gst_rtsp_media_ext_set_fec_value (GstRTSPMediaExt * media, guint max_k,
 +    guint max_p)
 +{
 +  GstRTSPMediaExtPrivate *priv;
 +
 +  g_return_if_fail (GST_IS_RTSP_MEDIA_EXT (media));
 +
 +  priv = media->priv;
 +  g_return_if_fail (priv != NULL);
 +
 +  priv->max_size_k = max_k;
 +  priv->max_size_p = max_p;
 +}
 +
 +void
 +gst_rtsp_media_ext_set_latency_mode (GstRTSPMediaExt * media,
 +    GstRTSPMediaExtLatency latency)
 +{
 +  GstRTSPMediaExtPrivate *priv;
 +
 +  g_return_if_fail (GST_IS_RTSP_MEDIA_EXT (media));
 +
 +  priv = media->priv;
 +  g_return_if_fail (priv != NULL);
 +
 +  priv->latency_mode = latency;
 +}
 +
 +void
 +gst_rtsp_media_ext_set_next_param (GstRTSPMediaExt * media, gint32 next_k,
 +    gint32 next_p)
 +{
 +  GstRTSPMediaExtPrivate *priv;
 +
 +  g_return_if_fail (GST_IS_RTSP_MEDIA_EXT (media));
 +
 +  priv = media->priv;
 +  g_return_if_fail (priv != NULL);
 +
 +  g_object_set (G_OBJECT (priv->fecenc), "next-k", next_k, NULL);
 +  g_object_set (G_OBJECT (priv->fecenc), "next-p", next_p, NULL);
 +}
index 1cca81f,0000000..1cca81f
mode 100755,000000..100755
--- /dev/null
@@@ -1,128 -1,0 +1,128 @@@
 +/* GStreamer
 + * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.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/gstrtsprange.h>
 +#include <gst/rtsp/gstrtspurl.h>
 +#include <gst/net/gstnet.h>
 +
 +#ifndef __GST_RTSP_MEDIA_EXT_H__
 +#define __GST_RTSP_MEDIA_EXT_H__
 +
 +G_BEGIN_DECLS
 +
 +/* types for the media */
 +#define GST_TYPE_RTSP_MEDIA_EXT              (gst_rtsp_media_ext_get_type ())
 +#define GST_IS_RTSP_MEDIA_EXT(obj)           (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_RTSP_MEDIA_EXT))
 +#define GST_IS_RTSP_MEDIA_EXT_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_RTSP_MEDIA_EXT))
 +#define GST_RTSP_MEDIA_EXT_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_RTSP_MEDIA_EXT, GstRTSPMediaExtClass))
 +#define GST_RTSP_MEDIA_EXT(obj)              (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_RTSP_MEDIA_EXT, GstRTSPMediaExt))
 +#define GST_RTSP_MEDIA_EXT_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_RTSP_MEDIA_EXT, GstRTSPMediaExtClass))
 +#define GST_RTSP_MEDIA_EXT_CAST(obj)         ((GstRTSPMediaExt*)(obj))
 +#define GST_RTSP_MEDIA_EXT_CLASS_CAST(klass) ((GstRTSPMediaExtClass*)(klass))
 +
 +typedef struct _GstRTSPMediaExt GstRTSPMediaExt;
 +typedef struct _GstRTSPMediaExtClass GstRTSPMediaExtClass;
 +typedef struct _GstRTSPMediaExtPrivate GstRTSPMediaExtPrivate;
 +
 +#include "rtsp-stream.h"
 +
 +typedef enum {
 +  MEDIA_EXT_MODE_NONE = (0 << 0),
 +  MEDIA_EXT_MODE_RESEND = (1 << 0),
 +  MEDIA_EXT_MODE_FEC    = (1 << 1)
 +} GstRTSPMediaExtMode;
 +
 +typedef enum {
 +  MEDIA_EXT_LATENCY_NONE,
 +  MEDIA_EXT_LATENCY_LOW,
 +  MEDIA_EXT_LATENCY_MID,
 +  MEDIA_EXT_LATENCY_HIGH
 +} GstRTSPMediaExtLatency;
 +
 +/**
 + * GstRTSPMedia:
 + *
 + * A class that contains the GStreamer element along with a list of
 + * #GstRTSPStream objects that can produce data.
 + *
 + * This object is usually created from a #GstRTSPMediaFactory.
 + */
 +struct _GstRTSPMediaExt {
 +  GstRTSPMedia            parent;
 +
 +  /*< private >*/
 +  GstRTSPMediaExtPrivate *priv;
 +  gpointer _gst_reserved[GST_PADDING];
 +};
 +
 +/**
 + * GstRTSPMediaClass:
 + * @handle_message: handle a message
 + * @prepare: the default implementation adds all elements and sets the
 + *           pipeline's state to GST_STATE_PAUSED (or GST_STATE_PLAYING
 + *           in case of NO_PREROLL elements).
 + * @unprepare: the default implementation sets the pipeline's state
 + *             to GST_STATE_NULL and removes all elements.
 + * @suspend: the default implementation sets the pipeline's state to
 + *           GST_STATE_NULL GST_STATE_PAUSED depending on the selected
 + *           suspend mode.
 + * @unsuspend: the default implementation reverts the suspend operation.
 + *             The pipeline will be prerolled again if it's state was
 + *             set to GST_STATE_NULL in suspend.
 + * @convert_range: convert a range to the given unit
 + * @query_position: query the current position in the pipeline
 + * @query_stop: query when playback will stop
 + *
 + * The RTSP media class
 + */
 +struct _GstRTSPMediaExtClass {
 +  GstRTSPMediaClass  parent_class;
 +
 +  /*< private >*/
 +  gpointer         _gst_reserved[GST_PADDING_LARGE];
 +};
 +
 +GType                 gst_rtsp_media_ext_get_type         (void);
 +
 +/* creating the media */
 +GST_RTSP_SERVER_API
 +GstRTSPMediaExt *  gst_rtsp_media_ext_new                (GstElement *element);
 +
 +GST_RTSP_SERVER_API
 +guint              gst_rtsp_media_ext_get_resent_packets (GstRTSPMediaExt *media);
 +
 +GST_RTSP_SERVER_API
 +void               gst_rtsp_media_ext_set_extended_mode  (GstRTSPMediaExt *media, GstRTSPMediaExtMode mode);
 +
 +GST_RTSP_SERVER_API
 +void               gst_rtsp_media_ext_set_retrans_port   (GstRTSPMediaExt *media, guint port);
 +
 +GST_RTSP_SERVER_API
 +void               gst_rtsp_media_ext_set_fec_value      (GstRTSPMediaExt *media, guint max_k, guint max_p);
 +
 +GST_RTSP_SERVER_API
 +void               gst_rtsp_media_ext_set_latency_mode   (GstRTSPMediaExt *media, GstRTSPMediaExtLatency latency);
 +
 +GST_RTSP_SERVER_API
 +void               gst_rtsp_media_ext_set_next_param     (GstRTSPMediaExt *media, gint32 next_k, gint32 next_p);
 +
 +G_END_DECLS
 +
 +#endif /* __GST_RTSP_MEDIA_EXT_H__ */
@@@ -641,7 -641,6 +641,7 @@@ no_uridecodebin
    {
      g_critical ("can't create uridecodebin element");
      gst_object_unref (element);
 +    gst_object_unref (topbin);
      return NULL;
    }
  }
index b6e087c,0000000..b6e087c
mode 100644,000000..100644
--- /dev/null
@@@ -1,2087 -1,0 +1,2087 @@@
 +/* 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)
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include "config.h"
 +#endif
 +
 +#include <stdio.h>
 +#include <string.h>
 +
 +#include "rtsp-media-factory-wfd.h"
 +#include "gstwfdmessage.h"
 +#include "rtsp-media-ext.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)))
 +
 +typedef struct _GstRTPSMediaWFDTypeFindResult GstRTPSMediaWFDTypeFindResult;
 +
 +struct _GstRTPSMediaWFDTypeFindResult{
 +  gint h264_found;
 +  gint aac_found;
 +  gint ac3_found;
 +  GstElementFactory *demux_fact;
 +  GstElementFactory *src_fact;
 +};
 +
 +typedef struct _GstRTSPMediaWFDDirectPipelineData GstRTSPMediaWFDDirectPipelineData;
 +
 +struct _GstRTSPMediaWFDDirectPipelineData {
 +  GstBin *pipeline;
 +  GstElement *ap;
 +  GstElement *vp;
 +  GstElement *aq;
 +  GstElement *vq;
 +  GstElement *tsmux;
 +  GstElement *mux_fs;
 +  gchar *uri;
 +};
 +
 +
 +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;
 +  GstBin *video_srcbin;
 +
 +  GstElement *venc;
 +  guint decide_udp_bitrate[21];
 +  guint min_udp_bitrate;
 +  guint max_udp_bitrate;
 +  gboolean decided_udp_bitrate;
 +
 +  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;
 +  GstBin *audio_srcbin;
 +
 +  GMutex direct_lock;
 +  GCond direct_cond;
 +  GType decodebin_type;
 +  GstBin *discover_pipeline;
 +  GstRTPSMediaWFDTypeFindResult res;
 +  GstRTSPMediaWFDDirectPipelineData *direct_pipe;
 +  GstBin *stream_bin;
 +  GstElement *mux;
 +  GstElement *mux_queue;
 +  GstElement *pay;
 +  GstElement *stub_fs;
 +  GMainLoop *discover_loop;
 +
 +  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_DIRECT_STREAMING_END,
 +  SIGNAL_LAST
 +};
 +
 +GST_DEBUG_CATEGORY_STATIC (rtsp_media_wfd_debug);
 +#define GST_CAT_DEFAULT rtsp_media_wfd_debug
 +
 +static guint gst_rtsp_media_factory_wfd_signals[SIGNAL_LAST] = { 0 };
 +
 +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);
 +
 +static void _config_bitrate (GstRTSPMediaFactoryWFD * factory);
 +
 +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;
 +
 +  gst_rtsp_media_factory_wfd_signals[SIGNAL_DIRECT_STREAMING_END] =
 +      g_signal_new ("direct-stream-end", G_TYPE_FROM_CLASS (klass),
 +      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTSPMediaFactoryWFDClass,
 +          direct_stream_end), NULL, NULL, g_cclosure_marshal_generic,
 +      G_TYPE_NONE, 0, G_TYPE_NONE);
 +
 +  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;
 +  _config_bitrate (factory_wfd);
 +}
 +
 +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;
 +}
 +
 +void
 +gst_rtsp_media_factory_wfd_set_video_codec (GstRTSPMediaFactory * factory,
 +    guint video_codec)
 +{
 +  GstRTSPMediaFactoryWFD *factory_wfd = GST_RTSP_MEDIA_FACTORY_WFD (factory);
 +  GstRTSPMediaFactoryWFDPrivate *priv = factory_wfd->priv;
 +
 +  priv->video_codec = video_codec;
 +}
 +
 +static void
 +_config_bitrate (GstRTSPMediaFactoryWFD * factory)
 +{
 +  GstRTSPMediaFactoryWFDPrivate *priv = factory->priv;
 +
 +  if (priv->decided_udp_bitrate) {
 +    priv->video_bitrate = priv->decide_udp_bitrate[0];
 +    priv->min_udp_bitrate = priv->decide_udp_bitrate[1];
 +    priv->max_udp_bitrate = priv->decide_udp_bitrate[2];
 +
 +    if ((priv->video_width * priv->video_height) >= (1920 * 1080)) {
 +      priv->video_bitrate = priv->decide_udp_bitrate[3];
 +      priv->min_udp_bitrate = priv->decide_udp_bitrate[4];
 +      priv->max_udp_bitrate = priv->decide_udp_bitrate[5];
 +    } else if ((priv->video_width * priv->video_height) >= (1280 * 720)) {
 +      priv->video_bitrate = priv->decide_udp_bitrate[6];
 +      priv->min_udp_bitrate = priv->decide_udp_bitrate[7];
 +      priv->max_udp_bitrate = priv->decide_udp_bitrate[8];
 +    } else if ((priv->video_width * priv->video_height) >= (960 * 540)) {
 +      priv->video_bitrate = priv->decide_udp_bitrate[9];
 +      priv->min_udp_bitrate = priv->decide_udp_bitrate[10];
 +      priv->max_udp_bitrate = priv->decide_udp_bitrate[11];
 +    } else if ((priv->video_width * priv->video_height) >= (854 * 480)) {
 +      priv->video_bitrate = priv->decide_udp_bitrate[12];
 +      priv->min_udp_bitrate = priv->decide_udp_bitrate[13];
 +      priv->max_udp_bitrate = priv->decide_udp_bitrate[14];
 +    } else if ((priv->video_width * priv->video_height) >= (640 * 480)) {
 +      priv->video_bitrate = priv->decide_udp_bitrate[15];
 +      priv->min_udp_bitrate = priv->decide_udp_bitrate[16];
 +      priv->max_udp_bitrate = priv->decide_udp_bitrate[17];
 +    }
 +  }
 +}
 +
 +void
 +gst_rtsp_media_factory_wfd_set_venc_bitrate (GstRTSPMediaFactory * factory,
 +    gint bitrate)
 +{
 +  GstRTSPMediaFactoryWFD *factory_wfd = GST_RTSP_MEDIA_FACTORY_WFD (factory);
 +  GstRTSPMediaFactoryWFDPrivate *priv = factory_wfd->priv;
 +
 +  g_object_set (priv->venc, "target-bitrate", bitrate, NULL);
 +  priv->video_bitrate = (guint) bitrate;
 +}
 +
 +void
 +gst_rtsp_media_factory_wfd_get_venc_bitrate (GstRTSPMediaFactory * factory,
 +    gint * bitrate)
 +{
 +  int cur_bitrate = 0;
 +
 +  GstRTSPMediaFactoryWFD *factory_wfd = GST_RTSP_MEDIA_FACTORY_WFD (factory);
 +  GstRTSPMediaFactoryWFDPrivate *priv = factory_wfd->priv;
 +
 +  g_object_get (priv->venc, "target-bitrate", &cur_bitrate, NULL);
 +
 +  if (cur_bitrate == 0) {
 +    *bitrate = priv->video_bitrate;
 +  } else {
 +    *bitrate = (gint) cur_bitrate;
 +  }
 +}
 +
 +void
 +gst_rtsp_media_factory_wfd_get_config_bitrate (GstRTSPMediaFactory * factory,
 +    guint32 * min, guint32 * max)
 +{
 +  GstRTSPMediaFactoryWFD *factory_wfd = GST_RTSP_MEDIA_FACTORY_WFD (factory);
 +  GstRTSPMediaFactoryWFDPrivate *priv = factory_wfd->priv;
 +
 +  *min = priv->min_udp_bitrate;
 +  *max = priv->max_udp_bitrate;
 +}
 +
 +void
 +gst_rtsp_media_factory_wfd_set_config_bitrate (GstRTSPMediaFactoryWFD * factory,
 +    guint * config_bitrate)
 +{
 +  GstRTSPMediaFactoryWFDPrivate *priv = factory->priv;
 +
 +  gint idx = 0;
 +  for (idx = 0; idx < 21; idx++) {
 +    priv->decide_udp_bitrate[idx] = config_bitrate[idx];
 +  }
 +  priv->decided_udp_bitrate = TRUE;
 +
 +  _config_bitrate (factory);
 +}
 +
 +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->video_srcbin = NULL;
 +  priv->min_udp_bitrate = 938861;
 +  priv->max_udp_bitrate = 1572864;
 +  priv->decided_udp_bitrate = FALSE;
 +
 +  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;
 +  priv->audio_srcbin = NULL;
 +
 +  g_mutex_init (&priv->direct_lock);
 +  g_cond_init (&priv->direct_cond);
 +
 +  priv->discover_pipeline = NULL;
 +  priv->direct_pipe = NULL;
 +  memset (&priv->res, 0x00, sizeof (GstRTPSMediaWFDTypeFindResult));
 +  priv->stream_bin = NULL;
 +  priv->mux = NULL;
 +  priv->mux_queue = NULL;
 +  priv->pay = NULL;
 +
 +  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);
 +
 +  g_mutex_clear (&priv->direct_lock);
 +  g_cond_clear (&priv->direct_cond);
 +
 +  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;
 +  GstStructure *audio_properties_name = NULL;
 +
 +  guint channels = 0;
 +  gboolean is_enc_req = TRUE;
 +  guint freq = 0;
 +  g_autofree gchar *acodec = NULL;
 +
 +  priv = factory->priv;
 +
 +  if (priv->audio_codec == GST_WFD_AUDIO_UNKNOWN) {
 +    GST_INFO_OBJECT (factory, "Skip create audio source");
 +    return TRUE;
 +  }
 +
 +  priv->audio_srcbin = (GstBin *)gst_bin_new ("audio");
 +
 +  /* 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);
 +
 +  audio_properties_name = gst_structure_new_from_string (priv->audio_device);
 +
 +  g_object_set (audiosrc, "stream-properties", audio_properties_name, 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 (priv->audio_srcbin, audiosrc, acaps, aenc, aqueue, NULL);
 +    gst_bin_add (srcbin, GST_ELEMENT (priv->audio_srcbin));
 +
 +    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 (priv->audio_srcbin, audiosrc, acaps2, audio_convert, acaps, aqueue, NULL);
 +    gst_bin_add (srcbin, GST_ELEMENT (priv->audio_srcbin));
 +
 +    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 (audio_properties_name)
 +    gst_structure_free (audio_properties_name);
 +  return TRUE;
 +
 +create_error:
 +  gst_object_unref (acaps);
 +  gst_object_unref (aqueue);
 +  if (audio_properties_name)
 +    gst_structure_free (audio_properties_name);
 +  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;
 +  GstElement *venc = NULL;
 +  GstElement *vparse = NULL;
 +  GstElement *vqueue = NULL;
 +  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
 +
 +  priv = factory->priv;
 +
 +  GST_INFO_OBJECT (factory, "picked videotestsrc as video source");
 +  priv->video_srcbin = (GstBin *)gst_bin_new ("video");
 +
 +  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) {
 +    GST_ERROR_OBJECT (factory, "Yet to support other than H264 format");
 +    goto create_error;
 +  }
 +
 +  venc = gst_element_factory_make (priv->video_encoder, "videoenc");
 +  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 (priv->video_srcbin, videosrc, vcaps, videoconvert, venc_caps, venc, vparse, vqueue, NULL);
 +  gst_bin_add (srcbin, GST_ELEMENT (priv->video_srcbin));
 +  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;
 +  priv->venc = venc;
 +
 +  return TRUE;
 +
 +create_error:
 +  gst_object_unref(videosrc);
 +  gst_object_unref(vcaps);
 +  gst_object_unref(videoconvert);
 +  gst_object_unref(venc_caps);
 +  gst_object_unref(venc);
 +  gst_object_unref(vparse);
 +  gst_object_unref(vqueue);
 +  return FALSE;
 +}
 +
 +static gboolean
 +_rtsp_media_factory_wfd_create_waylandsrc_bin (GstRTSPMediaFactoryWFD * factory,
 +    GstBin * srcbin)
 +{
 +  GstElement *videosrc = NULL;
 +  GstElement *vcaps = 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");
 +
 +  if (priv->video_codec == GST_WFD_VIDEO_UNKNOWN) {
 +    GST_INFO_OBJECT (factory, "Skip create video source.");
 +    return TRUE;
 +  }
 +
 +  priv->video_srcbin = (GstBin *)gst_bin_new ("video");
 +
 +  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) {
 +    GST_ERROR_OBJECT (factory, "Yet to support other than H264 format");
 +    goto create_error;
 +  }
 +
 +  venc = gst_element_factory_make (priv->video_encoder, "videoenc");
 +  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);
 +  g_object_set (venc, "target-bitrate", priv->video_bitrate, 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 (priv->video_srcbin, videosrc, vcaps, venc, vparse, vqueue, NULL);
 +  gst_bin_add (srcbin, GST_ELEMENT (priv->video_srcbin));
 +  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;
 +  priv->venc = venc;
 +
 +  return TRUE;
 +
 +create_error:
 +  gst_object_unref (videosrc);
 +  gst_object_unref (vqueue);
 +  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;
 +  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
 +
 +  priv = factory->priv;
 +  priv->video_srcbin = (GstBin *)gst_bin_new ("video");
 +
 +  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) {
 +    GST_ERROR_OBJECT (factory, "Yet to support other than H264 format");
 +    goto create_error;
 +  }
 +
 +  venc = gst_element_factory_make (priv->video_encoder, "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);
 +
 +  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 (priv->video_srcbin, videosrc, vcaps, venc, vparse, vqueue, NULL);
 +  gst_bin_add (srcbin, GST_ELEMENT (priv->video_srcbin));
 +
 +  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;
 +  priv->venc = venc;
 +
 +  return TRUE;
 +
 +create_error:
 +  gst_object_unref (videosrc);
 +  gst_object_unref (vqueue);
 +  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;
 +  GstElement *venc = NULL;
 +  GstElement *vparse = NULL;
 +  GstElement *vqueue = NULL;
 +  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
 +
 +  priv = factory->priv;
 +
 +  GST_INFO_OBJECT (factory, "picked ximagesrc as video source");
 +  priv->video_srcbin = (GstBin *)gst_bin_new ("video");
 +
 +  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) {
 +    GST_ERROR_OBJECT (factory, "Yet to support other than H264 format");
 +    goto create_error;
 +  }
 +
 +  venc = gst_element_factory_make (priv->video_encoder, "videoenc");
 +  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 (priv->video_srcbin, videosrc, videoscale, videoconvert, vcaps, venc,
 +      venc_caps, vparse, vqueue, NULL);
 +  gst_bin_add (srcbin, GST_ELEMENT (priv->video_srcbin));
 +  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;
 +  priv->venc = venc;
 +
 +  return TRUE;
 +
 +create_error:
 +  gst_object_unref(videosrc);
 +  gst_object_unref(vcaps);
 +  gst_object_unref(venc_caps);
 +  gst_object_unref(videoconvert);
 +  gst_object_unref(videoscale);
 +  gst_object_unref(venc);
 +  gst_object_unref(vparse);
 +  gst_object_unref(vqueue);
 +  return FALSE;
 +}
 +
 +static gboolean
 +_rtsp_media_factory_wfd_create_xvcapture_bin (GstRTSPMediaFactoryWFD * factory,
 +    GstBin * srcbin)
 +{
 +  GstElement *videosrc = NULL;
 +  GstElement *vcaps = 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");
 +  priv->video_srcbin = (GstBin *)gst_bin_new ("video");
 +
 +  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) {
 +    GST_ERROR_OBJECT (factory, "Yet to support other than H264 format");
 +    goto create_error;
 +  }
 +
 +  venc = gst_element_factory_make (priv->video_encoder, "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 (priv->video_srcbin, videosrc, vcaps, venc, vparse, vqueue, NULL);
 +  gst_bin_add (srcbin, GST_ELEMENT (priv->video_srcbin));
 +  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;
 +  priv->venc = venc;
 +
 +  return TRUE;
 +
 +create_error:
 +  gst_object_unref (videosrc);
 +  gst_object_unref (vqueue);
 +
 +  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;
 +  GstPad *ghost_pad = 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;
 +  }
 +
 +  GST_INFO_OBJECT (factory, "Check video codec... %d", priv->video_codec);
 +  /* 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;
 +  }
 +
 +  if (priv->video_codec > GST_WFD_VIDEO_UNKNOWN) {
 +    /* 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;
 +    }
 +  ghost_pad = gst_ghost_pad_new ("video_src", srcpad);
 +  gst_element_add_pad (GST_ELEMENT (priv->video_srcbin), ghost_pad);
 +
 +  if (gst_pad_link (ghost_pad, 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;
 +  ghost_pad = NULL;
 +  }
 +
 +  GST_INFO_OBJECT (factory, "Check audio codec... %d", priv->audio_codec);
 +
 +  /* create audio source elements & add to pipeline */
 +  if (!_rtsp_media_factory_wfd_create_audio_capture_bin (factory, srcbin))
 +    goto create_error;
 +
 +  if (priv->audio_codec > GST_WFD_AUDIO_UNKNOWN) {
 +    /* 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;
 +    }
 +  ghost_pad = gst_ghost_pad_new ("audio_src", srcpad);
 +  gst_element_add_pad (GST_ELEMENT (priv->audio_srcbin), ghost_pad);
 +
 +    /* link audio queue's srcpad & muxer sink pad */
 +  if (gst_pad_link (ghost_pad, 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);
 +    if (pad_probe)
 +      gst_object_unref (pad_probe);
 +  }
 +
 +  GST_DEBUG_OBJECT (factory, "successfully created source bin...");
 +
 +  priv->stream_bin = srcbin;
 +  priv->mux = gst_object_ref (mux);
 +  priv->mux_queue = gst_object_ref (mux_queue);
 +  priv->pay = gst_object_ref (payload);
 +
 +  return GST_ELEMENT_CAST (srcbin);
 +
 +create_error:
 +  GST_ERROR_OBJECT (factory, "Failed to create pipeline");
 +  if (mux_vsinkpad)
 +    gst_object_unref (mux_vsinkpad);
 +  if (mux_asinkpad)
 +    gst_object_unref (mux_asinkpad);
 +  if (srcpad)
 +    gst_object_unref (srcpad);
 +  if (srcbin)
 +    gst_object_unref (srcbin);
 +  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);
 +  //media = g_object_new (GST_TYPE_RTSP_MEDIA_EXT, "element", element, NULL);
 +
 +  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;
 +  }
 +}
 +
 +gint type_detected = FALSE;
 +gint linked = FALSE;
 +static gint in_pad_probe;
 +
 +static GstPadProbeReturn
 +_rtsp_media_factory_wfd_restore_pipe_probe_cb (GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
 +{
 +  GstPad *old_src = NULL;
 +  GstPad *sink = NULL;
 +  GstPad *old_sink = NULL;
 +  GstPad *new_src = NULL;
 +  GstRTSPMediaFactoryWFD *factory = NULL;
 +  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
 +  GstRTSPMediaWFDDirectPipelineData *pipe_data = NULL;
 +
 +  if (!g_atomic_int_compare_and_exchange (&in_pad_probe, FALSE, TRUE))
 +    return GST_PAD_PROBE_OK;
 +
 +  factory = (GstRTSPMediaFactoryWFD *) user_data;
 +  priv = factory->priv;
 +  pipe_data = priv->direct_pipe;
 +
 +  gst_element_sync_state_with_parent (GST_ELEMENT(priv->audio_srcbin));
 +  gst_element_sync_state_with_parent (GST_ELEMENT(priv->video_srcbin));
 +  gst_element_sync_state_with_parent (GST_ELEMENT(priv->mux));
 +  gst_element_sync_state_with_parent (GST_ELEMENT(priv->mux_queue));
 +
 +  sink = gst_element_get_static_pad (priv->pay, "sink");
 +  old_src = gst_pad_get_peer (sink);
 +  gst_pad_unlink (old_src, sink);
 +
 +  new_src = gst_element_get_static_pad (priv->mux_queue, "src");
 +  old_sink = gst_pad_get_peer (new_src);
 +  gst_pad_unlink (new_src, old_sink);
 +  gst_element_set_state (priv->stub_fs, GST_STATE_NULL);
 +  gst_bin_remove ((GstBin *)priv->stream_bin, priv->stub_fs);
 +
 +  gst_pad_link (new_src, sink);
 +  gst_object_unref (new_src);
 +  gst_object_unref (old_sink);
 +
 +  gst_element_set_state (GST_ELEMENT(pipe_data->pipeline), GST_STATE_PAUSED);
 +
 +  /* signal that new pipeline linked */
 +  g_mutex_lock (&priv->direct_lock);
 +  g_cond_signal (&priv->direct_cond);
 +  linked = TRUE;
 +  g_mutex_unlock (&priv->direct_lock);
 +
 +  return GST_PAD_PROBE_REMOVE;
 +}
 +
 +static gboolean
 +_rtsp_media_factory_wfd_destroy_direct_pipe(void *user_data)
 +{
 +  GstRTSPMediaFactoryWFD *factory = NULL;
 +  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
 +  GstRTSPMediaWFDDirectPipelineData *pipe_data = NULL;
 +
 +  factory = (GstRTSPMediaFactoryWFD *) user_data;
 +  priv = factory->priv;
 +  pipe_data = priv->direct_pipe;
 +
 +  GST_DEBUG_OBJECT (factory, "Deleting pipeline");
 +  gst_element_set_state (GST_ELEMENT(pipe_data->pipeline), GST_STATE_NULL);
 +  gst_bin_remove ((GstBin *)priv->stream_bin, GST_ELEMENT(pipe_data->pipeline));
 +  g_free (pipe_data);
 +  g_signal_emit (factory,
 +      gst_rtsp_media_factory_wfd_signals[SIGNAL_DIRECT_STREAMING_END], 0, NULL);
 +  return FALSE;
 +}
 +
 +static void
 +_rtsp_media_factory_wfd_demux_pad_added_cb (GstElement *element,
 +              GstPad     *pad,
 +              gpointer    data)
 +{
 +  GstPad *sinkpad = NULL;
 +  GstRTSPMediaFactoryWFD *factory = NULL;
 +  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
 +  GstRTSPMediaWFDDirectPipelineData *pipe_data = NULL;
 +
 +  GstCaps *caps = gst_pad_get_current_caps (pad);
 +  g_autofree gchar *pad_name = gst_pad_get_name (pad);
 +  g_autofree gchar *caps_string = gst_caps_to_string (caps);
 +  g_autofree gchar *temp_caps = NULL;
 +
 +  gst_caps_unref (caps);
 +
 +  factory = (GstRTSPMediaFactoryWFD *) data;
 +  priv = factory->priv;
 +  pipe_data = priv->direct_pipe;
 +  temp_caps = g_ascii_strdown(caps_string, -1);
 +
 +  if (g_strrstr (temp_caps, "audio")) {
 +    sinkpad = gst_element_get_static_pad (pipe_data->ap, "sink");
 +    if (gst_pad_is_linked (sinkpad)) {
 +      gst_object_unref (sinkpad);
 +      GST_DEBUG_OBJECT (factory, "pad linked");
 +      return;
 +    }
 +    if (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)
 +      GST_DEBUG_OBJECT (factory, "can't link demux %s pad", pad_name);
 +
 +    gst_object_unref (sinkpad);
 +    sinkpad = NULL;
 +  }
 +
 +  if (g_strrstr (temp_caps, "video")) {
 +    if (g_strrstr (temp_caps, "h264")) {
 +      sinkpad = gst_element_get_static_pad (pipe_data->vp, "sink");
 +      if (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)
 +        GST_DEBUG_OBJECT (factory, "can't link demux %s pad", pad_name);
 +
 +      gst_object_unref (sinkpad);
 +      sinkpad = NULL;
 +    }
 +  }
 +}
 +
 +static GstPadProbeReturn
 +_rtsp_media_factory_wfd_pay_pad_probe_cb (GstPad *pad, GstPadProbeInfo *info, gpointer user_data)
 +{
 +  GstPad *old_src = NULL;
 +  GstPad *sink = NULL;
 +  GstPad *old_sink = NULL;
 +  GstPad *new_src = NULL;
 +  GstPad *fas_sink = NULL;
 +  GstPad *gp = NULL;
 +  GstRTSPMediaFactoryWFD *factory = NULL;
 +  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
 +  GstRTSPMediaWFDDirectPipelineData *pipe_data = NULL;
 +
 +  if (!g_atomic_int_compare_and_exchange (&in_pad_probe, FALSE, TRUE))
 +    return GST_PAD_PROBE_OK;
 +
 +  factory = (GstRTSPMediaFactoryWFD *) user_data;
 +  priv = factory->priv;
 +  pipe_data = priv->direct_pipe;
 +
 +  sink = gst_element_get_static_pad (priv->pay, "sink");
 +  old_src = gst_pad_get_peer (sink);
 +  gst_pad_unlink (old_src, sink);
 +
 +  new_src = gst_element_get_static_pad (pipe_data->tsmux, "src");
 +  old_sink = gst_pad_get_peer (new_src);
 +  gst_pad_unlink (new_src, old_sink);
 +  gst_element_set_state (pipe_data->mux_fs, GST_STATE_NULL);
 +  gst_bin_remove ((GstBin *)pipe_data->pipeline, pipe_data->mux_fs);
 +
 +  gp = gst_ghost_pad_new ("audio_file", new_src);
 +  gst_pad_set_active(gp,TRUE);
 +  gst_element_add_pad (GST_ELEMENT (pipe_data->pipeline), gp);
 +  gst_pad_link (gp, sink);
 +  gst_object_unref (new_src);
 +  gst_object_unref (old_sink);
 +
 +  priv->stub_fs = gst_element_factory_make ("fakesink", NULL);
 +  gst_bin_add (priv->stream_bin, priv->stub_fs);
 +  gst_element_sync_state_with_parent (priv->stub_fs);
 +  fas_sink = gst_element_get_static_pad (priv->stub_fs, "sink");
 +  gst_pad_link (old_src, fas_sink);
 +  gst_object_unref (old_src);
 +  gst_object_unref (fas_sink);
 +  gst_element_set_state (GST_ELEMENT(priv->audio_srcbin), GST_STATE_PAUSED);
 +  gst_element_set_state (GST_ELEMENT(priv->video_srcbin), GST_STATE_PAUSED);
 +  gst_element_set_state (GST_ELEMENT(priv->mux), GST_STATE_PAUSED);
 +  gst_element_set_state (GST_ELEMENT(priv->mux_queue), GST_STATE_PAUSED);
 +
 +  /* signal that new pipeline linked */
 +  g_mutex_lock (&priv->direct_lock);
 +  linked = TRUE;
 +  g_cond_signal (&priv->direct_cond);
 +  g_mutex_unlock (&priv->direct_lock);
 +
 +  return GST_PAD_PROBE_REMOVE;
 +}
 +
 +static gboolean
 +_rtsp_media_factory_wfd_relink_pipeline(GstRTSPMediaFactoryWFD * factory)
 +{
 +  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
 +  GstPad *probe_pad = NULL;
 +  gint64 end_time = 0;
 +
 +  priv = factory->priv;
 +
 +  probe_pad = gst_element_get_static_pad (priv->pay, "sink");
 +  if (probe_pad == NULL)
 +    return FALSE;
 +
 +  in_pad_probe = FALSE;
 +  linked = FALSE;
 +  gst_pad_add_probe (probe_pad, GST_PAD_PROBE_TYPE_IDLE, _rtsp_media_factory_wfd_restore_pipe_probe_cb, factory, NULL);
 +
 +  g_mutex_lock (&factory->priv->direct_lock);
 +  end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND;
 +  if (!g_cond_wait_until (&factory->priv->direct_cond, &factory->priv->direct_lock, end_time)) {
 +    g_mutex_unlock (&factory->priv->direct_lock);
 +    GST_ERROR_OBJECT (factory, "Failed to relink pipeline");
 +    return linked;
 +  }
 +  g_mutex_unlock (&factory->priv->direct_lock);
 +  return linked;
 +}
 +
 +
 +static GstPadProbeReturn
 +_rtsp_media_factory_wfd_src_pad_probe_cb(GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
 +{
 +  GstRTSPMediaFactoryWFD *factory = NULL;
 +  GstEvent *event = GST_PAD_PROBE_INFO_EVENT(info);
 +
 +  factory = (GstRTSPMediaFactoryWFD *) user_data;
 +
 +  if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
 +    GST_INFO_OBJECT (factory, "Got event: %s in direct streaming", GST_EVENT_TYPE_NAME (event));
 +    info->data = NULL;
 +    info->data = gst_event_new_custom (GST_EVENT_CUSTOM_DOWNSTREAM, gst_structure_new_empty ("fillEOS"));
 +
 +    if (!_rtsp_media_factory_wfd_relink_pipeline(factory)) {
 +      GST_ERROR_OBJECT (factory, "Failed to relink pipeline");
 +      return GST_PAD_PROBE_REMOVE;
 +    }
 +
 +    g_idle_add((GSourceFunc)_rtsp_media_factory_wfd_destroy_direct_pipe, factory);
 +    return GST_PAD_PROBE_REMOVE;
 +  }
 +
 +  return GST_PAD_PROBE_OK;
 +}
 +
 +static gboolean
 +_rtsp_media_factory_wfd_create_direct_pipeline(GstRTSPMediaFactoryWFD * factory)
 +{
 +  GstElement *src = NULL;
 +  GstElement *demux = NULL;
 +  g_autofree gchar *path = NULL;
 +  g_autofree gchar *elem_name = NULL;
 +  GstPad *srcpad = NULL;
 +  GstPad *mux_vsinkpad = NULL;
 +  GstPad *mux_asinkpad = NULL;
 +  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
 +  GstRTSPMediaWFDDirectPipelineData *pipe_data = NULL;
 +
 +  priv = factory->priv;
 +  pipe_data = priv->direct_pipe;
 +
 +  pipe_data->pipeline = (GstBin *) gst_bin_new ("direct");
 +
 +  src = gst_element_factory_create(priv->res.src_fact, NULL);
 +  demux = gst_element_factory_create(priv->res.demux_fact, NULL);
 +  pipe_data->ap = gst_element_factory_make ("aacparse", NULL);
 +  pipe_data->vp = gst_element_factory_make ("h264parse", NULL);
 +  pipe_data->aq = gst_element_factory_make ("queue", NULL);
 +  pipe_data->vq = gst_element_factory_make ("queue", NULL);
 +  pipe_data->tsmux = gst_element_factory_make ("mpegtsmux", NULL);
 +  pipe_data->mux_fs = gst_element_factory_make ("fakesink", NULL);
 +
 +  if (src == NULL || demux == NULL || pipe_data->tsmux == NULL ||
 +      pipe_data->ap == NULL || pipe_data->vp == NULL ||
 +      pipe_data->aq == NULL || pipe_data->vq == NULL ||
 +      pipe_data->mux_fs == NULL) {
 +    GST_ERROR_OBJECT (factory, "Not all element created");
 +    return FALSE;
 +  }
 +
 +  elem_name = g_ascii_strdown(g_type_name(G_OBJECT_TYPE(src)), -1);
 +
 +  if (g_strrstr (elem_name, "file")) {
 +    path = g_filename_from_uri (pipe_data->uri, NULL, NULL);
 +
 +    if (path == NULL) {
 +      GST_ERROR_OBJECT(factory, "No file path");
 +      return FALSE;
 +    }
 +    g_object_set (src, "location", path, NULL);
 +  } else
 +    g_object_set (src, "uri", pipe_data->uri, NULL);
 +
 +  gst_bin_add_many (pipe_data->pipeline, src, demux, pipe_data->ap,
 +      pipe_data->vp, pipe_data->aq, pipe_data->vq,
 +      pipe_data->tsmux, pipe_data->mux_fs, NULL);
 +
 +  if (!gst_element_link (src, demux)) {
 +    GST_ERROR_OBJECT (factory, "Can't link src with demux");
 +    return FALSE;
 +  }
 +
 +  if (!gst_element_link (pipe_data->ap, pipe_data->aq)) {
 +    GST_ERROR_OBJECT (factory, "Can't link audio parse and queue");
 +    return FALSE;
 +  }
 +
 +  if (!gst_element_link (pipe_data->vp, pipe_data->vq)) {
 +    GST_ERROR_OBJECT (factory, "Can't link video parse and queue");
 +    return FALSE;
 +  }
 +
 +  if (!gst_element_link (pipe_data->tsmux, pipe_data->mux_fs)) {
 +    GST_DEBUG_OBJECT (factory, "Can't link muxer and fakesink");
 +    return FALSE;
 +  }
 +
 +  g_signal_connect_object (demux, "pad-added", G_CALLBACK (_rtsp_media_factory_wfd_demux_pad_added_cb), factory, 0);
 +
 +  gst_bin_add (priv->stream_bin, GST_ELEMENT (pipe_data->pipeline));
 +
 +
 +  /* request video sink pad from muxer, which has elementary pid 0x1011 */
 +  mux_vsinkpad = gst_element_get_request_pad (pipe_data->tsmux, "sink_4113");
 +  if (!mux_vsinkpad) {
 +    GST_ERROR_OBJECT (factory, "Failed to get sink pad from muxer...");
 +    return FALSE;
 +  }
 +
 +  /* request srcpad from video queue */
 +  srcpad = gst_element_get_static_pad (pipe_data->vq, "src");
 +  if (!srcpad) {
 +    GST_ERROR_OBJECT (factory, "Failed to get srcpad from video queue...");
 +  }
 +
 +  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...");
 +    return FALSE;
 +  }
 +
 +  gst_object_unref (mux_vsinkpad);
 +  gst_object_unref (srcpad);
 +  srcpad = NULL;
 +
 +  /* request audio sink pad from muxer, which has elementary pid 0x1100 */
 +  mux_asinkpad = gst_element_get_request_pad (pipe_data->tsmux, "sink_4352");
 +  if (!mux_asinkpad) {
 +    GST_ERROR_OBJECT (factory, "Failed to get sinkpad from muxer...");
 +    return FALSE;
 +  }
 +
 +  /* request srcpad from audio queue */
 +  srcpad = gst_element_get_static_pad (pipe_data->aq, "src");
 +  if (!srcpad) {
 +    GST_ERROR_OBJECT (factory, "Failed to get srcpad from audio queue...");
 +    return FALSE;
 +  }
 +
 +  /* 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...");
 +    return FALSE;
 +  }
 +  gst_object_unref (mux_asinkpad);
 +  gst_object_unref (srcpad);
 +  srcpad = NULL;
 +
 +  gst_element_sync_state_with_parent (GST_ELEMENT (pipe_data->pipeline));
 +
 +  srcpad = gst_element_get_static_pad (priv->pay, "sink");
 +
 +  in_pad_probe = FALSE;
 +  gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_IDLE, _rtsp_media_factory_wfd_pay_pad_probe_cb, factory, NULL);
 +  gst_pad_add_probe (srcpad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, _rtsp_media_factory_wfd_src_pad_probe_cb, factory, NULL);
 +
 +  return TRUE;
 +}
 +
 +static void
 +_rtsp_media_factory_wfd_decodebin_element_added_cb (GstElement *decodebin,
 +        GstElement *child, void *user_data)
 +{
 +  g_autofree gchar *elem_name = g_ascii_strdown(g_type_name(G_OBJECT_TYPE(child)), -1);
 +  GstRTSPMediaFactoryWFD *factory = NULL;
 +  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
 +
 +  factory = (GstRTSPMediaFactoryWFD *) user_data;
 +  priv = factory->priv;
 +
 +  if (g_strrstr (elem_name, "h264"))
 +    priv->res.h264_found++;
 +  if (g_strrstr (elem_name, "aac"))
 +    priv->res.aac_found++;
 +  if (g_strrstr (elem_name, "ac3"))
 +    priv->res.ac3_found++;
 +  if (g_strrstr (elem_name, "demux"))
 +    priv->res.demux_fact = gst_element_get_factory(child);
 +}
 +
 +static void
 +_rtsp_media_factory_wfd_uridecodebin_element_added_cb (GstElement *uridecodebin,
 +        GstElement *child, void *user_data)
 +{
 +  g_autofree gchar *elem_name = g_ascii_strdown(g_type_name(G_OBJECT_TYPE(child)), -1);
 +  GstRTSPMediaFactoryWFD *factory = NULL;
 +  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
 +
 +  factory = (GstRTSPMediaFactoryWFD *) user_data;
 +  priv = factory->priv;
 +
 +  if (g_strrstr (elem_name, "src"))
 +    priv->res.src_fact = gst_element_get_factory(child);
 +
 +  if (G_OBJECT_TYPE(child) == priv->decodebin_type)
 +    g_signal_connect_object (child, "element-added",
 +        G_CALLBACK (_rtsp_media_factory_wfd_decodebin_element_added_cb), factory, 0);
 +}
 +
 +static void
 +_rtsp_media_factory_wfd_discover_pad_added_cb (GstElement *uridecodebin, GstPad *pad,
 +    GstBin *pipeline)
 +{
 +  GstPad *sinkpad = NULL;
 +  GstCaps *caps;
 +
 +  GstElement *queue = gst_element_factory_make ("queue", NULL);
 +  GstElement *sink = gst_element_factory_make ("fakesink", NULL);
 +
 +  if (G_UNLIKELY (queue == NULL || sink == NULL))
 +    goto error;
 +
 +  g_object_set (sink, "silent", TRUE, NULL);
 +  g_object_set (queue, "max-size-buffers", 1, "silent", TRUE, NULL);
 +
 +  caps = gst_pad_query_caps (pad, NULL);
 +
 +  sinkpad = gst_element_get_static_pad (queue, "sink");
 +  if (sinkpad == NULL)
 +    goto error;
 +
 +  gst_caps_unref (caps);
 +
 +  gst_bin_add_many (pipeline, queue, sink, NULL);
 +
 +  if (!gst_element_link_pads_full (queue, "src", sink, "sink",
 +          GST_PAD_LINK_CHECK_NOTHING))
 +    goto error;
 +  if (!gst_element_sync_state_with_parent (sink))
 +    goto error;
 +  if (!gst_element_sync_state_with_parent (queue))
 +    goto error;
 +
 +  if (gst_pad_link_full (pad, sinkpad,
 +          GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK)
 +    goto error;
 +  gst_object_unref (sinkpad);
 +
 +  return;
 +
 +error:
 +  if (sinkpad)
 +    gst_object_unref (sinkpad);
 +  if (queue)
 +    gst_object_unref (queue);
 +  if (sink)
 +    gst_object_unref (sink);
 +  return;
 +}
 +
 +static void
 +_rtsp_media_factory_wfd_uridecode_no_pad_cb (GstElement * uridecodebin, void * user_data)
 +{
 +  GstRTSPMediaFactoryWFD *factory = NULL;
 +  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
 +
 +  factory = (GstRTSPMediaFactoryWFD *) user_data;
 +  priv = factory->priv;
 +  type_detected = TRUE;
 +  g_main_loop_quit (priv->discover_loop);
 +}
 +
 +static void
 +_rtsp_media_factory_wfd_discover_pipe_bus_call (GstBus *bus,
 +          GstMessage *msg,
 +          gpointer data)
 +{
 +  GstRTSPMediaFactoryWFD *factory = NULL;
 +  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
 +
 +  factory = (GstRTSPMediaFactoryWFD *) data;
 +  priv = factory->priv;
 +
 +  switch (GST_MESSAGE_TYPE (msg)) {
 +    case GST_MESSAGE_ERROR: {
 +      GError *error = NULL;
 +
 +      gst_message_parse_error (msg, &error, NULL);
 +
 +      GST_ERROR_OBJECT (factory, "Error: %s", error->message);
 +      g_error_free (error);
 +
 +      type_detected = FALSE;
 +      g_main_loop_quit (priv->discover_loop);
 +      break;
 +    }
 +    default:
 +      break;
 +  }
 +}
 +
 +static gboolean
 +_rtsp_media_factory_wfd_find_media_type (GstRTSPMediaFactoryWFD * factory, gchar *uri)
 +{
 +  GstRTSPMediaFactoryWFDPrivate *priv = NULL;
 +  GstElement *uridecode = NULL;
 +  GstElement *tmp = NULL;
 +  GstBus *bus;
 +  GMainContext *context;
 +  GSource *source;
 +
 +  priv = factory->priv;
 +
 +  context = g_main_context_new();
 +  priv->discover_loop = g_main_loop_new(context, FALSE);
 +
 +  tmp = gst_element_factory_make ("decodebin", NULL);
 +  priv->decodebin_type = G_OBJECT_TYPE (tmp);
 +  gst_object_unref (tmp);
 +
 +  /* if a URI was provided, use it instead of the default one */
 +  priv->discover_pipeline = (GstBin *) gst_pipeline_new ("Discover");
 +  uridecode = gst_element_factory_make("uridecodebin", "uri");
 +  g_object_set (G_OBJECT (uridecode), "uri", uri, NULL);
 +  gst_bin_add (priv->discover_pipeline, uridecode);
 +  if (priv->decodebin_type == NULL || priv->discover_pipeline == NULL || uridecode == NULL) {
 +    GST_INFO_OBJECT (factory, "Failed to create type find pipeline");
 +    type_detected = FALSE;
 +    return FALSE;
 +  }
 +
 +  /* we add a message handler */
 +  bus = gst_pipeline_get_bus (GST_PIPELINE (priv->discover_pipeline));
 +  source = gst_bus_create_watch (bus);
 +  gst_bus_add_signal_watch (bus);
 +
 +  g_source_set_callback (source, (GSourceFunc) gst_bus_async_signal_func, NULL, NULL);
 +  g_source_attach (source, context);
 +  g_signal_connect_object (bus, "message",
 +      G_CALLBACK (_rtsp_media_factory_wfd_discover_pipe_bus_call), factory, 0);
 +
 +  g_signal_connect_object (uridecode, "pad-added",
 +      G_CALLBACK (_rtsp_media_factory_wfd_discover_pad_added_cb), priv->discover_pipeline, 0);
 +  g_signal_connect_object (uridecode, "element-added",
 +            G_CALLBACK (_rtsp_media_factory_wfd_uridecodebin_element_added_cb),
 +            factory, 0);
 +  g_signal_connect_object (uridecode, "no-more-pads",
 +            G_CALLBACK (_rtsp_media_factory_wfd_uridecode_no_pad_cb), factory, 0);
 +  gst_element_set_state (GST_ELEMENT (priv->discover_pipeline), GST_STATE_PLAYING);
 +
 +  g_main_loop_run(priv->discover_loop);
 +
 +  gst_element_set_state (GST_ELEMENT (priv->discover_pipeline), GST_STATE_NULL);
 +  g_source_destroy(source);
 +  g_source_unref (source);
 +  g_main_loop_unref(priv->discover_loop);
 +  g_main_context_unref(context);
 +  gst_object_unref(bus);
 +  gst_object_unref (GST_OBJECT (priv->discover_pipeline));
 +
 +  return TRUE;
 +}
 +
 +gint
 +gst_rtsp_media_factory_wfd_uri_type_find(GstRTSPMediaFactory *factory,
 +    gchar *filesrc, guint8 *detected_video_codec, guint8 *detected_audio_codec)
 +{
 +  GstRTSPMediaFactoryWFD *_factory = GST_RTSP_MEDIA_FACTORY_WFD_CAST (factory);
 +  GstRTSPMediaFactoryWFDPrivate *priv = _factory->priv;
 +
 +  type_detected = FALSE;
 +
 +  _rtsp_media_factory_wfd_find_media_type (_factory, filesrc);
 +
 +  if (type_detected == FALSE) {
 +    GST_ERROR_OBJECT (_factory, "Media type cannot be detected");
 +    return GST_RTSP_ERROR;
 +  }
 +  GST_INFO_OBJECT (_factory, "Media type detected");
 +
 +  if (priv->res.h264_found)
 +    *detected_video_codec = GST_WFD_VIDEO_H264;
 +
 +  if (priv->res.aac_found)
 +    *detected_audio_codec = GST_WFD_AUDIO_AAC;
 +
 +  if (priv->res.ac3_found)
 +    *detected_audio_codec = GST_WFD_AUDIO_AC3;
 +
 +  return GST_RTSP_OK;
 +}
 +
 +gint
 +gst_rtsp_media_factory_wfd_set_direct_streaming(GstRTSPMediaFactory * factory,
 +    gint direct_streaming, gchar *filesrc)
 +{
 +  GstRTSPMediaFactoryWFD *_factory = GST_RTSP_MEDIA_FACTORY_WFD_CAST (factory);
 +  linked = FALSE;
 +
 +  if (direct_streaming == 0) {
 +    if (!_rtsp_media_factory_wfd_relink_pipeline(_factory)) {
 +      GST_ERROR_OBJECT (factory, "Failed to relink pipeline");
 +      return GST_RTSP_ERROR;
 +    }
 +
 +    _rtsp_media_factory_wfd_destroy_direct_pipe ((void *)_factory);
 +
 +    GST_INFO_OBJECT (_factory, "Direct streaming bin removed");
 +
 +    return GST_RTSP_OK;
 +  }
 +
 +  _factory->priv->direct_pipe = g_new0 (GstRTSPMediaWFDDirectPipelineData, 1);
 +  _factory->priv->direct_pipe->uri = g_strdup(filesrc);
 +
 +  if (!_rtsp_media_factory_wfd_create_direct_pipeline(_factory)) {
 +    GST_ERROR_OBJECT (_factory, "Direct pipeline creation failed");
 +    return GST_RTSP_ERROR;
 +  }
 +
 +  g_mutex_lock (&_factory->priv->direct_lock);
 +  while (linked != TRUE) {
 +    gint64 end_time = g_get_monotonic_time () + 5 * G_TIME_SPAN_SECOND;
 +    if (!g_cond_wait_until (&_factory->priv->direct_cond, &_factory->priv->direct_lock, end_time)) {
 +      g_mutex_unlock (&_factory->priv->direct_lock);
 +      GST_ERROR_OBJECT (_factory, "Direct pipeline linking failed");
 +      return GST_RTSP_ERROR;
 +    }
 +  }
 +  g_mutex_unlock (&_factory->priv->direct_lock);
 +
 +  GST_INFO_OBJECT (_factory, "Direct streaming bin created");
 +
 +  return GST_RTSP_OK;
 +}
index 0690908,0000000..0690908
mode 100644,000000..100644
--- /dev/null
@@@ -1,175 -1,0 +1,175 @@@
 +/* 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);
 +  void (*direct_stream_end) (GstRTSPMediaFactoryWFD * factory);
 +
 +  /*< private > */
 +  gpointer _gst_reserved[GST_PADDING_LARGE];
 +};
 +
 +GST_RTSP_SERVER_API
 +GType gst_rtsp_media_factory_wfd_get_type (void);
 +
 +/* creating the factory */
 +GST_RTSP_SERVER_API
 +GstRTSPMediaFactoryWFD *gst_rtsp_media_factory_wfd_new (void);
 +
 +GST_RTSP_SERVER_API
 +GstElement *gst_rtsp_media_factory_wfd_create_element (GstRTSPMediaFactoryWFD *
 +    factory, const GstRTSPUrl * url);
 +
 +
 +GST_RTSP_SERVER_API
 +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);
 +
 +GST_RTSP_SERVER_API
 +void  gst_rtsp_media_factory_wfd_set_encoders (GstRTSPMediaFactoryWFD * factory,
 +    gchar *video_encoder, gchar *audio_encoder_aac, gchar *audio_encoder_ac3);
 +
 +GST_RTSP_SERVER_API
 +void  gst_rtsp_media_factory_wfd_set_dump_ts (GstRTSPMediaFactoryWFD * factory,
 +    gboolean dump_ts);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_media_factory_wfd_set_negotiated_resolution (GstRTSPMediaFactory *factory,
 +   guint32 width, guint32 height);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_media_factory_wfd_set_audio_codec (GstRTSPMediaFactory *factory,
 +    guint audio_codec);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_media_factory_wfd_set_video_codec (GstRTSPMediaFactory * factory,
 +    guint video_codec);
 +
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_media_factory_wfd_set_venc_bitrate (GstRTSPMediaFactory *factory,
 +    gint bitrate);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_media_factory_wfd_get_venc_bitrate (GstRTSPMediaFactory *factory,
 +    gint *bitrate);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_media_factory_wfd_get_config_bitrate (GstRTSPMediaFactory *factory,
 +    guint32 *min, guint32 *max);
 +
 +GST_RTSP_SERVER_API
 +void gst_rtsp_media_factory_wfd_set_config_bitrate (GstRTSPMediaFactoryWFD *factory,
 +    guint *config_bitrate);
 +
 +GST_RTSP_SERVER_API
 +gint gst_rtsp_media_factory_wfd_uri_type_find(GstRTSPMediaFactory *factory,
 +    gchar *filesrc, guint8 *detected_video_codec, guint8 *detected_audio_codec);
 +
 +GST_RTSP_SERVER_API
 +gint gst_rtsp_media_factory_wfd_set_direct_streaming(GstRTSPMediaFactory *factory,
 +    gint direct_streaming, gchar *filesrc);
 +
 +G_END_DECLS
 +#endif /* __GST_RTSP_MEDIA_FACTORY_WFD_H__ */
@@@ -217,8 -217,6 +217,8 @@@ enu
    SIGNAL_UNPREPARED,
    SIGNAL_TARGET_STATE,
    SIGNAL_NEW_STATE,
 +  SIGNAL_PREPARING,
 +  SIGNAL_UNPREPARING,
    SIGNAL_LAST
  };
  
@@@ -235,7 -233,6 +235,7 @@@ static gboolean default_handle_message 
      GstMessage * message);
  static void finish_unprepare (GstRTSPMedia * media);
  static gboolean default_prepare (GstRTSPMedia * media, GstRTSPThread * thread);
 +static gboolean default_start_preroll (GstRTSPMedia * media);
  static gboolean default_unprepare (GstRTSPMedia * media);
  static gboolean default_suspend (GstRTSPMedia * media);
  static gboolean default_unsuspend (GstRTSPMedia * media);
@@@ -248,7 -245,6 +248,7 @@@ static GstElement *default_create_rtpbi
  static gboolean default_setup_sdp (GstRTSPMedia * media, GstSDPMessage * sdp,
      GstSDPInfo * info);
  static gboolean default_handle_sdp (GstRTSPMedia * media, GstSDPMessage * sdp);
 +static gboolean default_start_prepare (GstRTSPMedia * media);
  
  static gboolean wait_preroll (GstRTSPMedia * media);
  
@@@ -455,23 -451,10 +455,23 @@@ gst_rtsp_media_class_init (GstRTSPMedia
        G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL, NULL,
        G_TYPE_NONE, 1, G_TYPE_INT);
  
 +  gst_rtsp_media_signals[SIGNAL_PREPARING] =
 +      g_signal_new ("preparing", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
 +      G_STRUCT_OFFSET (GstRTSPMediaClass, preparing), NULL, NULL,
 +      g_cclosure_marshal_generic, G_TYPE_NONE, 2, GST_TYPE_RTSP_STREAM,
 +      G_TYPE_UINT);
 +
 +  gst_rtsp_media_signals[SIGNAL_UNPREPARING] =
 +      g_signal_new ("unpreparing", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
 +      G_STRUCT_OFFSET (GstRTSPMediaClass, unpreparing), NULL, NULL,
 +      g_cclosure_marshal_generic, G_TYPE_NONE, 2, GST_TYPE_RTSP_STREAM,
 +      G_TYPE_UINT);
 +
    GST_DEBUG_CATEGORY_INIT (rtsp_media_debug, "rtspmedia", 0, "GstRTSPMedia");
  
    klass->handle_message = default_handle_message;
    klass->prepare = default_prepare;
 +  klass->start_preroll = default_start_preroll;
    klass->unprepare = default_unprepare;
    klass->suspend = default_suspend;
    klass->unsuspend = default_unsuspend;
    klass->create_rtpbin = default_create_rtpbin;
    klass->setup_sdp = default_setup_sdp;
    klass->handle_sdp = default_handle_sdp;
 +  klass->start_prepare = default_start_prepare;
  }
  
  static void
@@@ -2799,7 -2781,7 +2799,7 @@@ media_streams_set_blocked (GstRTSPMedi
      priv->blocking_msg_received = 0;
  }
  
 -static void
 +void
  gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status)
  {
    GstRTSPMediaPrivate *priv = media->priv;
@@@ -3157,20 -3139,11 +3157,20 @@@ set_state (GstRTSPMedia * media, GstSta
        media);
    ret = gst_element_set_state (priv->pipeline, state);
  
 +  {
 +    gchar *filename = NULL;
 +    filename = g_strdup_printf ("media_%s", gst_element_state_get_name (state));
 +    GST_DEBUG_BIN_TO_DOT_FILE (GST_BIN (priv->pipeline),
 +        GST_DEBUG_GRAPH_SHOW_ALL, filename);
 +
 +    g_free (filename);
 +  }
 +
    return ret;
  }
  
 -static GstStateChangeReturn
 -set_target_state (GstRTSPMedia * media, GstState state, gboolean do_state)
 +GstStateChangeReturn
 +gst_rtsp_media_set_target_state (GstRTSPMedia * media, GstState state, gboolean do_state)
  {
    GstRTSPMediaPrivate *priv = media->priv;
    GstStateChangeReturn ret;
@@@ -3559,7 -3532,7 +3559,7 @@@ struct _DynPaySignalHandler
  };
  
  static gboolean
 -start_preroll (GstRTSPMedia * media)
 +default_start_preroll (GstRTSPMedia * media)
  {
    GstRTSPMediaPrivate *priv = media->priv;
    GstStateChangeReturn ret;
  
    /* start blocked since it is possible that there are no sink elements yet */
    media_streams_set_blocked (media, TRUE);
 -  ret = set_target_state (media, GST_STATE_PAUSED, TRUE);
 +  ret = gst_rtsp_media_set_target_state (media, GST_STATE_PAUSED, TRUE);
  
    switch (ret) {
      case GST_STATE_CHANGE_SUCCESS:
@@@ -3700,10 -3673,9 +3700,10 @@@ request_fec_decoder (GstElement * rtpbi
  }
  
  static gboolean
 -start_prepare (GstRTSPMedia * media)
 +default_start_prepare (GstRTSPMedia * media)
  {
    GstRTSPMediaPrivate *priv = media->priv;
 +  GstRTSPMediaClass *klass;
    guint i;
    GList *walk;
  
    g_signal_connect (priv->rtpbin, "request-fec-decoder",
        G_CALLBACK (request_fec_decoder), media);
  
 +  klass = GST_RTSP_MEDIA_GET_CLASS (media);
 +
    /* link streams we already have, other streams might appear when we have
     * dynamic elements */
    for (i = 0; i < priv->streams->len; i++) {
              priv->rtpbin, GST_STATE_NULL)) {
        goto join_bin_failed;
      }
 +
 +    g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_PREPARING], 0, stream,
 +        i, NULL);
    }
  
    if (priv->rtpbin)
       * a second ASYNC state change failing */
      priv->is_live = TRUE;
      gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARED);
 -  } else if (!start_preroll (media)) {
 +  } else if (!klass->start_preroll (media)) {
      goto preroll_failed;
    }
  
@@@ -3850,9 -3817,8 +3850,9 @@@ default_prepare (GstRTSPMedia * media, 
  
    /* do remainder in context */
    source = g_idle_source_new ();
 -  g_source_set_callback (source, (GSourceFunc) start_prepare,
 -      g_object_ref (media), (GDestroyNotify) g_object_unref);
 +  if (klass->start_prepare)
 +    g_source_set_callback (source, (GSourceFunc) klass->start_prepare,
 +        g_object_ref (media), (GDestroyNotify) g_object_unref);
    g_source_attach (source, context);
    g_source_unref (source);
  
@@@ -4031,9 -3997,6 +4031,9 @@@ finish_unprepare (GstRTSPMedia * media
      stream = g_ptr_array_index (priv->streams, i);
  
      gst_rtsp_stream_leave_bin (stream, GST_BIN (priv->pipeline), priv->rtpbin);
 +
 +    g_signal_emit (media, gst_rtsp_media_signals[SIGNAL_UNPREPARING], 0, stream,
 +        i, NULL);
    }
  
    /* remove the pad signal handlers */
@@@ -4140,7 -4103,7 +4140,7 @@@ gst_rtsp_media_unprepare (GstRTSPMedia 
      goto is_busy;
  
    GST_INFO ("unprepare media %p", media);
 -  set_target_state (media, GST_STATE_NULL, FALSE);
 +  gst_rtsp_media_set_target_state (media, GST_STATE_NULL, FALSE);
    success = TRUE;
  
    if (priv->status == GST_RTSP_MEDIA_STATUS_PREPARED) {
@@@ -4553,13 -4516,13 +4553,13 @@@ default_suspend (GstRTSPMedia * media
        break;
      case GST_RTSP_SUSPEND_MODE_PAUSE:
        GST_DEBUG ("media %p suspend to PAUSED", media);
 -      ret = set_target_state (media, GST_STATE_PAUSED, TRUE);
 +      ret = gst_rtsp_media_set_target_state (media, GST_STATE_PAUSED, TRUE);
        if (ret == GST_STATE_CHANGE_FAILURE)
          goto state_failed;
        break;
      case GST_RTSP_SUSPEND_MODE_RESET:
        GST_DEBUG ("media %p suspend to NULL", media);
 -      ret = set_target_state (media, GST_STATE_NULL, TRUE);
 +      ret = gst_rtsp_media_set_target_state (media, GST_STATE_NULL, TRUE);
        if (ret == GST_STATE_CHANGE_FAILURE)
          goto state_failed;
        /* Because payloader needs to set the sequence number as
@@@ -4666,9 -4629,6 +4666,9 @@@ default_unsuspend (GstRTSPMedia * media
  {
    GstRTSPMediaPrivate *priv = media->priv;
    gboolean preroll_ok;
 +  GstRTSPMediaClass *klass;
 +
 +  klass = GST_RTSP_MEDIA_GET_CLASS (media);
  
    switch (priv->suspend_mode) {
      case GST_RTSP_SUSPEND_MODE_NONE:
         * specific transport parts: all active streams contain at least one sink
         * element and it's safe to unblock all blocked streams */
        media_streams_set_blocked (media, FALSE);
 -      if (!start_preroll (media))
 -        goto start_failed;
 +       if (klass->start_preroll)
 +        if (!klass->start_preroll (media))
 +          goto start_failed;
  
        g_rec_mutex_unlock (&priv->state_lock);
        preroll_ok = wait_preroll (media);
@@@ -4794,7 -4753,7 +4794,7 @@@ media_set_pipeline_state_locked (GstRTS
      gst_rtsp_media_unprepare (media);
    } else {
      GST_INFO ("state %s media %p", gst_element_state_get_name (state), media);
 -    set_target_state (media, state, FALSE);
 +    gst_rtsp_media_set_target_state (media, state, FALSE);
  
      if (state == GST_STATE_PLAYING) {
        /* make sure pads are not blocking anymore when going to PLAYING */
@@@ -5234,36 -5193,3 +5234,36 @@@ gst_rtsp_media_get_rate_control (GstRTS
  
    return res;
  }
 +
 +GstElement *
 +gst_rtsp_media_get_pipeline (GstRTSPMedia * media)
 +{
 +  GstRTSPMediaPrivate *priv;
 +
 +  g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
 +
 +  priv = media->priv;
 +
 +  g_mutex_lock (&priv->lock);
 +  g_object_ref (priv->pipeline);
 +  g_mutex_unlock (&priv->lock);
 +
 +  return priv->pipeline;
 +}
 +
 +
 +GstElement *
 +gst_rtsp_media_get_rtpbin (GstRTSPMedia * media)
 +{
 +  GstRTSPMediaPrivate *priv;
 +
 +  g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
 +
 +  priv = media->priv;
 +
 +  g_mutex_lock (&priv->lock);
 +  g_object_ref (priv->rtpbin);
 +  g_mutex_unlock (&priv->lock);
 +
 +  return priv->rtpbin;
 +}
@@@ -164,7 -164,6 +164,7 @@@ struct _GstRTSPMediaClass 
    /* vmethods */
    gboolean        (*handle_message)  (GstRTSPMedia *media, GstMessage *message);
    gboolean        (*prepare)         (GstRTSPMedia *media, GstRTSPThread *thread);
 +  gboolean        (*start_preroll)   (GstRTSPMedia *media);
    gboolean        (*unprepare)       (GstRTSPMedia *media);
    gboolean        (*suspend)         (GstRTSPMedia *media);
    gboolean        (*unsuspend)       (GstRTSPMedia *media);
    GstElement *    (*create_rtpbin)   (GstRTSPMedia *media);
    gboolean        (*setup_rtpbin)    (GstRTSPMedia *media, GstElement *rtpbin);
    gboolean        (*setup_sdp)       (GstRTSPMedia *media, GstSDPMessage *sdp, GstSDPInfo *info);
 +  gboolean        (*start_prepare)   (GstRTSPMedia *media);
  
    /* signals */
    void            (*new_stream)      (GstRTSPMedia *media, GstRTSPStream * stream);
  
    gboolean        (*handle_sdp)      (GstRTSPMedia *media, GstSDPMessage *sdp);
  
 +  void            (*preparing)       (GstRTSPMedia *media, GstRTSPStream * stream, guint idx);
 +  void            (*unpreparing)     (GstRTSPMedia *media, GstRTSPStream * stream, guint idx);
    /*< private >*/
    gpointer         _gst_reserved[GST_PADDING_LARGE-1];
  };
@@@ -430,18 -426,6 +430,18 @@@ void                  gst_rtsp_media_se
                                                           GstState state);
  
  GST_RTSP_SERVER_API
 +GstStateChangeReturn  gst_rtsp_media_set_target_state (GstRTSPMedia * media, GstState state, gboolean do_state);
 +
 +GST_RTSP_SERVER_API
 +void                  gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status);
 +
 +GST_RTSP_SERVER_API
 +GstElement *          gst_rtsp_media_get_pipeline     (GstRTSPMedia * media);
 +
 +GST_RTSP_SERVER_API
 +GstElement *          gst_rtsp_media_get_rtpbin       (GstRTSPMedia * media);
 +
 +GST_RTSP_SERVER_API
  gboolean              gst_rtsp_media_complete_pipeline (GstRTSPMedia * media, GPtrArray * transports);
  
  GST_RTSP_SERVER_API
@@@ -85,7 -85,6 +85,7 @@@ struct _GstRTSPServerClass 
    GObjectClass  parent_class;
  
    GstRTSPClient * (*create_client)      (GstRTSPServer *server);
 +  GSocket * (*create_socket)      (GstRTSPServer * server,  GCancellable * cancellable, GError ** error);
  
    /* signals */
    void            (*client_connected)   (GstRTSPServer *server, GstRTSPClient *client);
index 6e03395,0000000..6e03395
mode 100644,000000..100644
--- /dev/null
@@@ -1,495 -1,0 +1,495 @@@
 +/* 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)
 + */
 +
 +#ifdef HAVE_CONFIG_H
 +#include "config.h"
 +#endif
 +
 +#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;
 +  guint8 video_codec;
 +  gint wfd2_supported;
 +  gboolean coupling_mode;
 +};
 +
 +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;
 +  server->priv->coupling_mode = FALSE;
 +  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)
 +{
 +  gchar *server_addr = NULL;
 +  GST_INFO_OBJECT (server, "Client is connected");
 +
 +  server_addr = gst_rtsp_server_get_address (server);
 +  gst_rtsp_wfd_client_set_host_address (GST_RTSP_WFD_CLIENT_CAST (client),
 +      server_addr);
 +  g_free (server_addr);
 +  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_client_set_video_codec (client, priv->video_codec);
 +
 +  gst_rtsp_wfd_client_set_coupling_mode (client, priv->coupling_mode);
 +
 +  /* enable or disable R2 features following ini */
 +  gst_rtsp_wfd_client_set_wfd2_supported (client, priv->wfd2_supported);
 +
 +  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_video_codec (GstRTSPWFDServer * server,
 +    guint8 video_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->video_codec = video_codec;
 +
 +  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;
 +}
 +
 +GstRTSPResult
 +gst_rtsp_wfd_server_set_direct_streaming (GstRTSPWFDServer *server,
 +    gint direct_streaming, gchar *urisrc)
 +{
 +  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 (GST_RTSP_SERVER(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_set_direct_streaming (GST_RTSP_WFD_CLIENT (client),
 +        direct_streaming, urisrc);
 +    if (res != GST_RTSP_OK) {
 +      GST_ERROR_OBJECT (server, "Failed to set direct streaming to %d", direct_streaming);
 +    }
 +    g_object_unref (client);
 +  }
 +
 +  return res;
 +}
 +
 +
 +GstRTSPResult
 +gst_rtsp_wfd_server_set_coupling_mode (GstRTSPWFDServer * server,
 +    gboolean coupling_mode)
 +{
 +  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->coupling_mode = coupling_mode;
 +  GST_RTSP_WFD_SERVER_UNLOCK (server);
 +  return res;
 +}
 +
 +GstRTSPResult
 +gst_rtsp_wfd_server_switch_to_udp (GstRTSPWFDServer *server)
 +{
 +  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 (GST_RTSP_SERVER(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_switch_to_udp (GST_RTSP_WFD_CLIENT (client));
 +    if (res != GST_RTSP_OK) {
 +      GST_ERROR_OBJECT (server, "Failed to switch transport to UDP");
 +    }
 +    g_object_unref (client);
 +  }
 +
 +  return res;
 +}
 +
 +GstRTSPResult
 +gst_rtsp_wfd_server_switch_to_tcp (GstRTSPWFDServer *server)
 +{
 +  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 (GST_RTSP_SERVER(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_switch_to_tcp (GST_RTSP_WFD_CLIENT (client));
 +    if (res != GST_RTSP_OK) {
 +      GST_ERROR_OBJECT (server, "Failed to switch transport to TCP");
 +    }
 +    g_object_unref (client);
 +  }
 +
 +  return res;
 +}
 +
 +GstRTSPResult
 +gst_rtsp_wfd_server_set_wfd2_supported (GstRTSPWFDServer *server,
 +    guint flag)
 +{
 +  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->wfd2_supported = flag;
 +
 +  GST_RTSP_WFD_SERVER_UNLOCK (server);
 +  return res;
 +}
index ea2d319,0000000..ea2d319
mode 100644,000000..100644
--- /dev/null
@@@ -1,186 -1,0 +1,186 @@@
 +/* 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>
 +
 +#include "rtsp-server-prelude.h"
 +#include "rtsp-session-pool.h"
 +#include "rtsp-mount-points.h"
 +#include "rtsp-server.h"
 +#include "rtsp-client-wfd.h"
 +#include "rtsp-auth.h"
 +
 +G_BEGIN_DECLS
 +
 +typedef struct _GstRTSPWFDServer GstRTSPWFDServer;
 +typedef struct _GstRTSPWFDServerClass GstRTSPWFDServerClass;
 +typedef struct _GstRTSPWFDServerPrivate GstRTSPWFDServerPrivate;
 +
 +#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];
 +};
 +
 +GST_RTSP_SERVER_API
 +GType                 gst_rtsp_wfd_server_get_type            (void);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPWFDServer *    gst_rtsp_wfd_server_new                  (void);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_server_trigger_request      (GstRTSPServer *server, GstWFDTriggerType type);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_server_set_supported_reso (GstRTSPWFDServer *server, guint64 supported_reso);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_server_set_video_native_reso    (GstRTSPWFDServer *server, guint64 native_reso);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_server_set_video_codec    (GstRTSPWFDServer *server, guint8 video_codec);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_server_set_audio_codec    (GstRTSPWFDServer *server, guint8 audio_codec);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_server_set_direct_streaming (GstRTSPWFDServer *server, gint direct_streaming, gchar *urisrc);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_server_set_coupling_mode (GstRTSPWFDServer *server, gboolean coupling_mode);
 +
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_server_switch_to_udp (GstRTSPWFDServer *server);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_server_switch_to_tcp (GstRTSPWFDServer *server);
 +
 +GST_RTSP_SERVER_API
 +GstRTSPResult         gst_rtsp_wfd_server_set_wfd2_supported (GstRTSPWFDServer *server, guint flag);
 +
 +
 +#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__ */
@@@ -246,7 -246,6 +246,7 @@@ gst_rtsp_server_class_init (GstRTSPServ
        NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_RTSP_CLIENT);
  
    klass->create_client = default_create_client;
 +  klass->create_socket = gst_rtsp_server_create_socket;
  
    GST_DEBUG_CATEGORY_INIT (rtsp_server_debug, "rtspserver", 0, "GstRTSPServer");
  }
@@@ -1339,18 -1338,14 +1339,18 @@@ gst_rtsp_server_create_source (GstRTSPS
      GCancellable * cancellable, GError ** error)
  {
    GstRTSPServerPrivate *priv;
 -  GSocket *socket, *old;
 +  GstRTSPServerClass *klass;
 +  GSocket *socket = NULL, *old;
    GSource *source;
  
    g_return_val_if_fail (GST_IS_RTSP_SERVER (server), NULL);
  
    priv = server->priv;
 +  klass = GST_RTSP_SERVER_GET_CLASS (server);
 +
 +  if (klass->create_socket)
 +    socket = klass->create_socket (server, NULL, error);
  
 -  socket = gst_rtsp_server_create_socket (server, NULL, error);
    if (socket == NULL)
      goto no_socket;
  
@@@ -255,7 -255,6 +255,7 @@@ enu
    SIGNAL_NEW_RTP_ENCODER,
    SIGNAL_NEW_RTCP_ENCODER,
    SIGNAL_NEW_RTP_RTCP_DECODER,
 +  SIGNAL_RTCP_STATS,
    SIGNAL_LAST
  };
  
@@@ -317,11 -316,6 +317,11 @@@ gst_rtsp_stream_class_init (GstRTSPStre
        g_signal_new ("new-rtp-rtcp-decoder", G_TYPE_FROM_CLASS (klass),
        G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
  
 +  gst_rtsp_stream_signals[SIGNAL_RTCP_STATS] =
 +      g_signal_new ("rtcp-statistics", G_TYPE_FROM_CLASS (klass),
 +      G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic,
 +      G_TYPE_NONE, 1, GST_TYPE_STRUCTURE);
 +
    GST_DEBUG_CATEGORY_INIT (rtsp_stream_debug, "rtspstream", 0, "GstRTSPStream");
  
    ssrc_stream_map_key = g_quark_from_static_string ("GstRTSPServer.stream");
@@@ -2424,9 -2418,6 +2424,9 @@@ check_transport (GObject * source, GstR
  
        dump_structure (stats);
  
 +      g_signal_emit (stream, gst_rtsp_stream_signals[SIGNAL_RTCP_STATS], 0,
 +          stats);
 +
        rtcp_from = gst_structure_get_string (stats, "rtcp-from");
        if ((trans = find_transport (stream, rtcp_from))) {
          GST_INFO ("%p: found transport %p for source  %p", stream, trans,
@@@ -2476,9 -2467,6 +2476,9 @@@ on_ssrc_active (GObject * session, GObj
      GstStructure *stats;
      g_object_get (source, "stats", &stats, NULL);
      if (stats) {
 +      g_signal_emit (stream, gst_rtsp_stream_signals[SIGNAL_RTCP_STATS], 0,
 +          stats);
 +
        dump_structure (stats);
        gst_structure_free (stats);
      }
@@@ -5216,21 -5204,6 +5216,21 @@@ gst_rtsp_stream_get_current_seqnum (Gst
    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
@@@ -270,9 -270,6 +270,9 @@@ GST_RTSP_SERVER_AP
  guint16           gst_rtsp_stream_get_current_seqnum          (GstRTSPStream *stream);
  
  GST_RTSP_SERVER_API
 +guint64           gst_rtsp_stream_get_udp_sent_bytes          (GstRTSPStream *stream);
 +
 +GST_RTSP_SERVER_API
  void              gst_rtsp_stream_set_retransmission_time     (GstRTSPStream *stream, GstClockTime time);
  
  GST_RTSP_SERVER_API
@@@ -4449,10 -4449,8 +4449,10 @@@ gst_rtsp_client_sink_record (GstRTSPCli
    /* session ID doesn't have to be super-unique in this case */
    sess_id = g_strdup_printf ("%u", g_random_int ());
  
 -  if (sink->conninfo.connection == NULL)
 +  if (sink->conninfo.connection == NULL) {
 +    g_free (sess_id);
      return GST_RTSP_ERROR;
 +  }
  
    conn_socket = gst_rtsp_connection_get_read_socket (sink->conninfo.connection);