gstreamer/tests/check/gst/rtspserver.c
Patricia Muscalu a7732a68e8 Dynamically reconfigure pipeline in PLAY based on transports
The initial pipeline does not contain specific transport
elements. The receiver and the sender parts are added
after PLAY.
If the media is shared, the streams are dynamically
reconfigured after each PLAY.

https://bugzilla.gnome.org/show_bug.cgi?id=788340
2017-11-15 19:56:15 +02:00

2411 lines
72 KiB
C

/* GStreamer unit test for GstRTSPServer
* Copyright (C) 2012 Axis Communications <dev-gstreamer at axis dot com>
* @author David Svensson Fors <davidsf at axis dot com>
* Copyright (C) 2015 Centricular Ltd
* @author Tim-Philipp Müller <tim@centricular.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/check/gstcheck.h>
#include <gst/sdp/gstsdpmessage.h>
#include <gst/rtp/gstrtpbuffer.h>
#include <gst/rtp/gstrtcpbuffer.h>
#include <stdio.h>
#include <netinet/in.h>
#include "rtsp-server.h"
#define VIDEO_PIPELINE "videotestsrc ! " \
"video/x-raw,width=352,height=288 ! " \
"rtpgstpay name=pay0 pt=96"
#define AUDIO_PIPELINE "audiotestsrc ! " \
"audio/x-raw,rate=8000 ! " \
"rtpgstpay name=pay1 pt=97"
#define TEST_MOUNT_POINT "/test"
#define TEST_PROTO "RTP/AVP"
#define TEST_ENCODING "X-GST"
#define TEST_CLOCK_RATE "90000"
/* tested rtsp server */
static GstRTSPServer *server = NULL;
/* tcp port that the test server listens for rtsp requests on */
static gint test_port = 0;
/* id of the server's source within the GMainContext */
static guint source_id;
/* iterate the default main loop until there are no events to dispatch */
static void
iterate (void)
{
while (g_main_context_iteration (NULL, FALSE)) {
GST_DEBUG ("iteration");
}
}
static void
get_client_ports_full (GstRTSPRange * range, GSocket ** rtp_socket,
GSocket ** rtcp_socket)
{
GSocket *rtp = NULL;
GSocket *rtcp = NULL;
gint rtp_port = 0;
gint rtcp_port;
GInetAddress *anyaddr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4);
GSocketAddress *sockaddr;
gboolean bound;
for (;;) {
if (rtp_port != 0)
rtp_port += 2;
rtp = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM,
G_SOCKET_PROTOCOL_UDP, NULL);
fail_unless (rtp != NULL);
sockaddr = g_inet_socket_address_new (anyaddr, rtp_port);
fail_unless (sockaddr != NULL);
bound = g_socket_bind (rtp, sockaddr, FALSE, NULL);
g_object_unref (sockaddr);
if (!bound) {
g_object_unref (rtp);
continue;
}
sockaddr = g_socket_get_local_address (rtp, NULL);
fail_unless (sockaddr != NULL && G_IS_INET_SOCKET_ADDRESS (sockaddr));
rtp_port =
g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (sockaddr));
g_object_unref (sockaddr);
if (rtp_port % 2 != 0) {
rtp_port += 1;
g_object_unref (rtp);
continue;
}
rtcp_port = rtp_port + 1;
rtcp = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_DATAGRAM,
G_SOCKET_PROTOCOL_UDP, NULL);
fail_unless (rtcp != NULL);
sockaddr = g_inet_socket_address_new (anyaddr, rtcp_port);
fail_unless (sockaddr != NULL);
bound = g_socket_bind (rtcp, sockaddr, FALSE, NULL);
g_object_unref (sockaddr);
if (!bound) {
g_object_unref (rtp);
g_object_unref (rtcp);
continue;
}
sockaddr = g_socket_get_local_address (rtcp, NULL);
fail_unless (sockaddr != NULL && G_IS_INET_SOCKET_ADDRESS (sockaddr));
fail_unless (rtcp_port ==
g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (sockaddr)));
g_object_unref (sockaddr);
break;
}
range->min = rtp_port;
range->max = rtcp_port;
if (rtp_socket)
*rtp_socket = rtp;
else
g_object_unref (rtp);
if (rtcp_socket)
*rtcp_socket = rtcp;
else
g_object_unref (rtcp);
GST_DEBUG ("client_port=%d-%d", range->min, range->max);
g_object_unref (anyaddr);
}
/* get a free rtp/rtcp client port pair */
static void
get_client_ports (GstRTSPRange * range)
{
get_client_ports_full (range, NULL, NULL);
}
/* start the tested rtsp server */
static void
start_server (gboolean set_shared_factory)
{
GstRTSPMountPoints *mounts;
gchar *service;
GstRTSPMediaFactory *factory;
GstRTSPAddressPool *pool;
mounts = gst_rtsp_server_get_mount_points (server);
factory = gst_rtsp_media_factory_new ();
gst_rtsp_media_factory_set_launch (factory,
"( " VIDEO_PIPELINE " " AUDIO_PIPELINE " )");
gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT, factory);
g_object_unref (mounts);
/* use an address pool for multicast */
pool = gst_rtsp_address_pool_new ();
gst_rtsp_address_pool_add_range (pool,
"224.3.0.0", "224.3.0.10", 5500, 5510, 16);
gst_rtsp_address_pool_add_range (pool, GST_RTSP_ADDRESS_POOL_ANY_IPV4,
GST_RTSP_ADDRESS_POOL_ANY_IPV4, 6000, 6010, 0);
gst_rtsp_media_factory_set_address_pool (factory, pool);
gst_rtsp_media_factory_set_shared (factory, set_shared_factory);
gst_object_unref (pool);
/* set port to any */
gst_rtsp_server_set_service (server, "0");
/* attach to default main context */
source_id = gst_rtsp_server_attach (server, NULL);
fail_if (source_id == 0);
/* get port */
service = gst_rtsp_server_get_service (server);
test_port = atoi (service);
fail_unless (test_port != 0);
g_free (service);
GST_DEBUG ("rtsp server listening on port %d", test_port);
}
static void
start_tcp_server (void)
{
GstRTSPMountPoints *mounts;
gchar *service;
GstRTSPMediaFactory *factory;
mounts = gst_rtsp_server_get_mount_points (server);
factory = gst_rtsp_media_factory_new ();
gst_rtsp_media_factory_set_protocols (factory, GST_RTSP_LOWER_TRANS_TCP);
gst_rtsp_media_factory_set_launch (factory,
"( " VIDEO_PIPELINE " " AUDIO_PIPELINE " )");
gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT, factory);
g_object_unref (mounts);
/* set port to any */
gst_rtsp_server_set_service (server, "0");
/* attach to default main context */
source_id = gst_rtsp_server_attach (server, NULL);
fail_if (source_id == 0);
/* get port */
service = gst_rtsp_server_get_service (server);
test_port = atoi (service);
fail_unless (test_port != 0);
g_free (service);
GST_DEBUG ("rtsp server listening on port %d", test_port);
}
/* start the testing rtsp server for RECORD mode */
static GstRTSPMediaFactory *
start_record_server (const gchar * launch_line)
{
GstRTSPMediaFactory *factory;
GstRTSPMountPoints *mounts;
gchar *service;
mounts = gst_rtsp_server_get_mount_points (server);
factory = gst_rtsp_media_factory_new ();
gst_rtsp_media_factory_set_transport_mode (factory,
GST_RTSP_TRANSPORT_MODE_RECORD);
gst_rtsp_media_factory_set_launch (factory, launch_line);
gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT, factory);
g_object_unref (mounts);
/* set port to any */
gst_rtsp_server_set_service (server, "0");
/* attach to default main context */
source_id = gst_rtsp_server_attach (server, NULL);
fail_if (source_id == 0);
/* get port */
service = gst_rtsp_server_get_service (server);
test_port = atoi (service);
fail_unless (test_port != 0);
g_free (service);
GST_DEBUG ("rtsp server listening on port %d", test_port);
return factory;
}
/* stop the tested rtsp server */
static void
stop_server (void)
{
g_source_remove (source_id);
source_id = 0;
GST_DEBUG ("rtsp server stopped");
}
/* create an rtsp connection to the server on test_port */
static GstRTSPConnection *
connect_to_server (gint port, const gchar * mount_point)
{
GstRTSPConnection *conn = NULL;
gchar *address;
gchar *uri_string;
GstRTSPUrl *url = NULL;
address = gst_rtsp_server_get_address (server);
uri_string = g_strdup_printf ("rtsp://%s:%d%s", address, port, mount_point);
g_free (address);
fail_unless (gst_rtsp_url_parse (uri_string, &url) == GST_RTSP_OK);
g_free (uri_string);
fail_unless (gst_rtsp_connection_create (url, &conn) == GST_RTSP_OK);
gst_rtsp_url_free (url);
fail_unless (gst_rtsp_connection_connect (conn, NULL) == GST_RTSP_OK);
return conn;
}
/* create an rtsp request */
static GstRTSPMessage *
create_request (GstRTSPConnection * conn, GstRTSPMethod method,
const gchar * control)
{
GstRTSPMessage *request = NULL;
gchar *base_uri;
gchar *full_uri;
base_uri = gst_rtsp_url_get_request_uri (gst_rtsp_connection_get_url (conn));
full_uri = g_strdup_printf ("%s/%s", base_uri, control ? control : "");
g_free (base_uri);
if (gst_rtsp_message_new_request (&request, method, full_uri) != GST_RTSP_OK) {
GST_DEBUG ("failed to create request object");
g_free (full_uri);
return NULL;
}
g_free (full_uri);
return request;
}
/* send an rtsp request */
static gboolean
send_request (GstRTSPConnection * conn, GstRTSPMessage * request)
{
if (gst_rtsp_connection_send (conn, request, NULL) != GST_RTSP_OK) {
GST_DEBUG ("failed to send request");
return FALSE;
}
return TRUE;
}
/* read rtsp response. response must be freed by the caller */
static GstRTSPMessage *
read_response (GstRTSPConnection * conn)
{
GstRTSPMessage *response = NULL;
GstRTSPMsgType type;
if (gst_rtsp_message_new (&response) != GST_RTSP_OK) {
GST_DEBUG ("failed to create response object");
return NULL;
}
if (gst_rtsp_connection_receive (conn, response, NULL) != GST_RTSP_OK) {
GST_DEBUG ("failed to read response");
gst_rtsp_message_free (response);
return NULL;
}
type = gst_rtsp_message_get_type (response);
fail_unless (type == GST_RTSP_MESSAGE_RESPONSE || type == GST_RTSP_MESSAGE_DATA);
return response;
}
/* send an rtsp request and receive response. gchar** parameters are out
* parameters that have to be freed by the caller */
static GstRTSPStatusCode
do_request_full (GstRTSPConnection * conn, GstRTSPMethod method,
const gchar * control, const gchar * session_in, const gchar * transport_in,
const gchar * range_in, const gchar * require_in,
gchar ** content_type, gchar ** content_base, gchar ** body,
gchar ** session_out, gchar ** transport_out, gchar ** range_out,
gchar ** unsupported_out)
{
GstRTSPMessage *request;
GstRTSPMessage *response;
GstRTSPStatusCode code;
gchar *value;
GstRTSPMsgType msg_type;
/* create request */
request = create_request (conn, method, control);
/* add headers */
if (session_in) {
gst_rtsp_message_add_header (request, GST_RTSP_HDR_SESSION, session_in);
}
if (transport_in) {
gst_rtsp_message_add_header (request, GST_RTSP_HDR_TRANSPORT, transport_in);
}
if (range_in) {
gst_rtsp_message_add_header (request, GST_RTSP_HDR_RANGE, range_in);
}
if (require_in) {
gst_rtsp_message_add_header (request, GST_RTSP_HDR_REQUIRE, require_in);
}
/* send request */
fail_unless (send_request (conn, request));
gst_rtsp_message_free (request);
iterate ();
/* read response */
response = read_response (conn);
fail_unless (response != NULL);
msg_type = gst_rtsp_message_get_type (response);
if (msg_type == GST_RTSP_MESSAGE_DATA) {
do {
gst_rtsp_message_free (response);
response = read_response (conn);
msg_type = gst_rtsp_message_get_type (response);
} while (msg_type == GST_RTSP_MESSAGE_DATA);
}
fail_unless (msg_type == GST_RTSP_MESSAGE_RESPONSE);
/* check status line */
gst_rtsp_message_parse_response (response, &code, NULL, NULL);
if (code != GST_RTSP_STS_OK) {
if (unsupported_out != NULL && code == GST_RTSP_STS_OPTION_NOT_SUPPORTED) {
gst_rtsp_message_get_header (response, GST_RTSP_HDR_UNSUPPORTED,
&value, 0);
*unsupported_out = g_strdup (value);
}
gst_rtsp_message_free (response);
return code;
}
/* get information from response */
if (content_type) {
gst_rtsp_message_get_header (response, GST_RTSP_HDR_CONTENT_TYPE,
&value, 0);
*content_type = g_strdup (value);
}
if (content_base) {
gst_rtsp_message_get_header (response, GST_RTSP_HDR_CONTENT_BASE,
&value, 0);
*content_base = g_strdup (value);
}
if (body) {
*body = g_malloc (response->body_size + 1);
strncpy (*body, (gchar *) response->body, response->body_size);
}
if (session_out) {
gst_rtsp_message_get_header (response, GST_RTSP_HDR_SESSION, &value, 0);
value = g_strdup (value);
/* Remove the timeout */
if (value) {
char *pos = strchr (value, ';');
if (pos)
*pos = 0;
}
if (session_in) {
/* check that we got the same session back */
fail_unless (!g_strcmp0 (value, session_in));
}
*session_out = value;
}
if (transport_out) {
gst_rtsp_message_get_header (response, GST_RTSP_HDR_TRANSPORT, &value, 0);
*transport_out = g_strdup (value);
}
if (range_out) {
gst_rtsp_message_get_header (response, GST_RTSP_HDR_RANGE, &value, 0);
*range_out = g_strdup (value);
}
gst_rtsp_message_free (response);
return code;
}
/* send an rtsp request and receive response. gchar** parameters are out
* parameters that have to be freed by the caller */
static GstRTSPStatusCode
do_request (GstRTSPConnection * conn, GstRTSPMethod method,
const gchar * control, const gchar * session_in,
const gchar * transport_in, const gchar * range_in,
gchar ** content_type, gchar ** content_base, gchar ** body,
gchar ** session_out, gchar ** transport_out, gchar ** range_out)
{
return do_request_full (conn, method, control, session_in, transport_in,
range_in, NULL, content_type, content_base, body, session_out,
transport_out, range_out, NULL);
}
/* send an rtsp request with a method and a session, and receive response */
static GstRTSPStatusCode
do_simple_request (GstRTSPConnection * conn, GstRTSPMethod method,
const gchar * session)
{
return do_request (conn, method, NULL, session, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL);
}
/* send a DESCRIBE request and receive response. returns a received
* GstSDPMessage that must be freed by the caller */
static GstSDPMessage *
do_describe (GstRTSPConnection * conn, const gchar * mount_point)
{
GstSDPMessage *sdp_message;
gchar *content_type = NULL;
gchar *content_base = NULL;
gchar *body = NULL;
gchar *address;
gchar *expected_content_base;
/* send DESCRIBE request */
fail_unless (do_request (conn, GST_RTSP_DESCRIBE, NULL, NULL, NULL, NULL,
&content_type, &content_base, &body, NULL, NULL, NULL) ==
GST_RTSP_STS_OK);
/* check response values */
fail_unless (!g_strcmp0 (content_type, "application/sdp"));
address = gst_rtsp_server_get_address (server);
expected_content_base =
g_strdup_printf ("rtsp://%s:%d%s/", address, test_port, mount_point);
fail_unless (!g_strcmp0 (content_base, expected_content_base));
/* create sdp message */
fail_unless (gst_sdp_message_new (&sdp_message) == GST_SDP_OK);
fail_unless (gst_sdp_message_parse_buffer ((guint8 *) body,
strlen (body), sdp_message) == GST_SDP_OK);
/* clean up */
g_free (content_type);
g_free (content_base);
g_free (body);
g_free (address);
g_free (expected_content_base);
return sdp_message;
}
/* send a SETUP request and receive response. if *session is not NULL,
* it is used in the request. otherwise, *session is set to a returned
* session string that must be freed by the caller. the returned
* transport must be freed by the caller. */
static GstRTSPStatusCode
do_setup_full (GstRTSPConnection * conn, const gchar * control,
GstRTSPLowerTrans lower_transport, const GstRTSPRange * client_ports,
const gchar * require, gchar ** session, GstRTSPTransport ** transport,
gchar ** unsupported)
{
GstRTSPStatusCode code;
gchar *session_in = NULL;
GString *transport_string_in = NULL;
gchar **session_out = NULL;
gchar *transport_string_out = NULL;
/* prepare and send SETUP request */
if (session) {
if (*session) {
session_in = *session;
} else {
session_out = session;
}
}
transport_string_in = g_string_new (TEST_PROTO);
switch (lower_transport) {
case GST_RTSP_LOWER_TRANS_UDP:
transport_string_in =
g_string_append (transport_string_in, "/UDP;unicast");
break;
case GST_RTSP_LOWER_TRANS_UDP_MCAST:
transport_string_in =
g_string_append (transport_string_in, "/UDP;multicast");
break;
case GST_RTSP_LOWER_TRANS_TCP:
transport_string_in =
g_string_append (transport_string_in, "/TCP;unicast");
break;
default:
g_assert_not_reached ();
break;
}
if (client_ports) {
g_string_append_printf (transport_string_in, ";client_port=%d-%d",
client_ports->min, client_ports->max);
}
code =
do_request_full (conn, GST_RTSP_SETUP, control, session_in,
transport_string_in->str, NULL, require, NULL, NULL, NULL, session_out,
&transport_string_out, NULL, unsupported);
g_string_free (transport_string_in, TRUE);
if (transport_string_out) {
/* create transport */
fail_unless (gst_rtsp_transport_new (transport) == GST_RTSP_OK);
fail_unless (gst_rtsp_transport_parse (transport_string_out,
*transport) == GST_RTSP_OK);
g_free (transport_string_out);
}
GST_INFO ("code=%d", code);
return code;
}
/* send a SETUP request and receive response. if *session is not NULL,
* it is used in the request. otherwise, *session is set to a returned
* session string that must be freed by the caller. the returned
* transport must be freed by the caller. */
static GstRTSPStatusCode
do_setup (GstRTSPConnection * conn, const gchar * control,
const GstRTSPRange * client_ports, gchar ** session,
GstRTSPTransport ** transport)
{
return do_setup_full (conn, control, GST_RTSP_LOWER_TRANS_UDP, client_ports,
NULL, session, transport, NULL);
}
/* fixture setup function */
static void
setup (void)
{
server = gst_rtsp_server_new ();
}
/* fixture clean-up function */
static void
teardown (void)
{
if (server) {
g_object_unref (server);
server = NULL;
}
test_port = 0;
}
GST_START_TEST (test_connect)
{
GstRTSPConnection *conn;
start_server (FALSE);
/* connect to server */
conn = connect_to_server (test_port, TEST_MOUNT_POINT);
/* clean up */
gst_rtsp_connection_free (conn);
stop_server ();
/* iterate so the clean-up can finish */
iterate ();
}
GST_END_TEST;
GST_START_TEST (test_describe)
{
GstRTSPConnection *conn;
GstSDPMessage *sdp_message = NULL;
const GstSDPMedia *sdp_media;
gint32 format;
gchar *expected_rtpmap;
const gchar *rtpmap;
const gchar *control_video;
const gchar *control_audio;
start_server (FALSE);
conn = connect_to_server (test_port, TEST_MOUNT_POINT);
/* send DESCRIBE request */
sdp_message = do_describe (conn, TEST_MOUNT_POINT);
fail_unless (gst_sdp_message_medias_len (sdp_message) == 2);
/* check video sdp */
sdp_media = gst_sdp_message_get_media (sdp_message, 0);
fail_unless (!g_strcmp0 (gst_sdp_media_get_proto (sdp_media), TEST_PROTO));
fail_unless (gst_sdp_media_formats_len (sdp_media) == 1);
sscanf (gst_sdp_media_get_format (sdp_media, 0), "%" G_GINT32_FORMAT,
&format);
expected_rtpmap =
g_strdup_printf ("%d " TEST_ENCODING "/" TEST_CLOCK_RATE, format);
rtpmap = gst_sdp_media_get_attribute_val (sdp_media, "rtpmap");
fail_unless (!g_strcmp0 (rtpmap, expected_rtpmap));
g_free (expected_rtpmap);
control_video = gst_sdp_media_get_attribute_val (sdp_media, "control");
fail_unless (!g_strcmp0 (control_video, "stream=0"));
/* check audio sdp */
sdp_media = gst_sdp_message_get_media (sdp_message, 1);
fail_unless (!g_strcmp0 (gst_sdp_media_get_proto (sdp_media), TEST_PROTO));
fail_unless (gst_sdp_media_formats_len (sdp_media) == 1);
sscanf (gst_sdp_media_get_format (sdp_media, 0), "%" G_GINT32_FORMAT,
&format);
expected_rtpmap =
g_strdup_printf ("%d " TEST_ENCODING "/" TEST_CLOCK_RATE, format);
rtpmap = gst_sdp_media_get_attribute_val (sdp_media, "rtpmap");
fail_unless (!g_strcmp0 (rtpmap, expected_rtpmap));
g_free (expected_rtpmap);
control_audio = gst_sdp_media_get_attribute_val (sdp_media, "control");
fail_unless (!g_strcmp0 (control_audio, "stream=1"));
/* clean up and iterate so the clean-up can finish */
gst_sdp_message_free (sdp_message);
gst_rtsp_connection_free (conn);
stop_server ();
iterate ();
}
GST_END_TEST;
GST_START_TEST (test_describe_record_media)
{
GstRTSPConnection *conn;
start_record_server ("( fakesink name=depay0 )");
conn = connect_to_server (test_port, TEST_MOUNT_POINT);
/* send DESCRIBE request */
fail_unless_equals_int (do_request (conn, GST_RTSP_DESCRIBE, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL),
GST_RTSP_STS_METHOD_NOT_ALLOWED);
/* clean up and iterate so the clean-up can finish */
gst_rtsp_connection_free (conn);
stop_server ();
iterate ();
}
GST_END_TEST;
GST_START_TEST (test_describe_non_existing_mount_point)
{
GstRTSPConnection *conn;
start_server (FALSE);
/* send DESCRIBE request for a non-existing mount point
* and check that we get a 404 Not Found */
conn = connect_to_server (test_port, "/non-existing");
fail_unless (do_simple_request (conn, GST_RTSP_DESCRIBE, NULL)
== GST_RTSP_STS_NOT_FOUND);
/* clean up and iterate so the clean-up can finish */
gst_rtsp_connection_free (conn);
stop_server ();
iterate ();
}
GST_END_TEST;
static void
do_test_setup (GstRTSPLowerTrans lower_transport)
{
GstRTSPConnection *conn;
GstSDPMessage *sdp_message = NULL;
const GstSDPMedia *sdp_media;
const gchar *video_control;
const gchar *audio_control;
GstRTSPRange client_ports = { 0 };
gchar *session = NULL;
GstRTSPTransport *video_transport = NULL;
GstRTSPTransport *audio_transport = NULL;
start_server (FALSE);
conn = connect_to_server (test_port, TEST_MOUNT_POINT);
sdp_message = do_describe (conn, TEST_MOUNT_POINT);
/* get control strings from DESCRIBE response */
fail_unless (gst_sdp_message_medias_len (sdp_message) == 2);
sdp_media = gst_sdp_message_get_media (sdp_message, 0);
video_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
sdp_media = gst_sdp_message_get_media (sdp_message, 1);
audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
get_client_ports (&client_ports);
/* send SETUP request for video */
fail_unless (do_setup_full (conn, video_control, lower_transport,
&client_ports, NULL, &session, &video_transport,
NULL) == GST_RTSP_STS_OK);
GST_DEBUG ("set up video %s, got session '%s'", video_control, session);
/* check response from SETUP */
fail_unless (video_transport->trans == GST_RTSP_TRANS_RTP);
fail_unless (video_transport->profile == GST_RTSP_PROFILE_AVP);
fail_unless (video_transport->lower_transport == lower_transport);
fail_unless (video_transport->mode_play);
gst_rtsp_transport_free (video_transport);
/* send SETUP request for audio */
fail_unless (do_setup_full (conn, audio_control, lower_transport,
&client_ports, NULL, &session, &audio_transport,
NULL) == GST_RTSP_STS_OK);
GST_DEBUG ("set up audio %s with session '%s'", audio_control, session);
/* check response from SETUP */
fail_unless (audio_transport->trans == GST_RTSP_TRANS_RTP);
fail_unless (audio_transport->profile == GST_RTSP_PROFILE_AVP);
fail_unless (audio_transport->lower_transport == lower_transport);
fail_unless (audio_transport->mode_play);
gst_rtsp_transport_free (audio_transport);
/* send TEARDOWN request and check that we get 200 OK */
fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN,
session) == GST_RTSP_STS_OK);
/* clean up and iterate so the clean-up can finish */
g_free (session);
gst_sdp_message_free (sdp_message);
gst_rtsp_connection_free (conn);
stop_server ();
iterate ();
}
GST_START_TEST (test_setup_udp)
{
do_test_setup (GST_RTSP_LOWER_TRANS_UDP);
}
GST_END_TEST;
GST_START_TEST (test_setup_tcp)
{
do_test_setup (GST_RTSP_LOWER_TRANS_TCP);
}
GST_END_TEST;
GST_START_TEST (test_setup_udp_mcast)
{
do_test_setup (GST_RTSP_LOWER_TRANS_UDP_MCAST);
}
GST_END_TEST;
GST_START_TEST (test_setup_twice)
{
GstRTSPConnection *conn;
GstSDPMessage *sdp_message;
const GstSDPMedia *sdp_media;
const gchar *video_control;
GstRTSPRange client_ports;
GstRTSPTransport *video_transport = NULL;
gchar *session1 = NULL;
gchar *session2 = NULL;
start_server (FALSE);
conn = connect_to_server (test_port, TEST_MOUNT_POINT);
/* we wan't more than one session for this connection */
gst_rtsp_connection_set_remember_session_id (conn, FALSE);
sdp_message = do_describe (conn, TEST_MOUNT_POINT);
/* get the control url */
fail_unless (gst_sdp_message_medias_len (sdp_message) == 2);
sdp_media = gst_sdp_message_get_media (sdp_message, 0);
video_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
get_client_ports (&client_ports);
/* send SETUP request for one session */
fail_unless (do_setup (conn, video_control, &client_ports, &session1,
&video_transport) == GST_RTSP_STS_OK);
GST_DEBUG ("set up video %s, got session '%s'", video_control, session1);
/* check response from SETUP */
fail_unless (video_transport->trans == GST_RTSP_TRANS_RTP);
fail_unless (video_transport->profile == GST_RTSP_PROFILE_AVP);
fail_unless (video_transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP);
fail_unless (video_transport->mode_play);
gst_rtsp_transport_free (video_transport);
/* send SETUP request for another session */
fail_unless (do_setup (conn, video_control, &client_ports, &session2,
&video_transport) == GST_RTSP_STS_OK);
GST_DEBUG ("set up video %s, got session '%s'", video_control, session2);
/* check response from SETUP */
fail_unless (video_transport->trans == GST_RTSP_TRANS_RTP);
fail_unless (video_transport->profile == GST_RTSP_PROFILE_AVP);
fail_unless (video_transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP);
fail_unless (video_transport->mode_play);
gst_rtsp_transport_free (video_transport);
/* session can not be the same */
fail_unless (strcmp (session1, session2));
/* send TEARDOWN request for the first session */
fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN,
session1) == GST_RTSP_STS_OK);
/* send TEARDOWN request for the second session */
fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN,
session2) == GST_RTSP_STS_OK);
g_free (session1);
g_free (session2);
gst_sdp_message_free (sdp_message);
gst_rtsp_connection_free (conn);
stop_server ();
iterate ();
}
GST_END_TEST;
GST_START_TEST (test_setup_with_require_header)
{
GstRTSPConnection *conn;
GstSDPMessage *sdp_message = NULL;
const GstSDPMedia *sdp_media;
const gchar *video_control;
GstRTSPRange client_ports;
gchar *session = NULL;
gchar *unsupported = NULL;
GstRTSPTransport *video_transport = NULL;
start_server (FALSE);
conn = connect_to_server (test_port, TEST_MOUNT_POINT);
sdp_message = do_describe (conn, TEST_MOUNT_POINT);
/* get control strings from DESCRIBE response */
fail_unless (gst_sdp_message_medias_len (sdp_message) == 2);
sdp_media = gst_sdp_message_get_media (sdp_message, 0);
video_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
get_client_ports (&client_ports);
/* send SETUP request for video, with single Require header */
fail_unless_equals_int (do_setup_full (conn, video_control,
GST_RTSP_LOWER_TRANS_UDP, &client_ports, "funky-feature", &session,
&video_transport, &unsupported), GST_RTSP_STS_OPTION_NOT_SUPPORTED);
fail_unless_equals_string (unsupported, "funky-feature");
g_free (unsupported);
unsupported = NULL;
/* send SETUP request for video, with multiple Require headers */
fail_unless_equals_int (do_setup_full (conn, video_control,
GST_RTSP_LOWER_TRANS_UDP, &client_ports,
"funky-feature, foo-bar, superburst", &session, &video_transport,
&unsupported), GST_RTSP_STS_OPTION_NOT_SUPPORTED);
fail_unless_equals_string (unsupported, "funky-feature, foo-bar, superburst");
g_free (unsupported);
unsupported = NULL;
/* ok, just do a normal setup then (make sure that still works) */
fail_unless_equals_int (do_setup (conn, video_control, &client_ports,
&session, &video_transport), GST_RTSP_STS_OK);
GST_DEBUG ("set up video %s, got session '%s'", video_control, session);
/* check response from SETUP */
fail_unless (video_transport->trans == GST_RTSP_TRANS_RTP);
fail_unless (video_transport->profile == GST_RTSP_PROFILE_AVP);
fail_unless (video_transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP);
fail_unless (video_transport->mode_play);
gst_rtsp_transport_free (video_transport);
/* send TEARDOWN request and check that we get 200 OK */
fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN,
session) == GST_RTSP_STS_OK);
/* clean up and iterate so the clean-up can finish */
g_free (session);
gst_sdp_message_free (sdp_message);
gst_rtsp_connection_free (conn);
stop_server ();
iterate ();
}
GST_END_TEST;
GST_START_TEST (test_setup_non_existing_stream)
{
GstRTSPConnection *conn;
GstRTSPRange client_ports;
start_server (FALSE);
conn = connect_to_server (test_port, TEST_MOUNT_POINT);
get_client_ports (&client_ports);
/* send SETUP request with a non-existing stream and check that we get a
* 404 Not Found */
fail_unless (do_setup (conn, "stream=7", &client_ports, NULL,
NULL) == GST_RTSP_STS_NOT_FOUND);
/* clean up and iterate so the clean-up can finish */
gst_rtsp_connection_free (conn);
stop_server ();
iterate ();
}
GST_END_TEST;
static void
receive_rtp (GSocket * socket, GSocketAddress ** addr)
{
GstBuffer *buffer = gst_buffer_new_allocate (NULL, 65536, NULL);
for (;;) {
gssize bytes;
GstMapInfo map = GST_MAP_INFO_INIT;
GstRTPBuffer rtpbuffer = GST_RTP_BUFFER_INIT;
gst_buffer_map (buffer, &map, GST_MAP_WRITE);
bytes = g_socket_receive_from (socket, addr, (gchar *) map.data,
map.maxsize, NULL, NULL);
fail_unless (bytes > 0);
gst_buffer_unmap (buffer, &map);
gst_buffer_set_size (buffer, bytes);
if (gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtpbuffer)) {
gst_rtp_buffer_unmap (&rtpbuffer);
break;
}
if (addr)
g_clear_object (addr);
}
gst_buffer_unref (buffer);
}
static void
receive_rtcp (GSocket * socket, GSocketAddress ** addr, GstRTCPType type)
{
GstBuffer *buffer = gst_buffer_new_allocate (NULL, 65536, NULL);
for (;;) {
gssize bytes;
GstMapInfo map = GST_MAP_INFO_INIT;
gst_buffer_map (buffer, &map, GST_MAP_WRITE);
bytes = g_socket_receive_from (socket, addr, (gchar *) map.data,
map.maxsize, NULL, NULL);
fail_unless (bytes > 0);
gst_buffer_unmap (buffer, &map);
gst_buffer_set_size (buffer, bytes);
if (gst_rtcp_buffer_validate (buffer)) {
GstRTCPBuffer rtcpbuffer = GST_RTCP_BUFFER_INIT;
GstRTCPPacket packet;
if (type) {
fail_unless (gst_rtcp_buffer_map (buffer, GST_MAP_READ, &rtcpbuffer));
fail_unless (gst_rtcp_buffer_get_first_packet (&rtcpbuffer, &packet));
do {
if (gst_rtcp_packet_get_type (&packet) == type) {
gst_rtcp_buffer_unmap (&rtcpbuffer);
goto done;
}
} while (gst_rtcp_packet_move_to_next (&packet));
gst_rtcp_buffer_unmap (&rtcpbuffer);
} else {
break;
}
}
if (addr)
g_clear_object (addr);
}
done:
gst_buffer_unref (buffer);
}
static void
do_test_play_tcp_full (const gchar * range)
{
GstRTSPConnection *conn;
GstSDPMessage *sdp_message = NULL;
const GstSDPMedia *sdp_media;
const gchar *video_control;
const gchar *audio_control;
GstRTSPRange client_port;
gchar *session = NULL;
GstRTSPTransport *video_transport = NULL;
GstRTSPTransport *audio_transport = NULL;
gchar *range_out = NULL;
GstRTSPLowerTrans lower_transport = GST_RTSP_LOWER_TRANS_TCP;
conn = connect_to_server (test_port, TEST_MOUNT_POINT);
sdp_message = do_describe (conn, TEST_MOUNT_POINT);
get_client_ports (&client_port);
/* get control strings from DESCRIBE response */
fail_unless (gst_sdp_message_medias_len (sdp_message) == 2);
sdp_media = gst_sdp_message_get_media (sdp_message, 0);
video_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
sdp_media = gst_sdp_message_get_media (sdp_message, 1);
audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
/* do SETUP for video and audio */
fail_unless (do_setup_full (conn, video_control, lower_transport,
&client_port, NULL, &session, &video_transport,
NULL) == GST_RTSP_STS_OK);
fail_unless (do_setup_full (conn, audio_control, lower_transport,
&client_port, NULL, &session, &audio_transport,
NULL) == GST_RTSP_STS_OK);
/* send PLAY request and check that we get 200 OK */
fail_unless (do_request (conn, GST_RTSP_PLAY, NULL, session, NULL, range,
NULL, NULL, NULL, NULL, NULL, &range_out) == GST_RTSP_STS_OK);
if (range)
fail_unless_equals_string (range, range_out);
g_free (range_out);
{
GstRTSPMessage *message;
fail_unless (gst_rtsp_message_new (&message) == GST_RTSP_OK);
fail_unless (gst_rtsp_connection_receive (conn, message, NULL) == GST_RTSP_OK);
fail_unless (gst_rtsp_message_get_type (message) == GST_RTSP_MESSAGE_DATA);
gst_rtsp_message_free (message);
}
/* send TEARDOWN request and check that we get 200 OK */
fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN,
session) == GST_RTSP_STS_OK);
/* FIXME: The rtsp-server always disconnects the transport before
* sending the RTCP BYE
* receive_rtcp (rtcp_socket, NULL, GST_RTCP_TYPE_BYE);
*/
/* clean up and iterate so the clean-up can finish */
g_free (session);
gst_rtsp_transport_free (video_transport);
gst_rtsp_transport_free (audio_transport);
gst_sdp_message_free (sdp_message);
gst_rtsp_connection_free (conn);
}
static void
do_test_play_full (const gchar * range, GstRTSPLowerTrans lower_transport,
GMutex * lock)
{
GstRTSPConnection *conn;
GstSDPMessage *sdp_message = NULL;
const GstSDPMedia *sdp_media;
const gchar *video_control;
const gchar *audio_control;
GstRTSPRange client_port;
gchar *session = NULL;
GstRTSPTransport *video_transport = NULL;
GstRTSPTransport *audio_transport = NULL;
GSocket *rtp_socket, *rtcp_socket;
gchar *range_out = NULL;
conn = connect_to_server (test_port, TEST_MOUNT_POINT);
sdp_message = do_describe (conn, TEST_MOUNT_POINT);
/* get control strings from DESCRIBE response */
fail_unless (gst_sdp_message_medias_len (sdp_message) == 2);
sdp_media = gst_sdp_message_get_media (sdp_message, 0);
video_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
sdp_media = gst_sdp_message_get_media (sdp_message, 1);
audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
get_client_ports_full (&client_port, &rtp_socket, &rtcp_socket);
/* do SETUP for video and audio */
fail_unless (do_setup_full (conn, video_control, lower_transport,
&client_port, NULL, &session, &video_transport,
NULL) == GST_RTSP_STS_OK);
fail_unless (do_setup_full (conn, audio_control, lower_transport,
&client_port, NULL, &session, &audio_transport,
NULL) == GST_RTSP_STS_OK);
/* send PLAY request and check that we get 200 OK */
fail_unless (do_request (conn, GST_RTSP_PLAY, NULL, session, NULL, range,
NULL, NULL, NULL, NULL, NULL, &range_out) == GST_RTSP_STS_OK);
if (range)
fail_unless_equals_string (range, range_out);
g_free (range_out);
for (;;) {
receive_rtp (rtp_socket, NULL);
receive_rtcp (rtcp_socket, NULL, 0);
if (lock != NULL) {
if (g_mutex_trylock (lock) == TRUE) {
g_mutex_unlock (lock);
break;
}
} else {
break;
}
}
/* send TEARDOWN request and check that we get 200 OK */
fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN,
session) == GST_RTSP_STS_OK);
/* FIXME: The rtsp-server always disconnects the transport before
* sending the RTCP BYE
* receive_rtcp (rtcp_socket, NULL, GST_RTCP_TYPE_BYE);
*/
/* clean up and iterate so the clean-up can finish */
g_object_unref (rtp_socket);
g_object_unref (rtcp_socket);
g_free (session);
gst_rtsp_transport_free (video_transport);
gst_rtsp_transport_free (audio_transport);
gst_sdp_message_free (sdp_message);
gst_rtsp_connection_free (conn);
}
static void
do_test_play (const gchar * range)
{
do_test_play_full (range, GST_RTSP_LOWER_TRANS_UDP, NULL);
}
GST_START_TEST (test_play)
{
start_server (FALSE);
do_test_play (NULL);
stop_server ();
iterate ();
}
GST_END_TEST;
GST_START_TEST (test_play_tcp)
{
GstRTSPConnection *conn;
GstSDPMessage *sdp_message = NULL;
const GstSDPMedia *sdp_media;
const gchar *video_control;
const gchar *audio_control;
GstRTSPRange client_ports = { 0 };
gchar *session = NULL;
GstRTSPTransport *video_transport = NULL;
GstRTSPTransport *audio_transport = NULL;
start_tcp_server ();
conn = connect_to_server (test_port, TEST_MOUNT_POINT);
/* send DESCRIBE request */
sdp_message = do_describe (conn, TEST_MOUNT_POINT);
/* get control strings from DESCRIBE response */
fail_unless (gst_sdp_message_medias_len (sdp_message) == 2);
sdp_media = gst_sdp_message_get_media (sdp_message, 0);
video_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
sdp_media = gst_sdp_message_get_media (sdp_message, 1);
audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
get_client_ports (&client_ports);
/* send SETUP request for the first media */
fail_unless (do_setup_full (conn, video_control, GST_RTSP_LOWER_TRANS_TCP,
&client_ports, NULL, &session, &video_transport,
NULL) == GST_RTSP_STS_OK);
/* check response from SETUP */
fail_unless (video_transport->trans == GST_RTSP_TRANS_RTP);
fail_unless (video_transport->profile == GST_RTSP_PROFILE_AVP);
fail_unless (video_transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP);
fail_unless (video_transport->mode_play);
gst_rtsp_transport_free (video_transport);
/* send SETUP request for the second media */
fail_unless (do_setup_full (conn, audio_control, GST_RTSP_LOWER_TRANS_TCP,
&client_ports, NULL, &session, &audio_transport,
NULL) == GST_RTSP_STS_OK);
/* check response from SETUP */
fail_unless (audio_transport->trans == GST_RTSP_TRANS_RTP);
fail_unless (audio_transport->profile == GST_RTSP_PROFILE_AVP);
fail_unless (audio_transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP);
fail_unless (audio_transport->mode_play);
gst_rtsp_transport_free (audio_transport);
/* send PLAY request and check that we get 200 OK */
fail_unless (do_simple_request (conn, GST_RTSP_PLAY,
session)== GST_RTSP_STS_OK);
/* send TEARDOWN request and check that we get 200 OK */
fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN,
session) == GST_RTSP_STS_OK);
/* clean up and iterate so the clean-up can finish */
g_free (session);
gst_sdp_message_free (sdp_message);
gst_rtsp_connection_free (conn);
stop_server ();
iterate ();
}
GST_END_TEST;
GST_START_TEST (test_play_without_session)
{
GstRTSPConnection *conn;
start_server (FALSE);
conn = connect_to_server (test_port, TEST_MOUNT_POINT);
/* send PLAY request without a session and check that we get a
* 454 Session Not Found */
fail_unless (do_simple_request (conn, GST_RTSP_PLAY,
NULL) == GST_RTSP_STS_SESSION_NOT_FOUND);
/* clean up and iterate so the clean-up can finish */
gst_rtsp_connection_free (conn);
stop_server ();
iterate ();
}
GST_END_TEST;
GST_START_TEST (test_bind_already_in_use)
{
GstRTSPServer *serv;
GSocketService *service;
GError *error = NULL;
guint16 port;
gchar *port_str;
serv = gst_rtsp_server_new ();
service = g_socket_service_new ();
/* bind service to port */
port =
g_socket_listener_add_any_inet_port (G_SOCKET_LISTENER (service), NULL,
&error);
g_assert_no_error (error);
port_str = g_strdup_printf ("%d\n", port);
/* try to bind server to the same port */
g_object_set (serv, "service", port_str, NULL);
g_free (port_str);
/* attach to default main context */
fail_unless (gst_rtsp_server_attach (serv, NULL) == 0);
/* cleanup */
g_object_unref (serv);
g_socket_service_stop (service);
g_object_unref (service);
}
GST_END_TEST;
GST_START_TEST (test_play_multithreaded)
{
GstRTSPThreadPool *pool;
pool = gst_rtsp_server_get_thread_pool (server);
gst_rtsp_thread_pool_set_max_threads (pool, 2);
g_object_unref (pool);
start_server (FALSE);
do_test_play (NULL);
stop_server ();
iterate ();
}
GST_END_TEST;
enum
{
BLOCK_ME,
BLOCKED,
UNBLOCK
};
static void
media_constructed_block (GstRTSPMediaFactory * factory,
GstRTSPMedia * media, gpointer user_data)
{
gint *block_state = user_data;
g_mutex_lock (&check_mutex);
*block_state = BLOCKED;
g_cond_broadcast (&check_cond);
while (*block_state != UNBLOCK)
g_cond_wait (&check_cond, &check_mutex);
g_mutex_unlock (&check_mutex);
}
GST_START_TEST (test_play_multithreaded_block_in_describe)
{
GstRTSPConnection *conn;
GstRTSPMountPoints *mounts;
GstRTSPMediaFactory *factory;
gint block_state = BLOCK_ME;
GstRTSPMessage *request;
GstRTSPMessage *response;
GstRTSPStatusCode code;
GstRTSPThreadPool *pool;
pool = gst_rtsp_server_get_thread_pool (server);
gst_rtsp_thread_pool_set_max_threads (pool, 2);
g_object_unref (pool);
mounts = gst_rtsp_server_get_mount_points (server);
fail_unless (mounts != NULL);
factory = gst_rtsp_media_factory_new ();
gst_rtsp_media_factory_set_launch (factory,
"( " VIDEO_PIPELINE " " AUDIO_PIPELINE " )");
g_signal_connect (factory, "media-constructed",
G_CALLBACK (media_constructed_block), &block_state);
gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT "2", factory);
g_object_unref (mounts);
start_server (FALSE);
conn = connect_to_server (test_port, TEST_MOUNT_POINT "2");
iterate ();
/* do describe, it will not return now as we've blocked it */
request = create_request (conn, GST_RTSP_DESCRIBE, NULL);
fail_unless (send_request (conn, request));
gst_rtsp_message_free (request);
g_mutex_lock (&check_mutex);
while (block_state != BLOCKED)
g_cond_wait (&check_cond, &check_mutex);
g_mutex_unlock (&check_mutex);
/* Do a second connection while the first one is blocked */
do_test_play (NULL);
/* Now unblock the describe */
g_mutex_lock (&check_mutex);
block_state = UNBLOCK;
g_cond_broadcast (&check_cond);
g_mutex_unlock (&check_mutex);
response = read_response (conn);
gst_rtsp_message_parse_response (response, &code, NULL, NULL);
fail_unless (code == GST_RTSP_STS_OK);
gst_rtsp_message_free (response);
gst_rtsp_connection_free (conn);
stop_server ();
iterate ();
}
GST_END_TEST;
static void
new_session_timeout_one (GstRTSPClient * client,
GstRTSPSession * session, gpointer user_data)
{
gst_rtsp_session_set_timeout (session, 1);
g_signal_handlers_disconnect_by_func (client, new_session_timeout_one,
user_data);
}
static void
session_connected_new_session_cb (GstRTSPServer * server,
GstRTSPClient * client, gpointer user_data)
{
g_signal_connect (client, "new-session", user_data, NULL);
}
GST_START_TEST (test_play_multithreaded_timeout_client)
{
GstRTSPConnection *conn;
GstSDPMessage *sdp_message = NULL;
const GstSDPMedia *sdp_media;
const gchar *video_control;
const gchar *audio_control;
GstRTSPRange client_port;
gchar *session = NULL;
GstRTSPTransport *video_transport = NULL;
GstRTSPTransport *audio_transport = NULL;
GstRTSPSessionPool *pool;
GstRTSPThreadPool *thread_pool;
thread_pool = gst_rtsp_server_get_thread_pool (server);
gst_rtsp_thread_pool_set_max_threads (thread_pool, 2);
g_object_unref (thread_pool);
pool = gst_rtsp_server_get_session_pool (server);
g_signal_connect (server, "client-connected",
G_CALLBACK (session_connected_new_session_cb), new_session_timeout_one);
start_server (FALSE);
conn = connect_to_server (test_port, TEST_MOUNT_POINT);
sdp_message = do_describe (conn, TEST_MOUNT_POINT);
/* get control strings from DESCRIBE response */
fail_unless (gst_sdp_message_medias_len (sdp_message) == 2);
sdp_media = gst_sdp_message_get_media (sdp_message, 0);
video_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
sdp_media = gst_sdp_message_get_media (sdp_message, 1);
audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
get_client_ports (&client_port);
/* do SETUP for video and audio */
fail_unless (do_setup_full (conn, video_control, GST_RTSP_LOWER_TRANS_UDP,
&client_port, NULL, &session, &video_transport,
NULL) == GST_RTSP_STS_OK);
fail_unless (do_setup_full (conn, audio_control, GST_RTSP_LOWER_TRANS_UDP,
&client_port, NULL, &session, &audio_transport,
NULL) == GST_RTSP_STS_OK);
fail_unless (gst_rtsp_session_pool_get_n_sessions (pool) == 1);
/* send PLAY request and check that we get 200 OK */
fail_unless (do_simple_request (conn, GST_RTSP_PLAY,
session) == GST_RTSP_STS_OK);
sleep (7);
fail_unless (gst_rtsp_session_pool_cleanup (pool) == 1);
fail_unless (gst_rtsp_session_pool_get_n_sessions (pool) == 0);
/* clean up and iterate so the clean-up can finish */
g_object_unref (pool);
g_free (session);
gst_rtsp_transport_free (video_transport);
gst_rtsp_transport_free (audio_transport);
gst_sdp_message_free (sdp_message);
gst_rtsp_connection_free (conn);
stop_server ();
iterate ();
}
GST_END_TEST;
GST_START_TEST (test_play_multithreaded_timeout_session)
{
GstRTSPConnection *conn;
GstSDPMessage *sdp_message = NULL;
const GstSDPMedia *sdp_media;
const gchar *video_control;
const gchar *audio_control;
GstRTSPRange client_port;
gchar *session1 = NULL;
gchar *session2 = NULL;
GstRTSPTransport *video_transport = NULL;
GstRTSPTransport *audio_transport = NULL;
GstRTSPSessionPool *pool;
GstRTSPThreadPool *thread_pool;
thread_pool = gst_rtsp_server_get_thread_pool (server);
gst_rtsp_thread_pool_set_max_threads (thread_pool, 2);
g_object_unref (thread_pool);
pool = gst_rtsp_server_get_session_pool (server);
g_signal_connect (server, "client-connected",
G_CALLBACK (session_connected_new_session_cb), new_session_timeout_one);
start_server (FALSE);
conn = connect_to_server (test_port, TEST_MOUNT_POINT);
gst_rtsp_connection_set_remember_session_id (conn, FALSE);
sdp_message = do_describe (conn, TEST_MOUNT_POINT);
/* get control strings from DESCRIBE response */
fail_unless (gst_sdp_message_medias_len (sdp_message) == 2);
sdp_media = gst_sdp_message_get_media (sdp_message, 0);
video_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
sdp_media = gst_sdp_message_get_media (sdp_message, 1);
audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
get_client_ports (&client_port);
/* do SETUP for video and audio */
fail_unless (do_setup (conn, video_control, &client_port, &session1,
&video_transport) == GST_RTSP_STS_OK);
fail_unless (do_setup (conn, audio_control, &client_port, &session2,
&audio_transport) == GST_RTSP_STS_OK);
fail_unless (gst_rtsp_session_pool_get_n_sessions (pool) == 2);
/* send PLAY request and check that we get 200 OK */
fail_unless (do_simple_request (conn, GST_RTSP_PLAY,
session1) == GST_RTSP_STS_OK);
fail_unless (do_simple_request (conn, GST_RTSP_PLAY,
session2) == GST_RTSP_STS_OK);
sleep (7);
fail_unless (gst_rtsp_session_pool_cleanup (pool) == 1);
/* send TEARDOWN request and check that we get 454 Session Not found */
fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN,
session1) == GST_RTSP_STS_SESSION_NOT_FOUND);
fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN,
session2) == GST_RTSP_STS_OK);
/* clean up and iterate so the clean-up can finish */
g_object_unref (pool);
g_free (session1);
g_free (session2);
gst_rtsp_transport_free (video_transport);
gst_rtsp_transport_free (audio_transport);
gst_sdp_message_free (sdp_message);
gst_rtsp_connection_free (conn);
stop_server ();
iterate ();
}
GST_END_TEST;
GST_START_TEST (test_no_session_timeout)
{
GstRTSPSession *session;
gint64 now;
gboolean is_expired;
session = gst_rtsp_session_new ("test-session");
gst_rtsp_session_set_timeout (session, 0);
now = g_get_monotonic_time ();
/* add more than the extra 5 seconds that are usually added in
* gst_rtsp_session_next_timeout_usec */
now += 7000000;
is_expired = gst_rtsp_session_is_expired_usec (session, now);
fail_unless (is_expired == FALSE);
}
GST_END_TEST;
/* media contains two streams: video and audio but only one
* stream is requested */
GST_START_TEST (test_play_one_active_stream)
{
GstRTSPConnection *conn;
GstSDPMessage *sdp_message = NULL;
const GstSDPMedia *sdp_media;
const gchar *video_control;
GstRTSPRange client_port;
gchar *session = NULL;
GstRTSPTransport *video_transport = NULL;
GstRTSPSessionPool *pool;
GstRTSPThreadPool *thread_pool;
thread_pool = gst_rtsp_server_get_thread_pool (server);
gst_rtsp_thread_pool_set_max_threads (thread_pool, 2);
g_object_unref (thread_pool);
pool = gst_rtsp_server_get_session_pool (server);
g_signal_connect (server, "client-connected",
G_CALLBACK (session_connected_new_session_cb), new_session_timeout_one);
start_server (FALSE);
conn = connect_to_server (test_port, TEST_MOUNT_POINT);
gst_rtsp_connection_set_remember_session_id (conn, FALSE);
sdp_message = do_describe (conn, TEST_MOUNT_POINT);
/* get control strings from DESCRIBE response */
fail_unless (gst_sdp_message_medias_len (sdp_message) == 2);
sdp_media = gst_sdp_message_get_media (sdp_message, 0);
video_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
get_client_ports (&client_port);
/* do SETUP for video only */
fail_unless (do_setup (conn, video_control, &client_port, &session,
&video_transport) == GST_RTSP_STS_OK);
fail_unless (gst_rtsp_session_pool_get_n_sessions (pool) == 1);
/* send PLAY request and check that we get 200 OK */
fail_unless (do_simple_request (conn, GST_RTSP_PLAY,
session) == GST_RTSP_STS_OK);
/* send TEARDOWN request */
fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN,
session) == GST_RTSP_STS_OK);
/* clean up and iterate so the clean-up can finish */
g_object_unref (pool);
g_free (session);
gst_rtsp_transport_free (video_transport);
gst_sdp_message_free (sdp_message);
gst_rtsp_connection_free (conn);
stop_server ();
iterate ();
}
GST_END_TEST;
GST_START_TEST (test_play_disconnect)
{
GstRTSPConnection *conn;
GstSDPMessage *sdp_message = NULL;
const GstSDPMedia *sdp_media;
const gchar *video_control;
const gchar *audio_control;
GstRTSPRange client_port;
gchar *session = NULL;
GstRTSPTransport *video_transport = NULL;
GstRTSPTransport *audio_transport = NULL;
GstRTSPSessionPool *pool;
pool = gst_rtsp_server_get_session_pool (server);
g_signal_connect (server, "client-connected",
G_CALLBACK (session_connected_new_session_cb), new_session_timeout_one);
start_server (FALSE);
conn = connect_to_server (test_port, TEST_MOUNT_POINT);
sdp_message = do_describe (conn, TEST_MOUNT_POINT);
/* get control strings from DESCRIBE response */
fail_unless (gst_sdp_message_medias_len (sdp_message) == 2);
sdp_media = gst_sdp_message_get_media (sdp_message, 0);
video_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
sdp_media = gst_sdp_message_get_media (sdp_message, 1);
audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
get_client_ports (&client_port);
/* do SETUP for video and audio */
fail_unless (do_setup (conn, video_control, &client_port, &session,
&video_transport) == GST_RTSP_STS_OK);
fail_unless (do_setup (conn, audio_control, &client_port, &session,
&audio_transport) == GST_RTSP_STS_OK);
fail_unless (gst_rtsp_session_pool_get_n_sessions (pool) == 1);
/* send PLAY request and check that we get 200 OK */
fail_unless (do_simple_request (conn, GST_RTSP_PLAY,
session) == GST_RTSP_STS_OK);
gst_rtsp_connection_free (conn);
sleep (7);
fail_unless (gst_rtsp_session_pool_get_n_sessions (pool) == 1);
fail_unless (gst_rtsp_session_pool_cleanup (pool) == 1);
/* clean up and iterate so the clean-up can finish */
g_object_unref (pool);
g_free (session);
gst_rtsp_transport_free (video_transport);
gst_rtsp_transport_free (audio_transport);
gst_sdp_message_free (sdp_message);
stop_server ();
iterate ();
}
GST_END_TEST;
/* Only different with test_play is the specific ports selected */
GST_START_TEST (test_play_specific_server_port)
{
GstRTSPMountPoints *mounts;
gchar *service;
GstRTSPMediaFactory *factory;
GstRTSPAddressPool *pool;
GstRTSPConnection *conn;
GstSDPMessage *sdp_message = NULL;
const GstSDPMedia *sdp_media;
const gchar *video_control;
GstRTSPRange client_port;
gchar *session = NULL;
GstRTSPTransport *video_transport = NULL;
GSocket *rtp_socket, *rtcp_socket;
GSocketAddress *rtp_address, *rtcp_address;
guint16 rtp_port, rtcp_port;
mounts = gst_rtsp_server_get_mount_points (server);
factory = gst_rtsp_media_factory_new ();
/* we have to suspend media after SDP in order to make sure that
* we can reconfigure UDP sink with new UDP ports */
gst_rtsp_media_factory_set_suspend_mode (factory,
GST_RTSP_SUSPEND_MODE_RESET);
pool = gst_rtsp_address_pool_new ();
gst_rtsp_address_pool_add_range (pool, GST_RTSP_ADDRESS_POOL_ANY_IPV4,
GST_RTSP_ADDRESS_POOL_ANY_IPV4, 7770, 7780, 0);
gst_rtsp_media_factory_set_address_pool (factory, pool);
g_object_unref (pool);
gst_rtsp_media_factory_set_launch (factory, "( " VIDEO_PIPELINE " )");
gst_rtsp_mount_points_add_factory (mounts, TEST_MOUNT_POINT, factory);
g_object_unref (mounts);
/* set port to any */
gst_rtsp_server_set_service (server, "0");
/* attach to default main context */
source_id = gst_rtsp_server_attach (server, NULL);
fail_if (source_id == 0);
/* get port */
service = gst_rtsp_server_get_service (server);
test_port = atoi (service);
fail_unless (test_port != 0);
g_free (service);
GST_DEBUG ("rtsp server listening on port %d", test_port);
conn = connect_to_server (test_port, TEST_MOUNT_POINT);
sdp_message = do_describe (conn, TEST_MOUNT_POINT);
/* get control strings from DESCRIBE response */
fail_unless (gst_sdp_message_medias_len (sdp_message) == 1);
sdp_media = gst_sdp_message_get_media (sdp_message, 0);
video_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
get_client_ports_full (&client_port, &rtp_socket, &rtcp_socket);
/* do SETUP for video */
fail_unless (do_setup (conn, video_control, &client_port, &session,
&video_transport) == GST_RTSP_STS_OK);
/* send PLAY request and check that we get 200 OK */
fail_unless (do_simple_request (conn, GST_RTSP_PLAY,
session) == GST_RTSP_STS_OK);
receive_rtp (rtp_socket, &rtp_address);
receive_rtcp (rtcp_socket, &rtcp_address, 0);
fail_unless (G_IS_INET_SOCKET_ADDRESS (rtp_address));
fail_unless (G_IS_INET_SOCKET_ADDRESS (rtcp_address));
rtp_port =
g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (rtp_address));
rtcp_port =
g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (rtcp_address));
fail_unless (rtp_port >= 7770 && rtp_port <= 7780 && rtp_port % 2 == 0);
fail_unless (rtcp_port >= 7770 && rtcp_port <= 7780 && rtcp_port % 2 == 1);
fail_unless (rtp_port + 1 == rtcp_port);
g_object_unref (rtp_address);
g_object_unref (rtcp_address);
/* send TEARDOWN request and check that we get 200 OK */
fail_unless (do_simple_request (conn, GST_RTSP_TEARDOWN,
session) == GST_RTSP_STS_OK);
/* FIXME: The rtsp-server always disconnects the transport before
* sending the RTCP BYE
* receive_rtcp (rtcp_socket, NULL, GST_RTCP_TYPE_BYE);
*/
/* clean up and iterate so the clean-up can finish */
g_object_unref (rtp_socket);
g_object_unref (rtcp_socket);
g_free (session);
gst_rtsp_transport_free (video_transport);
gst_sdp_message_free (sdp_message);
gst_rtsp_connection_free (conn);
stop_server ();
iterate ();
}
GST_END_TEST;
GST_START_TEST (test_play_smpte_range)
{
start_server (FALSE);
do_test_play ("npt=5-");
do_test_play ("smpte=0:00:00-");
do_test_play ("smpte=1:00:00-");
do_test_play ("smpte=1:00:03-");
do_test_play ("clock=20120321T152256Z-");
stop_server ();
iterate ();
}
GST_END_TEST;
GST_START_TEST (test_play_smpte_range_tcp)
{
start_tcp_server ();
do_test_play_tcp_full ("npt=5-");
do_test_play_tcp_full ("smpte=0:00:00-");
do_test_play_tcp_full ("smpte=1:00:00-");
do_test_play_tcp_full ("smpte=1:00:03-");
do_test_play_tcp_full ("clock=20120321T152256Z-");
stop_server ();
iterate ();
}
GST_END_TEST;
static gpointer
thread_func (gpointer data)
{
do_test_play_full (NULL, GST_RTSP_LOWER_TRANS_UDP, (GMutex *) data);
return NULL;
}
/* Test adding and removing clients to a 'Shared' media. */
GST_START_TEST (test_shared)
{
GMutex lock1, lock2, lock3, lock4;
GThread *thread1, *thread2, *thread3, *thread4;
/* Locks for each thread. Each thread will keep reading data as long as the
* thread is locked. */
g_mutex_init (&lock1);
g_mutex_init (&lock2);
g_mutex_init (&lock3);
g_mutex_init (&lock4);
start_server (TRUE);
/* Start the first receiver thread. */
g_mutex_lock (&lock1);
thread1 = g_thread_new ("thread1", thread_func, &lock1);
/* Connect and disconnect another client. */
g_mutex_lock (&lock2);
thread2 = g_thread_new ("thread2", thread_func, &lock2);
g_mutex_unlock (&lock2);
g_mutex_clear (&lock2);
g_thread_join (thread2);
/* Do it again. */
g_mutex_lock (&lock3);
thread3 = g_thread_new ("thread3", thread_func, &lock3);
g_mutex_unlock (&lock3);
g_mutex_clear (&lock3);
g_thread_join (thread3);
/* Disconnect the last client. This will clean up the media. */
g_mutex_unlock (&lock1);
g_mutex_clear (&lock1);
g_thread_join (thread1);
/* Connect and disconnect another client. This will create and clean up the
* media. */
g_mutex_lock (&lock4);
thread4 = g_thread_new ("thread4", thread_func, &lock4);
g_mutex_unlock (&lock4);
g_mutex_clear (&lock4);
g_thread_join (thread4);
stop_server ();
iterate ();
}
GST_END_TEST;
GST_START_TEST (test_announce_without_sdp)
{
GstRTSPConnection *conn;
GstRTSPStatusCode status;
GstRTSPMessage *request;
GstRTSPMessage *response;
start_record_server ("( fakesink name=depay0 )");
conn = connect_to_server (test_port, TEST_MOUNT_POINT);
/* create and send ANNOUNCE request */
request = create_request (conn, GST_RTSP_ANNOUNCE, NULL);
fail_unless (send_request (conn, request));
iterate ();
response = read_response (conn);
/* check response */
gst_rtsp_message_parse_response (response, &status, NULL, NULL);
fail_unless_equals_int (status, GST_RTSP_STS_BAD_REQUEST);
gst_rtsp_message_free (response);
/* try again, this type with content-type, but still no SDP */
gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE,
"application/sdp");
fail_unless (send_request (conn, request));
iterate ();
response = read_response (conn);
/* check response */
gst_rtsp_message_parse_response (response, &status, NULL, NULL);
fail_unless_equals_int (status, GST_RTSP_STS_BAD_REQUEST);
gst_rtsp_message_free (response);
/* try again, this type with an unknown content-type */
gst_rtsp_message_remove_header (request, GST_RTSP_HDR_CONTENT_TYPE, -1);
gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE,
"application/x-something");
fail_unless (send_request (conn, request));
iterate ();
response = read_response (conn);
/* check response */
gst_rtsp_message_parse_response (response, &status, NULL, NULL);
fail_unless_equals_int (status, GST_RTSP_STS_BAD_REQUEST);
gst_rtsp_message_free (response);
/* clean up and iterate so the clean-up can finish */
gst_rtsp_message_free (request);
gst_rtsp_connection_free (conn);
stop_server ();
iterate ();
}
GST_END_TEST;
static GstRTSPStatusCode
do_announce (GstRTSPConnection * conn, GstSDPMessage * sdp)
{
GstRTSPMessage *request;
GstRTSPMessage *response;
GstRTSPStatusCode code;
gchar *str;
/* create request */
request = create_request (conn, GST_RTSP_ANNOUNCE, NULL);
gst_rtsp_message_add_header (request, GST_RTSP_HDR_CONTENT_TYPE,
"application/sdp");
/* add SDP to the response body */
str = gst_sdp_message_as_text (sdp);
gst_rtsp_message_take_body (request, (guint8 *) str, strlen (str));
gst_sdp_message_free (sdp);
/* send request */
fail_unless (send_request (conn, request));
gst_rtsp_message_free (request);
iterate ();
/* read response */
response = read_response (conn);
/* check status line */
gst_rtsp_message_parse_response (response, &code, NULL, NULL);
gst_rtsp_message_free (response);
return code;
}
static void
media_constructed_cb (GstRTSPMediaFactory * mfactory, GstRTSPMedia * media,
gpointer user_data)
{
GstElement **p_sink = user_data;
GstElement *bin;
bin = gst_rtsp_media_get_element (media);
*p_sink = gst_bin_get_by_name (GST_BIN (bin), "sink");
GST_INFO ("media constructed!: %" GST_PTR_FORMAT, *p_sink);
}
#define RECORD_N_BUFS 10
GST_START_TEST (test_record_tcp)
{
GstRTSPMediaFactory *mfactory;
GstRTSPConnection *conn;
GstRTSPStatusCode status;
GstRTSPMessage *response;
GstRTSPMessage *request;
GstSDPMessage *sdp;
GstRTSPResult rres;
GSocketAddress *sa;
GInetAddress *ia;
GstElement *server_sink = NULL;
GSocket *conn_socket;
const gchar *proto;
gchar *client_ip, *sess_id, *session = NULL;
gint i;
mfactory =
start_record_server
("( rtppcmadepay name=depay0 ! appsink name=sink async=false )");
g_signal_connect (mfactory, "media-constructed",
G_CALLBACK (media_constructed_cb), &server_sink);
conn = connect_to_server (test_port, TEST_MOUNT_POINT);
conn_socket = gst_rtsp_connection_get_read_socket (conn);
sa = g_socket_get_local_address (conn_socket, NULL);
ia = g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (sa));
client_ip = g_inet_address_to_string (ia);
if (g_socket_address_get_family (sa) == G_SOCKET_FAMILY_IPV6)
proto = "IP6";
else if (g_socket_address_get_family (sa) == G_SOCKET_FAMILY_IPV4)
proto = "IP4";
else
g_assert_not_reached ();
g_object_unref (sa);
gst_sdp_message_new (&sdp);
/* some standard things first */
gst_sdp_message_set_version (sdp, "0");
/* session ID doesn't have to be super-unique in this case */
sess_id = g_strdup_printf ("%u", g_random_int ());
gst_sdp_message_set_origin (sdp, "-", sess_id, "1", "IN", proto, client_ip);
g_free (sess_id);
g_free (client_ip);
gst_sdp_message_set_session_name (sdp, "Session streamed with GStreamer");
gst_sdp_message_set_information (sdp, "rtsp-server-test");
gst_sdp_message_add_time (sdp, "0", "0", NULL);
gst_sdp_message_add_attribute (sdp, "tool", "GStreamer");
/* add stream 0 */
{
GstSDPMedia *smedia;
gst_sdp_media_new (&smedia);
gst_sdp_media_set_media (smedia, "audio");
gst_sdp_media_add_format (smedia, "8"); /* pcma/alaw */
gst_sdp_media_set_port_info (smedia, 0, 1);
gst_sdp_media_set_proto (smedia, "RTP/AVP");
gst_sdp_media_add_attribute (smedia, "rtpmap", "8 PCMA/8000");
gst_sdp_message_add_media (sdp, smedia);
gst_sdp_media_free (smedia);
}
/* send ANNOUNCE request */
status = do_announce (conn, sdp);
fail_unless_equals_int (status, GST_RTSP_STS_OK);
/* create and send SETUP request */
request = create_request (conn, GST_RTSP_SETUP, NULL);
gst_rtsp_message_add_header (request, GST_RTSP_HDR_TRANSPORT,
"RTP/AVP/TCP;interleaved=0;mode=record");
fail_unless (send_request (conn, request));
gst_rtsp_message_free (request);
iterate ();
response = read_response (conn);
gst_rtsp_message_parse_response (response, &status, NULL, NULL);
fail_unless_equals_int (status, GST_RTSP_STS_OK);
rres =
gst_rtsp_message_get_header (response, GST_RTSP_HDR_SESSION, &session, 0);
session = g_strdup (session);
fail_unless_equals_int (rres, GST_RTSP_OK);
gst_rtsp_message_free (response);
/* send RECORD */
request = create_request (conn, GST_RTSP_RECORD, NULL);
gst_rtsp_message_add_header (request, GST_RTSP_HDR_SESSION, session);
fail_unless (send_request (conn, request));
gst_rtsp_message_free (request);
iterate ();
response = read_response (conn);
gst_rtsp_message_parse_response (response, &status, NULL, NULL);
fail_unless_equals_int (status, GST_RTSP_STS_OK);
gst_rtsp_message_free (response);
/* send some data */
{
GstElement *pipeline, *src, *enc, *pay, *sink;
pipeline = gst_pipeline_new ("send-pipeline");
src = gst_element_factory_make ("audiotestsrc", NULL);
g_object_set (src, "num-buffers", RECORD_N_BUFS,
"samplesperbuffer", 1000, NULL);
enc = gst_element_factory_make ("alawenc", NULL);
pay = gst_element_factory_make ("rtppcmapay", NULL);
sink = gst_element_factory_make ("appsink", NULL);
fail_unless (pipeline && src && enc && pay && sink);
gst_bin_add_many (GST_BIN (pipeline), src, enc, pay, sink, NULL);
gst_element_link_many (src, enc, pay, sink, NULL);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
do {
GstRTSPMessage *data_msg;
GstMapInfo map = GST_MAP_INFO_INIT;
GstRTSPResult rres;
GstSample *sample = NULL;
GstBuffer *buf;
g_signal_emit_by_name (G_OBJECT (sink), "pull-sample", &sample);
if (sample == NULL)
break;
buf = gst_sample_get_buffer (sample);
rres = gst_rtsp_message_new_data (&data_msg, 0);
fail_unless_equals_int (rres, GST_RTSP_OK);
gst_buffer_map (buf, &map, GST_MAP_READ);
GST_INFO ("sending %u bytes of data on channel 0", (guint) map.size);
GST_MEMDUMP ("data on channel 0", map.data, map.size);
rres = gst_rtsp_message_set_body (data_msg, map.data, map.size);
fail_unless_equals_int (rres, GST_RTSP_OK);
gst_buffer_unmap (buf, &map);
rres = gst_rtsp_connection_send (conn, data_msg, NULL);
fail_unless_equals_int (rres, GST_RTSP_OK);
gst_rtsp_message_free (data_msg);
gst_sample_unref (sample);
} while (TRUE);
gst_element_set_state (pipeline, GST_STATE_NULL);
gst_object_unref (pipeline);
}
/* check received data (we assume every buffer created by audiotestsrc and
* subsequently encoded by mulawenc results in exactly one RTP packet) */
for (i = 0; i < RECORD_N_BUFS; ++i) {
GstSample *sample = NULL;
g_signal_emit_by_name (G_OBJECT (server_sink), "pull-sample", &sample);
GST_INFO ("%2d recv sample: %p", i, sample);
gst_sample_unref (sample);
}
fail_unless_equals_int (GST_STATE (server_sink), GST_STATE_PLAYING);
/* clean up and iterate so the clean-up can finish */
gst_rtsp_connection_free (conn);
stop_server ();
iterate ();
g_free (session);
}
GST_END_TEST;
static void
do_test_multiple_transports (GstRTSPLowerTrans trans1, GstRTSPLowerTrans trans2)
{
GstRTSPConnection *conn1;
GstRTSPConnection *conn2;
GstSDPMessage *sdp_message1 = NULL;
GstSDPMessage *sdp_message2 = NULL;
const GstSDPMedia *sdp_media;
const gchar *video_control;
const gchar *audio_control;
GstRTSPRange client_port1, client_port2;
gchar *session1 = NULL;
gchar *session2 = NULL;
GstRTSPTransport *video_transport = NULL;
GstRTSPTransport *audio_transport = NULL;
GSocket *rtp_socket, *rtcp_socket;
conn1 = connect_to_server (test_port, TEST_MOUNT_POINT);
conn2 = connect_to_server (test_port, TEST_MOUNT_POINT);
sdp_message1 = do_describe (conn1, TEST_MOUNT_POINT);
get_client_ports_full (&client_port1, &rtp_socket, &rtcp_socket);
/* get control strings from DESCRIBE response */
sdp_media = gst_sdp_message_get_media (sdp_message1, 0);
video_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
sdp_media = gst_sdp_message_get_media (sdp_message1, 1);
audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
/* do SETUP for video and audio */
fail_unless (do_setup_full (conn1, video_control, trans1,
&client_port1, NULL, &session1, &video_transport,
NULL) == GST_RTSP_STS_OK);
fail_unless (do_setup_full (conn1, audio_control, trans1,
&client_port1, NULL, &session1, &audio_transport,
NULL) == GST_RTSP_STS_OK);
gst_rtsp_transport_free (video_transport);
gst_rtsp_transport_free (audio_transport);
sdp_message2 = do_describe (conn2, TEST_MOUNT_POINT);
/* get control strings from DESCRIBE response */
sdp_media = gst_sdp_message_get_media (sdp_message2, 0);
video_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
sdp_media = gst_sdp_message_get_media (sdp_message2, 1);
audio_control = gst_sdp_media_get_attribute_val (sdp_media, "control");
get_client_ports_full (&client_port2, NULL, NULL);
/* do SETUP for video and audio */
fail_unless (do_setup_full (conn2, video_control, trans2,
&client_port2, NULL, &session2, &video_transport,
NULL) == GST_RTSP_STS_OK);
fail_unless (do_setup_full (conn2, audio_control, trans2,
&client_port2, NULL, &session2, &audio_transport,
NULL) == GST_RTSP_STS_OK);
/* send PLAY request and check that we get 200 OK */
fail_unless (do_request (conn1, GST_RTSP_PLAY, NULL, session1, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL) == GST_RTSP_STS_OK);
/* send PLAY request and check that we get 200 OK */
fail_unless (do_request (conn2, GST_RTSP_PLAY, NULL, session2, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL) == GST_RTSP_STS_OK);
/* receive UDP data */
receive_rtp (rtp_socket, NULL);
receive_rtcp (rtcp_socket, NULL, 0);
/* receive TCP data */
{
GstRTSPMessage *message;
fail_unless (gst_rtsp_message_new (&message) == GST_RTSP_OK);
fail_unless (gst_rtsp_connection_receive (conn2, message, NULL) == GST_RTSP_OK);
fail_unless (gst_rtsp_message_get_type (message) == GST_RTSP_MESSAGE_DATA);
gst_rtsp_message_free (message);
}
/* send TEARDOWN request and check that we get 200 OK */
fail_unless (do_simple_request (conn1, GST_RTSP_TEARDOWN,
session1) == GST_RTSP_STS_OK);
/* send TEARDOWN request and check that we get 200 OK */
fail_unless (do_simple_request (conn2, GST_RTSP_TEARDOWN,
session2) == GST_RTSP_STS_OK);
/* clean up and iterate so the clean-up can finish */
g_object_unref (rtp_socket);
g_object_unref (rtcp_socket);
g_free (session1);
g_free (session2);
gst_rtsp_transport_free (video_transport);
gst_rtsp_transport_free (audio_transport);
gst_sdp_message_free (sdp_message1);
gst_sdp_message_free (sdp_message2);
gst_rtsp_connection_free (conn1);
gst_rtsp_connection_free (conn2);
}
GST_START_TEST (test_multiple_transports)
{
start_server (TRUE);
do_test_multiple_transports (GST_RTSP_LOWER_TRANS_UDP, GST_RTSP_LOWER_TRANS_TCP);
stop_server ();
}
GST_END_TEST;
static Suite *
rtspserver_suite (void)
{
Suite *s = suite_create ("rtspserver");
TCase *tc = tcase_create ("general");
suite_add_tcase (s, tc);
tcase_add_checked_fixture (tc, setup, teardown);
tcase_set_timeout (tc, 120);
tcase_add_test (tc, test_connect);
tcase_add_test (tc, test_describe);
tcase_add_test (tc, test_describe_non_existing_mount_point);
tcase_add_test (tc, test_describe_record_media);
tcase_add_test (tc, test_setup_udp);
tcase_add_test (tc, test_setup_tcp);
tcase_add_test (tc, test_setup_udp_mcast);
tcase_add_test (tc, test_setup_twice);
tcase_add_test (tc, test_setup_with_require_header);
tcase_add_test (tc, test_setup_non_existing_stream);
tcase_add_test (tc, test_play);
tcase_add_test (tc, test_play_tcp);
tcase_add_test (tc, test_play_without_session);
tcase_add_test (tc, test_bind_already_in_use);
tcase_add_test (tc, test_play_multithreaded);
tcase_add_test (tc, test_play_multithreaded_block_in_describe);
tcase_add_test (tc, test_play_multithreaded_timeout_client);
tcase_add_test (tc, test_play_multithreaded_timeout_session);
tcase_add_test (tc, test_no_session_timeout);
tcase_add_test (tc, test_play_one_active_stream);
tcase_add_test (tc, test_play_disconnect);
tcase_add_test (tc, test_play_specific_server_port);
tcase_add_test (tc, test_play_smpte_range);
tcase_add_test (tc, test_play_smpte_range_tcp);
tcase_add_test (tc, test_shared);
tcase_add_test (tc, test_announce_without_sdp);
tcase_add_test (tc, test_record_tcp);
tcase_add_test (tc, test_multiple_transports);
return s;
}
GST_CHECK_MAIN (rtspserver);