GstRTSPClientClass *klass;
GstRTSPSession *session;
GstRTSPSessionMedia *sessmedia;
+ GstRTSPMedia *media;
GstRTSPStatusCode code;
gchar *path;
gint matched;
ctx->sessmedia = sessmedia;
+ media = gst_rtsp_session_media_get_media (sessmedia);
+ g_object_ref (media);
+ gst_rtsp_media_lock (media);
+
g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_TEARDOWN_REQUEST],
0, ctx, &sig_result);
if (sig_result != GST_RTSP_STS_OK) {
gst_rtsp_session_pool_remove (priv->session_pool, session);
}
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
+
return TRUE;
/* ERRORS */
GST_ERROR ("client %p: pre signal returned error: %s", client,
gst_rtsp_status_as_text (sig_result));
send_generic_response (client, sig_result, ctx);
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
return FALSE;
}
}
g_free (path);
media = gst_rtsp_session_media_get_media (sessmedia);
+ g_object_ref (media);
+ gst_rtsp_media_lock (media);
n = gst_rtsp_media_n_streams (media);
for (i = 0; i < n; i++) {
GstRTSPStream *stream = gst_rtsp_media_get_stream (media, i);
g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PAUSE_REQUEST], 0, ctx);
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
+
return TRUE;
/* ERRORS */
GST_ERROR ("client %p: pre signal returned error: %s", client,
gst_rtsp_status_as_text (sig_result));
send_generic_response (client, sig_result, ctx);
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
return FALSE;
}
invalid_state:
GST_ERROR ("client %p: not PLAYING or RECORDING", client);
send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
ctx);
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
return FALSE;
}
not_supported:
{
GST_ERROR ("client %p: pausing not supported", client);
send_generic_response (client, GST_RTSP_STS_BAD_REQUEST, ctx);
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
return FALSE;
}
}
ctx->sessmedia = sessmedia;
ctx->media = media = gst_rtsp_session_media_get_media (sessmedia);
+ g_object_ref (media);
+ gst_rtsp_media_lock (media);
+
g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_PLAY_REQUEST], 0,
ctx, &sig_result);
if (sig_result != GST_RTSP_STS_OK) {
g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PLAY_REQUEST], 0, ctx);
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
+
return TRUE;
/* ERRORS */
GST_ERROR ("client %p: pre signal returned error: %s", client,
gst_rtsp_status_as_text (sig_result));
send_generic_response (client, sig_result, ctx);
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
return FALSE;
}
invalid_state:
GST_ERROR ("client %p: not PLAYING or READY", client);
send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
ctx);
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
return FALSE;
}
pipeline_error:
GST_ERROR ("client %p: failed to configure the pipeline", client);
send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
ctx);
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
return FALSE;
}
unsuspend_failed:
{
GST_ERROR ("client %p: unsuspend failed", client);
send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
return FALSE;
}
invalid_mode:
{
GST_ERROR ("client %p: seek failed", client);
send_generic_response (client, code, ctx);
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
return FALSE;
}
unsupported_mode:
{
GST_ERROR ("client %p: media does not support PLAY", client);
send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
return FALSE;
}
get_rates_error:
{
GST_ERROR ("client %p: failed obtaining rate and applied_rate", client);
send_generic_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR, ctx);
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
return FALSE;
}
adjust_play_response_failed:
{
GST_ERROR ("client %p: failed to adjust play response", client);
send_generic_response (client, code, ctx);
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
return FALSE;
}
rtp_info_error:
{
GST_ERROR ("client %p: failed to add RTP-Info", client);
send_generic_response (client, GST_RTSP_STS_INTERNAL_SERVER_ERROR, ctx);
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
return FALSE;
}
}
/* get a handle to the configuration of the media in the session */
media = find_media (client, ctx, path, &matched);
/* need to suspend the media, if the protocol has changed */
- if (media != NULL)
+ if (media != NULL) {
+ gst_rtsp_media_lock (media);
gst_rtsp_media_suspend (media);
+ }
} else {
- if ((media = gst_rtsp_session_media_get_media (sessmedia)))
+ if ((media = gst_rtsp_session_media_get_media (sessmedia))) {
g_object_ref (media);
- else
+ gst_rtsp_media_lock (media);
+ } else {
goto media_not_found;
+ }
}
/* no media, not found then */
if (media == NULL)
gst_rtsp_session_media_set_rtsp_state (sessmedia, GST_RTSP_STATE_READY);
break;
}
+
+ g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST], 0, ctx);
+
+ gst_rtsp_media_unlock (media);
g_object_unref (media);
g_object_unref (session);
g_free (path);
- g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_SETUP_REQUEST], 0, ctx);
-
return TRUE;
/* ERRORS */
{
GST_ERROR ("client %p: no control in path '%s'", client, path);
send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
+ gst_rtsp_media_unlock (media);
g_object_unref (media);
goto cleanup_session;
}
GST_ERROR ("client %p: stream '%s' not found", client,
GST_STR_NULL (control));
send_generic_response (client, GST_RTSP_STS_NOT_FOUND, ctx);
+ gst_rtsp_media_unlock (media);
g_object_unref (media);
goto cleanup_session;
}
GST_ERROR ("client %p: pre signal returned error: %s", client,
gst_rtsp_status_as_text (sig_result));
send_generic_response (client, sig_result, ctx);
+ gst_rtsp_media_unlock (media);
g_object_unref (media);
goto cleanup_path;
}
{
GST_ERROR ("client %p: can't create session", client);
send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
+ gst_rtsp_media_unlock (media);
g_object_unref (media);
goto cleanup_session;
}
configure_media_failed_no_reply:
{
GST_ERROR ("client %p: configure_media failed", client);
+ gst_rtsp_media_unlock (media);
g_object_unref (media);
/* error reply is already sent */
goto cleanup_session;
{
cleanup_transport:
gst_rtsp_transport_free (ct);
- if (media)
+ if (media) {
+ gst_rtsp_media_unlock (media);
g_object_unref (media);
+ }
cleanup_session:
if (new_session)
gst_rtsp_session_pool_remove (priv->session_pool, session);
if (!(media = find_media (client, ctx, path, NULL)))
goto no_media;
+ gst_rtsp_media_lock (media);
+
if (!(gst_rtsp_media_get_transport_mode (media) &
GST_RTSP_TRANSPORT_MODE_PLAY))
goto unsupported_mode;
/* we suspend after the describe */
gst_rtsp_media_suspend (media);
- g_object_unref (media);
gst_rtsp_message_init_response (ctx->response, GST_RTSP_STS_OK,
gst_rtsp_status_as_text (GST_RTSP_STS_OK), ctx->request);
g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_DESCRIBE_REQUEST],
0, ctx);
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
+
return TRUE;
/* ERRORS */
GST_ERROR ("client %p: media does not support DESCRIBE", client);
send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
g_free (path);
+ gst_rtsp_media_unlock (media);
g_object_unref (media);
return FALSE;
}
GST_ERROR ("client %p: can't create SDP", client);
send_generic_response (client, GST_RTSP_STS_SERVICE_UNAVAILABLE, ctx);
g_free (path);
+ gst_rtsp_media_unlock (media);
g_object_unref (media);
return FALSE;
}
goto no_media;
ctx->media = media;
+ gst_rtsp_media_lock (media);
g_signal_emit (client, gst_rtsp_client_signals[SIGNAL_PRE_ANNOUNCE_REQUEST],
0, ctx, &sig_result);
/* we suspend after the announce */
gst_rtsp_media_suspend (media);
- g_object_unref (media);
send_message (client, ctx, ctx->response, FALSE);
gst_sdp_message_free (sdp);
g_free (path);
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
+
return TRUE;
no_uri:
gst_rtsp_status_as_text (sig_result));
send_generic_response (client, sig_result, ctx);
gst_sdp_message_free (sdp);
+ gst_rtsp_media_unlock (media);
+ g_object_unref (media);
return FALSE;
}
unsupported_mode:
GST_ERROR ("client %p: media does not support ANNOUNCE", client);
send_generic_response (client, GST_RTSP_STS_METHOD_NOT_ALLOWED, ctx);
g_free (path);
+ gst_rtsp_media_unlock (media);
g_object_unref (media);
gst_sdp_message_free (sdp);
return FALSE;
GST_ERROR ("client %p: can't handle SDP", client);
send_generic_response (client, GST_RTSP_STS_UNSUPPORTED_MEDIA_TYPE, ctx);
g_free (path);
+ gst_rtsp_media_unlock (media);
g_object_unref (media);
gst_sdp_message_free (sdp);
return FALSE;
GMutex lock;
GCond cond;
+ /* the global lock is used to lock the entire media. This is needed by callers
+ such as rtsp_client to protect the media when it is shared by many clients.
+ The lock prevents that concurrenting clients messes up media.
+ Typically the lock is taken in external API calls such as SETUP */
+ GMutex global_lock;
+
/* protected by lock */
GstRTSPPermissions *permissions;
gboolean shared;
priv->streams = g_ptr_array_new_with_free_func (g_object_unref);
g_mutex_init (&priv->lock);
+ g_mutex_init (&priv->global_lock);
g_cond_init (&priv->cond);
g_rec_mutex_init (&priv->state_lock);
gst_object_unref (priv->clock);
g_free (priv->multicast_iface);
g_mutex_clear (&priv->lock);
+ g_mutex_clear (&priv->global_lock);
g_cond_clear (&priv->cond);
g_rec_mutex_clear (&priv->state_lock);
}
/**
+ * gst_rtsp_media_lock:
+ * @media: a #GstRTSPMedia
+ *
+ * Lock the entire media. This is needed by callers such as rtsp_client to
+ * protect the media when it is shared by many clients.
+ * The lock prevents that concurrent clients alters the shared media,
+ * while one client already is working with it.
+ * Typically the lock is taken in external RTSP API calls that uses shared media
+ * such as DESCRIBE, SETUP, ANNOUNCE, TEARDOWN, PLAY, PAUSE.
+ *
+ * As best practice take the lock as soon as the function get hold of a shared
+ * media object. Release the lock right before the function returns.
+ *
+ * Since: 1.18
+ */
+void
+gst_rtsp_media_lock (GstRTSPMedia * media)
+{
+ GstRTSPMediaPrivate *priv;
+
+ g_return_if_fail (GST_IS_RTSP_MEDIA (media));
+
+ priv = media->priv;
+
+ g_mutex_lock (&priv->global_lock);
+}
+
+/**
+ * gst_rtsp_media_unlock:
+ * @media: a #GstRTSPMedia
+ *
+ * Unlock the media.
+ *
+ * Since: 1.18
+ */
+void
+gst_rtsp_media_unlock (GstRTSPMedia * media)
+{
+ GstRTSPMediaPrivate *priv;
+
+ g_return_if_fail (GST_IS_RTSP_MEDIA (media));
+
+ priv = media->priv;
+
+ g_mutex_unlock (&priv->global_lock);
+}
+
+/**
* gst_rtsp_media_get_clock:
* @media: a #GstRTSPMedia
*
GST_FIXME ("suspend for dynamic pipelines needs fixing");
+ /* this typically can happen for shared media. */
+ if (priv->prepare_count > 1 &&
+ priv->status == GST_RTSP_MEDIA_STATUS_SUSPENDED) {
+ goto done;
+ } else if (priv->prepare_count > 1) {
+ goto prepared_by_other_client;
+ }
+
g_rec_mutex_lock (&priv->state_lock);
if (priv->status != GST_RTSP_MEDIA_STATUS_PREPARED)
goto not_prepared;
return TRUE;
/* ERRORS */
+prepared_by_other_client:
+ {
+ GST_WARNING ("media %p was prepared by other client", media);
+ return FALSE;
+ }
not_prepared:
{
g_rec_mutex_unlock (&priv->state_lock);