gst/rtsp/gstrtspsrc.*: Small cleanups, added documentation.

Original commit message from CVS:
* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_media_to_caps),
(gst_rtspsrc_send), (gst_rtspsrc_parse_methods),
(gst_rtspsrc_open), (gst_rtspsrc_close), (gst_rtspsrc_play),
(gst_rtspsrc_pause), (gst_rtspsrc_change_state),
(gst_rtspsrc_uri_get_uri), (gst_rtspsrc_uri_set_uri):
* gst/rtsp/gstrtspsrc.h:
Small cleanups, added documentation.
Try to clean up the requests and responses.
Refactor parsing the supported methods.
* gst/rtsp/rtspconnection.c: (rtsp_connection_open),
(rtsp_connection_create), (rtsp_connection_send),
(parse_response_status), (parse_request_line),
(rtsp_connection_receive), (rtsp_connection_close),
(rtsp_connection_free):
* gst/rtsp/rtsptransport.c: (rtsp_transport_new),
(rtsp_transport_init), (rtsp_transport_parse),
(rtsp_transport_free):
* gst/rtsp/rtspurl.c: (rtsp_url_parse):
* gst/rtsp/sdpmessage.c: (sdp_message_new), (sdp_message_init),
(sdp_message_clean), (sdp_message_free), (sdp_media_new),
(sdp_media_init), (sdp_message_parse_buffer), (sdp_message_dump):
Use g_return_val some more.
* gst/rtsp/rtspdefs.h:
Add more enum values to track initial states.
* gst/rtsp/rtspmessage.c: (rtsp_message_new_request),
(rtsp_message_init_request), (rtsp_message_new_response),
(rtsp_message_init_response), (rtsp_message_init_data),
(rtsp_message_unset), (rtsp_message_free),
(rtsp_message_add_header), (rtsp_message_remove_header),
(rtsp_message_get_header), (rtsp_message_set_body),
(rtsp_message_take_body), (rtsp_message_get_body),
(rtsp_message_steal_body), (rtsp_message_dump):
* gst/rtsp/rtspmessage.h:
Reorder arguments, object goes as the first one.
Use g_return_val some more.
This commit is contained in:
Wim Taymans 2006-09-18 17:37:46 +00:00
parent ee58147b3d
commit a437e9f0ed
10 changed files with 467 additions and 306 deletions

View File

@ -1,3 +1,44 @@
2006-09-18 Wim Taymans <wim@fluendo.com>
* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_media_to_caps),
(gst_rtspsrc_send), (gst_rtspsrc_parse_methods),
(gst_rtspsrc_open), (gst_rtspsrc_close), (gst_rtspsrc_play),
(gst_rtspsrc_pause), (gst_rtspsrc_change_state),
(gst_rtspsrc_uri_get_uri), (gst_rtspsrc_uri_set_uri):
* gst/rtsp/gstrtspsrc.h:
Small cleanups, added documentation.
Try to clean up the requests and responses.
Refactor parsing the supported methods.
* gst/rtsp/rtspconnection.c: (rtsp_connection_open),
(rtsp_connection_create), (rtsp_connection_send),
(parse_response_status), (parse_request_line),
(rtsp_connection_receive), (rtsp_connection_close),
(rtsp_connection_free):
* gst/rtsp/rtsptransport.c: (rtsp_transport_new),
(rtsp_transport_init), (rtsp_transport_parse),
(rtsp_transport_free):
* gst/rtsp/rtspurl.c: (rtsp_url_parse):
* gst/rtsp/sdpmessage.c: (sdp_message_new), (sdp_message_init),
(sdp_message_clean), (sdp_message_free), (sdp_media_new),
(sdp_media_init), (sdp_message_parse_buffer), (sdp_message_dump):
Use g_return_val some more.
* gst/rtsp/rtspdefs.h:
Add more enum values to track initial states.
* gst/rtsp/rtspmessage.c: (rtsp_message_new_request),
(rtsp_message_init_request), (rtsp_message_new_response),
(rtsp_message_init_response), (rtsp_message_init_data),
(rtsp_message_unset), (rtsp_message_free),
(rtsp_message_add_header), (rtsp_message_remove_header),
(rtsp_message_get_header), (rtsp_message_set_body),
(rtsp_message_take_body), (rtsp_message_get_body),
(rtsp_message_steal_body), (rtsp_message_dump):
* gst/rtsp/rtspmessage.h:
Reorder arguments, object goes as the first one.
Use g_return_val some more.
2006-09-18 Wim Taymans <wim@fluendo.com>
* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_base_init),

View File

@ -354,6 +354,10 @@ G_STMT_START { \
while (*p && g_ascii_isspace (*p)) \
p++;
/* rtpmap contains:
*
* <payload> <encoding_name>/<clock_rate>[/<encoding_params>]
*/
static gboolean
gst_rtspsrc_parse_rtpmap (gchar * rtpmap, gint * payload, gchar ** name,
gint * rate, gchar ** params)
@ -413,10 +417,9 @@ gst_rtspsrc_media_to_caps (SDPMedia * media)
GstStructure *s;
payload = sdp_media_get_format (media, 0);
if (payload == NULL) {
g_warning ("payload type not given");
return NULL;
}
if (payload == NULL)
goto no_payload;
pt = atoi (payload);
/* dynamic payloads need rtpmap */
@ -428,18 +431,18 @@ gst_rtspsrc_media_to_caps (SDPMedia * media)
ret = gst_rtspsrc_parse_rtpmap (rtpmap, &payload, &name, &rate, &params);
if (ret) {
if (payload != pt) {
/* FIXME, not fatal? */
g_warning ("rtpmap of wrong payload type");
name = NULL;
rate = -1;
params = NULL;
}
} else {
/* FIXME, not fatal? */
g_warning ("error parsing rtpmap");
}
} else {
g_warning ("rtpmap type not given for dynamic payload %d", pt);
return NULL;
}
} else
goto no_rtpmap;
}
caps = gst_caps_new_simple ("application/x-rtp",
@ -494,6 +497,18 @@ gst_rtspsrc_media_to_caps (SDPMedia * media)
}
}
return caps;
/* ERRORS */
no_payload:
{
g_warning ("payload type not given");
return NULL;
}
no_rtpmap:
{
g_warning ("rtpmap type not given for dynamic payload %d", pt);
return NULL;
}
}
static gboolean
@ -948,29 +963,48 @@ need_pause:
}
}
/**
* gst_rtspsrc_send:
* @src: the rtsp source
* @request: must point to a valid request
* @response: must point to an empty #RTSPMessage
*
* send @request and retrieve the response in @response. optionally @code can be
* non-NULL in which case it will contain the status code of the response.
*
* If This function returns TRUE, @response will contain a valid response
* message that should be cleaned with rtsp_message_unset() after usage.
*
* If @code is NULL, this function will return FALSE (with an invalid @response
* message) if the response code was not 200 (OK).
*
* Returns: TRUE if the processing was successful.
*/
static gboolean
gst_rtspsrc_send (GstRTSPSrc * src, RTSPMessage * request,
RTSPMessage * response, RTSPStatusCode * code)
{
RTSPResult res;
RTSPStatusCode thecode;
if (src->debug) {
if (src->debug)
rtsp_message_dump (request);
}
if ((res = rtsp_connection_send (src->connection, request)) < 0)
goto send_error;
if ((res = rtsp_connection_receive (src->connection, response)) < 0)
goto receive_error;
if (code) {
*code = response->type_data.response.code;
}
if (src->debug) {
if (src->debug)
rtsp_message_dump (response);
}
if (response->type_data.response.code != RTSP_STS_OK)
thecode = response->type_data.response.code;
/* if the caller wanted the result code, we store it. Else we check if it's
* OK. */
if (code)
*code = thecode;
else if (thecode != RTSP_STS_OK)
goto error_response;
return TRUE;
@ -990,9 +1024,92 @@ receive_error:
}
error_response:
{
GST_ELEMENT_ERROR (src, RESOURCE, READ, ("Got error response: %d (%s).",
response->type_data.response.code,
response->type_data.response.reason), (NULL));
switch (response->type_data.response.code) {
case RTSP_STS_NOT_FOUND:
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, ("%s",
response->type_data.response.reason), (NULL));
break;
default:
GST_ELEMENT_ERROR (src, RESOURCE, READ, ("Got error response: %d (%s).",
response->type_data.response.code,
response->type_data.response.reason), (NULL));
break;
}
/* we return FALSE so we should unset the response ourselves */
rtsp_message_unset (response);
return FALSE;
}
}
/* parse the response and collect all the supported methods. We need this
* information so that we don't try to send an unsupported request to the
* server.
*/
static gboolean
gst_rtspsrc_parse_methods (GstRTSPSrc * src, RTSPMessage * response)
{
gchar *respoptions = NULL;
gchar **options;
gint i;
/* clear supported methods */
src->methods = 0;
/* Try Allow Header first */
rtsp_message_get_header (response, RTSP_HDR_ALLOW, &respoptions);
if (!respoptions)
/* Then maybe Public Header... */
rtsp_message_get_header (response, RTSP_HDR_PUBLIC, &respoptions);
if (!respoptions) {
/* this field is not required, assume the server supports
* DESCRIBE and SETUP*/
GST_DEBUG_OBJECT (src, "could not get OPTIONS");
src->methods = RTSP_DESCRIBE | RTSP_SETUP;
goto done;
}
/* If we get here, the server gave a list of supported methods, parse
* them here. The string is like:
*
* OPTIONS, DESCRIBE, ANNOUNCE, PLAY, SETUP, ...
*/
options = g_strsplit (respoptions, ",", 0);
i = 0;
while (options[i]) {
gchar *stripped;
gint method;
stripped = g_strstrip (options[i]);
method = rtsp_find_method (stripped);
/* keep bitfield of supported methods */
if (method != -1)
src->methods |= method;
i++;
}
g_strfreev (options);
/* we need describe and setup */
if (!(src->methods & RTSP_DESCRIBE))
goto no_describe;
if (!(src->methods & RTSP_SETUP))
goto no_setup;
done:
return TRUE;
/* ERRORS */
no_describe:
{
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
("Server does not support DESCRIBE."), (NULL));
return FALSE;
}
no_setup:
{
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ,
("Server does not support SETUP."), (NULL));
return FALSE;
}
}
@ -1005,11 +1122,13 @@ gst_rtspsrc_open (GstRTSPSrc * src)
RTSPMessage response = { 0 };
guint8 *data;
guint size;
gint i, n_streams;
SDPMessage sdp = { 0 };
GstRTSPProto protocols;
GstRTSPStream *stream = NULL;
/* can't continue without a valid url */
if (src->url == NULL)
if (G_UNLIKELY (src->url == NULL))
goto no_url;
/* open connection */
@ -1019,7 +1138,7 @@ gst_rtspsrc_open (GstRTSPSrc * src)
/* create OPTIONS */
GST_DEBUG_OBJECT (src, "create options...");
res = rtsp_message_init_request (RTSP_OPTIONS, src->location, &request);
res = rtsp_message_init_request (&request, RTSP_OPTIONS, src->location);
if (res < 0)
goto create_request_failed;
@ -1028,56 +1147,13 @@ gst_rtspsrc_open (GstRTSPSrc * src)
if (!gst_rtspsrc_send (src, &request, &response, NULL))
goto send_error;
{
gchar *respoptions = NULL;
gchar **options;
gint i;
/* Try Allow Header first */
rtsp_message_get_header (&response, RTSP_HDR_ALLOW, &respoptions);
if (!respoptions) {
/* Then maybe Public Header... */
rtsp_message_get_header (&response, RTSP_HDR_PUBLIC, &respoptions);
if (!respoptions) {
/* this field is not required, assume the server supports
* DESCRIBE and SETUP*/
GST_DEBUG_OBJECT (src, "could not get OPTIONS");
src->options = RTSP_DESCRIBE | RTSP_SETUP;
goto no_options;
}
}
/* parse options */
options = g_strsplit (respoptions, ",", 0);
i = 0;
while (options[i]) {
gchar *stripped;
gint method;
stripped = g_strdup (options[i]);
stripped = g_strstrip (stripped);
method = rtsp_find_method (stripped);
g_free (stripped);
/* keep bitfield of supported methods */
if (method != -1)
src->options |= method;
i++;
}
g_strfreev (options);
no_options:
/* we need describe and setup */
if (!(src->options & RTSP_DESCRIBE))
goto no_describe;
if (!(src->options & RTSP_SETUP))
goto no_setup;
}
/* parse OPTIONS */
if (!gst_rtspsrc_parse_methods (src, &response))
goto methods_error;
/* create DESCRIBE */
GST_DEBUG_OBJECT (src, "create describe...");
res = rtsp_message_init_request (RTSP_DESCRIBE, src->location, &request);
res = rtsp_message_init_request (&request, RTSP_DESCRIBE, src->location);
if (res < 0)
goto create_request_failed;
@ -1117,134 +1193,138 @@ gst_rtspsrc_open (GstRTSPSrc * src)
protocols = src->protocols;
/* setup streams */
{
gint i;
n_streams = sdp_message_medias_len (&sdp);
for (i = 0; i < n_streams; i++) {
SDPMedia *media;
gchar *setup_url;
gchar *control_url;
gchar *transports;
for (i = 0; i < sdp_message_medias_len (&sdp); i++) {
SDPMedia *media;
gchar *setup_url;
gchar *control_url;
gchar *transports;
GstRTSPStream *stream;
media = sdp_message_get_media (&sdp, i);
media = sdp_message_get_media (&sdp, i);
GST_DEBUG_OBJECT (src, "setup media %d", i);
control_url = sdp_media_get_attribute_val (media, "control");
if (control_url == NULL) {
GST_DEBUG_OBJECT (src, "no control url found, skipping stream %d", i);
continue;
}
stream = gst_rtspsrc_create_stream (src);
/* check absolute/relative URL */
/* FIXME, what if the control_url starts with a '/' or a non rtsp: protocol? */
if (g_str_has_prefix (control_url, "rtsp://")) {
setup_url = g_strdup (control_url);
} else {
setup_url = g_strdup_printf ("%s/%s", src->location, control_url);
}
GST_DEBUG_OBJECT (src, "setup media %d", i);
control_url = sdp_media_get_attribute_val (media, "control");
if (control_url == NULL) {
GST_DEBUG_OBJECT (src, "no control url found, skipping stream");
continue;
}
GST_DEBUG_OBJECT (src, "setup %s", setup_url);
/* check absolute/relative URL */
/* FIXME, what if the control_url starts with a '/' or a non rtsp: protocol? */
if (g_str_has_prefix (control_url, "rtsp://")) {
setup_url = g_strdup (control_url);
} else {
setup_url = g_strdup_printf ("%s/%s", src->location, control_url);
}
/* create SETUP request */
res = rtsp_message_init_request (&request, RTSP_SETUP, setup_url);
g_free (setup_url);
if (res < 0)
goto create_request_failed;
GST_DEBUG_OBJECT (src, "setup %s", setup_url);
stream = gst_rtspsrc_create_stream (src);
/* create SETUP request */
res = rtsp_message_init_request (RTSP_SETUP, setup_url, &request);
g_free (setup_url);
if (res < 0)
goto create_request_failed;
transports = g_strdup ("");
if (protocols & GST_RTSP_PROTO_UDP_UNICAST) {
gchar *new;
gint rtpport, rtcpport;
gchar *trxparams;
transports = g_strdup ("");
if (protocols & GST_RTSP_PROTO_UDP_UNICAST) {
gchar *new;
gint rtpport, rtcpport;
gchar *trxparams;
/* allocate two UDP ports */
if (!gst_rtspsrc_stream_setup_rtp (stream, media, &rtpport, &rtcpport))
goto setup_rtp_failed;
/* allocate two UDP ports */
if (!gst_rtspsrc_stream_setup_rtp (stream, media, &rtpport, &rtcpport))
goto setup_rtp_failed;
GST_DEBUG_OBJECT (src, "setting up RTP ports %d-%d", rtpport, rtcpport);
GST_DEBUG_OBJECT (src, "setting up RTP ports %d-%d", rtpport, rtcpport);
trxparams = g_strdup_printf ("client_port=%d-%d", rtpport, rtcpport);
new = g_strconcat (transports, "RTP/AVP/UDP;unicast;", trxparams, NULL);
g_free (trxparams);
g_free (transports);
transports = new;
}
if (protocols & GST_RTSP_PROTO_UDP_MULTICAST) {
gchar *new;
GST_DEBUG_OBJECT (src, "setting up MULTICAST");
/* we don't hav to allocate any UDP ports yet, if the selected transport
* turns out to be multicast we can create them and join the multicast
* group indicated in the transport reply */
new =
g_strconcat (transports, transports[0] ? "," : "",
"RTP/AVP/UDP;multicast", NULL);
g_free (transports);
transports = new;
}
if (protocols & GST_RTSP_PROTO_TCP) {
gchar *new;
GST_DEBUG_OBJECT (src, "setting up TCP");
new =
g_strconcat (transports, transports[0] ? "," : "", "RTP/AVP/TCP",
NULL);
g_free (transports);
transports = new;
}
/* select transport, copy is made when adding to header */
rtsp_message_add_header (&request, RTSP_HDR_TRANSPORT, transports);
trxparams = g_strdup_printf ("client_port=%d-%d", rtpport, rtcpport);
new = g_strconcat (transports, "RTP/AVP/UDP;unicast;", trxparams, NULL);
g_free (trxparams);
g_free (transports);
transports = new;
}
if (protocols & GST_RTSP_PROTO_UDP_MULTICAST) {
gchar *new;
if (!gst_rtspsrc_send (src, &request, &response, NULL))
goto send_error;
GST_DEBUG_OBJECT (src, "setting up MULTICAST");
/* parse response transport */
{
gchar *resptrans = NULL;
RTSPTransport transport = { 0 };
/* we don't hav to allocate any UDP ports yet, if the selected transport
* turns out to be multicast we can create them and join the multicast
* group indicated in the transport reply */
new =
g_strconcat (transports, transports[0] ? "," : "",
"RTP/AVP/UDP;multicast", NULL);
g_free (transports);
transports = new;
}
if (protocols & GST_RTSP_PROTO_TCP) {
gchar *new;
rtsp_message_get_header (&response, RTSP_HDR_TRANSPORT, &resptrans);
if (!resptrans)
goto no_transport;
GST_DEBUG_OBJECT (src, "setting up TCP");
/* parse transport */
rtsp_transport_parse (resptrans, &transport);
new =
g_strconcat (transports, transports[0] ? "," : "", "RTP/AVP/TCP",
NULL);
g_free (transports);
transports = new;
}
/* update allowed transports for other streams. once the transport of
* one stream has been determined, we make sure that all other streams
* are configured in the same way */
if (transport.lower_transport == RTSP_LOWER_TRANS_TCP) {
GST_DEBUG_OBJECT (src, "stream %d as TCP", i);
protocols = GST_RTSP_PROTO_TCP;
src->interleaved = TRUE;
/* select transport, copy is made when adding to header */
rtsp_message_add_header (&request, RTSP_HDR_TRANSPORT, transports);
g_free (transports);
if (!gst_rtspsrc_send (src, &request, &response, NULL))
goto send_error;
/* parse response transport */
{
gchar *resptrans = NULL;
RTSPTransport transport = { 0 };
rtsp_message_get_header (&response, RTSP_HDR_TRANSPORT, &resptrans);
if (!resptrans)
goto no_transport;
/* parse transport */
rtsp_transport_parse (resptrans, &transport);
/* update allowed transports for other streams. once the transport of
* one stream has been determined, we make sure that all other streams
* are configured in the same way */
if (transport.lower_transport == RTSP_LOWER_TRANS_TCP) {
GST_DEBUG_OBJECT (src, "stream %d as TCP", i);
protocols = GST_RTSP_PROTO_TCP;
src->interleaved = TRUE;
} else {
if (transport.multicast) {
/* only allow multicast for other streams */
GST_DEBUG_OBJECT (src, "stream %d as MULTICAST", i);
protocols = GST_RTSP_PROTO_UDP_MULTICAST;
} else {
if (transport.multicast) {
/* only allow multicast for other streams */
GST_DEBUG_OBJECT (src, "stream %d as MULTICAST", i);
protocols = GST_RTSP_PROTO_UDP_MULTICAST;
} else {
/* only allow unicast for other streams */
GST_DEBUG_OBJECT (src, "stream %d as UNICAST", i);
protocols = GST_RTSP_PROTO_UDP_UNICAST;
}
/* only allow unicast for other streams */
GST_DEBUG_OBJECT (src, "stream %d as UNICAST", i);
protocols = GST_RTSP_PROTO_UDP_UNICAST;
}
/* now configure the stream with the transport */
if (!gst_rtspsrc_stream_configure_transport (stream, media, &transport)) {
GST_DEBUG_OBJECT (src,
"could not configure stream transport, skipping stream");
}
/* clean up our transport struct */
rtsp_transport_init (&transport);
}
/* now configure the stream with the transport */
if (!gst_rtspsrc_stream_configure_transport (stream, media, &transport)) {
GST_DEBUG_OBJECT (src,
"could not configure stream %d transport, skipping stream", i);
}
/* clean up our transport struct */
rtsp_transport_init (&transport);
}
}
/* if we got here all was configured. We have dynamic pads so we notify that
* we are done */
gst_element_no_more_pads (GST_ELEMENT_CAST (src));
/* clean up any messages */
rtsp_message_unset (&request);
rtsp_message_unset (&response);
return TRUE;
/* ERRORS */
@ -1252,53 +1332,53 @@ no_url:
{
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
("No valid RTSP url was provided"), (NULL));
return FALSE;
goto cleanup_error;
}
could_not_open:
{
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE,
("Could not open connection."), (NULL));
return FALSE;
goto cleanup_error;
}
create_request_failed:
{
GST_ELEMENT_ERROR (src, LIBRARY, INIT,
("Could not create request."), (NULL));
return FALSE;
goto cleanup_error;
}
send_error:
{
GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
("Could not send message."), (NULL));
return FALSE;
goto cleanup_error;
}
no_describe:
methods_error:
{
GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
("Server does not support DESCRIBE."), (NULL));
return FALSE;
}
no_setup:
{
GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
("Server does not support SETUP."), (NULL));
return FALSE;
/* error was posted */
goto cleanup_error;
}
wrong_content_type:
{
GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS,
("Server does not support SDP."), (NULL));
return FALSE;
goto cleanup_error;
}
setup_rtp_failed:
{
GST_ELEMENT_ERROR (src, RESOURCE, WRITE, ("Could not setup rtp."), (NULL));
return FALSE;
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, ("Could not setup rtp."),
(NULL));
goto cleanup_error;
}
no_transport:
{
GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS,
("Server did not select transport."), (NULL));
goto cleanup_error;
}
cleanup_error:
{
rtsp_message_unset (&request);
rtsp_message_unset (&response);
return FALSE;
}
}
@ -1328,14 +1408,18 @@ gst_rtspsrc_close (GstRTSPSrc * src)
src->task = NULL;
}
if (src->options & RTSP_PLAY) {
if (src->methods & RTSP_PLAY) {
/* do TEARDOWN */
res = rtsp_message_init_request (RTSP_TEARDOWN, src->location, &request);
res = rtsp_message_init_request (&request, RTSP_TEARDOWN, src->location);
if (res < 0)
goto create_request_failed;
if (!gst_rtspsrc_send (src, &request, &response, NULL))
goto send_error;
/* FIXME, parse result? */
rtsp_message_unset (&request);
rtsp_message_unset (&response);
}
/* close connection */
@ -1354,6 +1438,7 @@ create_request_failed:
}
send_error:
{
rtsp_message_unset (&request);
GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
("Could not send message."), (NULL));
return FALSE;
@ -1372,13 +1457,13 @@ gst_rtspsrc_play (GstRTSPSrc * src)
RTSPMessage response = { 0 };
RTSPResult res;
if (!(src->options & RTSP_PLAY))
if (!(src->methods & RTSP_PLAY))
return TRUE;
GST_DEBUG_OBJECT (src, "PLAY...");
/* do play */
res = rtsp_message_init_request (RTSP_PLAY, src->location, &request);
res = rtsp_message_init_request (&request, RTSP_PLAY, src->location);
if (res < 0)
goto create_request_failed;
@ -1387,10 +1472,16 @@ gst_rtspsrc_play (GstRTSPSrc * src)
if (!gst_rtspsrc_send (src, &request, &response, NULL))
goto send_error;
rtsp_message_unset (&request);
rtsp_message_unset (&response);
/* for interleaved transport, we receive the data on the RTSP connection
* instead of UDP. We start a task to select and read from that connection. */
if (src->interleaved) {
src->task = gst_task_create ((GstTaskFunction) gst_rtspsrc_loop, src);
gst_task_set_lock (src->task, src->stream_rec_lock);
src->running = TRUE;
gst_task_start (src->task);
}
@ -1405,6 +1496,7 @@ create_request_failed:
}
send_error:
{
rtsp_message_unset (&request);
GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
("Could not send message."), (NULL));
return FALSE;
@ -1418,18 +1510,21 @@ gst_rtspsrc_pause (GstRTSPSrc * src)
RTSPMessage response = { 0 };
RTSPResult res;
if (!(src->options & RTSP_PAUSE))
if (!(src->methods & RTSP_PAUSE))
return TRUE;
GST_DEBUG_OBJECT (src, "PAUSE...");
/* do pause */
res = rtsp_message_init_request (RTSP_PAUSE, src->location, &request);
res = rtsp_message_init_request (&request, RTSP_PAUSE, src->location);
if (res < 0)
goto create_request_failed;
if (!gst_rtspsrc_send (src, &request, &response, NULL))
goto send_error;
rtsp_message_unset (&request);
rtsp_message_unset (&response);
return TRUE;
/* ERRORS */
@ -1441,6 +1536,7 @@ create_request_failed:
}
send_error:
{
rtsp_message_unset (&request);
GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
("Could not send message."), (NULL));
return FALSE;
@ -1461,7 +1557,7 @@ gst_rtspsrc_change_state (GstElement * element, GstStateChange transition)
break;
case GST_STATE_CHANGE_READY_TO_PAUSED:
rtspsrc->interleaved = FALSE;
rtspsrc->options = 0;
gst_segment_init (&rtspsrc->segment, GST_FORMAT_TIME);
if (!gst_rtspsrc_open (rtspsrc))
goto open_failed;
break;
@ -1521,6 +1617,7 @@ gst_rtspsrc_uri_get_uri (GstURIHandler * handler)
{
GstRTSPSrc *src = GST_RTSPSRC (handler);
/* should not dup */
return src->location;
}
@ -1560,8 +1657,8 @@ was_ok:
}
parse_error:
{
GST_ERROR_OBJECT (src, "Not a valid RTSP url '%s' (%d)", GST_STR_NULL (uri),
res);
GST_ERROR_OBJECT (src, "Not a valid RTSP url '%s' (%d)",
GST_STR_NULL (uri), res);
return FALSE;
}
}

View File

@ -103,8 +103,8 @@ struct _GstRTSPSrc {
guint retry;
GstRTSPProto protocols;
/* supported options */
gint options;
/* supported methods */
gint methods;
RTSPConnection *connection;
RTSPMessage *request;

View File

@ -71,8 +71,8 @@ rtsp_connection_open (RTSPUrl * url, RTSPConnection ** conn)
struct in_addr addr;
gint ret;
if (url == NULL || conn == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (url != NULL, RTSP_EINVAL);
g_return_val_if_fail (conn != NULL, RTSP_EINVAL);
if (url->protocol != RTSP_PROTO_TCP)
return RTSP_ENOTIMPL;
@ -128,6 +128,8 @@ rtsp_connection_create (gint fd, RTSPConnection ** conn)
{
RTSPConnection *newconn;
g_return_val_if_fail (conn != NULL, RTSP_EINVAL);
/* FIXME check fd, must be connected SOCK_STREAM */
newconn = g_new (RTSPConnection, 1);
@ -157,8 +159,8 @@ rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message)
gint towrite;
gchar *data;
if (conn == NULL || message == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (conn != NULL, RTSP_EINVAL);
g_return_val_if_fail (message != NULL, RTSP_EINVAL);
#ifdef G_OS_WIN32
WSADATA w;
@ -333,7 +335,7 @@ parse_response_status (gchar * buffer, RTSPMessage * msg)
while (g_ascii_isspace (*bptr))
bptr++;
rtsp_message_init_response (code, bptr, NULL, msg);
rtsp_message_init_response (msg, code, bptr, NULL);
return RTSP_OK;
@ -365,7 +367,7 @@ parse_request_line (gchar * buffer, RTSPMessage * msg)
if (strcmp (versionstr, "RTSP/1.0") != 0)
goto wrong_version;
rtsp_message_init_request (method, urlstr, msg);
rtsp_message_init_request (msg, method, urlstr);
return RTSP_OK;
@ -456,8 +458,8 @@ rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg)
RTSPResult res;
gboolean need_body;
if (conn == NULL || msg == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (conn != NULL, RTSP_EINVAL);
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
line = 0;
@ -490,7 +492,7 @@ rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg)
goto error;
/* now we create a data message */
rtsp_message_init_data ((gint) c, msg);
rtsp_message_init_data (msg, (gint) c);
/* next two bytes are the length of the data */
ret = read (conn->fd, &size, 2);
@ -590,8 +592,7 @@ rtsp_connection_close (RTSPConnection * conn)
{
gint res;
if (conn == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (conn != NULL, RTSP_EINVAL);
res = CLOSE_SOCKET (conn->fd);
#ifdef G_OS_WIN32
@ -612,8 +613,7 @@ sys_error:
RTSPResult
rtsp_connection_free (RTSPConnection * conn)
{
if (conn == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (conn != NULL, RTSP_EINVAL);
#ifdef G_OS_WIN32
WSACleanup ();

View File

@ -50,6 +50,7 @@ typedef enum {
} RTSPFamily;
typedef enum {
RTSP_STATE_INVALID,
RTSP_STATE_INIT,
RTSP_STATE_READY,
RTSP_STATE_PLAYING,
@ -57,6 +58,7 @@ typedef enum {
} RTSPState;
typedef enum {
RTSP_INVALID = 0,
RTSP_DESCRIBE = (1 << 0),
RTSP_ANNOUNCE = (1 << 1),
RTSP_GET_PARAMETER = (1 << 2),
@ -120,6 +122,7 @@ typedef enum {
} RTSPHeaderField;
typedef enum {
RTSP_STS_INVALID = 0,
RTSP_STS_CONTINUE = 100,
RTSP_STS_OK = 200,
RTSP_STS_CREATED = 201,

View File

@ -20,84 +20,69 @@
#include "rtspmessage.h"
RTSPResult
rtsp_message_new_request (RTSPMethod method, gchar * uri, RTSPMessage ** msg)
rtsp_message_new_request (RTSPMessage ** msg, RTSPMethod method, gchar * uri)
{
RTSPMessage *newmsg;
if (msg == NULL || uri == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
g_return_val_if_fail (uri != NULL, RTSP_EINVAL);
newmsg = g_new0 (RTSPMessage, 1);
*msg = newmsg;
return rtsp_message_init_request (method, uri, newmsg);
return rtsp_message_init_request (newmsg, method, uri);
}
RTSPResult
rtsp_message_init_request (RTSPMethod method, gchar * uri, RTSPMessage * msg)
rtsp_message_init_request (RTSPMessage * msg, RTSPMethod method, gchar * uri)
{
if (msg == NULL || uri == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (uri != NULL, RTSP_EINVAL);
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
rtsp_message_unset (msg);
msg->type = RTSP_MESSAGE_REQUEST;
msg->type_data.request.method = method;
g_free (msg->type_data.request.uri);
msg->type_data.request.uri = g_strdup (uri);
if (msg->hdr_fields != NULL)
g_hash_table_destroy (msg->hdr_fields);
msg->hdr_fields =
g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
if (msg->body) {
g_free (msg->body);
msg->body = NULL;
}
msg->body_size = 0;
return RTSP_OK;
}
RTSPResult
rtsp_message_new_response (RTSPStatusCode code, gchar * reason,
RTSPMessage * request, RTSPMessage ** msg)
rtsp_message_new_response (RTSPMessage ** msg, RTSPStatusCode code,
gchar * reason, RTSPMessage * request)
{
RTSPMessage *newmsg;
if (msg == NULL || reason == NULL || request == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (reason != NULL, RTSP_EINVAL);
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
g_return_val_if_fail (request != NULL, RTSP_EINVAL);
newmsg = g_new0 (RTSPMessage, 1);
*msg = newmsg;
return rtsp_message_init_response (code, reason, request, newmsg);
return rtsp_message_init_response (newmsg, code, reason, request);
}
RTSPResult
rtsp_message_init_response (RTSPStatusCode code, gchar * reason,
RTSPMessage * request, RTSPMessage * msg)
rtsp_message_init_response (RTSPMessage * msg, RTSPStatusCode code,
gchar * reason, RTSPMessage * request)
{
if (reason == NULL || msg == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
g_return_val_if_fail (reason != NULL, RTSP_EINVAL);
rtsp_message_unset (msg);
msg->type = RTSP_MESSAGE_RESPONSE;
msg->type_data.response.code = code;
g_free (msg->type_data.response.reason);
msg->type_data.response.reason = g_strdup (reason);
if (msg->hdr_fields != NULL)
g_hash_table_destroy (msg->hdr_fields);
msg->hdr_fields =
g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
if (msg->body) {
g_free (msg->body);
msg->body = NULL;
}
msg->body_size = 0;
if (request) {
/* FIXME copy headers */
}
@ -106,10 +91,11 @@ rtsp_message_init_response (RTSPStatusCode code, gchar * reason,
}
RTSPResult
rtsp_message_init_data (gint channel, RTSPMessage * msg)
rtsp_message_init_data (RTSPMessage * msg, gint channel)
{
if (msg == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
rtsp_message_unset (msg);
msg->type = RTSP_MESSAGE_DATA;
msg->type_data.data.channel = channel;
@ -117,13 +103,51 @@ rtsp_message_init_data (gint channel, RTSPMessage * msg)
return RTSP_OK;
}
RTSPResult
rtsp_message_unset (RTSPMessage * msg)
{
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
msg->type = RTSP_MESSAGE_INVALID;
msg->type_data.request.method = RTSP_INVALID;
g_free (msg->type_data.request.uri);
msg->type_data.request.uri = NULL;
msg->type_data.response.code = RTSP_STS_INVALID;
g_free (msg->type_data.response.reason);
msg->type_data.response.reason = NULL;
if (msg->hdr_fields != NULL)
g_hash_table_destroy (msg->hdr_fields);
msg->hdr_fields = NULL;
g_free (msg->body);
msg->body = NULL;
msg->body_size = 0;
return RTSP_OK;
}
RTSPResult
rtsp_message_free (RTSPMessage * msg)
{
RTSPResult res;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
res = rtsp_message_unset (msg);
if (res == RTSP_OK)
g_free (msg);
return res;
}
RTSPResult
rtsp_message_add_header (RTSPMessage * msg, RTSPHeaderField field,
gchar * value)
{
if (msg == NULL || value == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
g_return_val_if_fail (value != NULL, RTSP_EINVAL);
g_hash_table_insert (msg->hdr_fields, GINT_TO_POINTER (field),
g_strdup (value));
@ -134,8 +158,7 @@ rtsp_message_add_header (RTSPMessage * msg, RTSPHeaderField field,
RTSPResult
rtsp_message_remove_header (RTSPMessage * msg, RTSPHeaderField field)
{
if (msg == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
g_hash_table_remove (msg->hdr_fields, GINT_TO_POINTER (field));
@ -148,8 +171,8 @@ rtsp_message_get_header (RTSPMessage * msg, RTSPHeaderField field,
{
gchar *val;
if (msg == NULL || value == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
g_return_val_if_fail (value != NULL, RTSP_EINVAL);
val = g_hash_table_lookup (msg->hdr_fields, GINT_TO_POINTER (field));
if (val == NULL)
@ -163,8 +186,7 @@ rtsp_message_get_header (RTSPMessage * msg, RTSPHeaderField field,
RTSPResult
rtsp_message_set_body (RTSPMessage * msg, guint8 * data, guint size)
{
if (msg == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
return rtsp_message_take_body (msg, g_memdup (data, size), size);
}
@ -172,8 +194,7 @@ rtsp_message_set_body (RTSPMessage * msg, guint8 * data, guint size)
RTSPResult
rtsp_message_take_body (RTSPMessage * msg, guint8 * data, guint size)
{
if (msg == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
if (msg->body)
g_free (msg->body);
@ -187,8 +208,9 @@ rtsp_message_take_body (RTSPMessage * msg, guint8 * data, guint size)
RTSPResult
rtsp_message_get_body (RTSPMessage * msg, guint8 ** data, guint * size)
{
if (msg == NULL || data == NULL || size == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
g_return_val_if_fail (data != NULL, RTSP_EINVAL);
g_return_val_if_fail (size != NULL, RTSP_EINVAL);
*data = msg->body;
*size = msg->body_size;
@ -199,8 +221,9 @@ rtsp_message_get_body (RTSPMessage * msg, guint8 ** data, guint * size)
RTSPResult
rtsp_message_steal_body (RTSPMessage * msg, guint8 ** data, guint * size)
{
if (msg == NULL || data == NULL || size == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
g_return_val_if_fail (data != NULL, RTSP_EINVAL);
g_return_val_if_fail (size != NULL, RTSP_EINVAL);
*data = msg->body;
*size = msg->body_size;
@ -257,8 +280,7 @@ rtsp_message_dump (RTSPMessage * msg)
guint8 *data;
guint size;
if (msg == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
if (msg->type == RTSP_MESSAGE_REQUEST) {
g_print ("request message %p\n", msg);

View File

@ -28,6 +28,7 @@ G_BEGIN_DECLS
typedef enum
{
RTSP_MESSAGE_INVALID,
RTSP_MESSAGE_REQUEST,
RTSP_MESSAGE_RESPONSE,
RTSP_MESSAGE_DATA,
@ -58,15 +59,16 @@ typedef struct _RTSPMessage
} RTSPMessage;
RTSPResult rtsp_message_new_request (RTSPMethod method, gchar *uri, RTSPMessage **msg);
RTSPResult rtsp_message_init_request (RTSPMethod method, gchar *uri, RTSPMessage *msg);
RTSPResult rtsp_message_new_request (RTSPMessage **msg, RTSPMethod method, gchar *uri);
RTSPResult rtsp_message_init_request (RTSPMessage *msg, RTSPMethod method, gchar *uri);
RTSPResult rtsp_message_new_response (RTSPStatusCode code, gchar *reason,
RTSPMessage *request, RTSPMessage **msg);
RTSPResult rtsp_message_init_response (RTSPStatusCode code, gchar *reason,
RTSPMessage *request, RTSPMessage *msg);
RTSPResult rtsp_message_init_data (gint channel, RTSPMessage *msg);
RTSPResult rtsp_message_new_response (RTSPMessage **msg, RTSPStatusCode code, gchar *reason,
RTSPMessage *request);
RTSPResult rtsp_message_init_response (RTSPMessage *msg, RTSPStatusCode code, gchar *reason,
RTSPMessage *request);
RTSPResult rtsp_message_init_data (RTSPMessage *msg, gint channel);
RTSPResult rtsp_message_unset (RTSPMessage *msg);
RTSPResult rtsp_message_free (RTSPMessage *msg);

View File

@ -27,8 +27,7 @@ rtsp_transport_new (RTSPTransport ** transport)
{
RTSPTransport *trans;
if (transport == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (transport != NULL, RTSP_EINVAL);
trans = g_new0 (RTSPTransport, 1);
@ -40,6 +39,8 @@ rtsp_transport_new (RTSPTransport ** transport)
RTSPResult
rtsp_transport_init (RTSPTransport * transport)
{
g_return_val_if_fail (transport != NULL, RTSP_EINVAL);
g_free (transport->destination);
g_free (transport->source);
g_free (transport->ssrc);
@ -83,8 +84,8 @@ rtsp_transport_parse (gchar * str, RTSPTransport * transport)
gchar **split, *down;
gint i;
if (str == NULL || transport == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (transport != NULL, RTSP_EINVAL);
g_return_val_if_fail (str != NULL, RTSP_EINVAL);
rtsp_transport_init (transport);
@ -141,6 +142,8 @@ rtsp_transport_parse (gchar * str, RTSPTransport * transport)
RTSPResult
rtsp_transport_free (RTSPTransport * transport)
{
g_return_val_if_fail (transport != NULL, RTSP_EINVAL);
rtsp_transport_init (transport);
g_free (transport);
return RTSP_OK;

View File

@ -34,10 +34,10 @@ rtsp_url_parse (const gchar * urlstr, RTSPUrl ** url)
RTSPUrl *res;
gchar *p, *slash, *at, *col;
res = g_new0 (RTSPUrl, 1);
g_return_val_if_fail (urlstr != NULL, RTSP_EINVAL);
g_return_val_if_fail (url != NULL, RTSP_EINVAL);
if (urlstr == NULL)
goto invalid;
res = g_new0 (RTSPUrl, 1);
p = (gchar *) urlstr;
if (g_str_has_prefix (p, RTSP_PROTO)) {

View File

@ -76,8 +76,7 @@ sdp_message_new (SDPMessage ** msg)
{
SDPMessage *newmsg;
if (msg == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
newmsg = g_new0 (SDPMessage, 1);
@ -89,8 +88,7 @@ sdp_message_new (SDPMessage ** msg)
RTSPResult
sdp_message_init (SDPMessage * msg)
{
if (msg == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
FREE_STRING (msg->version);
FREE_STRING (msg->origin.username);
@ -123,8 +121,7 @@ sdp_message_init (SDPMessage * msg)
RTSPResult
sdp_message_clean (SDPMessage * msg)
{
if (msg == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
FREE_ARRAY (msg->emails);
FREE_ARRAY (msg->phones);
@ -140,8 +137,7 @@ sdp_message_clean (SDPMessage * msg)
RTSPResult
sdp_message_free (SDPMessage * msg)
{
if (msg == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
sdp_message_clean (msg);
@ -156,8 +152,7 @@ sdp_media_new (SDPMedia ** media)
{
SDPMedia *newmedia;
if (media == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (media != NULL, RTSP_EINVAL);
newmedia = g_new0 (SDPMedia, 1);
@ -169,8 +164,7 @@ sdp_media_new (SDPMedia ** media)
RTSPResult
sdp_media_init (SDPMedia * media)
{
if (media == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (media != NULL, RTSP_EINVAL);
FREE_STRING (media->media);
media->port = 0;
@ -578,8 +572,9 @@ sdp_message_parse_buffer (guint8 * data, guint size, SDPMessage * msg)
gchar buffer[4096];
gint idx = 0;
if (msg == NULL || data == NULL || size == 0)
return RTSP_EINVAL;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
g_return_val_if_fail (data != NULL, RTSP_EINVAL);
g_return_val_if_fail (size != 0, RTSP_EINVAL);
c.state = SDP_SESSION;
c.msg = msg;
@ -651,8 +646,7 @@ print_media (SDPMedia * media)
RTSPResult
sdp_message_dump (SDPMessage * msg)
{
if (msg == NULL)
return RTSP_EINVAL;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
g_print ("sdp packet %p:\n", msg);
g_print (" version: '%s'\n", msg->version);
@ -666,6 +660,7 @@ sdp_message_dump (SDPMessage * msg)
g_print (" session_name: '%s'\n", msg->session_name);
g_print (" information: '%s'\n", msg->information);
g_print (" uri: '%s'\n", msg->uri);
if (msg->emails->len > 0) {
gint i;
@ -710,7 +705,5 @@ sdp_message_dump (SDPMessage * msg)
print_media (&g_array_index (msg->medias, SDPMedia, i));
}
}
return RTSP_OK;
}