|
|
|
@ -56,6 +56,11 @@ struct sdp_media { |
|
|
|
struct sdp_attributes attributes; |
|
|
|
}; |
|
|
|
|
|
|
|
struct attribute_rtcp { |
|
|
|
long int port_num; |
|
|
|
struct network_address address; |
|
|
|
}; |
|
|
|
|
|
|
|
struct sdp_attribute { |
|
|
|
str full_line, /* including a= and \r\n */ |
|
|
|
line_value, /* without a= and without \r\n */ |
|
|
|
@ -63,6 +68,15 @@ struct sdp_attribute { |
|
|
|
value, /* just "8 PCMA/8000" */ |
|
|
|
key, /* "rtpmap:8" */ |
|
|
|
param; /* "PCMA/8000" */ |
|
|
|
|
|
|
|
enum { |
|
|
|
ATTR_OTHER = 0, |
|
|
|
ATTR_RTCP, |
|
|
|
} attr; |
|
|
|
|
|
|
|
union { |
|
|
|
struct attribute_rtcp rtcp; |
|
|
|
} u; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
@ -138,7 +152,7 @@ static inline int extract_token(char **sp, char *end, str *out) { |
|
|
|
EXTRACT_TOKEN(field.network_type); \ |
|
|
|
EXTRACT_TOKEN(field.address_type); \ |
|
|
|
EXTRACT_TOKEN(field.address); \ |
|
|
|
if (parse_address(&output->address)) return -1 |
|
|
|
if (parse_address(&output->field)) return -1 |
|
|
|
|
|
|
|
static int parse_origin(char *start, char *end, struct sdp_origin *output) { |
|
|
|
if (output->parsed) |
|
|
|
@ -194,6 +208,62 @@ static void attrs_init(struct sdp_attributes *a) { |
|
|
|
a->hash = g_hash_table_new(str_hash, str_equal); |
|
|
|
} |
|
|
|
|
|
|
|
static int parse_attribute_rtcp(struct sdp_attribute *output) { |
|
|
|
char *ep, *start, *end; |
|
|
|
|
|
|
|
end = output->value.s + output->value.len; |
|
|
|
output->attr = ATTR_RTCP; |
|
|
|
output->u.rtcp.port_num = strtol(output->value.s, &ep, 10); |
|
|
|
if (ep == output->value.s) |
|
|
|
return -1; |
|
|
|
if (output->u.rtcp.port_num <= 0 || output->u.rtcp.port_num > 0xffff) { |
|
|
|
output->u.rtcp.port_num = 0; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
if (*ep != ' ') |
|
|
|
return 0; |
|
|
|
ep++; |
|
|
|
if (ep >= end) |
|
|
|
return 0; |
|
|
|
|
|
|
|
start = ep; |
|
|
|
EXTRACT_NETWORK_ADDRESS(u.rtcp.address); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static void parse_attribute(struct sdp_attribute *a) { |
|
|
|
a->name = a->line_value; |
|
|
|
str_chr_str(&a->value, &a->name, ':'); |
|
|
|
if (a->value.s) { |
|
|
|
a->name.len -= a->value.len; |
|
|
|
a->value.s++; |
|
|
|
a->value.len--; |
|
|
|
|
|
|
|
a->key = a->name; |
|
|
|
str_chr_str(&a->param, &a->value, ' '); |
|
|
|
if (a->param.s) { |
|
|
|
a->key.len += 1 + |
|
|
|
(a->value.len - a->param.len); |
|
|
|
|
|
|
|
a->param.s++; |
|
|
|
a->param.len--; |
|
|
|
|
|
|
|
if (!a->param.len) |
|
|
|
a->param.s = NULL; |
|
|
|
} |
|
|
|
else |
|
|
|
a->key.len += 1 + a->value.len; |
|
|
|
} |
|
|
|
|
|
|
|
switch (a->name.len) { |
|
|
|
case 4: |
|
|
|
if (!str_cmp(&a->name, "rtcp")) |
|
|
|
parse_attribute_rtcp(a); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
int sdp_parse(str *body, GQueue *sessions) { |
|
|
|
char *b, *end, *value, *line_end, *next_line; |
|
|
|
struct sdp_session *session = NULL; |
|
|
|
@ -279,28 +349,7 @@ int sdp_parse(str *body, GQueue *sessions) { |
|
|
|
attr->line_value.s = value; |
|
|
|
attr->line_value.len = line_end - value; |
|
|
|
|
|
|
|
attr->name = attr->line_value; |
|
|
|
str_chr_str(&attr->value, &attr->name, ':'); |
|
|
|
if (attr->value.s) { |
|
|
|
attr->name.len -= attr->value.len; |
|
|
|
attr->value.s++; |
|
|
|
attr->value.len--; |
|
|
|
|
|
|
|
attr->key = attr->name; |
|
|
|
str_chr_str(&attr->param, &attr->value, ' '); |
|
|
|
if (attr->param.s) { |
|
|
|
attr->key.len += 1 + |
|
|
|
(attr->value.len - attr->param.len); |
|
|
|
|
|
|
|
attr->param.s++; |
|
|
|
attr->param.len--; |
|
|
|
|
|
|
|
if (!attr->param.len) |
|
|
|
attr->param.s = NULL; |
|
|
|
} |
|
|
|
else |
|
|
|
attr->key.len += 1 + attr->value.len; |
|
|
|
} |
|
|
|
parse_attribute(attr); |
|
|
|
|
|
|
|
attrs = media ? &media->attributes : &session->attributes; |
|
|
|
g_queue_push_tail(&attrs->list, attr); |
|
|
|
@ -385,6 +434,8 @@ int sdp_streams(const GQueue *sessions, GQueue *streams, GHashTable *streamhash) |
|
|
|
GList *l, *k; |
|
|
|
const char *errstr; |
|
|
|
int i, num; |
|
|
|
str s; |
|
|
|
struct sdp_attribute *attr; |
|
|
|
|
|
|
|
num = 0; |
|
|
|
for (l = sessions->head; l; l = l->next) { |
|
|
|
@ -393,6 +444,7 @@ int sdp_streams(const GQueue *sessions, GQueue *streams, GHashTable *streamhash) |
|
|
|
for (k = session->media_streams.head; k; k = k->next) { |
|
|
|
media = k->data; |
|
|
|
|
|
|
|
si = NULL; |
|
|
|
for (i = 0; i < media->port_count; i++) { |
|
|
|
si = g_slice_alloc0(sizeof(*si)); |
|
|
|
|
|
|
|
@ -411,6 +463,13 @@ int sdp_streams(const GQueue *sessions, GQueue *streams, GHashTable *streamhash) |
|
|
|
g_hash_table_insert(streamhash, si, si); |
|
|
|
g_queue_push_tail(streams, si); |
|
|
|
} |
|
|
|
|
|
|
|
if (!si || media->port_count != 1) |
|
|
|
continue; |
|
|
|
str_init(&s, "rtcp"); |
|
|
|
attr = g_hash_table_lookup(media->attributes.hash, &s); |
|
|
|
if (!attr) |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -762,6 +821,7 @@ int sdp_replace(struct sdp_chopper *chop, GQueue *sessions, struct call *call, |
|
|
|
chopper_append_c(chop, " 2 UDP 2130706430 "); |
|
|
|
insert_ice_address(chop, m, off, flags, 1); |
|
|
|
chopper_append_c(chop, " typ host\r\n"); |
|
|
|
/* XXX handle rtcp here too */ |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|