+ 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);
+
+ receive_rtp (rtp_socket, NULL);
+ receive_rtcp (rtcp_socket, NULL, 0);
+
+ /* 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);
+}
+
+GST_START_TEST (test_play)
+{
+ start_server ();
+
+ do_test_play (NULL);
+
+ stop_server ();
+ iterate ();
+}
+
+GST_END_TEST;
+
+GST_START_TEST (test_play_without_session)
+{
+ GstRTSPConnection *conn;
+
+ start_server ();
+
+ 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 ();
+
+ 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 ();
+
+ 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 ();
+
+
+ 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 ();
+
+
+ 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_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 ();
+
+ 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 ();
+ 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 ();
+
+ 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_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 )");
+
+ 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 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_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_play_disconnect);
+ tcase_add_test (tc, test_play_specific_server_port);
+ tcase_add_test (tc, test_play_smpte_range);
+ tcase_add_test (tc, test_announce_without_sdp);
+ tcase_add_test (tc, test_record_tcp);