#include <gst/rtsp-server/rtsp-server.h>
#define DEFAULT_RTSP_PORT "8554"
+#define DEFAULT_DISABLE_RTCP FALSE
static char *port = (char *) DEFAULT_RTSP_PORT;
+static gboolean disable_rtcp = DEFAULT_DISABLE_RTCP;
static GOptionEntry entries[] = {
{"port", 'p', 0, G_OPTION_ARG_STRING, &port,
"Port to listen on (default: " DEFAULT_RTSP_PORT ")", "PORT"},
+ {"disable-rtcp", '\0', 0, G_OPTION_ARG_NONE, &disable_rtcp,
+ "Whether RTCP should be disabled (default false)", NULL},
{NULL}
};
factory = gst_rtsp_media_factory_new ();
gst_rtsp_media_factory_set_launch (factory, argv[1]);
gst_rtsp_media_factory_set_shared (factory, TRUE);
+ gst_rtsp_media_factory_set_enable_rtcp (factory, !disable_rtcp);
/* attach the test factory to the /test url */
gst_rtsp_mount_points_add_factory (mounts, "/test", factory);
#include "config.h"
#endif
+#include "rtsp-server-internal.h"
#include "rtsp-media-factory.h"
#define GST_RTSP_MEDIA_FACTORY_GET_LOCK(f) (&(GST_RTSP_MEDIA_FACTORY_CAST(f)->priv->lock))
gchar *multicast_iface;
guint max_mcast_ttl;
gboolean bind_mcast_address;
+ gboolean enable_rtcp;
GstClockTime rtx_time;
guint latency;
#define DEFAULT_STOP_ON_DISCONNECT TRUE
#define DEFAULT_DO_RETRANSMISSION FALSE
#define DEFAULT_DSCP_QOS (-1)
+#define DEFAULT_ENABLE_RTCP TRUE
enum
{
PROP_MAX_MCAST_TTL,
PROP_BIND_MCAST_ADDRESS,
PROP_DSCP_QOS,
+ PROP_ENABLE_RTCP,
PROP_LAST
};
DEFAULT_BIND_MCAST_ADDRESS,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /**
+ * GstRTSPMediaFactory:enable-rtcp:
+ *
+ * Whether the created media should send and receive RTCP
+ *
+ * Since: 1.20
+ */
+ g_object_class_install_property (gobject_class, PROP_ENABLE_RTCP,
+ g_param_spec_boolean ("enable-rtcp", "Enable RTCP",
+ "Whether the created media should send and receive RTCP",
+ DEFAULT_ENABLE_RTCP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
g_object_class_install_property (gobject_class, PROP_DSCP_QOS,
g_param_spec_int ("dscp-qos", "DSCP QoS",
"The IP DSCP field to use", -1, 63,
priv->do_retransmission = DEFAULT_DO_RETRANSMISSION;
priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL;
priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS;
+ priv->enable_rtcp = DEFAULT_ENABLE_RTCP;
priv->dscp_qos = DEFAULT_DSCP_QOS;
g_mutex_init (&priv->lock);
case PROP_DSCP_QOS:
g_value_set_int (value, gst_rtsp_media_factory_get_dscp_qos (factory));
break;
+ case PROP_ENABLE_RTCP:
+ g_value_set_boolean (value,
+ gst_rtsp_media_factory_is_enable_rtcp (factory));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
}
case PROP_DSCP_QOS:
gst_rtsp_media_factory_set_dscp_qos (factory, g_value_get_int (value));
break;
+ case PROP_ENABLE_RTCP:
+ gst_rtsp_media_factory_set_enable_rtcp (factory,
+ g_value_get_boolean (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, propid, pspec);
}
return result;
}
+/**
+ * gst_rtsp_media_factory_set_enable_rtcp:
+ * @factory: a #GstRTSPMediaFactory
+ * @enable: the new value
+ *
+ * Decide whether the created media should send and receive RTCP
+ *
+ * Since: 1.20
+ */
+void
+gst_rtsp_media_factory_set_enable_rtcp (GstRTSPMediaFactory * factory,
+ gboolean enable)
+{
+ GstRTSPMediaFactoryPrivate *priv;
+
+ g_return_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory));
+
+ priv = factory->priv;
+
+ GST_RTSP_MEDIA_FACTORY_LOCK (factory);
+ priv->enable_rtcp = enable;
+ GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
+}
+
+/**
+ * gst_rtsp_media_factory_is_enable_rtcp:
+ * @factory: a #GstRTSPMediaFactory
+ *
+ * Check if created media will send and receive RTCP
+ *
+ * Returns: %TRUE if created media will send and receive RTCP
+ *
+ * Since: 1.20
+ */
+gboolean
+gst_rtsp_media_factory_is_enable_rtcp (GstRTSPMediaFactory * factory)
+{
+ GstRTSPMediaFactoryPrivate *priv;
+ gboolean result;
+
+ g_return_val_if_fail (GST_IS_RTSP_MEDIA_FACTORY (factory), FALSE);
+
+ priv = factory->priv;
+
+ GST_RTSP_MEDIA_FACTORY_LOCK (factory);
+ result = priv->enable_rtcp;
+ GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
+
+ return result;
+}
+
static gchar *
default_gen_key (GstRTSPMediaFactory * factory, const GstRTSPUrl * url)
{
GstElement *element, *pipeline;
GstRTSPMediaFactoryClass *klass;
GType media_gtype;
+ gboolean enable_rtcp;
klass = GST_RTSP_MEDIA_FACTORY_GET_CLASS (factory);
GST_RTSP_MEDIA_FACTORY_LOCK (factory);
media_gtype = factory->priv->media_gtype;
+ enable_rtcp = factory->priv->enable_rtcp;
GST_RTSP_MEDIA_FACTORY_UNLOCK (factory);
/* create a new empty media */
g_object_new (media_gtype, "element", element, "transport-mode",
factory->priv->transport_mode, NULL);
+ /* We need to call this prior to collecting streams */
+ gst_rtsp_media_set_enable_rtcp (media, enable_rtcp);
+
gst_rtsp_media_collect_streams (media);
pipeline = klass->create_pipeline (factory, media);
GST_RTSP_SERVER_API
gint gst_rtsp_media_factory_get_dscp_qos (GstRTSPMediaFactory * factory);
+GST_RTSP_SERVER_API
+void gst_rtsp_media_factory_set_enable_rtcp (GstRTSPMediaFactory * factory,
+ gboolean enable);
+
+GST_RTSP_SERVER_API
+gboolean gst_rtsp_media_factory_is_enable_rtcp (GstRTSPMediaFactory * factory);
+
/* creating the media from the factory and a url */
GST_RTSP_SERVER_API
gchar *multicast_iface;
guint max_mcast_ttl;
gboolean bind_mcast_address;
+ gboolean enable_rtcp;
gboolean blocked;
GstRTSPTransportMode transport_mode;
gboolean stop_on_disconnect;
#define DEFAULT_MAX_MCAST_TTL 255
#define DEFAULT_BIND_MCAST_ADDRESS FALSE
#define DEFAULT_DO_RATE_CONTROL TRUE
+#define DEFAULT_ENABLE_RTCP TRUE
#define DEFAULT_DO_RETRANSMISSION FALSE
priv->do_retransmission = DEFAULT_DO_RETRANSMISSION;
priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL;
priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS;
+ priv->enable_rtcp = DEFAULT_ENABLE_RTCP;
priv->do_rate_control = DEFAULT_DO_RATE_CONTROL;
priv->dscp_qos = DEFAULT_DSCP_QOS;
priv->expected_async_done = FALSE;
return result;
}
+void
+gst_rtsp_media_set_enable_rtcp (GstRTSPMedia * media, gboolean enable)
+{
+ GstRTSPMediaPrivate *priv;
+
+ g_return_if_fail (GST_IS_RTSP_MEDIA (media));
+
+ priv = media->priv;
+
+ g_mutex_lock (&priv->lock);
+ priv->enable_rtcp = enable;
+ g_mutex_unlock (&priv->lock);
+}
+
static GList *
_find_payload_types (GstRTSPMedia * media)
{
gst_rtsp_stream_set_multicast_iface (stream, priv->multicast_iface);
gst_rtsp_stream_set_max_mcast_ttl (stream, priv->max_mcast_ttl);
gst_rtsp_stream_set_bind_mcast_address (stream, priv->bind_mcast_address);
+ gst_rtsp_stream_set_enable_rtcp (stream, priv->enable_rtcp);
gst_rtsp_stream_set_profiles (stream, priv->profiles);
gst_rtsp_stream_set_protocols (stream, priv->protocols);
gst_rtsp_stream_set_retransmission_time (stream, priv->rtx_time);
gboolean gst_rtsp_stream_is_tcp_receiver (GstRTSPStream * stream);
+void gst_rtsp_media_set_enable_rtcp (GstRTSPMedia *media, gboolean enable);
+void gst_rtsp_stream_set_enable_rtcp (GstRTSPStream *stream, gboolean enable);
+
G_END_DECLS
#endif /* __GST_RTSP_SERVER_INTERNAL_H__ */
guint32 blocked_seqnum;
guint32 blocked_rtptime;
GstClockTime blocked_running_time;
+
+ /* Whether we should send and receive RTCP */
+ gboolean enable_rtcp;
};
#define DEFAULT_CONTROL NULL
#define DEFAULT_MAX_MCAST_TTL 255
#define DEFAULT_BIND_MCAST_ADDRESS FALSE
#define DEFAULT_DO_RATE_CONTROL TRUE
+#define DEFAULT_ENABLE_RTCP TRUE
enum
{
priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL;
priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS;
priv->do_rate_control = DEFAULT_DO_RATE_CONTROL;
+ priv->enable_rtcp = DEFAULT_ENABLE_RTCP;
g_mutex_init (&priv->lock);
/* Start with random port */
tmp_rtp = 0;
+ tmp_rtcp = 0;
if (use_transport_settings) {
if (!multicast)
}
}
- rtcp_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM,
- G_SOCKET_PROTOCOL_UDP, NULL);
- if (!rtcp_socket)
- goto no_udp_protocol;
- g_socket_set_multicast_loopback (rtcp_socket, FALSE);
+ if (priv->enable_rtcp) {
+ rtcp_socket = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM,
+ G_SOCKET_PROTOCOL_UDP, NULL);
+ if (!rtcp_socket)
+ goto no_udp_protocol;
+ g_socket_set_multicast_loopback (rtcp_socket, FALSE);
+ }
- /* try to allocate 2 UDP ports, the RTP port should be an even
- * number and the RTCP port should be the next (uneven) port */
+ /* try to allocate UDP ports, the RTP port should be an even
+ * number and the RTCP port (if enabled) should be the next (uneven) port */
again:
if (rtp_socket == NULL) {
if (*server_addr_out)
addr = *server_addr_out;
else
- addr = gst_rtsp_address_pool_acquire_address (pool, flags, 2);
+ addr = gst_rtsp_address_pool_acquire_address (pool, flags,
+ priv->enable_rtcp ? 2 : 1);
if (addr == NULL)
goto no_address;
g_object_unref (rtp_sockaddr);
/* set port */
- tmp_rtcp = tmp_rtp + 1;
+ if (priv->enable_rtcp) {
+ tmp_rtcp = tmp_rtp + 1;
- rtcp_sockaddr = g_inet_socket_address_new (inetaddr, tmp_rtcp);
- if (!g_socket_bind (rtcp_socket, rtcp_sockaddr, FALSE, NULL)) {
- GST_DEBUG_OBJECT (stream, "rctp bind() failed, will try again");
+ rtcp_sockaddr = g_inet_socket_address_new (inetaddr, tmp_rtcp);
+ if (!g_socket_bind (rtcp_socket, rtcp_sockaddr, FALSE, NULL)) {
+ GST_DEBUG_OBJECT (stream, "rctp bind() failed, will try again");
+ g_object_unref (rtcp_sockaddr);
+ g_clear_object (&rtp_socket);
+ if (transport_settings_defined)
+ goto transport_settings_error;
+ goto again;
+ }
g_object_unref (rtcp_sockaddr);
- g_clear_object (&rtp_socket);
- if (transport_settings_defined)
- goto transport_settings_error;
- goto again;
}
- g_object_unref (rtcp_sockaddr);
if (!addr) {
addr = g_slice_new0 (GstRTSPAddress);
if (multicast && (ct->ttl > 0) && (ct->ttl <= priv->max_mcast_ttl)) {
GST_DEBUG ("setting mcast ttl to %d", ct->ttl);
g_socket_set_multicast_ttl (rtp_socket, ct->ttl);
- g_socket_set_multicast_ttl (rtcp_socket, ct->ttl);
+ if (rtcp_socket)
+ g_socket_set_multicast_ttl (rtcp_socket, ct->ttl);
}
socket_out[0] = rtp_socket;
socket_out[1] = rtcp_socket;
*server_addr_out = addr;
- GST_DEBUG_OBJECT (stream, "allocated address: %s and ports: %d, %d",
- addr->address, tmp_rtp, tmp_rtcp);
+ if (priv->enable_rtcp) {
+ GST_DEBUG_OBJECT (stream, "allocated address: %s and ports: %d, %d",
+ addr->address, tmp_rtp, tmp_rtcp);
+ } else {
+ GST_DEBUG_OBJECT (stream, "allocated address: %s and port: %d",
+ addr->address, tmp_rtp);
+ }
g_list_free_full (rejected_addresses, (GDestroyNotify) gst_rtsp_address_free);
if (family == G_SOCKET_FAMILY_IPV4) {
if (server_port && priv->server_addr_v4) {
server_port->min = priv->server_addr_v4->port;
- server_port->max =
- priv->server_addr_v4->port + priv->server_addr_v4->n_ports - 1;
+ if (priv->enable_rtcp) {
+ server_port->max =
+ priv->server_addr_v4->port + priv->server_addr_v4->n_ports - 1;
+ }
}
} else {
if (server_port && priv->server_addr_v6) {
server_port->min = priv->server_addr_v6->port;
- server_port->max =
- priv->server_addr_v6->port + priv->server_addr_v6->n_ports - 1;
+ if (priv->enable_rtcp) {
+ server_port->max =
+ priv->server_addr_v6->port + priv->server_addr_v6->n_ports - 1;
+ }
}
}
g_mutex_unlock (&priv->lock);
return result;
}
+void
+gst_rtsp_stream_set_enable_rtcp (GstRTSPStream * stream, gboolean enable)
+{
+ g_return_if_fail (GST_IS_RTSP_STREAM (stream));
+
+ g_mutex_lock (&stream->priv->lock);
+ stream->priv->enable_rtcp = enable;
+ g_mutex_unlock (&stream->priv->lock);
+}
+
/* executed from streaming thread */
static void
caps_notify (GstPad * pad, GParamSpec * unused, GstRTSPStream * stream)
g_object_set (priv->payloader, "onvif-no-rate-control",
!priv->do_rate_control, NULL);
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < (priv->enable_rtcp ? 2 : 1); i++) {
gboolean link_tee = FALSE;
/* For the sender we create this bit of pipeline for both
- * RTP and RTCP.
+ * RTP and RTCP (when enabled).
* Initially there will be only one active transport for
* the stream, so the pipeline will look like this:
*
"RTP caps: %" GST_PTR_FORMAT " RTCP caps: %" GST_PTR_FORMAT, rtp_caps,
rtcp_caps);
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < (priv->enable_rtcp ? 2 : 1); i++) {
/* For the receiver we create this bit of pipeline for both
- * RTP and RTCP. We receive RTP/RTCP on appsrc and udpsrc
+ * RTP and RTCP (when enabled). We receive RTP/RTCP on appsrc and udpsrc
* and it is all funneled into the rtpbin receive pad.
*
*
g_free (name);
}
- name = g_strdup_printf ("send_rtcp_src_%u", idx);
- priv->send_src[1] = gst_element_get_request_pad (rtpbin, name);
- g_free (name);
- name = g_strdup_printf ("recv_rtcp_sink_%u", idx);
- priv->recv_sink[1] = gst_element_get_request_pad (rtpbin, name);
- g_free (name);
+ if (priv->enable_rtcp) {
+ name = g_strdup_printf ("send_rtcp_src_%u", idx);
+ priv->send_src[1] = gst_element_get_request_pad (rtpbin, name);
+ g_free (name);
+
+ name = g_strdup_printf ("recv_rtcp_sink_%u", idx);
+ priv->recv_sink[1] = gst_element_get_request_pad (rtpbin, name);
+ g_free (name);
+ }
/* get the session */
g_signal_emit_by_name (rtpbin, "get-internal-session", idx, &priv->session);
priv->recv_rtp_src = NULL;
}
- for (i = 0; i < 2; i++) {
+ for (i = 0; i < (priv->enable_rtcp ? 2 : 1); i++) {
clear_element (bin, &priv->udpsrc_v4[i]);
clear_element (bin, &priv->udpsrc_v6[i]);
clear_element (bin, &priv->udpqueue[i]);
priv->send_src[0] = NULL;
}
- gst_element_release_request_pad (rtpbin, priv->send_src[1]);
- gst_object_unref (priv->send_src[1]);
- priv->send_src[1] = NULL;
+ if (priv->enable_rtcp) {
+ gst_element_release_request_pad (rtpbin, priv->send_src[1]);
+ gst_object_unref (priv->send_src[1]);
+ priv->send_src[1] = NULL;
+ }
g_object_unref (priv->session);
priv->session = NULL;
if (stream->priv->appsink[0])
g_object_set (stream->priv->appsink[0], "sync", enabled, NULL);
if (stream->priv->payloader
- && g_object_class_find_property (G_OBJECT_GET_CLASS (stream->
- priv->payloader), "onvif-no-rate-control"))
+ && g_object_class_find_property (G_OBJECT_GET_CLASS (stream->priv->
+ payloader), "onvif-no-rate-control"))
g_object_set (stream->priv->payloader, "onvif-no-rate-control", !enabled,
NULL);
if (stream->priv->session) {
}
static GstRTSPClient *
-setup_client (const gchar * launch_line)
+setup_client (const gchar * launch_line, gboolean enable_rtcp)
{
GstRTSPClient *client;
GstRTSPSessionPool *session_pool;
else
gst_rtsp_media_factory_set_launch (factory, launch_line);
+ gst_rtsp_media_factory_set_enable_rtcp (factory, enable_rtcp);
+
gst_rtsp_mount_points_add_factory (mount_points, "/test", factory);
gst_rtsp_client_set_mount_points (client, mount_points);
g_object_unref (client);
/* simple DESCRIBE for an existing url */
- client = setup_client (NULL);
+ client = setup_client (NULL, TRUE);
fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_DESCRIBE,
"rtsp://localhost/test") == GST_RTSP_OK);
str = g_strdup_printf ("%d", cseq);
GstRTSPMessage request = { 0, };
gchar *str;
- client = setup_client (NULL);
+ client = setup_client (NULL, TRUE);
create_connection (&conn);
fail_unless (gst_rtsp_client_set_connection (client, conn));
GST_END_TEST;
+GST_START_TEST (test_setup_no_rtcp)
+{
+ GstRTSPClient *client;
+ GstRTSPConnection *conn;
+ GstRTSPMessage request = { 0, };
+ gchar *str;
+
+ client = setup_client (NULL, FALSE);
+ create_connection (&conn);
+ fail_unless (gst_rtsp_client_set_connection (client, conn));
+
+ fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_SETUP,
+ "rtsp://localhost/test/stream=0") == GST_RTSP_OK);
+ str = g_strdup_printf ("%d", cseq);
+ gst_rtsp_message_add_header (&request, GST_RTSP_HDR_CSEQ, str);
+ g_free (str);
+ gst_rtsp_message_add_header (&request, GST_RTSP_HDR_TRANSPORT,
+ "RTP/AVP;unicast;client_port=5000-5001");
+
+ gst_rtsp_client_set_send_func (client, test_setup_response_200, NULL, NULL);
+ /* We want to verify that server_port holds a single number, not a range */
+ expected_transport =
+ "RTP/AVP;unicast;client_port=5000-5001;server_port=[0-9]+;ssrc=.*;mode=\"PLAY\"";
+ fail_unless (gst_rtsp_client_handle_message (client,
+ &request) == GST_RTSP_OK);
+
+ gst_rtsp_message_unset (&request);
+
+ send_teardown (client);
+ teardown_client (client);
+}
+
+GST_END_TEST;
+
GST_START_TEST (test_setup_tcp_two_streams_same_channels)
{
GstRTSPClient *client;
GstRTSPMessage request = { 0, };
gchar *str;
- client = setup_client (NULL);
+ client = setup_client (NULL, TRUE);
create_connection (&conn);
fail_unless (gst_rtsp_client_set_connection (client, conn));
gchar *str;
/* simple DESCRIBE for an existing url */
- client = setup_client (launch_line);
+ client = setup_client (launch_line, TRUE);
fail_unless (gst_rtsp_message_init_request (&request, GST_RTSP_DESCRIBE,
"rtsp://localhost/test") == GST_RTSP_OK);
str = g_strdup_printf ("%d", cseq);
tcase_add_test (tc, test_options);
tcase_add_test (tc, test_describe);
tcase_add_test (tc, test_setup_tcp);
+ tcase_add_test (tc, test_setup_no_rtcp);
tcase_add_test (tc, test_setup_tcp_two_streams_same_channels);
tcase_add_test (tc, test_client_multicast_transport_404);
tcase_add_test (tc, test_client_multicast_transport);