rtsp-media: Unblock all streams
[platform/upstream/gstreamer.git] / tests / check / gst / rtspserver.c
index 805b177..0a0eec4 100644 (file)
 
 #include "rtsp-server.h"
 
+#define ERRORIGNORE "errorignore ignore-error=false ignore-notlinked=true " \
+  "ignore-notnegotiated=false convert-to=ok"
 #define VIDEO_PIPELINE "videotestsrc ! " \
+  ERRORIGNORE " ! " \
   "video/x-raw,width=352,height=288 ! " \
   "rtpgstpay name=pay0 pt=96"
 #define AUDIO_PIPELINE "audiotestsrc ! " \
+  ERRORIGNORE " ! " \
   "audio/x-raw,rate=8000 ! " \
   "rtpgstpay name=pay1 pt=97"
 
@@ -168,7 +172,7 @@ start_server (gboolean set_shared_factory)
   /* 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", 5000, 5010, 16);
+      "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);
@@ -191,6 +195,41 @@ start_server (gboolean set_shared_factory)
   GST_DEBUG ("rtsp server listening on port %d", test_port);
 }
 
+static void
+start_tcp_server (gboolean set_shared_factory)
+{
+  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);
+  gst_rtsp_media_factory_set_shared (factory, set_shared_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)
@@ -296,6 +335,7 @@ 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");
@@ -306,8 +346,9 @@ read_response (GstRTSPConnection * conn)
     gst_rtsp_message_free (response);
     return NULL;
   }
-  fail_unless (gst_rtsp_message_get_type (response) ==
-      GST_RTSP_MESSAGE_RESPONSE);
+  type = gst_rtsp_message_get_type (response);
+  fail_unless (type == GST_RTSP_MESSAGE_RESPONSE
+      || type == GST_RTSP_MESSAGE_DATA);
   return response;
 }
 
@@ -325,6 +366,7 @@ do_request_full (GstRTSPConnection * conn, GstRTSPMethod method,
   GstRTSPMessage *response;
   GstRTSPStatusCode code;
   gchar *value;
+  GstRTSPMsgType msg_type;
 
   /* create request */
   request = create_request (conn, method, control);
@@ -351,6 +393,19 @@ do_request_full (GstRTSPConnection * conn, GstRTSPMethod method,
 
   /* 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);
@@ -432,6 +487,16 @@ do_simple_request (GstRTSPConnection * conn, GstRTSPMethod method,
       NULL, NULL, NULL, NULL, NULL);
 }
 
+/* send an rtsp request with a method,session and range in,
+ * and receive response. range_in is the Range in req header */
+static GstRTSPStatusCode
+do_simple_request_rangein (GstRTSPConnection * conn, GstRTSPMethod method,
+    const gchar * session, const gchar * rangein)
+{
+  return do_request (conn, method, NULL, session, NULL, rangein, 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 *
@@ -1010,6 +1075,75 @@ done:
 }
 
 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)
 {
@@ -1105,6 +1239,76 @@ GST_START_TEST (test_play)
 
 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 (FALSE);
+
+  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;
@@ -1440,6 +1644,93 @@ GST_START_TEST (test_play_multithreaded_timeout_session)
 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);
+
+  g_object_unref (session);
+}
+
+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;
@@ -1632,15 +1923,38 @@ GST_START_TEST (test_play_smpte_range)
 
 GST_END_TEST;
 
+GST_START_TEST (test_play_smpte_range_tcp)
+{
+  start_tcp_server (FALSE);
+
+  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)
+thread_func_udp (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)
+static gpointer
+thread_func_tcp (gpointer data)
+{
+  do_test_play_tcp_full (NULL);
+  return NULL;
+}
+
+static void
+test_shared (gpointer (thread_func) (gpointer data))
 {
   GMutex lock1, lock2, lock3, lock4;
   GThread *thread1, *thread2, *thread3, *thread4;
@@ -1652,7 +1966,10 @@ GST_START_TEST (test_shared)
   g_mutex_init (&lock3);
   g_mutex_init (&lock4);
 
-  start_server (TRUE);
+  if (thread_func == thread_func_tcp)
+    start_tcp_server (TRUE);
+  else
+    start_server (TRUE);
 
   /* Start the first receiver thread. */
   g_mutex_lock (&lock1);
@@ -1689,6 +2006,22 @@ GST_START_TEST (test_shared)
   iterate ();
 }
 
+/* Test adding and removing clients to a 'Shared' media.
+ * CASE: unicast UDP */
+GST_START_TEST (test_shared_udp)
+{
+  test_shared (thread_func_udp);
+}
+
+GST_END_TEST;
+
+/* Test adding and removing clients to a 'Shared' media.
+ * CASE: unicast TCP */
+GST_START_TEST (test_shared_tcp)
+{
+  test_shared (thread_func_tcp);
+}
+
 GST_END_TEST;
 
 GST_START_TEST (test_announce_without_sdp)
@@ -1801,6 +2134,7 @@ media_constructed_cb (GstRTSPMediaFactory * mfactory, GstRTSPMedia * media,
   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);
+  gst_object_unref (bin);
 }
 
 #define RECORD_N_BUFS 10
@@ -1972,6 +2306,302 @@ GST_START_TEST (test_record_tcp)
 
 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;
+
+GST_START_TEST (test_suspend_mode_reset_only_audio)
+{
+  GstRTSPMountPoints *mounts;
+  gchar *service;
+  GstRTSPMediaFactory *factory;
+  GstRTSPConnection *conn;
+  GstSDPMessage *sdp_message = NULL;
+  const GstSDPMedia *sdp_media;
+  const gchar *audio_control;
+  GstRTSPRange client_port;
+  gchar *session = NULL;
+  GstRTSPTransport *audio_transport = NULL;
+  GSocket *rtp_socket, *rtcp_socket;
+
+  mounts = gst_rtsp_server_get_mount_points (server);
+
+  factory = gst_rtsp_media_factory_new ();
+  gst_rtsp_media_factory_set_suspend_mode (factory,
+      GST_RTSP_SUSPEND_MODE_RESET);
+  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);
+
+  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, 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 audio */
+  fail_unless (do_setup (conn, audio_control, &client_port, &session,
+          &audio_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);
+
+  /* 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_rtsp_transport_free (audio_transport);
+  gst_sdp_message_free (sdp_message);
+  gst_rtsp_connection_free (conn);
+
+  stop_server ();
+  iterate ();
+}
+
+GST_END_TEST;
+
+
+static GstRTSPStatusCode
+adjust_play_mode (GstRTSPClient * client, GstRTSPContext * ctx,
+    GstRTSPTimeRange ** range, GstSeekFlags * flags, gdouble * rate,
+    GstClockTime * trickmode_interval, gboolean * enable_rate_control)
+{
+  GstRTSPState rtspstate;
+
+  rtspstate = gst_rtsp_session_media_get_rtsp_state (ctx->sessmedia);
+  if (rtspstate == GST_RTSP_STATE_PLAYING) {
+    if (!gst_rtsp_session_media_set_state (ctx->sessmedia, GST_STATE_PAUSED))
+      return GST_RTSP_STS_INTERNAL_SERVER_ERROR;
+
+    if (!gst_rtsp_media_unsuspend (ctx->media))
+      return GST_RTSP_STS_INTERNAL_SERVER_ERROR;
+  }
+
+  return GST_RTSP_STS_OK;
+}
+
+GST_START_TEST (test_double_play)
+{
+  GstRTSPMountPoints *mounts;
+  gchar *service;
+  GstRTSPMediaFactory *factory;
+  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 *audio_transport = NULL;
+  GstRTSPTransport *video_transport = NULL;
+  GSocket *rtp_socket, *rtcp_socket;
+  GstRTSPClient *client;
+  GstRTSPClientClass *klass;
+
+  client = gst_rtsp_client_new ();
+  klass = GST_RTSP_CLIENT_GET_CLASS (client);
+  klass->adjust_play_mode = adjust_play_mode;
+
+  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);
+
+
+  /* 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);
+
+  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 */
+  fail_unless (do_setup (conn, video_control, &client_port, &session,
+          &video_transport) == GST_RTSP_STS_OK);
+
+  /* do SETUP for audio */
+  fail_unless (do_setup (conn, audio_control, &client_port, &session,
+          &audio_transport) == GST_RTSP_STS_OK);
+
+  /* send PLAY request and check that we get 200 OK */
+  fail_unless (do_simple_request_rangein (conn, GST_RTSP_PLAY,
+          session, "npt=0-") == GST_RTSP_STS_OK);
+
+  /* let it play for a while, so it needs to seek
+   * for next play (npt=0-) */
+  g_usleep (30000);
+
+  /* send PLAY request and check that we get 200 OK */
+  fail_unless (do_simple_request_rangein (conn, GST_RTSP_PLAY,
+          session, "npt=0-") == 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_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;
+
+
 static Suite *
 rtspserver_suite (void)
 {
@@ -1992,18 +2622,27 @@ rtspserver_suite (void)
   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_shared);
+  tcase_add_test (tc, test_play_smpte_range_tcp);
+  tcase_add_test (tc, test_shared_udp);
+  tcase_add_test (tc, test_shared_tcp);
   tcase_add_test (tc, test_announce_without_sdp);
   tcase_add_test (tc, test_record_tcp);
+  tcase_add_test (tc, test_multiple_transports);
+  tcase_add_test (tc, test_suspend_mode_reset_only_audio);
+  tcase_add_test (tc, test_double_play);
+
   return s;
 }