Rework the way we handle transports for streams

Make the media accept an array of transports for the streams that we have
configured for the play/pause requests.

Implement server states for a client and its media.

Require 0.10.22.1 (git HEAD) of gstreamer.
This commit is contained in:
Wim Taymans 2009-02-03 19:32:38 +01:00
parent f303eef9bb
commit d5a00f1f23
6 changed files with 208 additions and 115 deletions

View file

@ -37,8 +37,8 @@ AC_SUBST(GST_MAJORMINOR)
AM_PROG_LIBTOOL
dnl *** required versions of GStreamer stuff ***
GST_REQ=0.10.20
GSTPB_REQ=0.10.20
GST_REQ=0.10.22.1
GSTPB_REQ=0.10.22.1
dnl export for .pc files
AC_SUBST([GST_REQ])

View file

@ -287,8 +287,12 @@ handle_pause_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re
if (!media)
goto not_found;
/* the session state must be playing or recording */
if (media->state != GST_RTSP_STATE_PLAYING &&
media->state != GST_RTSP_STATE_RECORDING)
goto invalid_state;
gst_rtsp_session_media_pause (media);
g_object_unref (session);
/* construct the response now */
code = GST_RTSP_STS_OK;
@ -296,6 +300,10 @@ handle_pause_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re
send_response (client, &response);
/* the state is now READY */
media->state = GST_RTSP_STATE_READY;
g_object_unref (session);
return FALSE;
/* ERRORS */
@ -308,6 +316,11 @@ not_found:
send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
return FALSE;
}
invalid_state:
{
send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, request);
return FALSE;
}
}
static gboolean
@ -329,6 +342,11 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *req
if (!media)
goto not_found;
/* the session state must be playing or ready */
if (media->state != GST_RTSP_STATE_PLAYING &&
media->state != GST_RTSP_STATE_READY)
goto invalid_state;
/* grab RTPInfo from the payloaders now */
rtpinfo = g_string_new ("");
@ -362,6 +380,8 @@ handle_play_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *req
/* start playing after sending the request */
gst_rtsp_session_media_play (media);
media->state = GST_RTSP_STATE_PLAYING;
g_object_unref (session);
return FALSE;
@ -377,6 +397,11 @@ not_found:
send_generic_response (client, GST_RTSP_STS_NOT_FOUND, request);
return FALSE;
}
invalid_state:
{
send_generic_response (client, GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE, request);
return FALSE;
}
}
static gboolean
@ -508,10 +533,23 @@ handle_setup_request (GstRTSPClient *client, GstRTSPUrl *uri, GstRTSPMessage *re
gst_rtsp_message_add_header (&response, GST_RTSP_HDR_TRANSPORT, trans_str);
g_free (trans_str);
g_object_unref (session);
send_response (client, &response);
/* update the state */
switch (media->state) {
case GST_RTSP_STATE_PLAYING:
case GST_RTSP_STATE_RECORDING:
case GST_RTSP_STATE_READY:
/* no state change */
break;
default:
media->state = GST_RTSP_STATE_READY;
break;
}
g_object_unref (session);
return TRUE;
/* ERRORS */

View file

@ -538,100 +538,125 @@ state_failed:
}
}
gboolean
gst_rtsp_media_stream_add (GstRTSPMediaStream *stream, GstRTSPTransport *ct)
{
g_return_val_if_fail (stream != NULL, FALSE);
g_return_val_if_fail (ct != NULL, FALSE);
g_return_val_if_fail (stream->prepared, FALSE);
g_message ("adding %s:%d", ct->destination, ct->client_port.min);
g_signal_emit_by_name (stream->udpsink[0], "add", ct->destination, ct->client_port.min, NULL);
g_signal_emit_by_name (stream->udpsink[1], "add", ct->destination, ct->client_port.max, NULL);
return TRUE;
}
gboolean
gst_rtsp_media_stream_remove (GstRTSPMediaStream *stream, GstRTSPTransport *ct)
{
g_return_val_if_fail (stream != NULL, FALSE);
g_return_val_if_fail (ct != NULL, FALSE);
g_return_val_if_fail (stream->prepared, FALSE);
g_message ("removing %s:%d", ct->destination, ct->client_port.min);
g_signal_emit_by_name (stream->udpsink[0], "remove", ct->destination, ct->client_port.min, NULL);
g_signal_emit_by_name (stream->udpsink[1], "remove", ct->destination, ct->client_port.max, NULL);
return TRUE;
}
/**
* gst_rtsp_media_play:
* @media: a #GstRTSPMedia
* @transports: a GArray of #GstRTSPMediaTrans pointers
*
* Tell the @media to start playing and streaming to the client.
* Start playing @media for to the transports in @transports.
*
* Returns: a #GstStateChangeReturn
* Returns: %TRUE on success.
*/
GstStateChangeReturn
gst_rtsp_media_play (GstRTSPMedia *media)
gboolean
gst_rtsp_media_play (GstRTSPMedia *media, GArray *transports)
{
gint i;
GstStateChangeReturn ret;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_STATE_CHANGE_FAILURE);
g_return_val_if_fail (media->prepared, GST_STATE_CHANGE_FAILURE);
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
g_return_val_if_fail (transports != NULL, FALSE);
g_return_val_if_fail (media->prepared, FALSE);
for (i = 0; i < transports->len; i++) {
GstRTSPMediaTrans *tr;
GstRTSPMediaStream *stream;
GstRTSPTransport *trans;
/* we need a non-NULL entry in the array */
tr = g_array_index (transports, GstRTSPMediaTrans *, i);
if (tr == NULL)
continue;
/* we need a transport */
if (!(trans = tr->transport))
continue;
/* get the stream and add the destinations */
stream = gst_rtsp_media_get_stream (media, tr->idx);
g_message ("adding %s:%d-%d", trans->destination, trans->client_port.min, trans->client_port.max);
g_signal_emit_by_name (stream->udpsink[0], "add", trans->destination, trans->client_port.min, NULL);
g_signal_emit_by_name (stream->udpsink[1], "add", trans->destination, trans->client_port.max, NULL);
}
g_message ("playing");
ret = gst_element_set_state (media->pipeline, GST_STATE_PLAYING);
return ret;
return TRUE;
}
/**
* gst_rtsp_media_pause:
* @media: a #GstRTSPMedia
* @transports: a array of #GstRTSPTransport pointers
*
* Tell the @media to pause.
* Pause playing @media for to the transports in @transports.
*
* Returns: a #GstStateChangeReturn
* Returns: %TRUE on success.
*/
GstStateChangeReturn
gst_rtsp_media_pause (GstRTSPMedia *media)
gboolean
gst_rtsp_media_pause (GstRTSPMedia *media, GArray *transports)
{
gint i;
GstStateChangeReturn ret;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_STATE_CHANGE_FAILURE);
g_return_val_if_fail (media->prepared, GST_STATE_CHANGE_FAILURE);
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
g_return_val_if_fail (transports != NULL, FALSE);
g_return_val_if_fail (media->prepared, FALSE);
g_message ("paused");
for (i = 0; i < transports->len; i++) {
GstRTSPMediaTrans *tr;
GstRTSPMediaStream *stream;
GstRTSPTransport *trans;
/* we need a non-NULL entry in the array */
tr = g_array_index (transports, GstRTSPMediaTrans *, i);
if (tr == NULL)
continue;
/* we need a transport */
if (!(trans = tr->transport))
continue;
/* get the stream and add the destinations */
stream = gst_rtsp_media_get_stream (media, tr->idx);
g_message ("removing %s:%d-%d", trans->destination, trans->client_port.min, trans->client_port.max);
g_signal_emit_by_name (stream->udpsink[0], "remove", trans->destination, trans->client_port.min, NULL);
g_signal_emit_by_name (stream->udpsink[1], "remove", trans->destination, trans->client_port.max, NULL);
}
g_message ("pause");
ret = gst_element_set_state (media->pipeline, GST_STATE_PAUSED);
return ret;
return TRUE;
}
/**
* gst_rtsp_media_stop:
* gst_rtsp_media_stream_stop:
* @media: a #GstRTSPMedia
* @transports: a GArray of #GstRTSPMediaTrans pointers
*
* Tell the @media to stop playing. After this call the media
* cannot be played or paused anymore
* Stop playing @media for to the transports in @transports.
*
* Returns: a #GstStateChangeReturn
* Returns: %TRUE on success.
*/
GstStateChangeReturn
gst_rtsp_media_stop (GstRTSPMedia *media)
gboolean
gst_rtsp_media_stop (GstRTSPMedia *media, GArray *transports)
{
GstStateChangeReturn ret;
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), GST_STATE_CHANGE_FAILURE);
g_return_val_if_fail (media->prepared, GST_STATE_CHANGE_FAILURE);
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), FALSE);
g_return_val_if_fail (transports != NULL, FALSE);
g_return_val_if_fail (media->prepared, FALSE);
gst_rtsp_media_pause (media, transports);
g_message ("stop");
ret = gst_element_set_state (media->pipeline, GST_STATE_NULL);
return ret;
return TRUE;
}

View file

@ -38,6 +38,20 @@ G_BEGIN_DECLS
typedef struct _GstRTSPMediaStream GstRTSPMediaStream;
typedef struct _GstRTSPMedia GstRTSPMedia;
typedef struct _GstRTSPMediaClass GstRTSPMediaClass;
typedef struct _GstRTSPMediaTrans GstRTSPMediaTrans;
/**
* GstRTSPMediaTrans:
* @idx: a stream index
* @transport: a transport description
*
* A Transport description for stream @idx
*/
struct _GstRTSPMediaTrans {
guint idx;
GstRTSPTransport *transport;
};
/**
* GstRTSPMediaStream:
@ -136,13 +150,9 @@ gboolean gst_rtsp_media_prepare (GstRTSPMedia *media);
guint gst_rtsp_media_n_streams (GstRTSPMedia *media);
GstRTSPMediaStream * gst_rtsp_media_get_stream (GstRTSPMedia *media, guint idx);
/* add destinations to a stream */
gboolean gst_rtsp_media_stream_add (GstRTSPMediaStream *stream, GstRTSPTransport *ct);
gboolean gst_rtsp_media_stream_remove (GstRTSPMediaStream *stream, GstRTSPTransport *ct);
GstStateChangeReturn gst_rtsp_media_play (GstRTSPMedia *media);
GstStateChangeReturn gst_rtsp_media_pause (GstRTSPMedia *media);
GstStateChangeReturn gst_rtsp_media_stop (GstRTSPMedia *media);
gboolean gst_rtsp_media_play (GstRTSPMedia *media, GArray *trans);
gboolean gst_rtsp_media_pause (GstRTSPMedia *media, GArray *trans);
gboolean gst_rtsp_media_stop (GstRTSPMedia *media, GArray *trans);
G_END_DECLS

View file

@ -42,10 +42,10 @@ gst_rtsp_session_init (GstRTSPSession * session)
}
static void
gst_rtsp_session_free_stream (GstRTSPSessionStream *stream, GstRTSPSessionMedia *media)
gst_rtsp_session_free_stream (GstRTSPSessionStream *stream)
{
if (stream->client_trans)
gst_rtsp_transport_free (stream->client_trans);
if (stream->trans.transport)
gst_rtsp_transport_free (stream->trans.transport);
g_free (stream);
}
@ -53,9 +53,19 @@ gst_rtsp_session_free_stream (GstRTSPSessionStream *stream, GstRTSPSessionMedia
static void
gst_rtsp_session_free_media (GstRTSPSessionMedia *media, GstRTSPSession *session)
{
g_list_foreach (media->streams, (GFunc) gst_rtsp_session_free_stream,
media);
g_list_free (media->streams);
guint size, i;
size = media->streams->len;
for (i = 0; i < size; i++) {
GstRTSPSessionStream *stream;
stream = g_array_index (media->streams, GstRTSPSessionStream *, i);
if (stream)
gst_rtsp_session_free_stream (stream);
}
g_array_free (media->streams, TRUE);
if (media->url)
gst_rtsp_url_free (media->url);
@ -100,10 +110,22 @@ gst_rtsp_session_manage_media (GstRTSPSession *sess, const GstRTSPUrl *uri,
GstRTSPMedia *media)
{
GstRTSPSessionMedia *result;
guint n_streams;
g_return_val_if_fail (GST_IS_RTSP_SESSION (sess), NULL);
g_return_val_if_fail (uri != NULL, NULL);
g_return_val_if_fail (GST_IS_RTSP_MEDIA (media), NULL);
g_return_val_if_fail (media->prepared, NULL);
result = g_new0 (GstRTSPSessionMedia, 1);
result->media = media;
result->url = gst_rtsp_url_copy ((GstRTSPUrl *)uri);
result->state = GST_RTSP_STATE_INIT;
/* prealloc the streams now, filled with NULL */
n_streams = gst_rtsp_media_n_streams (media);
result->streams = g_array_sized_new (FALSE, TRUE, sizeof (GstRTSPSessionStream *), n_streams);
g_array_set_size (result->streams, n_streams);
sess->medias = g_list_prepend (sess->medias, result);
@ -158,29 +180,25 @@ gst_rtsp_session_media_get_stream (GstRTSPSessionMedia *media, guint idx)
{
GstRTSPSessionStream *result;
GstRTSPMediaStream *media_stream;
GList *walk;
g_return_val_if_fail (media != NULL, NULL);
g_return_val_if_fail (media->media != NULL, NULL);
media_stream = gst_rtsp_media_get_stream (media->media, idx);
if (media_stream == NULL)
goto no_media;
if (idx >= media->streams->len)
return NULL;
result = NULL;
for (walk = media->streams; walk; walk = g_list_next (walk)) {
result = (GstRTSPSessionStream *) walk->data;
if (result->media_stream == media_stream)
break;
result = NULL;
}
result = g_array_index (media->streams, GstRTSPSessionStream *, idx);
if (result == NULL) {
media_stream = gst_rtsp_media_get_stream (media->media, idx);
if (media_stream == NULL)
goto no_media;
result = g_new0 (GstRTSPSessionStream, 1);
result->trans.idx = idx;
result->trans.transport = NULL;
result->media_stream = media_stream;
media->streams = g_list_prepend (media->streams, result);
g_array_insert_val (media->streams, idx, result);
}
return result;
@ -232,9 +250,9 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream,
st->client_port = ct->client_port;
/* keep track of the transports */
if (stream->client_trans)
gst_rtsp_transport_free (stream->client_trans);
stream->client_trans = ct;
if (stream->trans.transport)
gst_rtsp_transport_free (stream->trans.transport);
stream->trans.transport = ct;
st->server_port.min = stream->media_stream->server_port.min;
st->server_port.max = stream->media_stream->server_port.max;
@ -242,28 +260,20 @@ gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream,
return st;
}
/**
* gst_rtsp_session_media_play:
* @media: a #GstRTSPSessionMedia
*
* Tell the media object @media to start playing and streaming to the client.
*
* Returns: a #GstStateChangeReturn
* Returns: %TRUE on success.
*/
GstStateChangeReturn
gboolean
gst_rtsp_session_media_play (GstRTSPSessionMedia *media)
{
GstStateChangeReturn ret;
GstRTSPSessionStream *stream;
GList *walk;
gboolean ret;
for (walk = media->streams; walk; walk = g_list_next (walk)) {
stream = (GstRTSPSessionStream *) walk->data;
gst_rtsp_media_stream_add (stream->media_stream, stream->client_trans);
}
ret = gst_rtsp_media_play (media->media);
ret = gst_rtsp_media_play (media->media, media->streams);
return ret;
}
@ -274,14 +284,14 @@ gst_rtsp_session_media_play (GstRTSPSessionMedia *media)
*
* Tell the media object @media to pause.
*
* Returns: a #GstStateChangeReturn
* Returns: %TRUE on success.
*/
GstStateChangeReturn
gboolean
gst_rtsp_session_media_pause (GstRTSPSessionMedia *media)
{
GstStateChangeReturn ret;
gboolean ret;
ret = gst_rtsp_media_pause (media->media);
ret = gst_rtsp_media_pause (media->media, media->streams);
return ret;
}
@ -293,14 +303,14 @@ gst_rtsp_session_media_pause (GstRTSPSessionMedia *media)
* Tell the media object @media to stop playing. After this call the media
* cannot be played or paused anymore
*
* Returns: a #GstStateChangeReturn
* Returns: %TRUE on success.
*/
GstStateChangeReturn
gboolean
gst_rtsp_session_media_stop (GstRTSPSessionMedia *media)
{
GstStateChangeReturn ret;
gboolean ret;
ret = gst_rtsp_media_stop (media->media);
ret = gst_rtsp_media_stop (media->media, media->streams);
return ret;
}

View file

@ -45,17 +45,18 @@ typedef struct _GstRTSPSessionMedia GstRTSPSessionMedia;
/**
* GstRTSPSessionStream:
* @trans: the media transport
* @media_stream: the controlled media stream
*
* Configuration of a stream. A stream is an audio or video stream related to a
* media.
*/
struct _GstRTSPSessionStream
{
GstRTSPMediaTrans trans;
/* the stream of the media */
GstRTSPMediaStream *media_stream;
/* client and server transports */
GstRTSPTransport *client_trans;
};
/**
@ -71,8 +72,11 @@ struct _GstRTSPSessionMedia
/* the pipeline for the media */
GstRTSPMedia *media;
/* the server state */
GstRTSPState state;
/* configuration for the different streams */
GList *streams;
GArray *streams;
};
/**
@ -96,21 +100,27 @@ struct _GstRTSPSessionClass {
GType gst_rtsp_session_get_type (void);
/* create a new session */
GstRTSPSession * gst_rtsp_session_new (const gchar *sessionid);
/* handle media in a session */
GstRTSPSessionMedia * gst_rtsp_session_manage_media (GstRTSPSession *sess,
const GstRTSPUrl *uri,
GstRTSPMedia *media);
/* get media in a session */
GstRTSPSessionMedia * gst_rtsp_session_get_media (GstRTSPSession *sess,
const GstRTSPUrl *uri);
GstStateChangeReturn gst_rtsp_session_media_play (GstRTSPSessionMedia *media);
GstStateChangeReturn gst_rtsp_session_media_pause (GstRTSPSessionMedia *media);
GstStateChangeReturn gst_rtsp_session_media_stop (GstRTSPSessionMedia *media);
/* control media */
gboolean gst_rtsp_session_media_play (GstRTSPSessionMedia *media);
gboolean gst_rtsp_session_media_pause (GstRTSPSessionMedia *media);
gboolean gst_rtsp_session_media_stop (GstRTSPSessionMedia *media);
/* get stream config */
GstRTSPSessionStream * gst_rtsp_session_media_get_stream (GstRTSPSessionMedia *media,
guint idx);
/* configure transport */
GstRTSPTransport * gst_rtsp_session_stream_set_transport (GstRTSPSessionStream *stream,
GstRTSPTransport *ct);