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 \
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 = \
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 \
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
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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__ */
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;
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);
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);
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);
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",
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",
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);
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 {
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",
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);
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;
}
*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;
}
*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;
}
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
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;
}
}
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);
}
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;
}
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;
--- /dev/null
+/* 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;
+}
--- /dev/null
+/* 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__ */
typedef struct _GstRTSPClientRTPStats GstRTSPClientRTPStats;
-struct _GstRTSPClientRTPStats {
+struct _GstRTSPClientRTPStats
+{
GstRTSPStream *stream;
guint64 last_sent_bytes;
guint64 sent_bytes;
GMutex stats_lock;
guint stats_timer_id;
gboolean rtcp_stats_enabled;
+
+ gchar *sink_user_agent;
};
#define DEFAULT_WFD_TIMEOUT 60
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
};
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);
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");
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");
}
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);
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);
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
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);
}
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);
}
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;
break;
}
}
- break;
+ break;
default:
*cMaxWidth = 0;
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);
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) {
#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);
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);
}
}
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;
}
} 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);
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);
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;
}
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) {
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;
}
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...");
}
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...");
}
/* 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...");
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) {
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) {
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;
}
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;
}
static gboolean
wfd_ckeck_keep_alive_response (gpointer userdata)
{
- GstRTSPWFDClient *client = (GstRTSPWFDClient *)userdata;
+ GstRTSPWFDClient *client = (GstRTSPWFDClient *) userdata;
GstRTSPWFDClientPrivate *priv = NULL;
if (!client) {
return FALSE;
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;
}
}
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;
}
* 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;
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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);
}
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;
+}
struct _GstRTSPWFDClient {
GstRTSPClient parent;
+#if 0 /* unused variable */
gint supported_methods;
+#endif
/*< private >*/
GstRTSPWFDClientPrivate *priv;
gpointer _gst_reserved[GST_PADDING];
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];
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
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);
}
}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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__ */
#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))
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;
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);
"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 =
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);
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 =
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;
}
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 =
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;
}
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;
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,
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) {
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 */
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;
}
}
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");
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;
}
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");
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) {
}
priv->video_queue = vqueue;
+ priv->venc = venc;
return TRUE;
}
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");
}
priv->video_queue = vqueue;
+ priv->venc = venc;
return TRUE;
}
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");
}
priv->video_queue = vqueue;
+ priv->venc = venc;
return TRUE;
}
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;
}
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);
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__ */
SIGNAL_UNPREPARED,
SIGNAL_TARGET_STATE,
SIGNAL_NEW_STATE,
+ SIGNAL_PREPARING,
+ SIGNAL_UNPREPARING,
SIGNAL_LAST
};
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;
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;
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)
}
if (klass->start_preroll)
- if(!klass->start_preroll (media))
+ if (!klass->start_preroll (media))
goto preroll_failed;
return FALSE;
/* 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);
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 */
{
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);
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;
+}
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];
};
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__ */
#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))
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);
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);
}
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);
}
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);
}
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);
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))) {
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);
}
guint64
-gst_rtsp_stream_get_udp_sent_bytes (GstRTSPStream *stream)
+gst_rtsp_stream_get_udp_sent_bytes (GstRTSPStream * stream)
{
GstRTSPStreamPrivate *priv;
guint64 bytes = 0;
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+