diff options
author | Wim Taymans <wim.taymans@gmail.com> | 2005-05-11 07:44:44 +0000 |
---|---|---|
committer | Wim Taymans <wim.taymans@gmail.com> | 2005-05-11 07:44:44 +0000 |
commit | 6f0ea35883cec1b68eb1ac2f2bc511f856018f6f (patch) | |
tree | 601e40d1ac5cd282ad5f207f4a9a647da62fc126 /gst/rtsp/sdpmessage.c | |
parent | 6cacd6f64958db92328a9ae52563160a583a395a (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.c | 709 |
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; +} |