summaryrefslogtreecommitdiffstats
path: root/gst/rtsp/sdpmessage.c
diff options
context:
space:
mode:
authorWim Taymans <wim.taymans@gmail.com>2005-05-11 07:44:44 +0000
committerWim Taymans <wim.taymans@gmail.com>2005-05-11 07:44:44 +0000
commit6f0ea35883cec1b68eb1ac2f2bc511f856018f6f (patch)
tree601e40d1ac5cd282ad5f207f4a9a647da62fc126 /gst/rtsp/sdpmessage.c
parent6cacd6f64958db92328a9ae52563160a583a395a (diff)
Ported to 0.9.
Original commit message from CVS: Ported to 0.9. Set up transports, init UDP ports, init RTP session managers.
Diffstat (limited to 'gst/rtsp/sdpmessage.c')
-rw-r--r--gst/rtsp/sdpmessage.c709
1 files changed, 709 insertions, 0 deletions
diff --git a/gst/rtsp/sdpmessage.c b/gst/rtsp/sdpmessage.c
new file mode 100644
index 00000000..a9044c96
--- /dev/null
+++ b/gst/rtsp/sdpmessage.c
@@ -0,0 +1,709 @@
+/* GStreamer
+ * Copyright (C) <2005> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "sdpmessage.h"
+
+#define FREE_STRING(field) g_free ((field)); (field) = NULL;
+#define FREE_ARRAY(field) \
+G_STMT_START { \
+ if (field) \
+ g_array_free (field, TRUE); \
+ field = NULL; \
+} G_STMT_END
+#define REPLACE_STRING(field,val) FREE_STRING(field);field=g_strdup (val);
+
+#define INIT_ARRAY(field,type) \
+G_STMT_START { \
+ if (field) \
+ g_array_set_size (field,0); \
+ else \
+ field = g_array_new (FALSE, TRUE, sizeof(type)); \
+} G_STMT_END
+
+#define DEFINE_STRING_SETTER(field) \
+RTSPResult sdp_message_set_##field (SDPMessage *msg, gchar *val) { \
+ g_free (msg->field); \
+ msg->field = g_strdup (val); \
+ return RTSP_OK; \
+}
+#define DEFINE_STRING_GETTER(field) \
+char* sdp_message_get_##field (SDPMessage *msg) { \
+ return msg->field; \
+}
+
+#define DEFINE_ARRAY_LEN(field) \
+gint sdp_message_##field##_len (SDPMessage *msg) { \
+ return ((msg)->field->len); \
+}
+#define DEFINE_ARRAY_GETTER(method,field,type) \
+type sdp_message_get_##method (SDPMessage *msg, gint i) { \
+ return g_array_index ((msg)->field, type, i); \
+}
+#define DEFINE_ARRAY_P_GETTER(method,field,type) \
+type * sdp_message_get_##method (SDPMessage *msg, gint i) { \
+ return &g_array_index ((msg)->field, type, i); \
+}
+#define DEFINE_ARRAY_ADDER(method,field,type,dup_method) \
+RTSPResult sdp_message_add_##method (SDPMessage *msg, type val) { \
+ type v = dup_method(val); \
+ g_array_append_val((msg)->field, v); \
+ return RTSP_OK; \
+}
+
+
+
+RTSPResult
+sdp_message_new (SDPMessage ** msg)
+{
+ SDPMessage *newmsg;
+
+ if (msg == NULL)
+ return RTSP_EINVAL;
+
+ newmsg = g_new0 (SDPMessage, 1);
+
+ *msg = newmsg;
+
+ return sdp_message_init (newmsg);
+}
+
+RTSPResult
+sdp_message_init (SDPMessage * msg)
+{
+ if (msg == NULL)
+ return RTSP_EINVAL;
+
+ FREE_STRING (msg->version);
+ FREE_STRING (msg->origin.username);
+ FREE_STRING (msg->origin.sess_id);
+ FREE_STRING (msg->origin.sess_version);
+ FREE_STRING (msg->origin.nettype);
+ FREE_STRING (msg->origin.addrtype);
+ FREE_STRING (msg->origin.addr);
+ FREE_STRING (msg->session_name);
+ FREE_STRING (msg->information);
+ FREE_STRING (msg->uri);
+ INIT_ARRAY (msg->emails, gchar *);
+ INIT_ARRAY (msg->phones, gchar *);
+ FREE_STRING (msg->connection.nettype);
+ FREE_STRING (msg->connection.addrtype);
+ FREE_STRING (msg->connection.address);
+ msg->connection.ttl = 0;
+ msg->connection.addr_number = 0;
+ INIT_ARRAY (msg->bandwidths, SDPBandwidth);
+ INIT_ARRAY (msg->times, SDPTime);
+ INIT_ARRAY (msg->zones, SDPZone);
+ FREE_STRING (msg->key.type);
+ FREE_STRING (msg->key.data);
+ INIT_ARRAY (msg->attributes, SDPAttribute);
+ INIT_ARRAY (msg->medias, SDPMedia);
+
+ return RTSP_OK;
+}
+
+RTSPResult
+sdp_message_clean (SDPMessage * msg)
+{
+ if (msg == NULL)
+ return RTSP_EINVAL;
+
+ FREE_ARRAY (msg->emails);
+ FREE_ARRAY (msg->phones);
+ FREE_ARRAY (msg->bandwidths);
+ FREE_ARRAY (msg->times);
+ FREE_ARRAY (msg->zones);
+ FREE_ARRAY (msg->attributes);
+ FREE_ARRAY (msg->medias);
+
+ return RTSP_OK;
+}
+
+RTSPResult
+sdp_message_free (SDPMessage * msg)
+{
+ if (msg == NULL)
+ return RTSP_EINVAL;
+
+ sdp_message_clean (msg);
+
+ g_free (msg);
+
+ return RTSP_OK;
+}
+
+
+RTSPResult
+sdp_media_new (SDPMedia ** media)
+{
+ SDPMedia *newmedia;
+
+ if (media == NULL)
+ return RTSP_EINVAL;
+
+ newmedia = g_new0 (SDPMedia, 1);
+
+ *media = newmedia;
+
+ return sdp_media_init (newmedia);
+}
+
+RTSPResult
+sdp_media_init (SDPMedia * media)
+{
+ if (media == NULL)
+ return RTSP_EINVAL;
+
+ FREE_STRING (media->media);
+ media->port = 0;
+ media->num_ports = 0;
+ FREE_STRING (media->proto);
+ INIT_ARRAY (media->fmts, gchar *);
+ FREE_STRING (media->information);
+ INIT_ARRAY (media->connections, SDPConnection);
+ INIT_ARRAY (media->bandwidths, SDPBandwidth);
+ FREE_STRING (media->key.type);
+ FREE_STRING (media->key.data);
+ INIT_ARRAY (media->attributes, SDPAttribute);
+
+ return RTSP_OK;
+}
+
+DEFINE_STRING_SETTER (version);
+DEFINE_STRING_GETTER (version);
+
+RTSPResult
+sdp_message_set_origin (SDPMessage * msg, gchar * username, gchar * sess_id,
+ gchar * sess_version, gchar * nettype, gchar * addrtype, gchar * addr)
+{
+ REPLACE_STRING (msg->origin.username, username);
+ REPLACE_STRING (msg->origin.sess_id, sess_id);
+ REPLACE_STRING (msg->origin.sess_version, sess_version);
+ REPLACE_STRING (msg->origin.nettype, nettype);
+ REPLACE_STRING (msg->origin.addrtype, addrtype);
+ REPLACE_STRING (msg->origin.addr, addr);
+ return RTSP_OK;
+}
+
+SDPOrigin *
+sdp_message_get_origin (SDPMessage * msg)
+{
+ return &msg->origin;
+}
+
+DEFINE_STRING_SETTER (session_name);
+DEFINE_STRING_GETTER (session_name);
+DEFINE_STRING_SETTER (information);
+DEFINE_STRING_GETTER (information);
+DEFINE_STRING_SETTER (uri);
+DEFINE_STRING_GETTER (uri);
+
+DEFINE_ARRAY_LEN (emails);
+DEFINE_ARRAY_GETTER (email, emails, gchar *);
+DEFINE_ARRAY_ADDER (email, emails, gchar *, g_strdup);
+
+DEFINE_ARRAY_LEN (phones);
+DEFINE_ARRAY_GETTER (phone, phones, gchar *);
+DEFINE_ARRAY_ADDER (phone, phones, gchar *, g_strdup);
+
+RTSPResult
+sdp_message_set_connection (SDPMessage * msg, gchar * nettype, gchar * addrtype,
+ gchar * address, gint ttl, gint addr_number)
+{
+ REPLACE_STRING (msg->connection.nettype, nettype);
+ REPLACE_STRING (msg->connection.addrtype, addrtype);
+ REPLACE_STRING (msg->connection.address, address);
+ msg->connection.ttl = ttl;
+ msg->connection.addr_number = addr_number;
+ return RTSP_OK;
+}
+
+SDPConnection *
+sdp_message_get_connection (SDPMessage * msg)
+{
+ return &msg->connection;
+}
+
+DEFINE_ARRAY_LEN (bandwidths);
+DEFINE_ARRAY_P_GETTER (bandwidth, bandwidths, SDPBandwidth);
+
+RTSPResult
+sdp_message_add_bandwidth (SDPMessage * msg, gchar * bwtype, gint bandwidth)
+{
+ SDPBandwidth bw;
+
+ bw.bwtype = g_strdup (bwtype);
+ bw.bandwidth = bandwidth;
+
+ g_array_append_val (msg->bandwidths, bw);
+
+ return RTSP_OK;
+}
+
+DEFINE_ARRAY_LEN (times);
+DEFINE_ARRAY_P_GETTER (time, times, SDPTime);
+
+RTSPResult
+sdp_message_add_time (SDPMessage * msg, gchar * time)
+{
+ return RTSP_OK;
+}
+
+DEFINE_ARRAY_LEN (zones);
+DEFINE_ARRAY_P_GETTER (zone, zones, SDPZone);
+RTSPResult
+sdp_message_add_zone (SDPMessage * msg, gchar * time, gchar * typed_time)
+{
+ SDPZone zone;
+
+ zone.time = g_strdup (time);
+ zone.typed_time = g_strdup (typed_time);
+
+ g_array_append_val (msg->zones, zone);
+
+ return RTSP_OK;
+}
+
+RTSPResult
+sdp_message_set_key (SDPMessage * msg, gchar * type, gchar * data)
+{
+ REPLACE_STRING (msg->key.type, type);
+ REPLACE_STRING (msg->key.data, data);
+ return RTSP_OK;
+}
+
+SDPKey *
+sdp_message_get_key (SDPMessage * msg)
+{
+ return &msg->key;
+}
+
+
+DEFINE_ARRAY_LEN (attributes);
+DEFINE_ARRAY_P_GETTER (attribute, attributes, SDPAttribute);
+gchar *
+sdp_message_get_attribute_val (SDPMessage * msg, gchar * key)
+{
+ gint i;
+
+ for (i = 0; i < msg->attributes->len; i++) {
+ SDPAttribute *attr;
+
+ attr = &g_array_index (msg->attributes, SDPAttribute, i);
+ if (!strcmp (attr->key, key))
+ return attr->value;
+ }
+ return NULL;
+}
+
+RTSPResult
+sdp_message_add_attribute (SDPMessage * msg, gchar * key, gchar * value)
+{
+ SDPAttribute attr;
+
+ attr.key = g_strdup (key);
+ attr.value = g_strdup (value);
+
+ g_array_append_val (msg->attributes, attr);
+
+ return RTSP_OK;
+}
+
+DEFINE_ARRAY_LEN (medias);
+DEFINE_ARRAY_P_GETTER (media, medias, SDPMedia);
+RTSPResult
+sdp_message_add_media (SDPMessage * msg, SDPMedia * media)
+{
+ gint len;
+ SDPMedia *nmedia;
+
+ len = msg->medias->len;
+ g_array_set_size (msg->medias, len + 1);
+ nmedia = &g_array_index (msg->medias, SDPMedia, len);
+
+ memcpy (nmedia, media, sizeof (SDPMedia));
+
+ return RTSP_OK;
+}
+
+/* media access */
+
+RTSPResult
+sdp_media_add_attribute (SDPMedia * media, gchar * key, gchar * value)
+{
+ SDPAttribute attr;
+
+ attr.key = g_strdup (key);
+ attr.value = g_strdup (value);
+
+ g_array_append_val (media->attributes, attr);
+
+ return RTSP_OK;
+}
+
+RTSPResult
+sdp_media_add_bandwidth (SDPMedia * media, gchar * bwtype, gint bandwidth)
+{
+ SDPBandwidth bw;
+
+ bw.bwtype = g_strdup (bwtype);
+ bw.bandwidth = bandwidth;
+
+ g_array_append_val (media->bandwidths, bw);
+
+ return RTSP_OK;
+}
+
+RTSPResult
+sdp_media_add_format (SDPMedia * media, gchar * format)
+{
+ gchar *fmt;
+
+ fmt = g_strdup (format);
+
+ g_array_append_val (media->fmts, fmt);
+
+ return RTSP_OK;
+}
+
+gchar *
+sdp_media_get_attribute_val (SDPMedia * media, gchar * key)
+{
+ gint i;
+
+ for (i = 0; i < media->attributes->len; i++) {
+ SDPAttribute *attr;
+
+ attr = &g_array_index (media->attributes, SDPAttribute, i);
+ if (!strcmp (attr->key, key))
+ return attr->value;
+ }
+ return NULL;
+}
+
+static void
+read_string (gchar * dest, gint size, gchar ** src)
+{
+ gint idx;
+
+ idx = 0;
+ /* skip spaces */
+ while (g_ascii_isspace (**src))
+ (*src)++;
+
+ while (!g_ascii_isspace (**src) && **src != '\0') {
+ if (idx < size - 1)
+ dest[idx++] = **src;
+ (*src)++;
+ }
+ if (size > 0)
+ dest[idx] = '\0';
+}
+
+static void
+read_string_del (gchar * dest, gint size, gchar del, gchar ** src)
+{
+ gint idx;
+
+ idx = 0;
+ /* skip spaces */
+ while (g_ascii_isspace (**src))
+ (*src)++;
+
+ while (**src != del && **src != '\0') {
+ if (idx < size - 1)
+ dest[idx++] = **src;
+ (*src)++;
+ }
+ if (size > 0)
+ dest[idx] = '\0';
+}
+
+enum
+{
+ SDP_SESSION,
+ SDP_MEDIA,
+};
+
+typedef struct
+{
+ gint state;
+ SDPMessage *msg;
+ SDPMedia *media;
+} SDPContext;
+
+static gboolean
+sdp_parse_line (SDPContext * c, gchar type, guint8 * buffer)
+{
+ gchar str[4096];
+ gchar *p = buffer;
+
+#define READ_STRING(field) read_string (str, sizeof(str), &p);REPLACE_STRING (field, str);
+#define READ_INT(field) read_string (str, sizeof(str), &p);field = atoi(str);
+
+ switch (type) {
+ case 'v':
+ if (buffer[0] != '0')
+ g_print ("wrong SDP version\n");
+ sdp_message_set_version (c->msg, buffer);
+ break;
+ case 'o':
+ READ_STRING (c->msg->origin.username);
+ READ_STRING (c->msg->origin.sess_id);
+ READ_STRING (c->msg->origin.sess_version);
+ READ_STRING (c->msg->origin.nettype);
+ READ_STRING (c->msg->origin.addrtype);
+ READ_STRING (c->msg->origin.addr);
+ break;
+ case 's':
+ REPLACE_STRING (c->msg->session_name, buffer);
+ break;
+ case 'i':
+ if (c->state == SDP_SESSION) {
+ REPLACE_STRING (c->msg->information, buffer);
+ } else {
+ REPLACE_STRING (c->media->information, buffer);
+ }
+ break;
+ case 'u':
+ REPLACE_STRING (c->msg->uri, buffer);
+ break;
+ case 'e':
+ sdp_message_add_email (c->msg, buffer);
+ break;
+ case 'p':
+ sdp_message_add_phone (c->msg, buffer);
+ break;
+ case 'c':
+ READ_STRING (c->msg->connection.nettype);
+ READ_STRING (c->msg->connection.addrtype);
+ READ_STRING (c->msg->connection.address);
+ READ_INT (c->msg->connection.ttl);
+ READ_INT (c->msg->connection.addr_number);
+ break;
+ case 'b':
+ {
+ gchar str2[4096];
+
+ read_string_del (str, sizeof (str), ':', &p);
+ read_string (str2, sizeof (str2), &p);
+ if (c->state == SDP_SESSION)
+ sdp_message_add_bandwidth (c->msg, str, atoi (str2));
+ else
+ sdp_media_add_bandwidth (c->media, str, atoi (str2));
+ break;
+ }
+ case 't':
+ break;
+ case 'k':
+
+ break;
+ case 'a':
+ read_string_del (str, sizeof (str), ':', &p);
+ if (p != '\0')
+ p++;
+ if (c->state == SDP_SESSION)
+ sdp_message_add_attribute (c->msg, str, p);
+ else
+ sdp_media_add_attribute (c->media, str, p);
+ break;
+ case 'm':
+ {
+ gchar *slash;
+ SDPMedia nmedia = { 0 };
+
+ c->state = SDP_MEDIA;
+ sdp_media_init (&nmedia);
+
+ READ_STRING (nmedia.media);
+ read_string (str, sizeof (str), &p);
+ slash = g_strrstr (str, "/");
+ if (slash) {
+ *slash = '\0';
+ nmedia.port = atoi (str);
+ nmedia.num_ports = atoi (slash + 1);
+ } else {
+ nmedia.port = atoi (str);
+ nmedia.num_ports = -1;
+ }
+ READ_STRING (nmedia.proto);
+ do {
+ read_string (str, sizeof (str), &p);
+ sdp_media_add_format (&nmedia, str);
+ } while (*p != '\0');
+
+ g_print ("%p\n", &nmedia);
+ sdp_message_add_media (c->msg, &nmedia);
+ c->media =
+ &g_array_index (c->msg->medias, SDPMedia, c->msg->medias->len - 1);
+ g_print ("%p\n", c->media);
+ break;
+ }
+ default:
+ break;
+ }
+ return TRUE;
+}
+
+RTSPResult
+sdp_message_parse_buffer (guint8 * data, guint size, SDPMessage * msg)
+{
+ gchar *p;
+ SDPContext c;
+ gchar type;
+ gchar buffer[4096];
+ gint idx = 0;
+
+ if (msg == NULL || data == NULL || size == 0)
+ return RTSP_EINVAL;
+
+ c.state = SDP_SESSION;
+ c.msg = msg;
+
+ p = data;
+ while (TRUE) {
+ while (g_ascii_isspace (*p))
+ p++;
+
+ type = *p++;
+ if (type == '\0')
+ break;
+
+ if (*p != '=')
+ goto line_done;
+ p++;
+
+ idx = 0;
+ while (*p != '\n' && *p != '\r' && *p != '\0') {
+ if (idx < sizeof (buffer) - 1)
+ buffer[idx++] = *p;
+ p++;
+ }
+ buffer[idx] = '\0';
+ sdp_parse_line (&c, type, buffer);
+
+ line_done:
+ while (*p != '\n' && *p != '\0')
+ p++;
+ if (*p == '\n')
+ p++;
+ }
+
+ return RTSP_OK;
+}
+
+static void
+print_media (SDPMedia * media)
+{
+ g_print (" media: '%s'\n", media->media);
+ g_print (" port: '%d'\n", media->port);
+ g_print (" num_ports: '%d'\n", media->num_ports);
+ g_print (" proto: '%s'\n", media->proto);
+ if (media->fmts->len > 0) {
+ gint i;
+
+ g_print (" formats:\n");
+ for (i = 0; i < media->fmts->len; i++) {
+ g_print (" format '%s'\n", g_array_index (media->fmts, gchar *, i));
+ }
+ }
+ g_print (" information: '%s'\n", media->information);
+ g_print (" key:\n");
+ g_print (" type: '%s'\n", media->key.type);
+ g_print (" data: '%s'\n", media->key.data);
+ if (media->attributes->len > 0) {
+ gint i;
+
+ g_print (" attributes:\n");
+ for (i = 0; i < media->attributes->len; i++) {
+ SDPAttribute *attr = &g_array_index (media->attributes, SDPAttribute, i);
+
+ g_print (" attribute '%s' : '%s'\n", attr->key, attr->value);
+ }
+ }
+}
+
+RTSPResult
+sdp_message_dump (SDPMessage * msg)
+{
+ if (msg == NULL)
+ return RTSP_EINVAL;
+
+ g_print ("sdp packet %p:\n", msg);
+ g_print (" version: '%s'\n", msg->version);
+ g_print (" origin:\n");
+ g_print (" username: '%s'\n", msg->origin.username);
+ g_print (" sess_id: '%s'\n", msg->origin.sess_id);
+ g_print (" sess_version: '%s'\n", msg->origin.sess_version);
+ g_print (" nettype: '%s'\n", msg->origin.nettype);
+ g_print (" addrtype: '%s'\n", msg->origin.addrtype);
+ g_print (" addr: '%s'\n", msg->origin.addr);
+ 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;
+
+ g_print (" emails:\n");
+ for (i = 0; i < msg->emails->len; i++) {
+ g_print (" email '%s'\n", g_array_index (msg->emails, gchar *, i));
+ }
+ }
+ if (msg->phones->len > 0) {
+ gint i;
+
+ g_print (" phones:\n");
+ for (i = 0; i < msg->phones->len; i++) {
+ g_print (" phone '%s'\n", g_array_index (msg->phones, gchar *, i));
+ }
+ }
+ g_print (" connection:\n");
+ g_print (" nettype: '%s'\n", msg->connection.nettype);
+ g_print (" addrtype: '%s'\n", msg->connection.addrtype);
+ g_print (" address: '%s'\n", msg->connection.address);
+ g_print (" ttl: '%d'\n", msg->connection.ttl);
+ g_print (" addr_number: '%d'\n", msg->connection.addr_number);
+ g_print (" key:\n");
+ g_print (" type: '%s'\n", msg->key.type);
+ g_print (" data: '%s'\n", msg->key.data);
+ if (msg->attributes->len > 0) {
+ gint i;
+
+ g_print (" attributes:\n");
+ for (i = 0; i < msg->attributes->len; i++) {
+ SDPAttribute *attr = &g_array_index (msg->attributes, SDPAttribute, i);
+
+ g_print (" attribute '%s' : '%s'\n", attr->key, attr->value);
+ }
+ }
+ if (msg->medias->len > 0) {
+ gint i;
+
+ g_print (" medias:\n");
+ for (i = 0; i < msg->medias->len; i++) {
+ g_print (" media %d:\n", i);
+ print_media (&g_array_index (msg->medias, SDPMedia, i));
+ }
+ }
+
+
+ return RTSP_OK;
+}