mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-10-06 18:52:07 +00:00
rtsp-media: Wait on async when needed.
Wait on asyn-done when needed in gst_rtsp_media_seek_trickmode. In the unit test the pause from adjust_play_mode will cause a preroll and after that async-done will be produced. Without this patch there are no one consuming this async-done and when later when seek fluch is done in gst_rtsp_media_seek_trickmode then it wait for async-done. But then it wrongly find the async-done prodused by adjus_play_mode and continue executing without waiting for the preroll to finish.
This commit is contained in:
parent
7e1edcf1a4
commit
18f4f4e509
2 changed files with 169 additions and 4 deletions
|
@ -152,6 +152,7 @@ struct _GstRTSPMediaPrivate
|
||||||
/* Dynamic element handling */
|
/* Dynamic element handling */
|
||||||
guint nb_dynamic_elements;
|
guint nb_dynamic_elements;
|
||||||
guint no_more_pads_pending;
|
guint no_more_pads_pending;
|
||||||
|
gboolean expected_async_done;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEFAULT_SHARED FALSE
|
#define DEFAULT_SHARED FALSE
|
||||||
|
@ -476,6 +477,7 @@ gst_rtsp_media_init (GstRTSPMedia * media)
|
||||||
priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL;
|
priv->max_mcast_ttl = DEFAULT_MAX_MCAST_TTL;
|
||||||
priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS;
|
priv->bind_mcast_address = DEFAULT_BIND_MCAST_ADDRESS;
|
||||||
priv->do_rate_control = DEFAULT_DO_RATE_CONTROL;
|
priv->do_rate_control = DEFAULT_DO_RATE_CONTROL;
|
||||||
|
priv->expected_async_done = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -2819,6 +2821,30 @@ gst_rtsp_media_seek_trickmode (GstRTSPMedia * media,
|
||||||
GstEvent *seek_event;
|
GstEvent *seek_event;
|
||||||
gboolean unblock = FALSE;
|
gboolean unblock = FALSE;
|
||||||
|
|
||||||
|
/* Handle expected async-done before waiting on next async-done.
|
||||||
|
*
|
||||||
|
* Since the seek further down in code will cause a preroll and
|
||||||
|
* a async-done will be generated it's important to wait on async-done
|
||||||
|
* if that is expected. Otherwise there is the risk that the waiting
|
||||||
|
* for async-done after the seek is detecting the expected async-done
|
||||||
|
* instead of the one that corresponds to the seek. Then execution
|
||||||
|
* continue and act as if the pipeline is prerolled, but it's not.
|
||||||
|
*
|
||||||
|
* During wait_preroll message GST_MESSAGE_ASYNC_DONE will come
|
||||||
|
* and then the state will change from preparing to prepared */
|
||||||
|
if (priv->expected_async_done) {
|
||||||
|
GST_DEBUG (" expected to get async-done, waiting ");
|
||||||
|
gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING);
|
||||||
|
g_rec_mutex_unlock (&priv->state_lock);
|
||||||
|
|
||||||
|
/* wait until pipeline is prerolled */
|
||||||
|
if (!wait_preroll (media))
|
||||||
|
goto preroll_failed_expected_async_done;
|
||||||
|
|
||||||
|
g_rec_mutex_lock (&priv->state_lock);
|
||||||
|
GST_DEBUG (" got expected async-done");
|
||||||
|
}
|
||||||
|
|
||||||
gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING);
|
gst_rtsp_media_set_status (media, GST_RTSP_MEDIA_STATUS_PREPARING);
|
||||||
|
|
||||||
if (rate < 0.0) {
|
if (rate < 0.0) {
|
||||||
|
@ -2910,6 +2936,11 @@ preroll_failed:
|
||||||
GST_WARNING ("failed to preroll after seek");
|
GST_WARNING ("failed to preroll after seek");
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
preroll_failed_expected_async_done:
|
||||||
|
{
|
||||||
|
GST_WARNING ("failed to preroll");
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3118,6 +3149,8 @@ default_handle_message (GstRTSPMedia * media, GstMessage * message)
|
||||||
case GST_MESSAGE_STREAM_STATUS:
|
case GST_MESSAGE_STREAM_STATUS:
|
||||||
break;
|
break;
|
||||||
case GST_MESSAGE_ASYNC_DONE:
|
case GST_MESSAGE_ASYNC_DONE:
|
||||||
|
if (priv->expected_async_done)
|
||||||
|
priv->expected_async_done = FALSE;
|
||||||
if (priv->complete) {
|
if (priv->complete) {
|
||||||
/* receive the final ASYNC_DONE, that is posted by the media pipeline
|
/* receive the final ASYNC_DONE, that is posted by the media pipeline
|
||||||
* after all the transport parts have been successfully added to
|
* after all the transport parts have been successfully added to
|
||||||
|
@ -4459,6 +4492,8 @@ static void
|
||||||
media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state)
|
media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state)
|
||||||
{
|
{
|
||||||
GstRTSPMediaPrivate *priv = media->priv;
|
GstRTSPMediaPrivate *priv = media->priv;
|
||||||
|
GstStateChangeReturn set_state_ret;
|
||||||
|
priv->expected_async_done = FALSE;
|
||||||
|
|
||||||
if (state == GST_STATE_NULL) {
|
if (state == GST_STATE_NULL) {
|
||||||
gst_rtsp_media_unprepare (media);
|
gst_rtsp_media_unprepare (media);
|
||||||
|
@ -4474,11 +4509,15 @@ media_set_pipeline_state_locked (GstRTSPMedia * media, GstState state)
|
||||||
/* make sure pads are not blocking anymore when going to PLAYING */
|
/* make sure pads are not blocking anymore when going to PLAYING */
|
||||||
media_unblock_linked (media);
|
media_unblock_linked (media);
|
||||||
|
|
||||||
set_state (media, state);
|
if (state == GST_STATE_PAUSED) {
|
||||||
|
set_state_ret = set_state (media, state);
|
||||||
|
if (set_state_ret == GST_STATE_CHANGE_ASYNC)
|
||||||
|
priv->expected_async_done = TRUE;
|
||||||
/* and suspend after pause */
|
/* and suspend after pause */
|
||||||
if (state == GST_STATE_PAUSED)
|
|
||||||
gst_rtsp_media_suspend (media);
|
gst_rtsp_media_suspend (media);
|
||||||
|
} else {
|
||||||
|
set_state (media, state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -483,6 +483,16 @@ do_simple_request (GstRTSPConnection * conn, GstRTSPMethod method,
|
||||||
NULL, NULL, NULL, NULL, NULL);
|
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
|
/* send a DESCRIBE request and receive response. returns a received
|
||||||
* GstSDPMessage that must be freed by the caller */
|
* GstSDPMessage that must be freed by the caller */
|
||||||
static GstSDPMessage *
|
static GstSDPMessage *
|
||||||
|
@ -2473,6 +2483,121 @@ GST_START_TEST (test_suspend_mode_reset_only_audio)
|
||||||
|
|
||||||
GST_END_TEST;
|
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 *
|
static Suite *
|
||||||
rtspserver_suite (void)
|
rtspserver_suite (void)
|
||||||
{
|
{
|
||||||
|
@ -2512,6 +2637,7 @@ rtspserver_suite (void)
|
||||||
tcase_add_test (tc, test_record_tcp);
|
tcase_add_test (tc, test_record_tcp);
|
||||||
tcase_add_test (tc, test_multiple_transports);
|
tcase_add_test (tc, test_multiple_transports);
|
||||||
tcase_add_test (tc, test_suspend_mode_reset_only_audio);
|
tcase_add_test (tc, test_suspend_mode_reset_only_audio);
|
||||||
|
tcase_add_test (tc, test_double_play);
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue