+2007-05-24 Wim Taymans <wim@fluendo.com>
+
+ Patch by: Peter Kjellerstedt <pkj at axis com>
+
+ * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_setup_auth),
+ (gst_rtspsrc_try_send), (gst_rtspsrc_parse_methods),
+ (gst_rtspsrc_setup_streams), (gst_rtspsrc_open),
+ (gst_rtspsrc_play):
+ (rtsp_connection_send), (rtsp_connection_receive):
+ * gst/rtsp/rtspextwms.c: (rtsp_ext_wms_after_send):
+ Fix for new API.
+
+ * gst/rtsp/rtspconnection.c: (add_auth_header),
+ Only add authorisation and session headers when sending messages.
+
+ * gst/rtsp/rtspmessage.c: (key_value_foreach), (rtsp_message_init),
+ (rtsp_message_init_request), (rtsp_message_init_response),
+ (rtsp_message_unset), (rtsp_message_add_header),
+ (rtsp_message_remove_header), (rtsp_message_get_header),
+ (rtsp_message_append_headers), (dump_key_value),
+ (rtsp_message_dump):
+ * gst/rtsp/rtspmessage.h:
+ Add support for multiple headers of the same type by storing the parsed
+ headers in a GArray instaed of a hashtable.
+
2007-05-21 Wim Taymans <wim@fluendo.com>
* gst/udp/gstudpsrc.c: (gst_udpsrc_class_init),
gchar *hdr;
/* Identify the available auth methods and see if any are supported */
- if (rtsp_message_get_header (response, RTSP_HDR_WWW_AUTHENTICATE, &hdr) ==
+ if (rtsp_message_get_header (response, RTSP_HDR_WWW_AUTHENTICATE, &hdr, 0) ==
RTSP_OK) {
gst_rtspsrc_parse_auth_hdr (hdr, &avail_methods);
}
return RTSP_OK;
/* store new content base if any */
- rtsp_message_get_header (response, RTSP_HDR_CONTENT_BASE, &content_base);
+ rtsp_message_get_header (response, RTSP_HDR_CONTENT_BASE, &content_base, 0);
g_free (src->content_base);
src->content_base = g_strdup (content_base);
static gboolean
gst_rtspsrc_parse_methods (GstRTSPSrc * src, RTSPMessage * response)
{
+ RTSPHeaderField field;
gchar *respoptions = NULL;
gchar **options;
+ gint indx = 0;
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, SETUP and PLAY */
- GST_DEBUG_OBJECT (src, "could not get OPTIONS");
- src->methods = RTSP_DESCRIBE | RTSP_SETUP | RTSP_PLAY | RTSP_PAUSE;
- goto done;
- }
+ /* try the Allow header first */
+ field = RTSP_HDR_ALLOW;
+ while (TRUE) {
+ rtsp_message_get_header (response, field, &respoptions, indx);
+ if (indx == 0 && !respoptions) {
+ /* if no Allow header was found then try the Public header... */
+ field = RTSP_HDR_PUBLIC;
+ rtsp_message_get_header (response, field, &respoptions, indx);
+ }
+ if (!respoptions)
+ break;
- /* 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);
+ /* 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);
- for (i = 0; options[i]; i++) {
- gchar *stripped;
- gint method;
+ for (i = 0; options[i]; i++) {
+ gchar *stripped;
+ gint method;
- stripped = g_strstrip (options[i]);
- method = rtsp_find_method (stripped);
+ stripped = g_strstrip (options[i]);
+ method = rtsp_find_method (stripped);
- /* keep bitfield of supported methods */
- if (method != RTSP_INVALID)
- src->methods |= method;
+ /* keep bitfield of supported methods */
+ if (method != RTSP_INVALID)
+ src->methods |= method;
+ }
+ g_strfreev (options);
+
+ indx++;
+ }
+
+ if (src->methods == 0) {
+ /* neither Allow nor Public are required, assume the server supports
+ * DESCRIBE, SETUP, PLAY and PAUSE */
+ GST_DEBUG_OBJECT (src, "could not get OPTIONS");
+ src->methods = RTSP_DESCRIBE | RTSP_SETUP | RTSP_PLAY | RTSP_PAUSE;
}
- g_strfreev (options);
/* we need describe and setup */
if (!(src->methods & RTSP_DESCRIBE))
if (!(src->methods & RTSP_SETUP))
goto no_setup;
-done:
return TRUE;
/* ERRORS */
gchar *resptrans = NULL;
RTSPTransport transport = { 0 };
- rtsp_message_get_header (&response, RTSP_HDR_TRANSPORT, &resptrans);
+ rtsp_message_get_header (&response, RTSP_HDR_TRANSPORT, &resptrans, 0);
if (!resptrans)
goto no_transport;
goto send_error;
/* check if reply is SDP */
- rtsp_message_get_header (&response, RTSP_HDR_CONTENT_TYPE, &respcont);
+ rtsp_message_get_header (&response, RTSP_HDR_CONTENT_TYPE, &respcont, 0);
/* could not be set but since the request returned OK, we assume it
* was SDP, else check it. */
if (respcont) {
/* parse RTP npt field. This is the current position in the stream (Normal
* Play Time) and should be put in the NEWSEGMENT position field. */
- if (rtsp_message_get_header (&response, RTSP_HDR_RANGE, &range) == RTSP_OK)
+ if (rtsp_message_get_header (&response, RTSP_HDR_RANGE, &range, 0) == RTSP_OK)
gst_rtspsrc_parse_range (src, range);
/* parse the RTP-Info header field (if ANY) to get the base seqnum and timestamp
* for the RTP packets. If this is not present, we assume all starts from 0...
* This is info for the RTP session manager that we pass to it in caps. */
if (rtsp_message_get_header (&response, RTSP_HDR_RTP_INFO,
- &rtpinfo) == RTSP_OK)
+ &rtpinfo, 0) == RTSP_OK)
gst_rtspsrc_parse_rtpinfo (src, rtpinfo);
rtsp_message_unset (&response);
}
static void
-append_header (gint key, gchar * value, GString * str)
-{
- const gchar *keystr = rtsp_header_as_text (key);
-
- g_string_append_printf (str, "%s: %s\r\n", keystr, value);
-}
-
-static void
-append_auth_header (RTSPConnection * conn, RTSPMessage * message, GString * str)
+add_auth_header (RTSPConnection * conn, RTSPMessage * message)
{
switch (conn->auth_method) {
case RTSP_AUTH_BASIC:{
gchar *user_pass64 = util_base64_encode (user_pass, strlen (user_pass));
gchar *auth_string = g_strdup_printf ("Basic %s", user_pass64);
- append_header (RTSP_HDR_AUTHORIZATION, auth_string, str);
+ rtsp_message_add_header (message, RTSP_HDR_AUTHORIZATION, auth_string);
g_free (user_pass);
g_free (user_pass64);
"CSeq: %d\r\n",
rtsp_method_as_text (message->type_data.request.method),
message->type_data.request.uri, conn->cseq++);
+ /* add session id if we have one */
+ if (conn->session_id[0] != '\0') {
+ rtsp_message_add_header (message, RTSP_HDR_SESSION, conn->session_id);
+ }
+ /* add any authentication headers */
+ add_auth_header (conn, message);
break;
case RTSP_MESSAGE_RESPONSE:
/* create response string */
break;
}
- /* append specific headers and body */
- switch (message->type) {
- case RTSP_MESSAGE_REQUEST:
- case RTSP_MESSAGE_RESPONSE:
- /* append session id if we have one */
- if (conn->session_id[0] != '\0') {
- append_header (RTSP_HDR_SESSION, conn->session_id, str);
- }
- /* append headers */
- g_hash_table_foreach (message->hdr_fields, (GHFunc) append_header, str);
-
- /* Append any authentication headers */
- append_auth_header (conn, message, str);
-
- /* append Content-Length and body if needed */
- if (message->body != NULL && message->body_size > 0) {
- gchar *len;
-
- len = g_strdup_printf ("%d", message->body_size);
- append_header (RTSP_HDR_CONTENT_LENGTH, len, str);
- g_free (len);
- /* header ends here */
- g_string_append (str, "\r\n");
- str =
- g_string_append_len (str, (gchar *) message->body,
- message->body_size);
- } else {
- /* just end headers */
- g_string_append (str, "\r\n");
- }
- break;
- default:
- break;
+ /* append headers and body */
+ if (message->type != RTSP_MESSAGE_DATA) {
+ /* append headers */
+ rtsp_message_append_headers (message, str);
+
+ /* append Content-Length and body if needed */
+ if (message->body != NULL && message->body_size > 0) {
+ gchar *len;
+
+ len = g_strdup_printf ("%d", message->body_size);
+ g_string_append_printf (str, "%s: %s\r\n",
+ rtsp_header_as_text (RTSP_HDR_CONTENT_LENGTH), len);
+ g_free (len);
+ /* header ends here */
+ g_string_append (str, "\r\n");
+ str =
+ g_string_append_len (str, (gchar *) message->body,
+ message->body_size);
+ } else {
+ /* just end headers */
+ g_string_append (str, "\r\n");
+ }
}
/* write request */
if (need_body) {
/* see if there is a Content-Length header */
if (rtsp_message_get_header (msg, RTSP_HDR_CONTENT_LENGTH,
- &hdrval) == RTSP_OK) {
+ &hdrval, 0) == RTSP_OK) {
/* there is, read the body */
content_length = atol (hdrval);
RTSP_CHECK (read_body (conn, content_length, msg, timeout), read_error);
gchar *session_id;
if (rtsp_message_get_header (msg, RTSP_HDR_SESSION,
- &session_id) == RTSP_OK) {
+ &session_id, 0) == RTSP_OK) {
gint sesslen, maxlen, i;
/* default session timeout */
{
gchar *server = NULL;
- rtsp_message_get_header (resp, RTSP_HDR_SERVER, &server);
+ rtsp_message_get_header (resp, RTSP_HDR_SERVER, &server, 0);
if (server && g_str_has_prefix (server, SERVER_PREFIX))
rext->active = TRUE;
else
#include "rtspmessage.h"
+typedef struct _RTSPKeyValue
+{
+ RTSPHeaderField field;
+ gchar *value;
+} RTSPKeyValue;
+
+static void
+key_value_foreach (GArray * array, GFunc func, gpointer user_data)
+{
+ guint i;
+
+ g_return_if_fail (array != NULL);
+
+ for (i = 0; i < array->len; i++) {
+ (*func) (&g_array_index (array, RTSPKeyValue, i), user_data);
+ }
+}
+
RTSPResult
rtsp_message_new (RTSPMessage ** msg)
{
rtsp_message_unset (msg);
msg->type = RTSP_MESSAGE_INVALID;
- msg->hdr_fields =
- g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+ msg->hdr_fields = g_array_new (FALSE, FALSE, sizeof (RTSPKeyValue));
return RTSP_OK;
}
msg->type = RTSP_MESSAGE_REQUEST;
msg->type_data.request.method = method;
msg->type_data.request.uri = g_strdup (uri);
- msg->hdr_fields =
- g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+ msg->hdr_fields = g_array_new (FALSE, FALSE, sizeof (RTSPKeyValue));
return RTSP_OK;
}
msg->type = RTSP_MESSAGE_RESPONSE;
msg->type_data.response.code = code;
msg->type_data.response.reason = g_strdup (reason);
- msg->hdr_fields =
- g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+ msg->hdr_fields = g_array_new (FALSE, FALSE, sizeof (RTSPKeyValue));
if (request) {
gchar *header;
/* copy CSEQ */
- if (rtsp_message_get_header (request, RTSP_HDR_CSEQ, &header) == RTSP_OK) {
+ if (rtsp_message_get_header (request, RTSP_HDR_CSEQ, &header, 0) == RTSP_OK) {
rtsp_message_add_header (msg, RTSP_HDR_CSEQ, header);
}
/* copy session id */
- if (rtsp_message_get_header (request, RTSP_HDR_SESSION, &header) == RTSP_OK) {
+ if (rtsp_message_get_header (request, RTSP_HDR_SESSION, &header,
+ 0) == RTSP_OK) {
char *pos;
header = g_strdup (header);
}
if (msg->hdr_fields != NULL)
- g_hash_table_destroy (msg->hdr_fields);
+ g_array_free (msg->hdr_fields, TRUE);
g_free (msg->body);
rtsp_message_add_header (RTSPMessage * msg, RTSPHeaderField field,
const gchar * value)
{
+ RTSPKeyValue key_value;
+
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));
+ key_value.field = field;
+ key_value.value = g_strdup (value);
+
+ g_array_append_val (msg->hdr_fields, key_value);
return RTSP_OK;
}
RTSPResult
-rtsp_message_remove_header (RTSPMessage * msg, RTSPHeaderField field)
+rtsp_message_remove_header (RTSPMessage * msg, RTSPHeaderField field, gint indx)
{
+ RTSPResult res = RTSP_ENOTIMPL;
+ guint i = 0;
+ gint cnt = 0;
+
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
- g_hash_table_remove (msg->hdr_fields, GINT_TO_POINTER (field));
+ while (i < msg->hdr_fields->len) {
+ RTSPKeyValue key_value = g_array_index (msg->hdr_fields, RTSPKeyValue, i);
- return RTSP_ENOTIMPL;
+ if (key_value.field == field && (indx == -1 || cnt++ == indx)) {
+ g_array_remove_index (msg->hdr_fields, i);
+ res = RTSP_OK;
+ if (indx != -1)
+ break;
+ } else {
+ i++;
+ }
+ }
+
+ return res;
}
RTSPResult
rtsp_message_get_header (const RTSPMessage * msg, RTSPHeaderField field,
- gchar ** value)
+ gchar ** value, gint indx)
{
- gchar *val;
+ guint i;
+ gint cnt = 0;
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
- if (msg->type == RTSP_MESSAGE_INVALID || msg->type == RTSP_MESSAGE_DATA)
- return RTSP_ENOTIMPL;
+ for (i = 0; i < msg->hdr_fields->len; i++) {
+ RTSPKeyValue key_value = g_array_index (msg->hdr_fields, RTSPKeyValue, i);
- val = g_hash_table_lookup (msg->hdr_fields, GINT_TO_POINTER (field));
- if (val == NULL)
- return RTSP_ENOTIMPL;
+ if (key_value.field == field && cnt++ == indx) {
+ if (value)
+ *value = key_value.value;
+ return RTSP_OK;
+ }
+ }
- if (value)
- *value = val;
+ return RTSP_ENOTIMPL;
+}
- return RTSP_OK;
+void
+rtsp_message_append_headers (const RTSPMessage * msg, GString * str)
+{
+ guint i;
+
+ g_return_if_fail (msg != NULL);
+ g_return_if_fail (str != NULL);
+
+ for (i = 0; i < msg->hdr_fields->len; i++) {
+ RTSPKeyValue key_value = g_array_index (msg->hdr_fields, RTSPKeyValue, i);
+ const gchar *keystr = rtsp_header_as_text (key_value.field);
+
+ g_string_append_printf (str, "%s: %s\r\n", keystr, key_value.value);
+ }
}
RTSPResult
}
static void
-dump_key_value (gpointer key, gpointer value, gpointer data)
+dump_key_value (gpointer data, gpointer user_data)
{
- RTSPHeaderField field = GPOINTER_TO_INT (key);
+ RTSPKeyValue *key_value = (RTSPKeyValue *) data;
- g_print (" key: '%s', value: '%s'\n", rtsp_header_as_text (field),
- (gchar *) value);
+ g_print (" key: '%s', value: '%s'\n",
+ rtsp_header_as_text (key_value->field), key_value->value);
}
RTSPResult
rtsp_method_as_text (msg->type_data.request.method));
g_print (" uri: '%s'\n", msg->type_data.request.uri);
g_print (" headers:\n");
- g_hash_table_foreach (msg->hdr_fields, dump_key_value, NULL);
+ key_value_foreach (msg->hdr_fields, dump_key_value, NULL);
g_print (" body:\n");
rtsp_message_get_body (msg, &data, &size);
dump_mem (data, size);
g_print (" code: '%d'\n", msg->type_data.response.code);
g_print (" reason: '%s'\n", msg->type_data.response.reason);
g_print (" headers:\n");
- g_hash_table_foreach (msg->hdr_fields, dump_key_value, NULL);
+ key_value_foreach (msg->hdr_fields, dump_key_value, NULL);
rtsp_message_get_body (msg, &data, &size);
g_print (" body: length %d\n", size);
dump_mem (data, size);
} data;
} type_data;
- GHashTable *hdr_fields;
+ GArray *hdr_fields;
guint8 *body;
guint body_size;
RTSPHeaderField field,
const gchar *value);
RTSPResult rtsp_message_remove_header (RTSPMessage *msg,
- RTSPHeaderField field);
+ RTSPHeaderField field,
+ gint indx);
RTSPResult rtsp_message_get_header (const RTSPMessage *msg,
RTSPHeaderField field,
- gchar **value);
+ gchar **value,
+ gint indx);
+
+void rtsp_message_append_headers (const RTSPMessage *msg,
+ GString *str);
RTSPResult rtsp_message_set_body (RTSPMessage *msg,
const guint8 *data,