belle_sdp_impl.c 69.2 KB
Newer Older
jehan's avatar
jehan committed
1 2
/*
	belle-sdp - SIP (RFC4566) library.
3
	Copyright (C) 2010  Belledonne Communications SARL
jehan's avatar
jehan committed
4

5 6 7 8
	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 2 of the License, or
	(at your option) any later version.
jehan's avatar
jehan committed
9

10 11 12 13
	This program 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 General Public License for more details.
jehan's avatar
jehan committed
14

15 16
	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
jehan's avatar
jehan committed
17
*/
jehan's avatar
jehan committed
18
#include "belle-sip/belle-sip.h"
Guillaume Beraudo's avatar
Guillaume Beraudo committed
19 20
#include "grammars/belle_sdpParser.h"
#include "grammars/belle_sdpLexer.h"
jehan's avatar
jehan committed
21
#include "belle_sip_internal.h"
22 23 24 25 26 27 28 29 30 31 32 33 34 35


struct _belle_sdp_mime_parameter {
	belle_sip_object_t base;
	int rate;
	int channel_count;
	int ptime;
	int max_ptime;
	int media_format;
	const char* type;
	const char* parameters;

};

36 37 38 39 40 41 42

static void belle_sip_object_freefunc(void* obj) {
	belle_sip_object_unref(BELLE_SIP_OBJECT(obj));
}
static void* belle_sip_object_copyfunc(void* obj) {
	return belle_sip_object_clone_and_ref(BELLE_SIP_OBJECT(obj));
}
Ghislain MARY's avatar
Ghislain MARY committed
43 44 45
static void * belle_sip_string_copyfunc(void *obj) {
	return (void *)belle_sip_strdup((const char *)obj);
}
46 47


jehan's avatar
jehan committed
48 49 50 51
/***************************************************************************************
 * Attribute
 *
 **************************************************************************************/
52 53 54 55 56 57
typedef belle_sdp_attribute_t* (*attribute_parse_func)(const char*) ;
struct attribute_name_func_pair {
	const char* name;
	attribute_parse_func func;
};
static struct attribute_name_func_pair attribute_table[] = {
58
	{ "rtcp-fb", (attribute_parse_func)belle_sdp_rtcp_fb_attribute_parse },
59 60
	{ "rtcp-xr", (attribute_parse_func)belle_sdp_rtcp_xr_attribute_parse }
};
jehan's avatar
jehan committed
61 62 63
struct _belle_sdp_attribute {
	belle_sip_object_t base;
	const char* name;
64
	char *unparsed_value;
jehan's avatar
jehan committed
65 66
};
void belle_sdp_attribute_destroy(belle_sdp_attribute_t* attribute) {
67
	DESTROY_STRING(attribute,name)
Simon Morlat's avatar
Simon Morlat committed
68
	DESTROY_STRING(attribute,unparsed_value)
jehan's avatar
jehan committed
69 70
}
void belle_sdp_attribute_clone(belle_sdp_attribute_t *attribute, const belle_sdp_attribute_t *orig){
71
	CLONE_STRING(belle_sdp_attribute,name,attribute,orig)
jehan's avatar
jehan committed
72
}
73
belle_sip_error_code belle_sdp_attribute_marshal(belle_sdp_attribute_t* attribute, char* buff, size_t buff_size, size_t *offset) {
74 75 76 77 78 79 80 81 82 83 84 85 86 87
	return belle_sip_snprintf(buff, buff_size, offset, "a=%s", attribute->name);
}
belle_sdp_attribute_t* belle_sdp_attribute_create(const char* name, const char* value) {
	belle_sdp_attribute_t* ret;
	int i;
	size_t elements = sizeof(attribute_table) / sizeof(attribute_table[0]);

	if (!name || name[0] == '\0') {
		belle_sip_error("Cannot create SDP attribute without name");
		return NULL;
	}

	for (i = 0; i < elements; i++) {
		if (strcasecmp(attribute_table[i].name, name) == 0) {
jehan's avatar
jehan committed
88 89 90 91 92
			char* raw;
			if (value)
				raw = belle_sip_strdup_printf("a=%s:%s", name, value);
			else
				raw = belle_sip_strdup_printf("a=%s", name);
93 94 95 96 97 98 99 100
			ret = attribute_table[i].func(raw);
			belle_sip_free(raw);
			return ret;
		}
	}
	/* Not a specialized SDP attribute */
	return BELLE_SDP_ATTRIBUTE(belle_sdp_raw_attribute_create(name, value));
}
101 102 103 104
const char *belle_sdp_attribute_get_value(belle_sdp_attribute_t *attribute) {
	char *ret;
	char *end;

105

106 107 108 109 110
	if (attribute->unparsed_value) {
		belle_sip_free(attribute->unparsed_value);
		attribute->unparsed_value = NULL;
	}
	attribute->unparsed_value = belle_sip_object_to_string(attribute);
111

112
	ret = attribute->unparsed_value;
113 114 115
	ret += strlen(attribute->name) + 2; /* "a=" + name*/
	if (*ret==':') ret++;
	for (; *ret == ' '; ret++) {}; /* skip eventual spaces */
116 117 118 119 120
	return ret;
}
unsigned int belle_sdp_attribute_has_value(belle_sdp_attribute_t* attribute) {
	return belle_sdp_attribute_get_value(attribute) != NULL;
}
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
BELLE_SDP_NEW(attribute,belle_sip_object)
BELLE_SDP_PARSE(attribute)
GET_SET_STRING(belle_sdp_attribute,name);
/***************************************************************************************
 * RAW Attribute
 *
 **************************************************************************************/
struct _belle_sdp_raw_attribute {
	belle_sdp_attribute_t base;
	const char* value;
};
void belle_sdp_raw_attribute_destroy(belle_sdp_raw_attribute_t* attribute) {
	DESTROY_STRING(attribute,value)
}
void belle_sdp_raw_attribute_clone(belle_sdp_raw_attribute_t* attribute, const belle_sdp_raw_attribute_t* orig) {
136 137 138
	if (belle_sdp_attribute_get_value(BELLE_SDP_ATTRIBUTE(orig))) {
		belle_sdp_raw_attribute_set_value(attribute, belle_sdp_attribute_get_value(BELLE_SDP_ATTRIBUTE(orig)));
	}
139 140 141 142
}
belle_sip_error_code belle_sdp_raw_attribute_marshal(belle_sdp_raw_attribute_t* attribute, char* buff, size_t buff_size, size_t* offset) {
	belle_sip_error_code error = belle_sdp_attribute_marshal(BELLE_SDP_ATTRIBUTE(attribute), buff, buff_size, offset);
	if (error != BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
143
	if (attribute->value) {
144 145
		error = belle_sip_snprintf(buff, buff_size, offset, ":%s", attribute->value);
		if (error != BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
146
	}
Ghislain MARY's avatar
Ghislain MARY committed
147
	return error;
jehan's avatar
jehan committed
148
}
149 150 151 152 153
BELLE_SDP_NEW(raw_attribute,belle_sdp_attribute)
belle_sdp_raw_attribute_t* belle_sdp_raw_attribute_create(const char* name, const char* value) {
	belle_sdp_raw_attribute_t* attribute = belle_sdp_raw_attribute_new();
	belle_sdp_attribute_set_name(BELLE_SDP_ATTRIBUTE(attribute), name);
	belle_sdp_raw_attribute_set_value(attribute, value);
jehan's avatar
jehan committed
154 155
	return attribute;
}
156 157 158 159 160
void belle_sdp_raw_attribute_set_value(belle_sdp_raw_attribute_t* attribute, const char* value) {
	if (attribute->value != NULL) belle_sip_free((void*)attribute->value);
	if (value) {
		attribute->value = belle_sip_strdup(value);
	} else attribute->value = NULL;
jehan's avatar
jehan committed
161
}
162 163 164 165 166 167 168 169
/***************************************************************************************
 * RTCP-FB Attribute
 *
 **************************************************************************************/
struct _belle_sdp_rtcp_fb_attribute {
	belle_sdp_attribute_t base;
	belle_sdp_rtcp_fb_val_type_t type;
	belle_sdp_rtcp_fb_val_param_t param;
170
	uint32_t smaxpr;
171
	uint16_t trr_int;
172
	int8_t id;
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
};
BELLESIP_EXPORT unsigned int belle_sdp_rtcp_fb_attribute_has_pli(const belle_sdp_rtcp_fb_attribute_t* attribute);
BELLESIP_EXPORT void belle_sdp_rtcp_fb_attribute_set_pli(belle_sdp_rtcp_fb_attribute_t* attribute, unsigned int enable);
BELLESIP_EXPORT unsigned int belle_sdp_rtcp_fb_attribute_has_sli(const belle_sdp_rtcp_fb_attribute_t* attribute);
BELLESIP_EXPORT void belle_sdp_rtcp_fb_attribute_set_sli(belle_sdp_rtcp_fb_attribute_t* attribute, unsigned int enable);
BELLESIP_EXPORT unsigned int belle_sdp_rtcp_fb_attribute_has_rpsi(const belle_sdp_rtcp_fb_attribute_t* attribute);
BELLESIP_EXPORT void belle_sdp_rtcp_fb_attribute_set_rpsi(belle_sdp_rtcp_fb_attribute_t* attribute, unsigned int enable);
BELLESIP_EXPORT unsigned int belle_sdp_rtcp_fb_attribute_has_app(const belle_sdp_rtcp_fb_attribute_t* attribute);
BELLESIP_EXPORT void belle_sdp_rtcp_fb_attribute_set_app(belle_sdp_rtcp_fb_attribute_t* attribute, unsigned int enable);
void belle_sdp_rtcp_fb_attribute_destroy(belle_sdp_rtcp_fb_attribute_t* attribute) {
}
void belle_sdp_rtcp_fb_attribute_clone(belle_sdp_rtcp_fb_attribute_t* attribute, const belle_sdp_rtcp_fb_attribute_t *orig) {
	attribute->type = orig->type;
	attribute->param = orig->param;
	attribute->trr_int = orig->trr_int;
	attribute->id = orig->id;
189
	attribute->smaxpr = orig->smaxpr;
190 191
}
belle_sip_error_code belle_sdp_rtcp_fb_attribute_marshal(belle_sdp_rtcp_fb_attribute_t* attribute, char * buff, size_t buff_size, size_t *offset) {
192
	int8_t id = belle_sdp_rtcp_fb_attribute_get_id(attribute);
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
	belle_sdp_rtcp_fb_val_type_t type = belle_sdp_rtcp_fb_attribute_get_type(attribute);
	belle_sdp_rtcp_fb_val_param_t param = belle_sdp_rtcp_fb_attribute_get_param(attribute);
	belle_sip_error_code error = belle_sdp_attribute_marshal(BELLE_SDP_ATTRIBUTE(attribute), buff, buff_size, offset);
	if (error != BELLE_SIP_OK) return error;
	if (id < 0) {
		error = belle_sip_snprintf(buff, buff_size, offset, ":* ");
	} else {
		error = belle_sip_snprintf(buff, buff_size, offset, ":%u ", id);
	}
	if (error != BELLE_SIP_OK) return error;
	switch (type) {
		case BELLE_SDP_RTCP_FB_ACK:
			error = belle_sip_snprintf(buff, buff_size, offset, "ack");
			if (error != BELLE_SIP_OK) return error;
			switch (param) {
				default:
				case BELLE_SDP_RTCP_FB_NONE:
					break;
				case BELLE_SDP_RTCP_FB_RPSI:
					error = belle_sip_snprintf(buff, buff_size, offset, " rpsi");
					break;
				case BELLE_SDP_RTCP_FB_APP:
					error = belle_sip_snprintf(buff, buff_size, offset, " app");
					break;
			}
			break;
		case BELLE_SDP_RTCP_FB_NACK:
			error = belle_sip_snprintf(buff, buff_size, offset, "nack");
			if (error != BELLE_SIP_OK) return error;
			switch (param) {
				default:
				case BELLE_SDP_RTCP_FB_NONE:
					break;
				case BELLE_SDP_RTCP_FB_PLI:
					error = belle_sip_snprintf(buff, buff_size, offset, " pli");
					break;
				case BELLE_SDP_RTCP_FB_SLI:
					error = belle_sip_snprintf(buff, buff_size, offset, " sli");
					break;
				case BELLE_SDP_RTCP_FB_RPSI:
					error = belle_sip_snprintf(buff, buff_size, offset, " rpsi");
					break;
				case BELLE_SDP_RTCP_FB_APP:
					error = belle_sip_snprintf(buff, buff_size, offset, " app");
					break;
			}
			break;
		case BELLE_SDP_RTCP_FB_TRR_INT:
			error = belle_sip_snprintf(buff, buff_size, offset, "trr-int %u", belle_sdp_rtcp_fb_attribute_get_trr_int(attribute));
			break;
243 244 245 246 247 248 249
		case BELLE_SDP_RTCP_FB_CCM:
			error = belle_sip_snprintf(buff, buff_size, offset, "ccm");
			if (error != BELLE_SIP_OK) return error;
			switch (param) {
				case BELLE_SDP_RTCP_FB_FIR:
					error = belle_sip_snprintf(buff, buff_size, offset, " fir");
					break;
250 251 252 253 254 255
				case BELLE_SDP_RTCP_FB_TMMBR:
					error = belle_sip_snprintf(buff, buff_size, offset, " tmmbr");
					if (belle_sdp_rtcp_fb_attribute_get_smaxpr(attribute) > 0) {
						error = belle_sip_snprintf(buff, buff_size, offset, " smaxpr=%u", belle_sdp_rtcp_fb_attribute_get_smaxpr(attribute));
					}
					break;
256 257 258 259
				default:
					break;
			}
			break;
260 261 262 263 264 265 266 267 268
	}
	return error;
}
static void belle_sdp_rtcp_fb_attribute_init(belle_sdp_rtcp_fb_attribute_t* attribute) {
	belle_sdp_attribute_set_name(BELLE_SDP_ATTRIBUTE(attribute), "rtcp-fb");
	attribute->id = -1;
	attribute->type = BELLE_SDP_RTCP_FB_TRR_INT;
	attribute->param = BELLE_SDP_RTCP_FB_NONE;
	attribute->trr_int = 0;
269
	attribute->smaxpr = 0;
270 271 272
}
BELLE_SDP_NEW_WITH_CTR(rtcp_fb_attribute,belle_sdp_attribute)
BELLE_SDP_PARSE(rtcp_fb_attribute)
273
GET_SET_INT(belle_sdp_rtcp_fb_attribute,id,int8_t)
274 275
GET_SET_INT(belle_sdp_rtcp_fb_attribute,type,belle_sdp_rtcp_fb_val_type_t)
GET_SET_INT(belle_sdp_rtcp_fb_attribute,param,belle_sdp_rtcp_fb_val_param_t)
276
GET_SET_INT(belle_sdp_rtcp_fb_attribute,trr_int,uint16_t)
277
GET_SET_INT(belle_sdp_rtcp_fb_attribute,smaxpr,uint32_t)
278 279 280 281 282 283 284 285 286 287 288 289
/***************************************************************************************
 * RTCP-XR Attribute
 *
 **************************************************************************************/
struct _belle_sdp_rtcp_xr_attribute {
	belle_sdp_attribute_t base;
	const char* rcvr_rtt_mode;
	int rcvr_rtt_max_size;
	unsigned int stat_summary;
	belle_sip_list_t* stat_summary_flags;
	unsigned int voip_metrics;
};
Ghislain MARY's avatar
Ghislain MARY committed
290
const belle_sip_list_t* belle_sdp_rtcp_xr_attribute_get_stat_summary_flags(const belle_sdp_rtcp_xr_attribute_t* attribute) {
291 292 293 294 295 296 297
	return attribute->stat_summary_flags;
}
void belle_sdp_rtcp_xr_attribute_add_stat_summary_flag(belle_sdp_rtcp_xr_attribute_t* attribute, const char* flag) {
	attribute->stat_summary_flags = belle_sip_list_append(attribute->stat_summary_flags, belle_sip_strdup(flag));
}
void belle_sdp_rtcp_xr_attribute_destroy(belle_sdp_rtcp_xr_attribute_t* attribute) {
	DESTROY_STRING(attribute,rcvr_rtt_mode)
Ghislain MARY's avatar
Ghislain MARY committed
298
	belle_sip_list_free_with_data(attribute->stat_summary_flags, belle_sip_free);
299 300 301 302 303
}
void belle_sdp_rtcp_xr_attribute_clone(belle_sdp_rtcp_xr_attribute_t* attribute, const belle_sdp_rtcp_xr_attribute_t *orig) {
	CLONE_STRING(belle_sdp_rtcp_xr_attribute,rcvr_rtt_mode,attribute,orig)
	attribute->rcvr_rtt_max_size = orig->rcvr_rtt_max_size;
	attribute->stat_summary = orig->stat_summary;
Ghislain MARY's avatar
Ghislain MARY committed
304
	attribute->stat_summary_flags = belle_sip_list_copy_with_data(orig->stat_summary_flags, belle_sip_string_copyfunc);
305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
	attribute->voip_metrics = orig->voip_metrics;
}
belle_sip_error_code belle_sdp_rtcp_xr_attribute_marshal(belle_sdp_rtcp_xr_attribute_t* attribute, char * buff, size_t buff_size, size_t *offset) {
	const char *rcvr_rtt_mode = NULL;
	int rcvr_rtt_max_size = -1;
	int nb_xr_formats = 0;
	belle_sip_error_code error = belle_sdp_attribute_marshal(BELLE_SDP_ATTRIBUTE(attribute), buff, buff_size, offset);
	if (error != BELLE_SIP_OK) return error;
	rcvr_rtt_mode = belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_mode(attribute);
	if (rcvr_rtt_mode != NULL) {
		error = belle_sip_snprintf(buff, buff_size, offset, "%srcvr-rtt=%s", nb_xr_formats++ == 0 ? ":" : " ", rcvr_rtt_mode);
		if (error != BELLE_SIP_OK) return error;
		rcvr_rtt_max_size = belle_sdp_rtcp_xr_attribute_get_rcvr_rtt_max_size(attribute);
		if (rcvr_rtt_max_size > 0) {
			error = belle_sip_snprintf(buff, buff_size, offset, ":%u", rcvr_rtt_max_size);
			if (error != BELLE_SIP_OK) return error;
		}
	}
	if (belle_sdp_rtcp_xr_attribute_has_stat_summary(attribute)) {
		belle_sip_list_t* list;
		int nb_stat_flags = 0;
		error = belle_sip_snprintf(buff, buff_size, offset, "%sstat-summary", nb_xr_formats++ == 0 ? ":" : " ");
		if (error != BELLE_SIP_OK) return error;
		for (list = attribute->stat_summary_flags; list != NULL; list = list->next) {
			error = belle_sip_snprintf(buff, buff_size, offset, "%s%s", nb_stat_flags++ == 0 ? "=" : ",", (const char*)list->data);
			if (error != BELLE_SIP_OK) return error;
		}
	}
	if (belle_sdp_rtcp_xr_attribute_has_voip_metrics(attribute)) {
		error = belle_sip_snprintf(buff, buff_size, offset, "%svoip-metrics", nb_xr_formats++ == 0 ? ":" : " ");
		if (error != BELLE_SIP_OK) return error;
	}
	return error;
}
static void belle_sdp_rtcp_xr_attribute_init(belle_sdp_rtcp_xr_attribute_t* attribute) {
	belle_sdp_attribute_set_name(BELLE_SDP_ATTRIBUTE(attribute), "rtcp-xr");
}
BELLE_SDP_NEW_WITH_CTR(rtcp_xr_attribute,belle_sdp_attribute)
BELLE_SDP_PARSE(rtcp_xr_attribute)
GET_SET_STRING(belle_sdp_rtcp_xr_attribute,rcvr_rtt_mode)
GET_SET_INT(belle_sdp_rtcp_xr_attribute,rcvr_rtt_max_size,int)
GET_SET_BOOL(belle_sdp_rtcp_xr_attribute,stat_summary,has)
GET_SET_BOOL(belle_sdp_rtcp_xr_attribute,voip_metrics,has)
348 349 350 351 352 353 354 355 356 357
/***************************************************************************************
 * Bandwidth
 *
 **************************************************************************************/
struct _belle_sdp_bandwidth {
	belle_sip_object_t base;
	const char* type;
	int value;
};
void belle_sdp_bandwidth_destroy(belle_sdp_bandwidth_t* bandwidth) {
358
	if (bandwidth->type) belle_sip_free((void*)bandwidth->type);
359 360 361
}

void belle_sdp_bandwidth_clone(belle_sdp_bandwidth_t *bandwidth, const belle_sdp_bandwidth_t *orig){
362 363
	CLONE_STRING(belle_sdp_bandwidth,type,bandwidth,orig)
	bandwidth->value=orig->value;
364
}
Ghislain MARY's avatar
Ghislain MARY committed
365

366
belle_sip_error_code belle_sdp_bandwidth_marshal(belle_sdp_bandwidth_t* bandwidth, char* buff, size_t buff_size, size_t *offset) {
Ghislain MARY's avatar
Ghislain MARY committed
367
	return belle_sip_snprintf(buff,buff_size,offset,"b=%s:%i",bandwidth->type,bandwidth->value);
368
}
Ghislain MARY's avatar
Ghislain MARY committed
369

370 371 372 373
BELLE_SDP_NEW(bandwidth,belle_sip_object)
BELLE_SDP_PARSE(bandwidth)
GET_SET_STRING(belle_sdp_bandwidth,type);
GET_SET_INT(belle_sdp_bandwidth,value,int)
jehan's avatar
jehan committed
374 375 376 377 378 379 380 381 382

/************************
 * connection
 ***********************/
struct _belle_sdp_connection {
	belle_sip_object_t base;
	const char* network_type;
	const char* address_type;
	const char* address;
383 384
	int ttl;
	int range;
jehan's avatar
jehan committed
385 386 387
 };

void belle_sdp_connection_destroy(belle_sdp_connection_t* connection) {
jehan's avatar
jehan committed
388 389 390
	DESTROY_STRING(connection,network_type)
	DESTROY_STRING(connection,address_type)
	DESTROY_STRING(connection,address)
jehan's avatar
jehan committed
391 392 393
}

void belle_sdp_connection_clone(belle_sdp_connection_t *connection, const belle_sdp_connection_t *orig){
jehan's avatar
jehan committed
394 395 396
	CLONE_STRING(belle_sdp_connection,network_type,connection,orig)
	CLONE_STRING(belle_sdp_connection,address_type,connection,orig)
	CLONE_STRING(belle_sdp_connection,address,connection,orig)
397 398
	connection->range=orig->range;
	connection->ttl=orig->ttl;
jehan's avatar
jehan committed
399
}
Ghislain MARY's avatar
Ghislain MARY committed
400

401
belle_sip_error_code belle_sdp_connection_marshal(belle_sdp_connection_t* connection, char* buff, size_t buff_size, size_t *offset) {
402 403 404 405 406 407 408 409
	belle_sip_error_code error = belle_sip_snprintf(buff,buff_size,offset,"c=%s %s %s",connection->network_type,connection->address_type,connection->address);
	if (error!=BELLE_SIP_OK) return error;
	if (connection->ttl>0)
		error = belle_sip_snprintf(buff,buff_size,offset,"/%i",connection->ttl);
	if (error!=BELLE_SIP_OK) return error;
	if (connection->range>0)
		error = belle_sip_snprintf(buff,buff_size,offset,"/%i",connection->range);
	return error;
jehan's avatar
jehan committed
410
}
Ghislain MARY's avatar
Ghislain MARY committed
411

jehan's avatar
jehan committed
412 413
BELLE_SDP_NEW(connection,belle_sip_object)
BELLE_SDP_PARSE(connection)
jehan's avatar
jehan committed
414 415 416 417 418 419 420
belle_sdp_connection_t* belle_sdp_connection_create(const char* net_type, const char* addr_type, const char* addr) {
	belle_sdp_connection_t* connection = belle_sdp_connection_new();
	belle_sdp_connection_set_network_type(connection,net_type);
	belle_sdp_connection_set_address_type(connection,addr_type);
	belle_sdp_connection_set_address(connection,addr);
	return connection;
}
jehan's avatar
jehan committed
421 422 423
GET_SET_STRING(belle_sdp_connection,network_type);
GET_SET_STRING(belle_sdp_connection,address_type);
GET_SET_STRING(belle_sdp_connection,address);
424 425
GET_SET_INT(belle_sdp_connection,ttl,int);
GET_SET_INT(belle_sdp_connection,range,int);
426 427 428 429 430
/************************
 * email
 ***********************/
struct _belle_sdp_email {
	belle_sip_object_t base;
431
	char* value;
432 433 434
 };

void belle_sdp_email_destroy(belle_sdp_email_t* email) {
jehan's avatar
jehan committed
435
	DESTROY_STRING(email,value)
436 437 438
}

void belle_sdp_email_clone(belle_sdp_email_t *email, const belle_sdp_email_t *orig){
jehan's avatar
jehan committed
439
	CLONE_STRING(belle_sdp_email,value,email,orig)
440
}
Ghislain MARY's avatar
Ghislain MARY committed
441

442
belle_sip_error_code belle_sdp_email_marshal(belle_sdp_email_t* email, char* buff, size_t buff_size, size_t *offset) {
Ghislain MARY's avatar
Ghislain MARY committed
443
	return belle_sip_snprintf(buff,buff_size,offset,"e=%s",email->value);
444
}
Ghislain MARY's avatar
Ghislain MARY committed
445

446 447 448 449 450 451 452 453 454 455 456 457
BELLE_SDP_NEW(email,belle_sip_object)
BELLE_SDP_PARSE(email)
GET_SET_STRING(belle_sdp_email,value);
/************************
 * info
 ***********************/
struct _belle_sdp_info {
	belle_sip_object_t base;
	const char* value;
 };

void belle_sdp_info_destroy(belle_sdp_info_t* info) {
jehan's avatar
jehan committed
458
	DESTROY_STRING(info,value)
459 460 461
}

void belle_sdp_info_clone(belle_sdp_info_t *info, const belle_sdp_info_t *orig){
jehan's avatar
jehan committed
462
	CLONE_STRING(belle_sdp_info,value,info,orig)
463
}
Ghislain MARY's avatar
Ghislain MARY committed
464

465
belle_sip_error_code belle_sdp_info_marshal(belle_sdp_info_t* info, char* buff, size_t buff_size, size_t *offset) {
Ghislain MARY's avatar
Ghislain MARY committed
466
	return belle_sip_snprintf(buff,buff_size,offset,"i=%s",info->value);
467
}
Ghislain MARY's avatar
Ghislain MARY committed
468

469 470 471 472 473 474 475 476
BELLE_SDP_NEW(info,belle_sip_object)
BELLE_SDP_PARSE(info)
GET_SET_STRING(belle_sdp_info,value);
/************************
 * media
 ***********************/
struct _belle_sdp_media {
	belle_sip_object_t base;
jehan's avatar
jehan committed
477
	const char* media_type;
478 479 480
	int media_port;
	belle_sip_list_t* media_formats;
	int port_count;
jehan's avatar
jehan committed
481
	const char* protocol;
482
	const char* raw_fmt;
483
 };
jehan's avatar
jehan committed
484 485 486 487
belle_sip_list_t*	belle_sdp_media_get_media_formats(const belle_sdp_media_t* media) {
	return media->media_formats;
}
void belle_sdp_media_set_media_formats( belle_sdp_media_t* media, belle_sip_list_t* formats) {
jehan's avatar
jehan committed
488
	/*belle_sip_list_free(media->media_formats); to allow easy list management might be better to add an append format method*/
jehan's avatar
jehan committed
489 490
	media->media_formats = formats;
}
491
void belle_sdp_media_destroy(belle_sdp_media_t* media) {
jehan's avatar
jehan committed
492 493 494
	DESTROY_STRING(media,media_type)
	belle_sip_list_free(media->media_formats);
	DESTROY_STRING(media,protocol)
495
}
jehan's avatar
jehan committed
496 497 498
static void belle_sdp_media_init(belle_sdp_media_t* media) {
	media->port_count=1;
}
499 500

void belle_sdp_media_clone(belle_sdp_media_t *media, const belle_sdp_media_t *orig){
jehan's avatar
jehan committed
501 502 503 504 505
	CLONE_STRING(belle_sdp_media,media_type,media,orig)
	media->media_port=orig->media_port;
	media->media_formats = belle_sip_list_copy(orig->media_formats);
	media->port_count=orig->port_count;
	CLONE_STRING(belle_sdp_media,protocol,media,orig)
506
}
Ghislain MARY's avatar
Ghislain MARY committed
507

508
belle_sip_error_code belle_sdp_media_marshal(belle_sdp_media_t* media, char* buff, size_t buff_size, size_t *offset) {
jehan's avatar
jehan committed
509
	belle_sip_list_t* list=media->media_formats;
Ghislain MARY's avatar
Ghislain MARY committed
510
	belle_sip_error_code error=belle_sip_snprintf(buff,buff_size,offset,"m=%s %i",media->media_type,media->media_port);
511
	if (error!=BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
512
	if (media->port_count>1) {
Ghislain MARY's avatar
Ghislain MARY committed
513
		error=belle_sip_snprintf(buff,buff_size,offset,"/%i",media->port_count);
514
		if (error!=BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
515
	}
Ghislain MARY's avatar
Ghislain MARY committed
516 517
	error=belle_sip_snprintf(buff,buff_size,offset," %s",media->protocol);
	if (error!=BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
518
	for(;list!=NULL;list=list->next){
Ghislain MARY's avatar
Ghislain MARY committed
519
		error=belle_sip_snprintf(buff,buff_size,offset," %li",(long)list->data);
520
		if (error!=BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
521
	}
Ghislain MARY's avatar
Ghislain MARY committed
522
	return error;
523
}
Ghislain MARY's avatar
Ghislain MARY committed
524

jehan's avatar
jehan committed
525
BELLE_SDP_NEW_WITH_CTR(media,belle_sip_object)
526
BELLE_SDP_PARSE(media)
jehan's avatar
jehan committed
527
belle_sdp_media_t* belle_sdp_media_create(const char* media_type
528 529 530 531
						 ,int media_port
						 ,int port_count
						 ,const char* protocol
						 ,belle_sip_list_t* static_media_formats) {
jehan's avatar
jehan committed
532 533 534 535 536 537 538 539
	belle_sdp_media_t* media= belle_sdp_media_new();
	belle_sdp_media_set_media_type(media,media_type);
	belle_sdp_media_set_media_port(media,media_port);
	belle_sdp_media_set_port_count(media,port_count);
	belle_sdp_media_set_protocol(media,protocol);
	if (static_media_formats) belle_sdp_media_set_media_formats(media,static_media_formats);
	return media;
}
540
GET_SET_STRING(belle_sdp_media,media_type);
jehan's avatar
jehan committed
541
GET_SET_STRING(belle_sdp_media,protocol);
542 543
GET_SET_INT(belle_sdp_media,media_port,int)
GET_SET_INT(belle_sdp_media,port_count,int)
jehan's avatar
jehan committed
544 545 546 547 548 549 550 551 552 553 554 555

/************************
 * base_description
 ***********************/
typedef struct _belle_sdp_base_description {
	belle_sip_object_t base;
	belle_sdp_info_t* info;
	belle_sdp_connection_t* connection;
	belle_sip_list_t* bandwidths;
	belle_sip_list_t* attributes;
} belle_sdp_base_description_t;

jehan's avatar
jehan committed
556 557 558 559 560
static void belle_sdp_base_description_destroy(belle_sdp_base_description_t* base_description) {
	if (base_description->info) belle_sip_object_unref(BELLE_SIP_OBJECT(base_description->info));
	if (base_description->connection) belle_sip_object_unref(BELLE_SIP_OBJECT(base_description->connection));
	belle_sip_list_free_with_data(base_description->bandwidths,belle_sip_object_freefunc);
	belle_sip_list_free_with_data(base_description->attributes,belle_sip_object_freefunc);
jehan's avatar
jehan committed
561
}
jehan's avatar
jehan committed
562
static void belle_sdp_base_description_init(belle_sdp_base_description_t* base_description) {
jehan's avatar
jehan committed
563
}
jehan's avatar
jehan committed
564
static void belle_sdp_base_description_clone(belle_sdp_base_description_t *base_description, const belle_sdp_base_description_t *orig){
565 566
	if (orig->info) base_description->info = BELLE_SDP_INFO(belle_sip_object_clone_and_ref(BELLE_SIP_OBJECT(orig->info)));
	if (orig->connection) base_description->connection = BELLE_SDP_CONNECTION(belle_sip_object_clone_and_ref(BELLE_SIP_OBJECT(orig->connection)));
jehan's avatar
jehan committed
567 568 569
	base_description->bandwidths = belle_sip_list_copy_with_data(orig->bandwidths,belle_sip_object_copyfunc);
	base_description->attributes = belle_sip_list_copy_with_data(orig->attributes,belle_sip_object_copyfunc);

jehan's avatar
jehan committed
570
}
Ghislain MARY's avatar
Ghislain MARY committed
571

572
belle_sip_error_code belle_sdp_base_description_marshal(belle_sdp_base_description_t* base_description, char* buff, size_t buff_size, size_t *offset) {
Ghislain MARY's avatar
Ghislain MARY committed
573
	belle_sip_error_code error=BELLE_SIP_OK;
jehan's avatar
jehan committed
574
	belle_sip_list_t* bandwidths;
575
//	belle_sip_list_t* attributes;
jehan's avatar
jehan committed
576
	if (base_description->info) {
Ghislain MARY's avatar
Ghislain MARY committed
577 578 579
		error=belle_sip_object_marshal(BELLE_SIP_OBJECT(base_description->info),buff,buff_size,offset);
		if (error!=BELLE_SIP_OK) return error;
		error=belle_sip_snprintf(buff, buff_size, offset, "\r\n");
580
		if (error!=BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
581 582
	}
	if (base_description->connection) {
Ghislain MARY's avatar
Ghislain MARY committed
583 584 585 586
		error=belle_sip_object_marshal(BELLE_SIP_OBJECT(base_description->connection),buff,buff_size,offset);
		if (error!=BELLE_SIP_OK) return error;
		error=belle_sip_snprintf(buff, buff_size, offset, "\r\n");
		if (error!=BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
587 588
	}
	for(bandwidths=base_description->bandwidths;bandwidths!=NULL;bandwidths=bandwidths->next){
Ghislain MARY's avatar
Ghislain MARY committed
589 590 591 592
		error=belle_sip_object_marshal(BELLE_SIP_OBJECT(bandwidths->data),buff,buff_size,offset);
		if (error!=BELLE_SIP_OK) return error;
		error=belle_sip_snprintf(buff, buff_size, offset, "\r\n");
		if (error!=BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
593
	}
594
//	for(attributes=base_description->attributes;attributes!=NULL;attributes=attributes->next){
595 596
//		error=belle_sip_object_marshal(BELLE_SIP_OBJECT(attributes->data),buff,buff_size,offset);
//		error=belle_sip_snprintf(buff, buff_size, offset, "\r\n");
597
//	}
Ghislain MARY's avatar
Ghislain MARY committed
598
	return error;
jehan's avatar
jehan committed
599
}
600 601

BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sdp_base_description_t);
jehan's avatar
jehan committed
602 603 604 605 606 607
BELLE_SIP_INSTANCIATE_VPTR(belle_sdp_base_description_t
							,belle_sip_object_t
							,belle_sdp_base_description_destroy
							,belle_sdp_base_description_clone
							,belle_sdp_base_description_marshal
							,FALSE);
jehan's avatar
jehan committed
608 609 610 611

static int belle_sdp_base_description_attribute_comp_func(const belle_sdp_attribute_t* a, const char*b) {
	return strcmp(a->name,b);
}
612
belle_sdp_attribute_t*	belle_sdp_base_description_get_attribute(const belle_sdp_base_description_t* base_description, const char* name) {
jehan's avatar
jehan committed
613 614 615
	belle_sip_list_t* attribute;
	attribute = belle_sip_list_find_custom(base_description->attributes, (belle_sip_compare_func)belle_sdp_base_description_attribute_comp_func, name);
	if (attribute) {
jehan's avatar
jehan committed
616
		return ((belle_sdp_attribute_t*)attribute->data);
jehan's avatar
jehan committed
617 618 619 620
	} else {
		return NULL;
	}
}
jehan's avatar
jehan committed
621
const char*	belle_sdp_base_description_get_attribute_value(const belle_sdp_base_description_t* base_description, const char* name) {
622
	belle_sdp_attribute_t* attribute = belle_sdp_base_description_get_attribute(base_description,name);
623
	if (attribute) {
624
		return belle_sdp_attribute_get_value(attribute);
625
	} else return NULL;
jehan's avatar
jehan committed
626 627

}
jehan's avatar
jehan committed
628 629 630 631 632 633 634
belle_sip_list_t* belle_sdp_base_description_get_attributes(const belle_sdp_base_description_t* base_description) {
	return base_description->attributes;
}
static int belle_sdp_base_description_bandwidth_comp_func(const belle_sdp_bandwidth_t* a, const char*b) {
	return strcmp(a->type,b);
}

635 636 637 638 639 640 641 642 643 644 645

belle_sdp_bandwidth_t* belle_sdp_base_description_get_bandwidth(const belle_sdp_base_description_t *base_description, const char *name){
	belle_sip_list_t* found = belle_sip_list_find_custom(base_description->bandwidths, (belle_sip_compare_func)belle_sdp_base_description_bandwidth_comp_func, name);
	if( found ){
		return ((belle_sdp_bandwidth_t*)found->data);
	} else {
		return NULL;
	}
}

int	belle_sdp_base_description_get_bandwidth_value(const belle_sdp_base_description_t* base_description, const char* name) {
jehan's avatar
jehan committed
646 647 648 649 650 651 652 653 654 655 656 657 658
	belle_sip_list_t* bandwidth;
	bandwidth = belle_sip_list_find_custom(base_description->bandwidths, (belle_sip_compare_func)belle_sdp_base_description_bandwidth_comp_func, name);
	if (bandwidth) {
		return ((belle_sdp_bandwidth_t*)bandwidth->data)->value;
	} else {
		return -1;
	}
}
void belle_sdp_base_description_remove_attribute(belle_sdp_base_description_t* base_description,const char* name) {
	belle_sip_list_t* attribute;
	attribute = belle_sip_list_find_custom(base_description->attributes, (belle_sip_compare_func)belle_sdp_base_description_attribute_comp_func, name);
	if (attribute) {
		belle_sip_object_unref(BELLE_SIP_OBJECT(attribute->data));
659
		base_description->attributes = belle_sip_list_delete_link(base_description->attributes,attribute);
jehan's avatar
jehan committed
660 661 662 663 664 665 666 667
	}

}
void belle_sdp_base_description_remove_bandwidth(belle_sdp_base_description_t* base_description,const char* name) {
	belle_sip_list_t* bandwidth;
	bandwidth = belle_sip_list_find_custom(base_description->bandwidths, (belle_sip_compare_func)belle_sdp_base_description_bandwidth_comp_func, name);
	if (bandwidth) {
		belle_sip_object_unref(BELLE_SIP_OBJECT(bandwidth->data));
668
		base_description->bandwidths = belle_sip_list_delete_link(base_description->bandwidths,bandwidth);
jehan's avatar
jehan committed
669 670
	}
}
jehan's avatar
jehan committed
671
void belle_sdp_base_description_set_attribute_value(belle_sdp_base_description_t* base_description, const char* name, const char* value) {
672 673 674
	belle_sdp_raw_attribute_t* attribute = belle_sdp_raw_attribute_new();
	belle_sdp_attribute_set_name(BELLE_SDP_ATTRIBUTE(attribute),name);
	belle_sdp_raw_attribute_set_value(attribute,value);
675
	base_description->attributes = belle_sip_list_append(base_description->attributes,belle_sip_object_ref(attribute));
jehan's avatar
jehan committed
676 677
}
void belle_sdp_base_description_add_attribute(belle_sdp_base_description_t* base_description, const belle_sdp_attribute_t* attribute) {
678
	base_description->attributes = belle_sip_list_append(base_description->attributes,(void*)belle_sip_object_ref(BELLE_SIP_OBJECT(attribute)));
jehan's avatar
jehan committed
679 680 681 682 683
}

#define SET_LIST(list_name,value) \
		belle_sip_list_t* list;\
		if (list_name) {\
684
			belle_sip_list_free_with_data(list_name,belle_sip_object_unref);\
jehan's avatar
jehan committed
685
		} \
686
		for (list=value;list !=NULL; list=list->next) {\
687
			belle_sip_object_ref(BELLE_SIP_OBJECT(list->data));\
688
		}\
jehan's avatar
jehan committed
689 690 691 692 693 694 695
		list_name=value;


void belle_sdp_base_description_set_attributes(belle_sdp_base_description_t* base_description, belle_sip_list_t* attributes) {
	SET_LIST(base_description->attributes,attributes)
}
void belle_sdp_base_description_set_bandwidth(belle_sdp_base_description_t* base_description, const char* type, int value) {
696

697
	belle_sdp_bandwidth_t* bandwidth = BELLE_SDP_BANDWIDTH(belle_sdp_base_description_get_bandwidth(base_description, type));
698 699 700 701 702 703 704 705
	if( bandwidth == NULL ){
		bandwidth= belle_sdp_bandwidth_new();
		belle_sdp_bandwidth_set_type(bandwidth,type);
		belle_sdp_bandwidth_set_value(bandwidth,value);
		base_description->bandwidths = belle_sip_list_append(base_description->bandwidths,belle_sip_object_ref(bandwidth));
	} else {
		belle_sdp_bandwidth_set_value(bandwidth,value);
	}
jehan's avatar
jehan committed
706 707
}
void belle_sdp_base_description_add_bandwidth(belle_sdp_base_description_t* base_description, const belle_sdp_bandwidth_t* bandwidth) {
708

709
	base_description->bandwidths = belle_sip_list_append(base_description->bandwidths,(void *)belle_sip_object_ref((void *)bandwidth));
jehan's avatar
jehan committed
710 711 712 713 714 715 716 717 718 719 720 721 722
}
void belle_sdp_base_description_set_bandwidths(belle_sdp_base_description_t* base_description, belle_sip_list_t* bandwidths) {
	SET_LIST(base_description->bandwidths,bandwidths)
}

/************************
 * media_description
 ***********************/
struct _belle_sdp_media_description {
	belle_sdp_base_description_t base_description;
	belle_sdp_media_t* media;
};
void belle_sdp_media_description_destroy(belle_sdp_media_description_t* media_description) {
jehan's avatar
jehan committed
723
	if (media_description->media) belle_sip_object_unref(BELLE_SIP_OBJECT((media_description->media)));
jehan's avatar
jehan committed
724 725 726
}

void belle_sdp_media_description_clone(belle_sdp_media_description_t *media_description, const belle_sdp_media_description_t *orig){
727
	if (orig->media) media_description->media = BELLE_SDP_MEDIA(belle_sip_object_clone_and_ref(BELLE_SIP_OBJECT((orig->media))));
jehan's avatar
jehan committed
728
}
Ghislain MARY's avatar
Ghislain MARY committed
729

730
belle_sip_error_code belle_sdp_media_description_marshal(belle_sdp_media_description_t* media_description, char* buff, size_t buff_size, size_t *offset) {
731
	belle_sip_list_t* attributes;
Ghislain MARY's avatar
Ghislain MARY committed
732 733 734 735 736 737
	belle_sip_error_code error=belle_sip_object_marshal(BELLE_SIP_OBJECT(media_description->media),buff,buff_size,offset);
	if (error!=BELLE_SIP_OK) return error;
	error=belle_sip_snprintf(buff, buff_size, offset, "\r\n");
	if (error!=BELLE_SIP_OK) return error;
	error=belle_sdp_base_description_marshal(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),buff,buff_size,offset);
	if (error!=BELLE_SIP_OK) return error;
738 739

	for(attributes=media_description->base_description.attributes;attributes!=NULL;attributes=attributes->next){
Ghislain MARY's avatar
Ghislain MARY committed
740 741 742 743
		error=belle_sip_object_marshal(BELLE_SIP_OBJECT(attributes->data),buff,buff_size,offset);
		if (error!=BELLE_SIP_OK) return error;
		error=belle_sip_snprintf(buff, buff_size, offset, "\r\n");
		if (error!=BELLE_SIP_OK) return error;
744
	}
Ghislain MARY's avatar
Ghislain MARY committed
745
	return error;
jehan's avatar
jehan committed
746
}
747

jehan's avatar
jehan committed
748
BELLE_SDP_NEW(media_description,belle_sdp_base_description)
jehan's avatar
jehan committed
749
belle_sdp_media_description_t* belle_sdp_media_description_create(const char* media_type
750 751 752 753
																 ,int media_port
																 ,int port_count
																 ,const char* protocol
																 ,belle_sip_list_t* static_media_formats) {
jehan's avatar
jehan committed
754 755 756 757
	belle_sdp_media_description_t* media_desc=belle_sdp_media_description_new();
	belle_sdp_media_description_set_media(media_desc,belle_sdp_media_create(media_type,media_port,port_count,protocol,static_media_formats));
	return media_desc;
}
jehan's avatar
jehan committed
758 759
BELLE_SDP_PARSE(media_description)
void belle_sdp_media_description_add_dynamic_payloads(belle_sdp_media_description_t* media_description, belle_sip_list_t* payloadNames, belle_sip_list_t* payloadValues) {
760
	belle_sip_error("belle_sdp_media_description_add_dynamic_payloads not implemented yet");
jehan's avatar
jehan committed
761
}
762
belle_sdp_attribute_t*	belle_sdp_media_description_get_attribute(const belle_sdp_media_description_t* media_description, const char* name) {
jehan's avatar
jehan committed
763 764
	return belle_sdp_base_description_get_attribute(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),name);
}
jehan's avatar
jehan committed
765 766 767
const char*	belle_sdp_media_description_get_attribute_value(const belle_sdp_media_description_t* media_description, const char* name) {
	return belle_sdp_base_description_get_attribute_value(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),name);
}
jehan's avatar
jehan committed
768 769 770 771 772
belle_sip_list_t* belle_sdp_media_description_get_attributes(const belle_sdp_media_description_t* media_description) {
	return BELLE_SIP_CAST(media_description,belle_sdp_base_description_t)->attributes;
}

int	belle_sdp_media_description_get_bandwidth(const belle_sdp_media_description_t* media_description, const char* name) {
773
	return belle_sdp_base_description_get_bandwidth_value(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),name);
jehan's avatar
jehan committed
774 775 776 777 778 779 780 781 782 783 784 785 786 787
}
belle_sip_list_t* belle_sdp_media_description_get_bandwidths(const belle_sdp_media_description_t* media_description) {
	return BELLE_SIP_CAST(media_description,belle_sdp_base_description_t)->bandwidths;
}
belle_sdp_connection_t*	belle_sdp_media_description_get_connection(const belle_sdp_media_description_t* media_description) {
	return BELLE_SIP_CAST(media_description,belle_sdp_base_description_t)->connection;
}
belle_sdp_info_t* belle_sdp_media_description_get_info(const belle_sdp_media_description_t* media_description) {
	return BELLE_SIP_CAST(media_description,belle_sdp_base_description_t)->info;
}
/*belle_sdp_key_t*  belle_sdp_media_description_get_key(const belle_sdp_media_description_t* media_description);*/
belle_sdp_media_t* belle_sdp_media_description_get_media(const belle_sdp_media_description_t* media_description) {
	return media_description->media;
}
788 789 790 791 792 793 794 795

struct static_payload {
	unsigned char number;
	int channel_count;
	const char* type;
	int	rate;
};
#define STATIC_PAYLOAD_LIST_LENTH 8
jehan's avatar
jehan committed
796 797 798
/*
 * rfc 3551
 * PT   encoding    media type  clock rate   channels
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820
					name                    (Hz)
			   ___________________________________________________
			   0    PCMU        A            8,000       1
			   1    reserved    A
			   2    reserved    A
			   3    GSM         A            8,000       1
			   4    G723        A            8,000       1
			   5    DVI4        A            8,000       1
			   6    DVI4        A           16,000       1
			   7    LPC         A            8,000       1
			   8    PCMA        A            8,000       1
			   9    G722        A            8,000       1
			   10   L16         A           44,100       2
			   11   L16         A           44,100       1
			   12   QCELP       A            8,000       1
			   13   CN          A            8,000       1
			   14   MPA         A           90,000       (see text)
			   15   G728        A            8,000       1
			   16   DVI4        A           11,025       1
			   17   DVI4        A           22,050       1
			   18   G729        A            8,000       1
			   Table 4: Payload types (PT) for audio encodings
jehan's avatar
jehan committed
821 822

  PT      encoding    media type  clock rate
823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
					   name                    (Hz)
			   _____________________________________________
			   24      unassigned  V
			   25      CelB        V           90,000
			   26      JPEG        V           90,000
			   27      unassigned  V
			   28      nv          V           90,000
			   29      unassigned  V
			   30      unassigned  V
			   31      H261        V           90,000
			   32      MPV         V           90,000
			   33      MP2T        AV          90,000
			   34      H263        V           90,000

			   Table 5: Payload types (PT) for video and combined
						encodings
jehan's avatar
jehan committed
839 840 841 842 843


 *
 * */

844
const struct static_payload static_payload_list [] ={
jehan's avatar
jehan committed
845
	/*audio*/
846 847 848 849 850
	{0,1,"PCMU",8000},
	{3,1,"GSM",8000},
	{4,1,"G723",8000},
	{5,1,"DVI4",8000},
	{6,1,"DVI4",16000},
jehan's avatar
jehan committed
851
	{7,1,"LPC",8000},
852 853
	{8,1,"PCMA",8000},
	{9,1,"G722",8000},
jehan's avatar
jehan committed
854 855 856 857 858 859 860 861 862 863
	{10,2,"L16",44100},
	{11,1,"L16",44100},
	{12,1,"QCELP",8000},
	{13,1,"CN",8000},
	{14,1,"MPA",90000},
	{15,1,"G728",8000},
	{16,1,"DVI4",11025},
	{17,1,"DVI4",22050},
	{18,1,"G729",8000},
	/*video*/
864 865 866 867 868 869 870
	{25,0,"CelB",90000},
	{26,0,"JPEG",90000},
	{28,0,"nv",90000},
	{31,0,"H261",90000},
	{32,0,"MPV",90000},
	{33,0,"MP2T",90000},
	{34,0,"H263",90000}
871
};
872

Simon Morlat's avatar
Simon Morlat committed
873
static const size_t payload_list_elements=sizeof(static_payload_list)/sizeof(struct static_payload);
874 875 876 877

static int mime_parameter_is_static(const belle_sdp_mime_parameter_t *param){
	const struct static_payload* iterator;
	int i;
878

Simon Morlat's avatar
Simon Morlat committed
879
	for (iterator = static_payload_list,i=0;i<payload_list_elements;i++,iterator++) {
880 881
		if (iterator->number == param->media_format &&
			strcasecmp(iterator->type,param->type)==0 &&
882 883 884 885 886 887 888 889
			iterator->channel_count==param->channel_count &&
			iterator->rate==param->rate ) {
			return TRUE;
		}
	}
	return FALSE;
}

890
static int mime_parameter_fill_from_static(belle_sdp_mime_parameter_t *mime_parameter,int format) {
891
	const struct static_payload* iterator;
892
	int i;
893

Simon Morlat's avatar
Simon Morlat committed
894
	for (iterator = static_payload_list,i=0;i<payload_list_elements;i++,iterator++) {
895 896 897 898
		if (iterator->number == format) {
			belle_sdp_mime_parameter_set_type(mime_parameter,iterator->type);
			belle_sdp_mime_parameter_set_rate(mime_parameter,iterator->rate);
			belle_sdp_mime_parameter_set_channel_count(mime_parameter,iterator->channel_count);
899
			break;
900 901 902 903
		}
	}
	return 0;
}
904

905
static int mime_parameter_fill_from_rtpmap(belle_sdp_mime_parameter_t *mime_parameter, const char *rtpmap, int is_audio){
906 907 908 909 910 911 912 913 914 915 916
	char *mime=belle_sip_strdup(rtpmap);
	char *p=strchr(mime,'/');
	if (p){
		char *chans;
		*p='\0';
		p++;
		chans=strchr(p,'/');
		if (chans){
			*chans='\0';
			chans++;
			belle_sdp_mime_parameter_set_channel_count(mime_parameter,atoi(chans));
917
		}else if (is_audio) belle_sdp_mime_parameter_set_channel_count(mime_parameter,1); /*in absence of channel count, 1 is implicit for audio streams*/
918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935
		belle_sdp_mime_parameter_set_rate(mime_parameter,atoi(p));
	}
	belle_sdp_mime_parameter_set_type(mime_parameter,mime);
	belle_sip_free(mime);
	return 0;
}
/* return the value of attr "field" for payload pt at line pos (field=rtpmap,fmtp...)*/
static const char *belle_sdp_media_description_a_attr_value_get_with_pt(const belle_sdp_media_description_t* media_description,int pt,const char *field)
{
	int tmppt=0,scanned=0;
	const char *tmp;
	belle_sdp_attribute_t *attr;
	belle_sip_list_t* attribute_list;
	for (	attribute_list =belle_sdp_media_description_get_attributes(media_description)
						;attribute_list!=NULL
						;attribute_list=attribute_list->next) {

		attr = BELLE_SDP_ATTRIBUTE(attribute_list->data);
936 937
		if (strcmp(field,belle_sdp_attribute_get_name(attr))==0 && belle_sdp_attribute_get_value(attr)!=NULL){
			int nb = sscanf(belle_sdp_attribute_get_value(attr),"%i %n",&tmppt,&scanned);
938 939 940
			/* the return value may depend on how %n is interpreted by the libc: see manpage*/
			if (nb == 1 || nb==2 ){
				if (pt==tmppt){
941
					tmp=belle_sdp_attribute_get_value(attr)+scanned;
942 943 944
					if (strlen(tmp)>0)
						return tmp;
				}
945
			}else belle_sip_warning("sdp has a strange a= line (%s) nb=%i",belle_sdp_attribute_get_value(attr),nb);
946 947
		}
	}
jehan's avatar
jehan committed
948 949
	return NULL;
}
950 951 952 953 954 955 956 957 958 959 960 961 962

belle_sip_list_t* belle_sdp_media_description_build_mime_parameters(const belle_sdp_media_description_t* media_description) {
	/*First, get media type*/
	belle_sdp_media_t* media = belle_sdp_media_description_get_media(media_description);
	belle_sip_list_t* mime_parameter_list=NULL;
	belle_sip_list_t* media_formats=NULL;
	belle_sdp_mime_parameter_t* mime_parameter;
	const char* rtpmap=NULL;
	const char* fmtp=NULL;
	const char* ptime=NULL;
	const char* max_ptime=NULL;
	int ptime_as_int=-1;
	int max_ptime_as_int=-1;
963
	int is_audio=0;
964

965 966 967 968
	if (!media) {
		belle_sip_error("belle_sdp_media_description_build_mime_parameters: no media");
		return NULL;
	}
969
	if (strcasecmp(belle_sdp_media_get_media_type(media),"audio")==0) is_audio=1;
jehan's avatar
jehan committed
970
	ptime = belle_sdp_media_description_get_attribute_value(media_description,"ptime");
971
	ptime?ptime_as_int=atoi(ptime):-1;
jehan's avatar
jehan committed
972
	max_ptime = belle_sdp_media_description_get_attribute_value(media_description,"maxptime");
973 974 975 976 977 978 979 980
	max_ptime?max_ptime_as_int=atoi(max_ptime):-1;

	for (media_formats = belle_sdp_media_get_media_formats(media);media_formats!=NULL;media_formats=media_formats->next) {
		/*create mime parameters with format*/
		mime_parameter = belle_sdp_mime_parameter_new();
		belle_sdp_mime_parameter_set_ptime(mime_parameter,ptime_as_int);
		belle_sdp_mime_parameter_set_max_ptime(mime_parameter,max_ptime_as_int);
		belle_sdp_mime_parameter_set_media_format(mime_parameter,(int)(long)media_formats->data);
981

982 983 984 985 986
		/*get rtpmap*/
		rtpmap = belle_sdp_media_description_a_attr_value_get_with_pt(media_description
																		,belle_sdp_mime_parameter_get_media_format(mime_parameter)
																		,"rtpmap");
		if (rtpmap) {
987
			mime_parameter_fill_from_rtpmap(mime_parameter,rtpmap,is_audio);
988 989
		}else{
			mime_parameter_fill_from_static(mime_parameter,belle_sdp_mime_parameter_get_media_format(mime_parameter));
990 991 992 993 994 995 996 997 998 999 1000 1001
		}
		fmtp = belle_sdp_media_description_a_attr_value_get_with_pt(media_description
																		,belle_sdp_mime_parameter_get_media_format(mime_parameter)
																		,"fmtp");
		if (fmtp) {
			belle_sdp_mime_parameter_set_parameters(mime_parameter,fmtp);
		}

		mime_parameter_list=belle_sip_list_append(mime_parameter_list,mime_parameter);
	}
	return mime_parameter_list;
}
Simon Morlat's avatar
Simon Morlat committed
1002
#define MAX_FMTP_LENGTH 512
1003

Simon Morlat's avatar
Simon Morlat committed
1004
void belle_sdp_media_description_append_values_from_mime_parameter(belle_sdp_media_description_t* media_description, const belle_sdp_mime_parameter_t* mime_parameter) {
1005
	belle_sdp_media_t* media = belle_sdp_media_description_get_media(media_description);
Simon Morlat's avatar
Simon Morlat committed
1006
	char atribute_value [MAX_FMTP_LENGTH];
1007 1008 1009
	int current_ptime=0;
	int current_max_ptime=0;

1010 1011
	belle_sdp_media_set_media_formats(media,belle_sip_list_append(belle_sdp_media_get_media_formats(media)
																,(void*)(long)(belle_sdp_mime_parameter_get_media_format(mime_parameter))));
1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022

	if (belle_sdp_media_description_get_attribute_value(media_description,"ptime")) {
		current_ptime=atoi(belle_sdp_media_description_get_attribute_value(media_description,"ptime"));
		belle_sdp_media_description_remove_attribute(media_description,"ptime");
	}

	if (belle_sdp_media_description_get_attribute_value(media_description,"maxptime")) {
		current_max_ptime=atoi(belle_sdp_media_description_get_attribute_value(media_description,"maxptime"));
		belle_sdp_media_description_remove_attribute(media_description,"maxptime");
	}

1023
#ifndef BELLE_SDP_FORCE_RTP_MAP /* defined to for RTP map even for static codec*/
1024
	if (!mime_parameter_is_static(mime_parameter)) {
1025
		/*dynamic payload*/
1026
#endif
1027
		if (belle_sdp_mime_parameter_get_channel_count(mime_parameter)>1) {
Simon Morlat's avatar
Simon Morlat committed
1028
			snprintf(atribute_value,MAX_FMTP_LENGTH,"%i %s/%i/%i"
1029 1030 1031 1032 1033
					,belle_sdp_mime_parameter_get_media_format(mime_parameter)
					,belle_sdp_mime_parameter_get_type(mime_parameter)
					,belle_sdp_mime_parameter_get_rate(mime_parameter)
					,belle_sdp_mime_parameter_get_channel_count(mime_parameter));
		} else {
Simon Morlat's avatar
Simon Morlat committed
1034
			snprintf(atribute_value,MAX_FMTP_LENGTH,"%i %s/%i"
1035 1036 1037 1038
					,belle_sdp_mime_parameter_get_media_format(mime_parameter)
					,belle_sdp_mime_parameter_get_type(mime_parameter)
					,belle_sdp_mime_parameter_get_rate(mime_parameter));
		}
jehan's avatar
jehan committed
1039
		belle_sdp_media_description_set_attribute_value(media_description,"rtpmap",atribute_value);
1040
#ifndef BELLE_SDP_FORCE_RTP_MAP
1041
	}