Add AL-FEC feature 10/94310/10
authorHyunsoo, Park <hance.park@samsung.com>
Fri, 28 Oct 2016 06:53:11 +0000 (15:53 +0900)
committerSeokHoon Lee <andy.shlee@samsung.com>
Mon, 7 Nov 2016 04:08:03 +0000 (13:08 +0900)
[Version] 1.6.1
[Profile] Common
[Issue Type] Add feature
[Dependency module] N/A
[Depends-on] https://review.tizen.org/gerrit/#/c/94313/(Change-Id: Iec3ba16bd8b61b96415e39126e25c4286cd02dc4)
[Test] [M(T) - Boot=(OK), sdb=(OK), Home=(OK), Touch=(OK), Version=tizen-mobile_20161025.2]

Change-Id: I534d3acf3aa5f0114c2282b3ea80a7b0f51216cc
Signed-off-by: Hyunsoo, Park <hance.park@samsung.com>
18 files changed:
gst/rtsp-server/Makefile.am
gst/rtsp-server/gstwfdmessage-ext.c [new file with mode: 0755]
gst/rtsp-server/gstwfdmessage-ext.h [new file with mode: 0755]
gst/rtsp-server/gstwfdmessage.c
gst/rtsp-server/rtsp-client-ext.c [new file with mode: 0755]
gst/rtsp-server/rtsp-client-ext.h [new file with mode: 0755]
gst/rtsp-server/rtsp-client-wfd.c [changed mode: 0644->0755]
gst/rtsp-server/rtsp-client-wfd.h
gst/rtsp-server/rtsp-client.c
gst/rtsp-server/rtsp-media-ext.c [new file with mode: 0755]
gst/rtsp-server/rtsp-media-ext.h [new file with mode: 0755]
gst/rtsp-server/rtsp-media-factory-wfd.c [changed mode: 0644->0755]
gst/rtsp-server/rtsp-media-factory-wfd.h
gst/rtsp-server/rtsp-media.c
gst/rtsp-server/rtsp-media.h
gst/rtsp-server/rtsp-server-wfd.c
gst/rtsp-server/rtsp-stream.c
packaging/gst-rtsp-server.spec

index 60eaf3e..aac53f0 100644 (file)
@@ -5,6 +5,7 @@ public_headers = \
                rtsp-params.h \
                rtsp-sdp.h \
                rtsp-thread-pool.h \
+               rtsp-media-ext.h \
                rtsp-media.h \
                rtsp-media-factory.h \
                rtsp-media-factory-wfd.h \
@@ -17,10 +18,12 @@ public_headers = \
                rtsp-session-media.h \
                rtsp-session-pool.h \
                rtsp-token.h \
+               rtsp-client-ext.h \
                rtsp-client-wfd.h \
                rtsp-client.h \
                rtsp-server-wfd.h \
                rtsp-server.h \
+               gstwfdmessage-ext.h \
                gstwfdmessage.h
 
 c_sources = \
@@ -30,6 +33,7 @@ c_sources = \
        rtsp-params.c \
        rtsp-sdp.c \
        rtsp-thread-pool.c \
+       rtsp-media-ext.c \
        rtsp-media.c \
        rtsp-media-factory.c \
        rtsp-media-factory-wfd.c \
@@ -42,13 +46,15 @@ c_sources = \
        rtsp-session-media.c \
        rtsp-session-pool.c \
        rtsp-token.c \
+       gstwfdmessage-ext.c \
        gstwfdmessage.c \
+       rtsp-client-ext.c \
        rtsp-client-wfd.c \
        rtsp-client.c \
        rtsp-server-wfd.c \
        rtsp-server.c
 
-noinst_HEADERS = 
+noinst_HEADERS =
 
 lib_LTLIBRARIES = \
        libgstrtspserver-@GST_API_VERSION@.la
diff --git a/gst/rtsp-server/gstwfdmessage-ext.c b/gst/rtsp-server/gstwfdmessage-ext.c
new file mode 100755 (executable)
index 0000000..d7d1ed4
--- /dev/null
@@ -0,0 +1,525 @@
+/* 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)              g_free (field); (field) = NULL
+#define REPLACE_STRING(field, val)      FREE_STRING(field); (field) = g_strdup (val)
+
+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_STRING(field) _read_string_space_ended (temp, sizeof (temp), v); v+=strlen(temp); REPLACE_STRING (field, temp)
+#define WFD_READ_UINT32(field) _read_string_space_ended (temp, sizeof (temp), v); v+=strlen(temp); field = strtoul (temp, NULL, 16)
+#define WFD_READ_UINT32_DIGIT(field) _read_string_space_ended (temp, sizeof (temp), v); v+=strlen(temp); field = strtoul (temp, NULL, 10)
+
+  _read_string_attr_and_value (attr, value, sizeof (attr), sizeof (value), ':',
+      p);
+
+  if (!g_strcmp0 (attr, GST_STRING_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;
+}
diff --git a/gst/rtsp-server/gstwfdmessage-ext.h b/gst/rtsp-server/gstwfdmessage-ext.h
new file mode 100755 (executable)
index 0000000..347a487
--- /dev/null
@@ -0,0 +1,123 @@
+/* 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;
+
+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 */
+GstWFDResult            gst_wfd_ext_message_new                 (GstWFDExtMessage **msg);
+GstWFDResult            gst_wfd_ext_message_init                (GstWFDExtMessage *msg);
+GstWFDResult            gst_wfd_ext_message_uninit              (GstWFDExtMessage *msg);
+GstWFDResult            gst_wfd_ext_message_free                (GstWFDExtMessage *msg);
+
+GstWFDResult            gst_wfd_ext_message_parse_buffer        (const guint8 *data, guint size, GstWFDExtMessage *msg);
+gchar*                  gst_wfd_ext_message_as_text             (const GstWFDExtMessage *msg);
+gchar*                  gst_wfd_ext_message_param_names_as_text (const GstWFDExtMessage *msg);
+GstWFDResult            gst_wfd_ext_message_dump                (const GstWFDExtMessage *msg);
+
+GstWFDResult            gst_wfd_ext_message_set_tizen_retransmission (GstWFDExtMessage *msg,
+                                                                  guint rtp_port,
+                                                                  guint rtcp_port);
+GstWFDResult            gst_wfd_ext_message_get_tizen_retransmission (GstWFDExtMessage *msg,
+                                                                  guint *rtp_port,
+                                                                  guint *rtcp_port);
+
+GstWFDResult            gst_wfd_ext_message_set_tizen_fec (GstWFDExtMessage *msg,
+                                                       guint t_max,
+                                                       guint p_max);
+GstWFDResult            gst_wfd_ext_message_get_tizen_fec (GstWFDExtMessage *msg,
+                                                       guint *t_max,
+                                                       guint *p_max);
+
+GstWFDResult            gst_wfd_ext_message_set_tizen_latency_mode (GstWFDExtMessage *msg,
+                                                                guint latency_mode);
+GstWFDResult            gst_wfd_ext_message_get_tizen_latency_mode (GstWFDExtMessage *msg,
+                                                                guint *latency_mode);
+
+G_END_DECLS
+
+#endif /* __GST_WFD_EXT_MESSAGE_H__ */
index fc81a9c..0e1f7dd 100644 (file)
@@ -243,96 +243,96 @@ gst_wfd_message_uninit (GstWFDMessage * msg)
     guint i = 0;
     if (msg->audio_codecs->list) {
       for (; i < msg->audio_codecs->count; i++) {
-        FREE_STRING(msg->audio_codecs->list[i].audio_format);
+        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->list);
     }
-    FREE_STRING(msg->audio_codecs);
+    FREE_STRING (msg->audio_codecs);
   }
 
   if (msg->video_formats) {
-    FREE_STRING(msg->video_formats->list);
-    FREE_STRING(msg->video_formats);
+    FREE_STRING (msg->video_formats->list);
+    FREE_STRING (msg->video_formats);
   }
 
   if (msg->video_3d_formats) {
-    FREE_STRING(msg->video_3d_formats->list);
-    FREE_STRING(msg->video_3d_formats);
+    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->hdcp2_spec->hdcpversion);
+      FREE_STRING (msg->content_protection->hdcp2_spec->TCPPort);
+      FREE_STRING (msg->content_protection->hdcp2_spec);
     }
-    FREE_STRING(msg->content_protection);
+    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);
+      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->coupled_sink_cap->sink_address);
+      FREE_STRING (msg->coupled_sink->coupled_sink_cap);
     }
-    FREE_STRING(msg->coupled_sink);
+    FREE_STRING (msg->coupled_sink);
   }
 
   if (msg->trigger_method) {
-    FREE_STRING(msg->trigger_method->wfd_trigger_method);
-    FREE_STRING(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);
+    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);
+    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);
+    FREE_STRING (msg->route->destination);
+    FREE_STRING (msg->route);
   }
 
   if (msg->I2C) {
-    FREE_STRING(msg->I2C);
+    FREE_STRING (msg->I2C);
   }
 
   if (msg->av_format_change_timing) {
-    FREE_STRING(msg->av_format_change_timing);
+    FREE_STRING (msg->av_format_change_timing);
   }
 
   if (msg->preferred_display_mode) {
-    FREE_STRING(msg->preferred_display_mode);
+    FREE_STRING (msg->preferred_display_mode);
   }
 
   if (msg->standby_resume_capability) {
-    FREE_STRING(msg->standby_resume_capability);
+    FREE_STRING (msg->standby_resume_capability);
   }
 
   if (msg->standby) {
-    FREE_STRING(msg->standby);
+    FREE_STRING (msg->standby);
   }
 
   if (msg->connector_type) {
-    FREE_STRING(msg->connector_type);
+    FREE_STRING (msg->connector_type);
   }
 
   if (msg->idr_request) {
-    FREE_STRING(msg->idr_request);
+    FREE_STRING (msg->idr_request);
   }
 
   return GST_WFD_OK;
@@ -473,33 +473,33 @@ gst_wfd_parse_attribute (gchar * buffer, GstWFDMessage * msg)
       WFD_SKIP_SPACE (v);
       WFD_READ_UINT32 (msg->video_formats->list->native);
       WFD_SKIP_SPACE (v);
-      WFD_READ_UINT32 (msg->video_formats->
-          list->preferred_display_mode_supported);
+      WFD_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_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_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_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_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_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_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_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);
@@ -516,27 +516,27 @@ gst_wfd_parse_attribute (gchar * buffer, GstWFDMessage * msg)
       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_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_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_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_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_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_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);
@@ -694,26 +694,26 @@ gst_wfd_parse_attribute (gchar * buffer, GstWFDMessage * msg)
         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_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_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_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_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_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_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_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);
@@ -876,8 +876,8 @@ gst_wfd_message_as_text (const GstWFDMessage * msg)
       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);
+          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",
@@ -908,8 +908,8 @@ gst_wfd_message_as_text (const GstWFDMessage * msg)
       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);
+          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",
@@ -917,8 +917,8 @@ gst_wfd_message_as_text (const GstWFDMessage * msg)
       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);
+          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);
@@ -959,8 +959,9 @@ gst_wfd_message_as_text (const GstWFDMessage * msg)
     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);
+        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 {
@@ -1261,26 +1262,26 @@ gst_wfd_message_dump (const GstWFDMessage * msg)
       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) {
+      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) {
+      } 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) {
+      } 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) {
+      } 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) {
+      } 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) {
+      } 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",
@@ -1290,8 +1291,8 @@ gst_wfd_message_dump (const GstWFDMessage * msg)
       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);
+          msg->video_formats->list->H264_codec.misc_params.
+          frame_rate_control_support);
       if (msg->video_formats->list->H264_codec.max_hres) {
         g_print ("     Max Height: %04d\n",
             msg->video_formats->list->H264_codec.max_hres);
@@ -1578,8 +1579,8 @@ gst_wfd_message_set_supported_video_format (GstWFDMessage * msg,
         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;
+    msg->video_formats->list->H264_codec.misc_params.
+        frame_rate_control_support = frame_rate_control;
   }
   return GST_WFD_OK;
 }
@@ -1681,8 +1682,8 @@ gst_wfd_message_get_supported_video_format (GstWFDMessage * msg,
   *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;
+      msg->video_formats->list->H264_codec.misc_params.
+      frame_rate_control_support;
   return GST_WFD_OK;
 }
 
@@ -1725,8 +1726,8 @@ gst_wfd_message_get_prefered_video_format (GstWFDMessage * msg,
   *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;
+      msg->video_formats->list->H264_codec.misc_params.
+      frame_rate_control_support;
   return GST_WFD_OK;
 }
 
@@ -1742,9 +1743,11 @@ gst_wfd_message_set_display_edid (GstWFDMessage * msg,
     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);
+    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);
+      memcpy (msg->display_edid->edid_payload, edid_playload,
+          EDID_BLOCK_SIZE * edid_blockcount);
     else
       msg->display_edid->edid_supported = FALSE;
   } else
@@ -1767,11 +1770,14 @@ gst_wfd_message_get_display_edid (GstWFDMessage * msg,
   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) {
+      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);
+        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);
+          memcpy (temp, msg->display_edid->edid_payload,
+              EDID_BLOCK_SIZE * msg->display_edid->edid_block_count);
           *edid_playload = temp;
           *edid_supported = TRUE;
         }
@@ -1830,7 +1836,8 @@ gst_wfd_message_get_contentprotection_type (GstWFDMessage * msg,
     }
 
     if (msg->content_protection->hdcp2_spec->TCPPort) {
-      result = strtok_r (msg->content_protection->hdcp2_spec->TCPPort, "=", &ptr);
+      result =
+          strtok_r (msg->content_protection->hdcp2_spec->TCPPort, "=", &ptr);
       while (result != NULL && ptr != NULL) {
         result = strtok_r (NULL, "=", &ptr);
         *TCPPort = atoi (result);
@@ -1947,12 +1954,13 @@ gst_wfd_message_get_presentation_url (GstWFDMessage * msg, gchar ** wfd_url0,
 }
 
 GstWFDResult
-gst_wfd_message_set_av_format_change_timing(GstWFDMessage *msg, guint64 PTS, guint64 DTS)
+gst_wfd_message_set_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 (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 = g_new0 (GstWFDAVFormatChangeTiming, 1);
 
   msg->av_format_change_timing->PTS = PTS;
   msg->av_format_change_timing->DTS = DTS;
@@ -1960,11 +1968,12 @@ gst_wfd_message_set_av_format_change_timing(GstWFDMessage *msg, guint64 PTS, gui
 }
 
 GstWFDResult
-gst_wfd_message_get_av_format_change_timing(GstWFDMessage *msg, guint64 *PTS, guint64 *DTS)
+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);
+  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;
diff --git a/gst/rtsp-server/rtsp-client-ext.c b/gst/rtsp-server/rtsp-client-ext.c
new file mode 100755 (executable)
index 0000000..5f73c99
--- /dev/null
@@ -0,0 +1,922 @@
+/* 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)
+ */
+
+#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_val_if_fail (priv != NULL, FALSE);
+
+  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_if_fail (client != 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_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;
+  }
+
+  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_val_if_fail (data != NULL, 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;
+  gboolean is_appended = FALSE;
+
+  g_return_if_fail (ext_priv != 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);
+    is_appended = TRUE;
+  } 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);
+
+  if (is_appended == FALSE) {
+    return NULL;
+  } else {
+    return data;
+  };
+
+  return data;
+error:
+  if (tmp != NULL)
+    g_free (tmp);
+
+  if (msg != NULL)
+    gst_wfd_ext_message_free (msg);
+
+  return NULL;
+}
diff --git a/gst/rtsp-server/rtsp-client-ext.h b/gst/rtsp-server/rtsp-client-ext.h
new file mode 100755 (executable)
index 0000000..34efcde
--- /dev/null
@@ -0,0 +1,73 @@
+/* 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];
+};
+
+GType                 gst_rtsp_ext_client_get_type          (void);
+
+GstRTSPExtClient *    gst_rtsp_ext_client_new               (void);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_EXT_CLIENT_H__ */
old mode 100644 (file)
new mode 100755 (executable)
index f0cd177..6e5729a
@@ -52,7 +52,8 @@
 
 typedef struct _GstRTSPClientRTPStats GstRTSPClientRTPStats;
 
-struct _GstRTSPClientRTPStats {
+struct _GstRTSPClientRTPStats
+{
   GstRTSPStream *stream;
   guint64 last_sent_bytes;
   guint64 sent_bytes;
@@ -138,6 +139,8 @@ struct _GstRTSPWFDClientPrivate
   GMutex stats_lock;
   guint stats_timer_id;
   gboolean rtcp_stats_enabled;
+
+  gchar *sink_user_agent;
 };
 
 #define DEFAULT_WFD_TIMEOUT 60
@@ -149,6 +152,11 @@ enum
   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
 };
 
@@ -174,15 +182,17 @@ 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 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 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);
+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);
@@ -240,17 +250,50 @@ gst_rtsp_wfd_client_class_init (GstRTSPWFDClientClass * klass)
       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);
+      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);
+      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");
@@ -278,6 +321,7 @@ gst_rtsp_wfd_client_init (GstRTSPWFDClient * client)
   priv->stats_timer_id = -1;
   priv->rtcp_stats_enabled = FALSE;
   memset (&priv->stats, 0x00, sizeof (GstRTSPClientRTPStats));
+  priv->sink_user_agent = NULL;
 
   GST_INFO_OBJECT (client, "Client is initialized");
 }
@@ -298,7 +342,12 @@ gst_rtsp_wfd_client_finalize (GObject * obj)
     g_free (priv->host_address);
 
   if (priv->stats_timer_id > 0)
-    g_source_remove(priv->stats_timer_id);
+    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);
@@ -373,48 +422,53 @@ wfd_display_rtp_stats (gpointer userdata)
   priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
 
   if (!priv) {
-    GST_ERROR("No priv");
+    GST_ERROR ("No priv");
     return FALSE;
   }
 
-  g_mutex_lock(&priv->stats_lock);
+  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);
+  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 ("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);
+  g_mutex_unlock (&priv->stats_lock);
 
   return TRUE;
 }
 
 static void
-on_rtcp_stats (GstRTSPStream *stream, GstStructure *stats, GstRTSPClient *client)
+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;
+  if (!priv)
+    return;
 
-  g_mutex_lock(&priv->stats_lock);
+  g_mutex_lock (&priv->stats_lock);
 
   gst_structure_get_uint (stats, "rb-fractionlost", &fraction_lost);
   gst_structure_get_int (stats, "rb-packetslost", &packetslost);
@@ -428,15 +482,17 @@ on_rtcp_stats (GstRTSPStream *stream, GstStructure *stats, GstRTSPClient *client
     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;
+  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_mutex_unlock (&priv->stats_lock);
+  g_signal_emit (client, gst_rtsp_client_wfd_signals[SIGNAL_WFD_RTP_STATS], 0,
+      stats);
 }
 
 static gboolean
@@ -447,13 +503,16 @@ wfd_configure_client_media (GstRTSPClient * client, GstRTSPMedia * media,
     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);
+    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);
+  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)
+wfd_options_request_done (GstRTSPWFDClient * client, GstRTSPContext * ctx)
 {
   GstRTSPResult res = GST_RTSP_OK;
   GstRTSPWFDClientClass *klass = GST_RTSP_WFD_CLIENT_GET_CLASS (client);
@@ -475,7 +534,7 @@ wfd_options_request_done (GstRTSPWFDClient * client, GstRTSPContext *ctx)
 }
 
 static void
-wfd_get_param_request_done (GstRTSPWFDClient * client, GstRTSPContext *ctx)
+wfd_get_param_request_done (GstRTSPWFDClient * client, GstRTSPContext * ctx)
 {
   GstRTSPResult res = GST_RTSP_OK;
   GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
@@ -499,8 +558,7 @@ wfd_get_param_request_done (GstRTSPWFDClient * client, GstRTSPContext *ctx)
 }
 
 static guint
-wfd_get_prefered_audio_codec (guint8 srcAudioCodec,
-    guint sinkAudioCodec)
+wfd_get_prefered_audio_codec (guint8 srcAudioCodec, guint sinkAudioCodec)
 {
   int i = 0;
   guint codec = 0;
@@ -909,7 +967,7 @@ wfd_get_prefered_resolution (guint64 srcResolution,
           break;
       }
     }
-    break;
+      break;
 
     default:
       *cMaxWidth = 0;
@@ -942,7 +1000,7 @@ handle_wfd_play (GstRTSPClient * client, GstRTSPContext * ctx)
 
   g_return_if_fail (priv != NULL);
 
-  wfd_set_keep_alive_condition(_client);
+  wfd_set_keep_alive_condition (_client);
 
   priv->stats_timer_id = g_timeout_add (2000, wfd_display_rtp_stats, _client);
 
@@ -974,6 +1032,15 @@ handle_wfd_response (GstRTSPClient * client, GstRTSPContext * ctx)
     goto error;
   }
 
+  if (priv->sink_user_agent == NULL) {
+    gchar *user_agent = NULL;
+    gst_rtsp_message_get_header (ctx->response, GST_RTSP_HDR_USER_AGENT,
+        &user_agent, 0);
+    priv->sink_user_agent = g_strdup (user_agent);
+
+    GST_INFO_OBJECT (_client, "sink user_agent : %s", priv->sink_user_agent);
+  }
+
   /* parsing the GET_PARAMTER response */
   res = gst_rtsp_message_get_body (ctx->response, (guint8 **) & data, &size);
   if (res != GST_RTSP_OK) {
@@ -1102,6 +1169,9 @@ handle_wfd_response (GstRTSPClient * client, GstRTSPContext * ctx)
 #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);
@@ -1118,12 +1188,12 @@ handle_wfd_response (GstRTSPClient * client, GstRTSPContext * ctx)
 
       gst_rtsp_wfd_client_trigger_request (_client, WFD_TRIGGER_SETUP);
     } else {
-      g_mutex_lock(&priv->keep_alive_lock);
+      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);
+      g_mutex_unlock (&priv->keep_alive_lock);
     }
   }
 
@@ -1235,11 +1305,11 @@ handle_wfd_set_param_request (GstRTSPClient * client, GstRTSPContext * ctx)
       GST_INFO_OBJECT (_client, "SET_PARAMETER Request : %s(%d)", data, size);
       if (g_strcmp0 ((const gchar *) data, "wfd_idr_request"))
         send_generic_wfd_response (_client, GST_RTSP_STS_OK, ctx);
-#if 0
-      else
-        /* TODO-WFD : Handle other set param request */
+      else {
         send_generic_wfd_response (_client, GST_RTSP_STS_OK, ctx);
-#endif
+        g_signal_emit (client,
+            gst_rtsp_client_wfd_signals[SIGNAL_WFD_SET_PARAM_MSG], 0, data);
+      }
     } else {
       goto bad_request;
     }
@@ -1364,8 +1434,7 @@ typedef enum
 } GstWFDMessageType;
 
 static gboolean
-_set_negotiated_audio_codec (GstRTSPWFDClient *client,
-    guint audio_codec)
+_set_negotiated_audio_codec (GstRTSPWFDClient * client, guint audio_codec)
 {
   GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
 
@@ -1377,40 +1446,41 @@ _set_negotiated_audio_codec (GstRTSPWFDClient *client,
 
   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...");
+    GST_ERROR_OBJECT (client,
+        "Failed to set negotiated audio codec: no mount points...");
     goto no_mount_points;
   }
 
-  path = g_strdup(WFD_MOUNT_POINT);
+  path = g_strdup (WFD_MOUNT_POINT);
   if (!path) {
     ret = FALSE;
-    GST_ERROR_OBJECT (client, "Failed to set negotiated audio codec: no path...");
+    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...");
+  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);
+  gst_rtsp_media_factory_wfd_set_audio_codec (factory, audio_codec);
   ret = TRUE;
 
-  g_object_unref(factory);
+  g_object_unref (factory);
 
 no_factory:
-  g_free(path);
+  g_free (path);
 no_path:
-  g_object_unref(mount_points);
+  g_object_unref (mount_points);
 no_mount_points:
   return ret;
 }
 
 static gboolean
-_set_negotiated_resolution(GstRTSPWFDClient *client,
+_set_negotiated_resolution (GstRTSPWFDClient * client,
     guint32 width, guint32 height)
 {
   GstRTSPClient *parent_client = GST_RTSP_CLIENT_CAST (client);
@@ -1423,34 +1493,35 @@ _set_negotiated_resolution(GstRTSPWFDClient *client,
 
   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...");
+    GST_ERROR_OBJECT (client,
+        "Failed to set negotiated resolution: no mount points...");
     goto no_mount_points;
   }
 
-  path = g_strdup(WFD_MOUNT_POINT);
+  path = g_strdup (WFD_MOUNT_POINT);
   if (!path) {
     ret = FALSE;
-    GST_ERROR_OBJECT (client, "Failed to set negotiated resolution: no 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...");
+  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);
+  gst_rtsp_media_factory_wfd_set_negotiated_resolution (factory, width, height);
   ret = TRUE;
 
-  g_object_unref(factory);
+  g_object_unref (factory);
 
 no_factory:
-  g_free(path);
+  g_free (path);
 no_path:
-  g_object_unref(mount_points);
+  g_object_unref (mount_points);
 no_mount_points:
   return ret;
 }
@@ -1539,6 +1610,16 @@ _set_wfd_message_body (GstRTSPWFDClient * client, GstWFDMessageType msg_type,
       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) {
@@ -1587,7 +1668,8 @@ _set_wfd_message_body (GstRTSPWFDClient * client, GstWFDMessageType msg_type,
       g_string_append (buf, priv->host_address);
     } else {
       GST_ERROR_OBJECT (client, "Failed to get host address");
-      if (buf) g_string_free (buf, TRUE);
+      if (buf)
+        g_string_free (buf, TRUE);
       goto error;
     }
 
@@ -1601,9 +1683,10 @@ _set_wfd_message_body (GstRTSPWFDClient * client, GstWFDMessageType msg_type,
       goto error;
     }
 
-    taudiocodec = wfd_get_prefered_audio_codec (priv->audio_codec, priv->caCodec);
+    taudiocodec =
+        wfd_get_prefered_audio_codec (priv->audio_codec, priv->caCodec);
     priv->caCodec = taudiocodec;
-    if (!_set_negotiated_audio_codec(client, priv->caCodec)) {
+    if (!_set_negotiated_audio_codec (client, priv->caCodec)) {
       GST_ERROR_OBJECT (client, "Failed to set negotiated "
           "audio codec to media factory...");
     }
@@ -1678,8 +1761,7 @@ _set_wfd_message_body (GstRTSPWFDClient * client, GstWFDMessageType msg_type,
           priv->cInterleaved);
     }
 
-    if (!_set_negotiated_resolution(client, priv->cMaxWidth,
-          priv->cMaxHeight)) {
+    if (!_set_negotiated_resolution (client, priv->cMaxWidth, priv->cMaxHeight)) {
       GST_ERROR_OBJECT (client, "Failed to set negotiated "
           "resolution to media factory...");
     }
@@ -1699,7 +1781,8 @@ _set_wfd_message_body (GstRTSPWFDClient * client, GstWFDMessageType msg_type,
     /* set the preffered RTP ports for the WFD server */
     wfd_res =
         gst_wfd_messge_set_prefered_rtp_ports (msg, GST_WFD_RTSP_TRANS_RTP,
-        GST_WFD_RTSP_PROFILE_AVP, GST_WFD_RTSP_LOWER_TRANS_UDP, priv->crtp_port0, priv->crtp_port1);
+        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...");
@@ -1711,6 +1794,16 @@ _set_wfd_message_body (GstRTSPWFDClient * client, GstWFDMessageType msg_type,
       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) {
@@ -1777,7 +1870,7 @@ gst_prepare_request (GstRTSPWFDClient * client, GstRTSPMessage * request,
   res = gst_rtsp_message_init_request (request, method, url);
 
   if (method == GST_RTSP_GET_PARAMETER || method == GST_RTSP_SET_PARAMETER) {
-    g_free(url);
+    g_free (url);
   }
 
   if (res < 0) {
@@ -2349,7 +2442,7 @@ gst_rtsp_wfd_client_set_video_supported_resolution (GstRTSPWFDClient * 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);
+  GST_DEBUG ("Resolution : %" G_GUINT64_FORMAT, supported_reso);
 
   return res;
 }
@@ -2364,7 +2457,7 @@ gst_rtsp_wfd_client_set_video_native_resolution (GstRTSPWFDClient * 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);
+  GST_DEBUG ("Native Resolution : %" G_GUINT64_FORMAT, native_reso);
 
   return res;
 }
@@ -2387,7 +2480,7 @@ gst_rtsp_wfd_client_set_audio_codec (GstRTSPWFDClient * client,
 static gboolean
 wfd_ckeck_keep_alive_response (gpointer userdata)
 {
-  GstRTSPWFDClient *client = (GstRTSPWFDClient *)userdata;
+  GstRTSPWFDClient *client = (GstRTSPWFDClient *) userdata;
   GstRTSPWFDClientPrivate *priv = NULL;
   if (!client) {
     return FALSE;
@@ -2403,8 +2496,7 @@ wfd_ckeck_keep_alive_response (gpointer userdata)
     GST_INFO ("%p: source error notification", client);
 
     g_signal_emit (client,
-        gst_rtsp_client_wfd_signals[SIGNAL_WFD_KEEP_ALIVE_FAIL], 0,
-        NULL);
+        gst_rtsp_client_wfd_signals[SIGNAL_WFD_KEEP_ALIVE_FAIL], 0, NULL);
     return FALSE;
   }
 }
@@ -2418,17 +2510,18 @@ handle_M16_message (GstRTSPWFDClient * client)
   GstRTSPMessage request = { 0 };
   gchar *url_str = NULL;
 
-  url_str = g_strdup("rtsp://localhost/wfd1.0");
+  url_str = g_strdup ("rtsp://localhost/wfd1.0");
 
-  res = gst_rtsp_message_init_request (&request, GST_RTSP_GET_PARAMETER, url_str);
+  res =
+      gst_rtsp_message_init_request (&request, GST_RTSP_GET_PARAMETER, url_str);
   if (res < 0) {
     GST_ERROR ("init request failed");
-    g_free(url_str);
+    g_free (url_str);
     return FALSE;
   }
 
   gst_send_request (client, NULL, &request);
-  g_free(url_str);
+  g_free (url_str);
   return GST_RTSP_OK;
 }
 
@@ -2436,12 +2529,12 @@ handle_M16_message (GstRTSPWFDClient * client)
  * If yes, keep alive message is sent otherwise error message
  * will be displayed.*/
 static gboolean
-keep_alive_condition(gpointer userdata)
+keep_alive_condition (gpointer userdata)
 {
   GstRTSPWFDClient *client;
   GstRTSPWFDClientPrivate *priv;
   GstRTSPResult res;
-  client = (GstRTSPWFDClient *)userdata;
+  client = (GstRTSPWFDClient *) userdata;
   if (!client) {
     return FALSE;
   }
@@ -2449,36 +2542,38 @@ keep_alive_condition(gpointer userdata)
 
   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);
+  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) {
+  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);
+    g_mutex_unlock (&priv->keep_alive_lock);
     return FALSE;
   }
 
-  g_mutex_unlock(&priv->keep_alive_lock);
+  g_mutex_unlock (&priv->keep_alive_lock);
   return TRUE;
 }
 
-static
-void wfd_set_keep_alive_condition(GstRTSPWFDClient * client)
+static void
+wfd_set_keep_alive_condition (GstRTSPWFDClient * client)
 {
-  g_timeout_add((DEFAULT_WFD_TIMEOUT-5)*1000, keep_alive_condition, 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)
+gst_rtsp_wfd_client_set_host_address (GstRTSPWFDClient * client,
+    const gchar * address)
 {
   GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
 
@@ -2492,7 +2587,7 @@ gst_rtsp_wfd_client_set_host_address (GstRTSPWFDClient *client, const gchar * ad
 }
 
 guint
-gst_rtsp_wfd_client_get_audio_codec(GstRTSPWFDClient *client)
+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);
@@ -2501,7 +2596,7 @@ gst_rtsp_wfd_client_get_audio_codec(GstRTSPWFDClient *client)
 }
 
 guint
-gst_rtsp_wfd_client_get_audio_freq(GstRTSPWFDClient *client)
+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);
@@ -2510,7 +2605,7 @@ gst_rtsp_wfd_client_get_audio_freq(GstRTSPWFDClient *client)
 }
 
 guint
-gst_rtsp_wfd_client_get_audio_channels(GstRTSPWFDClient *client)
+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);
@@ -2519,7 +2614,7 @@ gst_rtsp_wfd_client_get_audio_channels(GstRTSPWFDClient *client)
 }
 
 guint
-gst_rtsp_wfd_client_get_audio_bit_width(GstRTSPWFDClient *client)
+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);
@@ -2528,7 +2623,7 @@ gst_rtsp_wfd_client_get_audio_bit_width(GstRTSPWFDClient *client)
 }
 
 guint
-gst_rtsp_wfd_client_get_audio_latency(GstRTSPWFDClient *client)
+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);
@@ -2537,7 +2632,7 @@ gst_rtsp_wfd_client_get_audio_latency(GstRTSPWFDClient *client)
 }
 
 guint
-gst_rtsp_wfd_client_get_video_codec(GstRTSPWFDClient *client)
+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);
@@ -2546,7 +2641,7 @@ gst_rtsp_wfd_client_get_video_codec(GstRTSPWFDClient *client)
 }
 
 guint
-gst_rtsp_wfd_client_get_video_native(GstRTSPWFDClient *client)
+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);
@@ -2555,7 +2650,7 @@ gst_rtsp_wfd_client_get_video_native(GstRTSPWFDClient *client)
 }
 
 guint64
-gst_rtsp_wfd_client_get_video_native_resolution(GstRTSPWFDClient *client)
+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);
@@ -2564,7 +2659,7 @@ gst_rtsp_wfd_client_get_video_native_resolution(GstRTSPWFDClient *client)
 }
 
 guint64
-gst_rtsp_wfd_client_get_video_cea_resolution(GstRTSPWFDClient *client)
+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);
@@ -2573,7 +2668,7 @@ gst_rtsp_wfd_client_get_video_cea_resolution(GstRTSPWFDClient *client)
 }
 
 guint64
-gst_rtsp_wfd_client_get_video_vesa_resolution(GstRTSPWFDClient *client)
+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);
@@ -2582,7 +2677,7 @@ gst_rtsp_wfd_client_get_video_vesa_resolution(GstRTSPWFDClient *client)
 }
 
 guint64
-gst_rtsp_wfd_client_get_video_hh_resolution(GstRTSPWFDClient *client)
+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);
@@ -2591,7 +2686,7 @@ gst_rtsp_wfd_client_get_video_hh_resolution(GstRTSPWFDClient *client)
 }
 
 guint
-gst_rtsp_wfd_client_get_video_profile(GstRTSPWFDClient *client)
+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);
@@ -2600,7 +2695,7 @@ gst_rtsp_wfd_client_get_video_profile(GstRTSPWFDClient *client)
 }
 
 guint
-gst_rtsp_wfd_client_get_video_level(GstRTSPWFDClient *client)
+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);
@@ -2609,7 +2704,7 @@ gst_rtsp_wfd_client_get_video_level(GstRTSPWFDClient *client)
 }
 
 guint
-gst_rtsp_wfd_client_get_video_latency(GstRTSPWFDClient *client)
+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);
@@ -2618,7 +2713,7 @@ gst_rtsp_wfd_client_get_video_latency(GstRTSPWFDClient *client)
 }
 
 guint32
-gst_rtsp_wfd_client_get_video_max_height(GstRTSPWFDClient *client)
+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);
@@ -2627,7 +2722,7 @@ gst_rtsp_wfd_client_get_video_max_height(GstRTSPWFDClient *client)
 }
 
 guint32
-gst_rtsp_wfd_client_get_video_max_width(GstRTSPWFDClient *client)
+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);
@@ -2636,7 +2731,7 @@ gst_rtsp_wfd_client_get_video_max_width(GstRTSPWFDClient *client)
 }
 
 guint32
-gst_rtsp_wfd_client_get_video_framerate(GstRTSPWFDClient *client)
+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);
@@ -2645,7 +2740,7 @@ gst_rtsp_wfd_client_get_video_framerate(GstRTSPWFDClient *client)
 }
 
 guint32
-gst_rtsp_wfd_client_get_video_min_slice_size(GstRTSPWFDClient *client)
+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);
@@ -2654,7 +2749,7 @@ gst_rtsp_wfd_client_get_video_min_slice_size(GstRTSPWFDClient *client)
 }
 
 guint32
-gst_rtsp_wfd_client_get_video_slice_enc_params(GstRTSPWFDClient *client)
+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);
@@ -2663,7 +2758,7 @@ gst_rtsp_wfd_client_get_video_slice_enc_params(GstRTSPWFDClient *client)
 }
 
 guint
-gst_rtsp_wfd_client_get_video_framerate_control(GstRTSPWFDClient *client)
+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);
@@ -2672,7 +2767,7 @@ gst_rtsp_wfd_client_get_video_framerate_control(GstRTSPWFDClient *client)
 }
 
 guint32
-gst_rtsp_wfd_client_get_rtp_port0(GstRTSPWFDClient *client)
+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);
@@ -2681,7 +2776,7 @@ gst_rtsp_wfd_client_get_rtp_port0(GstRTSPWFDClient *client)
 }
 
 guint32
-gst_rtsp_wfd_client_get_rtp_port1(GstRTSPWFDClient *client)
+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);
@@ -2690,7 +2785,7 @@ gst_rtsp_wfd_client_get_rtp_port1(GstRTSPWFDClient *client)
 }
 
 gboolean
-gst_rtsp_wfd_client_get_edid_supported(GstRTSPWFDClient *client)
+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);
@@ -2699,7 +2794,7 @@ gst_rtsp_wfd_client_get_edid_supported(GstRTSPWFDClient *client)
 }
 
 guint32
-gst_rtsp_wfd_client_get_edid_hresolution(GstRTSPWFDClient *client)
+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);
@@ -2708,7 +2803,7 @@ gst_rtsp_wfd_client_get_edid_hresolution(GstRTSPWFDClient *client)
 }
 
 guint32
-gst_rtsp_wfd_client_get_edid_vresolution(GstRTSPWFDClient *client)
+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);
@@ -2717,7 +2812,7 @@ gst_rtsp_wfd_client_get_edid_vresolution(GstRTSPWFDClient *client)
 }
 
 gboolean
-gst_rtsp_wfd_client_get_protection_enabled(GstRTSPWFDClient *client)
+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);
@@ -2726,7 +2821,7 @@ gst_rtsp_wfd_client_get_protection_enabled(GstRTSPWFDClient *client)
 }
 
 void
-gst_rtsp_wfd_client_set_audio_freq(GstRTSPWFDClient *client, guint freq)
+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);
@@ -2735,7 +2830,8 @@ gst_rtsp_wfd_client_set_audio_freq(GstRTSPWFDClient *client, guint freq)
 }
 
 void
-gst_rtsp_wfd_client_set_edid_supported(GstRTSPWFDClient *client, gboolean supported)
+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);
@@ -2744,7 +2840,8 @@ gst_rtsp_wfd_client_set_edid_supported(GstRTSPWFDClient *client, gboolean suppor
 }
 
 void
-gst_rtsp_wfd_client_set_edid_hresolution(GstRTSPWFDClient *client, guint32 reso)
+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);
@@ -2753,7 +2850,8 @@ gst_rtsp_wfd_client_set_edid_hresolution(GstRTSPWFDClient *client, guint32 reso)
 }
 
 void
-gst_rtsp_wfd_client_set_edid_vresolution(GstRTSPWFDClient *client, guint32 reso)
+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);
@@ -2762,7 +2860,8 @@ gst_rtsp_wfd_client_set_edid_vresolution(GstRTSPWFDClient *client, guint32 reso)
 }
 
 void
-gst_rtsp_wfd_client_set_protection_enabled(GstRTSPWFDClient *client, gboolean enable)
+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);
@@ -2771,7 +2870,8 @@ gst_rtsp_wfd_client_set_protection_enabled(GstRTSPWFDClient *client, gboolean en
 }
 
 void
-gst_rtsp_wfd_client_set_hdcp_version(GstRTSPWFDClient *client, GstWFDHDCPProtection version)
+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);
@@ -2780,7 +2880,7 @@ gst_rtsp_wfd_client_set_hdcp_version(GstRTSPWFDClient *client, GstWFDHDCPProtect
 }
 
 void
-gst_rtsp_wfd_client_set_hdcp_port(GstRTSPWFDClient *client, guint32 port)
+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);
@@ -2788,19 +2888,21 @@ gst_rtsp_wfd_client_set_hdcp_port(GstRTSPWFDClient *client, guint32 port)
   priv->hdcp_tcpport = port;
 }
 
-void gst_rtsp_wfd_client_set_keep_alive_flag(GstRTSPWFDClient *client, gboolean flag)
+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);
+  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);
+  g_mutex_unlock (&priv->keep_alive_lock);
 }
 
 void
-gst_rtsp_wfd_client_set_aud_codec (GstRTSPWFDClient *client, guint acodec)
+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);
@@ -2809,7 +2911,8 @@ gst_rtsp_wfd_client_set_aud_codec (GstRTSPWFDClient *client, guint acodec)
 }
 
 void
-gst_rtsp_wfd_client_set_audio_channels(GstRTSPWFDClient *client, guint channels)
+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);
@@ -2818,7 +2921,8 @@ gst_rtsp_wfd_client_set_audio_channels(GstRTSPWFDClient *client, guint channels)
 }
 
 void
-gst_rtsp_wfd_client_set_audio_bit_width(GstRTSPWFDClient *client, guint bwidth)
+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);
@@ -2827,7 +2931,7 @@ gst_rtsp_wfd_client_set_audio_bit_width(GstRTSPWFDClient *client, guint bwidth)
 }
 
 void
-gst_rtsp_wfd_client_set_audio_latency(GstRTSPWFDClient *client, guint latency)
+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);
@@ -2836,7 +2940,7 @@ gst_rtsp_wfd_client_set_audio_latency(GstRTSPWFDClient *client, guint latency)
 }
 
 void
-gst_rtsp_wfd_client_set_video_codec(GstRTSPWFDClient *client, guint vcodec)
+gst_rtsp_wfd_client_set_video_codec (GstRTSPWFDClient * client, guint vcodec)
 {
   GstRTSPWFDClientPrivate *priv = GST_RTSP_WFD_CLIENT_GET_PRIVATE (client);
   g_return_if_fail (priv != NULL);
@@ -2845,7 +2949,7 @@ gst_rtsp_wfd_client_set_video_codec(GstRTSPWFDClient *client, guint vcodec)
 }
 
 void
-gst_rtsp_wfd_client_set_video_native(GstRTSPWFDClient *client, guint native)
+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);
@@ -2854,7 +2958,8 @@ gst_rtsp_wfd_client_set_video_native(GstRTSPWFDClient *client, guint native)
 }
 
 void
-gst_rtsp_wfd_client_set_vid_native_resolution(GstRTSPWFDClient *client, guint64 res)
+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);
@@ -2863,7 +2968,8 @@ gst_rtsp_wfd_client_set_vid_native_resolution(GstRTSPWFDClient *client, guint64
 }
 
 void
-gst_rtsp_wfd_client_set_video_cea_resolution(GstRTSPWFDClient *client, guint64 res)
+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);
@@ -2872,7 +2978,8 @@ gst_rtsp_wfd_client_set_video_cea_resolution(GstRTSPWFDClient *client, guint64 r
 }
 
 void
-gst_rtsp_wfd_client_set_video_vesa_resolution(GstRTSPWFDClient *client, guint64 res)
+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);
@@ -2881,7 +2988,8 @@ gst_rtsp_wfd_client_set_video_vesa_resolution(GstRTSPWFDClient *client, guint64
 }
 
 void
-gst_rtsp_wfd_client_set_video_hh_resolution(GstRTSPWFDClient *client, guint64 res)
+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);
@@ -2890,7 +2998,7 @@ gst_rtsp_wfd_client_set_video_hh_resolution(GstRTSPWFDClient *client, guint64 re
 }
 
 void
-gst_rtsp_wfd_client_set_video_profile(GstRTSPWFDClient *client, guint profile)
+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);
@@ -2899,7 +3007,7 @@ gst_rtsp_wfd_client_set_video_profile(GstRTSPWFDClient *client, guint profile)
 }
 
 void
-gst_rtsp_wfd_client_set_video_level(GstRTSPWFDClient *client, guint level)
+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);
@@ -2908,7 +3016,7 @@ gst_rtsp_wfd_client_set_video_level(GstRTSPWFDClient *client, guint level)
 }
 
 void
-gst_rtsp_wfd_client_set_video_latency(GstRTSPWFDClient *client, guint latency)
+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);
@@ -2917,7 +3025,8 @@ gst_rtsp_wfd_client_set_video_latency(GstRTSPWFDClient *client, guint latency)
 }
 
 void
-gst_rtsp_wfd_client_set_video_max_height(GstRTSPWFDClient *client, guint32 height)
+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);
@@ -2926,7 +3035,8 @@ gst_rtsp_wfd_client_set_video_max_height(GstRTSPWFDClient *client, guint32 heigh
 }
 
 void
-gst_rtsp_wfd_client_set_video_max_width(GstRTSPWFDClient *client, guint32 width)
+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);
@@ -2935,7 +3045,8 @@ gst_rtsp_wfd_client_set_video_max_width(GstRTSPWFDClient *client, guint32 width)
 }
 
 void
-gst_rtsp_wfd_client_set_video_framerate(GstRTSPWFDClient *client, guint32 framerate)
+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);
@@ -2944,7 +3055,8 @@ gst_rtsp_wfd_client_set_video_framerate(GstRTSPWFDClient *client, guint32 framer
 }
 
 void
-gst_rtsp_wfd_client_set_video_min_slice_size(GstRTSPWFDClient *client, guint32 slice_size)
+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);
@@ -2953,7 +3065,8 @@ gst_rtsp_wfd_client_set_video_min_slice_size(GstRTSPWFDClient *client, guint32 s
 }
 
 void
-gst_rtsp_wfd_client_set_video_slice_enc_params(GstRTSPWFDClient *client, guint32 enc_params)
+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);
@@ -2962,7 +3075,8 @@ gst_rtsp_wfd_client_set_video_slice_enc_params(GstRTSPWFDClient *client, guint32
 }
 
 void
-gst_rtsp_wfd_client_set_video_framerate_control(GstRTSPWFDClient *client, guint framerate)
+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);
@@ -2971,7 +3085,7 @@ gst_rtsp_wfd_client_set_video_framerate_control(GstRTSPWFDClient *client, guint
 }
 
 void
-gst_rtsp_wfd_client_set_rtp_port0(GstRTSPWFDClient *client, guint32 port)
+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);
@@ -2980,10 +3094,23 @@ gst_rtsp_wfd_client_set_rtp_port0(GstRTSPWFDClient *client, guint32 port)
 }
 
 void
-gst_rtsp_wfd_client_set_rtp_port1(GstRTSPWFDClient *client, guint32 port)
+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;
 }
+
+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 5cbf650..f59835b 100644 (file)
@@ -81,7 +81,9 @@ typedef gboolean (*GstRTSPWFDClientSendFunc)      (GstRTSPWFDClient *client,
 struct _GstRTSPWFDClient {
   GstRTSPClient  parent;
 
+#if 0 /* unused variable */
   gint           supported_methods;
+#endif
   /*< private >*/
   GstRTSPWFDClientPrivate *priv;
   gpointer _gst_reserved[GST_PADDING];
@@ -107,12 +109,20 @@ struct _GstRTSPWFDClientClass {
 
   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];
@@ -197,6 +207,8 @@ void gst_rtsp_wfd_client_set_video_framerate_control(GstRTSPWFDClient *client, g
 void gst_rtsp_wfd_client_set_rtp_port0(GstRTSPWFDClient *client, guint32 port);
 void gst_rtsp_wfd_client_set_rtp_port1(GstRTSPWFDClient *client, guint32 port);
 
+gchar *gst_rtsp_wfd_client_get_sink_user_agent(GstRTSPWFDClient *client);
+
 /**
  * GstRTSPWFDClientSessionFilterFunc:
  * @client: a #GstRTSPWFDClient object
index a600537..2017cc2 100644 (file)
@@ -3961,9 +3961,8 @@ gst_rtsp_client_set_watch_flushing (GstRTSPClient * client, gboolean val)
   priv = GST_RTSP_CLIENT_GET_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);
+  if (priv->watch != NULL) {
+    GST_INFO ("Set watch flushing as %d", val);
+    gst_rtsp_watch_set_flushing (priv->watch, val);
   }
 }
diff --git a/gst/rtsp-server/rtsp-media-ext.c b/gst/rtsp-server/rtsp-media-ext.c
new file mode 100755 (executable)
index 0000000..abecb86
--- /dev/null
@@ -0,0 +1,773 @@
+/* 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)
+ */
+
+#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;
+
+  if (inetaddr == NULL)
+    inetaddr = g_inet_address_new_any (family);
+
+  feedback_rtcp_sockaddr =
+      g_inet_socket_address_new (inetaddr, tmp_feedback_rtcp);
+  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_val_if_fail (priv != NULL, 0);
+
+  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_val_if_fail (priv != NULL, 0);
+
+  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_val_if_fail (GST_IS_RTSP_MEDIA_EXT (media), 0);
+
+  priv = media->priv;
+  g_return_val_if_fail (priv != NULL, 0);
+
+  priv->mode = mode;
+}
+
+void
+gst_rtsp_media_ext_set_retrans_port (GstRTSPMediaExt * media, guint port)
+{
+  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);
+
+  priv->retransmit_port = port;
+}
+
+void
+gst_rtsp_media_ext_set_fec_value (GstRTSPMediaExt * media, guint max_k,
+    guint max_p)
+{
+  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);
+
+  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_val_if_fail (GST_IS_RTSP_MEDIA_EXT (media), 0);
+
+  priv = media->priv;
+  g_return_val_if_fail (priv != NULL, 0);
+
+  priv->latency_mode = latency;
+}
+
+void
+gst_rtsp_media_ext_set_next_param (GstRTSPMediaExt * media, gint32 next_k,
+    gint32 next_p)
+{
+  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_set (G_OBJECT (priv->fecenc), "next-k", next_k, NULL);
+  g_object_set (G_OBJECT (priv->fecenc), "next-p", next_p, NULL);
+}
diff --git a/gst/rtsp-server/rtsp-media-ext.h b/gst/rtsp-server/rtsp-media-ext.h
new file mode 100755 (executable)
index 0000000..5bf4d93
--- /dev/null
@@ -0,0 +1,115 @@
+/* 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 */
+GstRTSPMediaExt *  gst_rtsp_media_ext_new                (GstElement *element);
+guint              gst_rtsp_media_ext_get_resent_packets (GstRTSPMediaExt *media);
+void               gst_rtsp_media_ext_set_extended_mode  (GstRTSPMediaExt *media, GstRTSPMediaExtMode mode);
+void               gst_rtsp_media_ext_set_retrans_port   (GstRTSPMediaExt *media, guint port);
+void               gst_rtsp_media_ext_set_fec_value      (GstRTSPMediaExt *media, guint max_k, guint max_p);
+void               gst_rtsp_media_ext_set_latency_mode   (GstRTSPMediaExt *media, GstRTSPMediaExtLatency latency);
+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__ */
old mode 100644 (file)
new mode 100755 (executable)
index 60371b1..c8ff33f
@@ -39,6 +39,7 @@
 #include <stdio.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))
@@ -67,6 +68,12 @@ struct _GstRTSPMediaFactoryWFDPrivate
   guint video_enc_skip_inbuf_value;
   GstElement *video_queue;
 
+  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;
@@ -125,6 +132,8 @@ static GstElement *rtsp_media_factory_wfd_create_element (GstRTSPMediaFactory *
 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);
 
@@ -150,8 +159,9 @@ gst_rtsp_media_factory_wfd_class_init (GstRTSPMediaFactoryWFDClass * klass)
       "GstRTSPMediaFactoryWFD");
 }
 
-void  gst_rtsp_media_factory_wfd_set (GstRTSPMediaFactoryWFD * factory,
-    guint8 videosrc_type, gchar *audio_device, guint64 audio_latency_time,
+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 =
@@ -166,8 +176,9 @@ void  gst_rtsp_media_factory_wfd_set (GstRTSPMediaFactoryWFD * factory,
   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)
+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);
@@ -178,7 +189,8 @@ void  gst_rtsp_media_factory_wfd_set_encoders (GstRTSPMediaFactoryWFD * factory,
   priv->audio_encoder_ac3 = audio_encoder_ac3;
 }
 
-void  gst_rtsp_media_factory_wfd_set_dump_ts (GstRTSPMediaFactoryWFD * factory,
+void
+gst_rtsp_media_factory_wfd_set_dump_ts (GstRTSPMediaFactoryWFD * factory,
     gboolean dump_ts)
 {
   GstRTSPMediaFactoryWFDPrivate *priv =
@@ -187,17 +199,22 @@ void  gst_rtsp_media_factory_wfd_set_dump_ts (GstRTSPMediaFactoryWFD * factory,
 
   priv->dump_ts = dump_ts;
 }
-void gst_rtsp_media_factory_wfd_set_negotiated_resolution (GstRTSPMediaFactory *factory,
-   guint32 width, guint32 height)
+
+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)
+
+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;
@@ -206,6 +223,95 @@ void gst_rtsp_media_factory_wfd_set_audio_codec (GstRTSPMediaFactory *factory,
 }
 
 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 =
@@ -228,6 +334,9 @@ gst_rtsp_media_factory_wfd_init (GstRTSPMediaFactoryWFD * factory)
   priv->video_height = 480;
   priv->video_framerate = 30;
   priv->video_enc_skip_inbuf_value = 5;
+  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;
@@ -301,7 +410,7 @@ gst_rtsp_media_factory_wfd_set_property (GObject * object,
 }
 
 static GstPadProbeReturn
-rtsp_media_wfd_dump_data (GstPad * pad, GstPadProbeInfo *info, gpointer u_data)
+rtsp_media_wfd_dump_data (GstPad * pad, GstPadProbeInfo * info, gpointer u_data)
 {
   guint8 *data;
   gsize size;
@@ -361,7 +470,7 @@ _rtsp_media_factory_wfd_create_audio_capture_bin (GstRTSPMediaFactoryWFD *
   GST_INFO_OBJECT (factory, "audio_do_timestamp  : %d",
       priv->audio_do_timestamp);
 
-  audio_properties_name = gst_structure_new_from_string(priv->audio_device);
+  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,
@@ -383,15 +492,15 @@ _rtsp_media_factory_wfd_create_audio_capture_bin (GstRTSPMediaFactoryWFD *
       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);
+    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) {
@@ -399,11 +508,11 @@ _rtsp_media_factory_wfd_create_audio_capture_bin (GstRTSPMediaFactoryWFD *
       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);
+    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 */
@@ -492,22 +601,28 @@ _rtsp_media_factory_wfd_create_audio_capture_bin (GstRTSPMediaFactoryWFD *
       goto create_error;
     }
 
-    gst_bin_add_many (srcbin, audiosrc, acaps2, audio_convert, acaps, aqueue, NULL);
+    gst_bin_add_many (srcbin, audiosrc, acaps2, audio_convert, acaps, aqueue,
+        NULL);
 
-    if (!gst_element_link_many (audiosrc, acaps2, audio_convert, acaps, aqueue, NULL)) {
+    if (!gst_element_link_many (audiosrc, acaps2, audio_convert, acaps, aqueue,
+            NULL)) {
       GST_ERROR_OBJECT (factory, "Failed to link audio src elements...");
       goto create_error;
     }
   }
 
   priv->audio_queue = aqueue;
-  if (acodec) g_free (acodec);
-  if (audio_properties_name) gst_structure_free(audio_properties_name);
+  if (acodec)
+    g_free (acodec);
+  if (audio_properties_name)
+    gst_structure_free (audio_properties_name);
   return TRUE;
 
 create_error:
-  if (acodec) g_free (acodec);
-  if (audio_properties_name) gst_structure_free(audio_properties_name);
+  if (acodec)
+    g_free (acodec);
+  if (audio_properties_name)
+    gst_structure_free (audio_properties_name);
   return FALSE;
 }
 
@@ -579,7 +694,8 @@ _rtsp_media_factory_wfd_create_videotest_bin (GstRTSPMediaFactoryWFD * factory,
   }
 
   venc = gst_element_factory_make (vcodec, "videoenc");
-  if (vcodec) g_free (vcodec);
+  if (vcodec)
+    g_free (vcodec);
 
   if (!venc) {
     GST_ERROR_OBJECT (factory, "failed to create video encoder element");
@@ -603,13 +719,16 @@ _rtsp_media_factory_wfd_create_videotest_bin (GstRTSPMediaFactoryWFD * factory,
     goto create_error;
   }
 
-  gst_bin_add_many (srcbin, videosrc, vcaps, videoconvert, venc_caps, venc, vparse, vqueue, NULL);
-  if (!gst_element_link_many (videosrc, vcaps, videoconvert, venc_caps, venc, vparse, vqueue, NULL)) {
+  gst_bin_add_many (srcbin, videosrc, vcaps, videoconvert, venc_caps, venc,
+      vparse, vqueue, NULL);
+  if (!gst_element_link_many (videosrc, vcaps, videoconvert, venc_caps, venc,
+          vparse, vqueue, NULL)) {
     GST_ERROR_OBJECT (factory, "Failed to link video src elements...");
     goto create_error;
   }
 
   priv->video_queue = vqueue;
+  priv->venc = venc;
 
   return TRUE;
 
@@ -662,7 +781,8 @@ _rtsp_media_factory_wfd_create_waylandsrc_bin (GstRTSPMediaFactoryWFD * factory,
   }
 
   venc = gst_element_factory_make (vcodec, "videoenc");
-  if (vcodec) g_free (vcodec);
+  if (vcodec)
+    g_free (vcodec);
 
   if (!venc) {
     GST_ERROR_OBJECT (factory, "failed to create video encoder element");
@@ -672,6 +792,7 @@ _rtsp_media_factory_wfd_create_waylandsrc_bin (GstRTSPMediaFactoryWFD * factory,
   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) {
@@ -693,6 +814,7 @@ _rtsp_media_factory_wfd_create_waylandsrc_bin (GstRTSPMediaFactoryWFD * factory,
   }
 
   priv->video_queue = vqueue;
+  priv->venc = venc;
 
   return TRUE;
 
@@ -744,7 +866,8 @@ _rtsp_media_factory_wfd_create_camera_capture_bin (GstRTSPMediaFactoryWFD *
   }
 
   venc = gst_element_factory_make (vcodec, "videoenc");
-  if (vcodec) g_free (vcodec);
+  if (vcodec)
+    g_free (vcodec);
 
   if (!venc) {
     GST_ERROR_OBJECT (factory, "failed to create video encoder element");
@@ -776,6 +899,7 @@ _rtsp_media_factory_wfd_create_camera_capture_bin (GstRTSPMediaFactoryWFD *
   }
 
   priv->video_queue = vqueue;
+  priv->venc = venc;
 
   return TRUE;
 
@@ -841,7 +965,8 @@ _rtsp_media_factory_wfd_create_xcapture_bin (GstRTSPMediaFactoryWFD * factory,
   }
 
   venc = gst_element_factory_make (vcodec, "videoenc");
-  if (vcodec) g_free (vcodec);
+  if (vcodec)
+    g_free (vcodec);
 
   if (!venc) {
     GST_ERROR_OBJECT (factory, "failed to create video encoder element");
@@ -884,6 +1009,7 @@ _rtsp_media_factory_wfd_create_xcapture_bin (GstRTSPMediaFactoryWFD * factory,
   }
 
   priv->video_queue = vqueue;
+  priv->venc = venc;
 
   return TRUE;
 
@@ -966,12 +1092,15 @@ _rtsp_media_factory_wfd_create_xvcapture_bin (GstRTSPMediaFactoryWFD * factory,
   }
 
   priv->video_queue = vqueue;
-  if (vcodec) g_free (vcodec);
+  priv->venc = venc;
+  if (vcodec)
+    g_free (vcodec);
 
   return TRUE;
 
 create_error:
-  if (vcodec) g_free (vcodec);
+  if (vcodec)
+    g_free (vcodec);
   return FALSE;
 }
 
@@ -1175,7 +1304,8 @@ rtsp_media_factory_wfd_construct (GstRTSPMediaFactory * factory,
     goto no_element;
 
   /* create a new empty media */
-  media = gst_rtsp_media_new (element);
+  //media = gst_rtsp_media_new (element);
+  media = g_object_new (GST_TYPE_RTSP_MEDIA_EXT, "element", element, NULL);
 
   gst_rtsp_media_collect_streams (media);
 
index 1751a22..582ded4 100644 (file)
@@ -127,5 +127,14 @@ void gst_rtsp_media_factory_wfd_set_negotiated_resolution (GstRTSPMediaFactory *
 void gst_rtsp_media_factory_wfd_set_audio_codec (GstRTSPMediaFactory *factory,
     guint audio_codec);
 
+void gst_rtsp_media_factory_wfd_set_venc_bitrate (GstRTSPMediaFactory *factory,
+    gint bitrate);
+void gst_rtsp_media_factory_wfd_get_venc_bitrate (GstRTSPMediaFactory *factory,
+    gint *bitrate);
+void gst_rtsp_media_factory_wfd_get_config_bitrate (GstRTSPMediaFactory *factory,
+    guint32 *min, guint32 *max);
+void gst_rtsp_media_factory_wfd_set_config_bitrate (GstRTSPMediaFactoryWFD *factory,
+    guint *config_bitrate);
+
 G_END_DECLS
 #endif /* __GST_RTSP_MEDIA_FACTORY_WFD_H__ */
index 079730c..569c747 100644 (file)
@@ -180,6 +180,8 @@ enum
   SIGNAL_UNPREPARED,
   SIGNAL_TARGET_STATE,
   SIGNAL_NEW_STATE,
+  SIGNAL_PREPARING,
+  SIGNAL_UNPREPARING,
   SIGNAL_LAST
 };
 
@@ -362,6 +364,18 @@ gst_rtsp_media_class_init (GstRTSPMediaClass * klass)
       G_STRUCT_OFFSET (GstRTSPMediaClass, new_state), NULL, NULL,
       g_cclosure_marshal_generic, 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;
@@ -2062,11 +2076,21 @@ set_state (GstRTSPMedia * media, GstState state)
       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;
 }
 
 GstStateChangeReturn
-gst_rtsp_media_set_target_state (GstRTSPMedia * media, GstState state, gboolean do_state)
+gst_rtsp_media_set_target_state (GstRTSPMedia * media, GstState state,
+    gboolean do_state)
 {
   GstRTSPMediaPrivate *priv = media->priv;
   GstStateChangeReturn ret;
@@ -2511,6 +2535,9 @@ default_start_prepare (GstRTSPMedia * media)
             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)
@@ -2540,7 +2567,7 @@ default_start_prepare (GstRTSPMedia * media)
   }
 
   if (klass->start_preroll)
-    if(!klass->start_preroll (media))
+    if (!klass->start_preroll (media))
       goto preroll_failed;
 
   return FALSE;
@@ -2611,9 +2638,9 @@ default_prepare (GstRTSPMedia * media, GstRTSPThread * thread)
 
   /* do remainder in context */
   source = g_idle_source_new ();
-  if(klass->start_prepare)
+  if (klass->start_prepare)
     g_source_set_callback (source, (GSourceFunc) klass->start_prepare,
-      g_object_ref (media), (GDestroyNotify) g_object_unref);
+        g_object_ref (media), (GDestroyNotify) g_object_unref);
   g_source_attach (source, context);
   g_source_unref (source);
 
@@ -2786,6 +2813,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 */
@@ -3845,7 +3875,7 @@ default_unsuspend (GstRTSPMedia * media)
     {
       gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING);
       if (klass->start_preroll)
-        if(!klass->start_preroll (media))
+        if (!klass->start_preroll (media))
           goto start_failed;
       g_rec_mutex_unlock (&priv->state_lock);
 
@@ -4148,3 +4178,37 @@ gst_rtsp_media_get_transport_mode (GstRTSPMedia * media)
 
   return res;
 }
+
+
+GstElement *
+gst_rtsp_media_get_pipeline (GstRTSPMedia * media)
+{
+  GstRTSPMediaPrivate *priv;
+
+  g_return_if_fail (GST_IS_RTSP_MEDIA (media));;
+
+  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_if_fail (GST_IS_RTSP_MEDIA (media));;
+
+  priv = media->priv;
+
+  g_mutex_lock (&priv->lock);
+  g_object_ref (priv->rtpbin);
+  g_mutex_unlock (&priv->lock);
+
+  return priv->rtpbin;
+}
index 6f0ffdd..0050add 100644 (file)
@@ -167,6 +167,8 @@ struct _GstRTSPMediaClass {
 
   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];
 };
@@ -262,6 +264,9 @@ void                  gst_rtsp_media_set_pipeline_state (GstRTSPMedia * media,
 GstStateChangeReturn  gst_rtsp_media_set_target_state (GstRTSPMedia * media, GstState state, gboolean do_state);
 void                 gst_rtsp_media_set_status (GstRTSPMedia * media, GstRTSPMediaStatus status);
 
+GstElement *          gst_rtsp_media_get_pipeline     (GstRTSPMedia * media);
+GstElement *          gst_rtsp_media_get_rtpbin       (GstRTSPMedia * media);
+
 G_END_DECLS
 
 #endif /* __GST_RTSP_MEDIA_H__ */
index 4e72093..0fa2cd5 100644 (file)
@@ -57,6 +57,7 @@
 
 #include "rtsp-server-wfd.h"
 #include "rtsp-client-wfd.h"
+#include "rtsp-client-ext.h"
 
 #define GST_RTSP_WFD_SERVER_GET_PRIVATE(obj)  \
        (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTSP_WFD_SERVER, GstRTSPWFDServerPrivate))
@@ -208,14 +209,15 @@ create_client_wfd (GstRTSPServer * server)
   GstRTSPSessionPool *session_pool = NULL;
   GstRTSPMountPoints *mount_points = NULL;
   GstRTSPAuth *auth = NULL;
-  GstRTSPWFDServerPrivate *priv = GST_RTSP_WFD_SERVER_GET_PRIVATE(server);
+  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 ();
+  //client = gst_rtsp_wfd_client_new();
+  client = (GstRTSPWFDClient *) gst_rtsp_ext_client_new ();
 
   thread_pool = gst_rtsp_server_get_thread_pool (server);
   session_pool = gst_rtsp_server_get_session_pool (server);
@@ -235,13 +237,12 @@ create_client_wfd (GstRTSPServer * server)
   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);
+      priv->supported_resolution);
 
   gst_rtsp_wfd_client_set_video_native_resolution (client,
-        priv->native_resolution);
+      priv->native_resolution);
 
-  gst_rtsp_wfd_client_set_audio_codec (client,
-        priv->audio_codec);
+  gst_rtsp_wfd_client_set_audio_codec (client, priv->audio_codec);
 
   GST_RTSP_WFD_SERVER_UNLOCK (server);
 
@@ -281,10 +282,11 @@ gst_rtsp_wfd_server_trigger_request (GstRTSPServer * server,
 }
 
 GstRTSPResult
-gst_rtsp_wfd_server_set_supported_reso(GstRTSPWFDServer *server, guint64 supported_reso)
+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);
+  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);
@@ -298,10 +300,11 @@ gst_rtsp_wfd_server_set_supported_reso(GstRTSPWFDServer *server, guint64 support
 }
 
 GstRTSPResult
-gst_rtsp_wfd_server_set_video_native_reso (GstRTSPWFDServer *server, guint64 native_reso)
+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);
+  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);
@@ -315,10 +318,11 @@ gst_rtsp_wfd_server_set_video_native_reso (GstRTSPWFDServer *server, guint64 nat
 }
 
 GstRTSPResult
-gst_rtsp_wfd_server_set_audio_codec (GstRTSPWFDServer *server, guint8 audio_codec)
+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);
+  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);
index ce2f5a4..6cf0c71 100644 (file)
@@ -1600,7 +1600,8 @@ check_transport (GObject * source, GstRTSPStream * stream)
 
       dump_structure (stats);
 
-      g_signal_emit (stream, gst_rtsp_stream_signals[SIGNAL_RTCP_STATS], 0, 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))) {
@@ -1651,7 +1652,8 @@ on_ssrc_active (GObject * session, GObject * source, GstRTSPStream * stream)
     GstStructure *stats;
     g_object_get (source, "stats", &stats, NULL);
     if (stats) {
-      g_signal_emit (stream, gst_rtsp_stream_signals[SIGNAL_RTCP_STATS], 0, stats);
+      g_signal_emit (stream, gst_rtsp_stream_signals[SIGNAL_RTCP_STATS], 0,
+          stats);
 
       dump_structure (stats);
       gst_structure_free (stats);
@@ -3165,7 +3167,7 @@ gst_rtsp_stream_get_current_seqnum (GstRTSPStream * stream)
 }
 
 guint64
-gst_rtsp_stream_get_udp_sent_bytes (GstRTSPStream *stream)
+gst_rtsp_stream_get_udp_sent_bytes (GstRTSPStream * stream)
 {
   GstRTSPStreamPrivate *priv;
   guint64 bytes = 0;
index b0e3187..41b739c 100644 (file)
@@ -1,7 +1,7 @@
 Name:       gst-rtsp-server
 Summary:    Multimedia Framework Library
 Version:    1.6.1
-Release:    1
+Release:    2
 Url:        http://gstreamer.freedesktop.org/
 Group:      System/Libraries
 License:    LGPL-2.0+