belle_sdp_impl.c 68.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
	uint16_t trr_int;
171
	int8_t id;
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
};
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;
}
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) {
190
	int8_t id = belle_sdp_rtcp_fb_attribute_get_id(attribute);
191 192 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
	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;
241 242 243 244 245 246 247 248 249 250 251
		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;
				default:
					break;
			}
			break;
252 253 254 255 256 257 258 259 260 261 262 263
	}
	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;
}
BELLE_SDP_NEW_WITH_CTR(rtcp_fb_attribute,belle_sdp_attribute)
BELLE_SDP_PARSE(rtcp_fb_attribute)
264
GET_SET_INT(belle_sdp_rtcp_fb_attribute,id,int8_t)
265 266
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)
267
GET_SET_INT(belle_sdp_rtcp_fb_attribute,trr_int,uint16_t)
268 269 270 271 272 273 274 275 276 277 278 279
/***************************************************************************************
 * 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
280
const belle_sip_list_t* belle_sdp_rtcp_xr_attribute_get_stat_summary_flags(const belle_sdp_rtcp_xr_attribute_t* attribute) {
281 282 283 284 285 286 287
	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
288
	belle_sip_list_free_with_data(attribute->stat_summary_flags, belle_sip_free);
289 290 291 292 293
}
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
294
	attribute->stat_summary_flags = belle_sip_list_copy_with_data(orig->stat_summary_flags, belle_sip_string_copyfunc);
295 296 297 298 299 300 301 302 303 304 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
	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)
338 339 340 341 342 343 344 345 346 347
/***************************************************************************************
 * 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) {
348
	if (bandwidth->type) belle_sip_free((void*)bandwidth->type);
349 350 351
}

void belle_sdp_bandwidth_clone(belle_sdp_bandwidth_t *bandwidth, const belle_sdp_bandwidth_t *orig){
352 353
	CLONE_STRING(belle_sdp_bandwidth,type,bandwidth,orig)
	bandwidth->value=orig->value;
354
}
Ghislain MARY's avatar
Ghislain MARY committed
355

356
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
357
	return belle_sip_snprintf(buff,buff_size,offset,"b=%s:%i",bandwidth->type,bandwidth->value);
358
}
Ghislain MARY's avatar
Ghislain MARY committed
359

360 361 362 363
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
364 365 366 367 368 369 370 371 372 373 374 375

/************************
 * connection
 ***********************/
struct _belle_sdp_connection {
	belle_sip_object_t base;
	const char* network_type;
	const char* address_type;
	const char* address;
 };

void belle_sdp_connection_destroy(belle_sdp_connection_t* connection) {
jehan's avatar
jehan committed
376 377 378
	DESTROY_STRING(connection,network_type)
	DESTROY_STRING(connection,address_type)
	DESTROY_STRING(connection,address)
jehan's avatar
jehan committed
379 380 381
}

void belle_sdp_connection_clone(belle_sdp_connection_t *connection, const belle_sdp_connection_t *orig){
jehan's avatar
jehan committed
382 383 384 385
	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)

jehan's avatar
jehan committed
386
}
Ghislain MARY's avatar
Ghislain MARY committed
387

388
belle_sip_error_code belle_sdp_connection_marshal(belle_sdp_connection_t* connection, char* buff, size_t buff_size, size_t *offset) {
Ghislain MARY's avatar
Ghislain MARY committed
389
	return belle_sip_snprintf(buff,buff_size,offset,"c=%s %s %s",connection->network_type,connection->address_type,connection->address);
jehan's avatar
jehan committed
390
}
Ghislain MARY's avatar
Ghislain MARY committed
391

jehan's avatar
jehan committed
392 393
BELLE_SDP_NEW(connection,belle_sip_object)
BELLE_SDP_PARSE(connection)
jehan's avatar
jehan committed
394 395 396 397 398 399 400
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
401 402 403
GET_SET_STRING(belle_sdp_connection,network_type);
GET_SET_STRING(belle_sdp_connection,address_type);
GET_SET_STRING(belle_sdp_connection,address);
404 405 406 407 408
/************************
 * email
 ***********************/
struct _belle_sdp_email {
	belle_sip_object_t base;
409
	char* value;
410 411 412
 };

void belle_sdp_email_destroy(belle_sdp_email_t* email) {
jehan's avatar
jehan committed
413
	DESTROY_STRING(email,value)
414 415 416
}

void belle_sdp_email_clone(belle_sdp_email_t *email, const belle_sdp_email_t *orig){
jehan's avatar
jehan committed
417
	CLONE_STRING(belle_sdp_email,value,email,orig)
418
}
Ghislain MARY's avatar
Ghislain MARY committed
419

420
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
421
	return belle_sip_snprintf(buff,buff_size,offset,"e=%s",email->value);
422
}
Ghislain MARY's avatar
Ghislain MARY committed
423

424 425 426 427 428 429 430 431 432 433 434 435
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
436
	DESTROY_STRING(info,value)
437 438 439
}

void belle_sdp_info_clone(belle_sdp_info_t *info, const belle_sdp_info_t *orig){
jehan's avatar
jehan committed
440
	CLONE_STRING(belle_sdp_info,value,info,orig)
441
}
Ghislain MARY's avatar
Ghislain MARY committed
442

443
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
444
	return belle_sip_snprintf(buff,buff_size,offset,"i=%s",info->value);
445
}
Ghislain MARY's avatar
Ghislain MARY committed
446

447 448 449 450 451 452 453 454
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
455
	const char* media_type;
456 457 458
	int media_port;
	belle_sip_list_t* media_formats;
	int port_count;
jehan's avatar
jehan committed
459
	const char* protocol;
460
	const char* raw_fmt;
461
 };
jehan's avatar
jehan committed
462 463 464 465
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
466
	/*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
467 468
	media->media_formats = formats;
}
469
void belle_sdp_media_destroy(belle_sdp_media_t* media) {
jehan's avatar
jehan committed
470 471 472
	DESTROY_STRING(media,media_type)
	belle_sip_list_free(media->media_formats);
	DESTROY_STRING(media,protocol)
473
}
jehan's avatar
jehan committed
474 475 476
static void belle_sdp_media_init(belle_sdp_media_t* media) {
	media->port_count=1;
}
477 478

void belle_sdp_media_clone(belle_sdp_media_t *media, const belle_sdp_media_t *orig){
jehan's avatar
jehan committed
479 480 481 482 483
	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)
484
}
Ghislain MARY's avatar
Ghislain MARY committed
485

486
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
487
	belle_sip_list_t* list=media->media_formats;
Ghislain MARY's avatar
Ghislain MARY committed
488
	belle_sip_error_code error=belle_sip_snprintf(buff,buff_size,offset,"m=%s %i",media->media_type,media->media_port);
489
	if (error!=BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
490
	if (media->port_count>1) {
Ghislain MARY's avatar
Ghislain MARY committed
491
		error=belle_sip_snprintf(buff,buff_size,offset,"/%i",media->port_count);
492
		if (error!=BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
493
	}
Ghislain MARY's avatar
Ghislain MARY committed
494 495
	error=belle_sip_snprintf(buff,buff_size,offset," %s",media->protocol);
	if (error!=BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
496
	for(;list!=NULL;list=list->next){
Ghislain MARY's avatar
Ghislain MARY committed
497
		error=belle_sip_snprintf(buff,buff_size,offset," %li",(long)list->data);
498
		if (error!=BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
499
	}
Ghislain MARY's avatar
Ghislain MARY committed
500
	return error;
501
}
Ghislain MARY's avatar
Ghislain MARY committed
502

jehan's avatar
jehan committed
503
BELLE_SDP_NEW_WITH_CTR(media,belle_sip_object)
504
BELLE_SDP_PARSE(media)
jehan's avatar
jehan committed
505
belle_sdp_media_t* belle_sdp_media_create(const char* media_type
506 507 508 509
						 ,int media_port
						 ,int port_count
						 ,const char* protocol
						 ,belle_sip_list_t* static_media_formats) {
jehan's avatar
jehan committed
510 511 512 513 514 515 516 517
	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;
}
518
GET_SET_STRING(belle_sdp_media,media_type);
jehan's avatar
jehan committed
519
GET_SET_STRING(belle_sdp_media,protocol);
520 521
GET_SET_INT(belle_sdp_media,media_port,int)
GET_SET_INT(belle_sdp_media,port_count,int)
jehan's avatar
jehan committed
522 523 524 525 526 527 528 529 530 531 532 533

/************************
 * 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
534 535 536 537 538
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
539
}
jehan's avatar
jehan committed
540
static void belle_sdp_base_description_init(belle_sdp_base_description_t* base_description) {
jehan's avatar
jehan committed
541
}
jehan's avatar
jehan committed
542
static void belle_sdp_base_description_clone(belle_sdp_base_description_t *base_description, const belle_sdp_base_description_t *orig){
543 544
	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
545 546 547
	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
548
}
Ghislain MARY's avatar
Ghislain MARY committed
549

550
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
551
	belle_sip_error_code error=BELLE_SIP_OK;
jehan's avatar
jehan committed
552
	belle_sip_list_t* bandwidths;
553
//	belle_sip_list_t* attributes;
jehan's avatar
jehan committed
554
	if (base_description->info) {
Ghislain MARY's avatar
Ghislain MARY committed
555 556 557
		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");
558
		if (error!=BELLE_SIP_OK) return error;
jehan's avatar
jehan committed
559 560
	}
	if (base_description->connection) {
Ghislain MARY's avatar
Ghislain MARY committed
561 562 563 564
		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
565 566
	}
	for(bandwidths=base_description->bandwidths;bandwidths!=NULL;bandwidths=bandwidths->next){
Ghislain MARY's avatar
Ghislain MARY committed
567 568 569 570
		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
571
	}
572
//	for(attributes=base_description->attributes;attributes!=NULL;attributes=attributes->next){
573 574
//		error=belle_sip_object_marshal(BELLE_SIP_OBJECT(attributes->data),buff,buff_size,offset);
//		error=belle_sip_snprintf(buff, buff_size, offset, "\r\n");
575
//	}
Ghislain MARY's avatar
Ghislain MARY committed
576
	return error;
jehan's avatar
jehan committed
577
}
578 579

BELLE_SIP_DECLARE_NO_IMPLEMENTED_INTERFACES(belle_sdp_base_description_t);
jehan's avatar
jehan committed
580 581 582 583 584 585
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
586 587 588 589

static int belle_sdp_base_description_attribute_comp_func(const belle_sdp_attribute_t* a, const char*b) {
	return strcmp(a->name,b);
}
590
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
591 592 593
	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
594
		return ((belle_sdp_attribute_t*)attribute->data);
jehan's avatar
jehan committed
595 596 597 598
	} else {
		return NULL;
	}
}
jehan's avatar
jehan committed
599
const char*	belle_sdp_base_description_get_attribute_value(const belle_sdp_base_description_t* base_description, const char* name) {
600
	belle_sdp_attribute_t* attribute = belle_sdp_base_description_get_attribute(base_description,name);
601
	if (attribute) {
602
		return belle_sdp_attribute_get_value(attribute);
603
	} else return NULL;
jehan's avatar
jehan committed
604 605

}
jehan's avatar
jehan committed
606 607 608 609 610 611 612
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);
}

613 614 615 616 617 618 619 620 621 622 623

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
624 625 626 627 628 629 630 631 632 633 634 635 636
	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));
637
		base_description->attributes = belle_sip_list_delete_link(base_description->attributes,attribute);
jehan's avatar
jehan committed
638 639 640 641 642 643 644 645
	}

}
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));
646
		base_description->bandwidths = belle_sip_list_delete_link(base_description->bandwidths,bandwidth);
jehan's avatar
jehan committed
647 648
	}
}
jehan's avatar
jehan committed
649
void belle_sdp_base_description_set_attribute_value(belle_sdp_base_description_t* base_description, const char* name, const char* value) {
650 651 652
	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);
653
	base_description->attributes = belle_sip_list_append(base_description->attributes,belle_sip_object_ref(attribute));
jehan's avatar
jehan committed
654 655
}
void belle_sdp_base_description_add_attribute(belle_sdp_base_description_t* base_description, const belle_sdp_attribute_t* attribute) {
656
	base_description->attributes = belle_sip_list_append(base_description->attributes,(void*)belle_sip_object_ref(BELLE_SIP_OBJECT(attribute)));
jehan's avatar
jehan committed
657 658 659 660 661
}

#define SET_LIST(list_name,value) \
		belle_sip_list_t* list;\
		if (list_name) {\
662
			belle_sip_list_free_with_data(list_name,belle_sip_object_unref);\
jehan's avatar
jehan committed
663
		} \
664
		for (list=value;list !=NULL; list=list->next) {\
665
			belle_sip_object_ref(BELLE_SIP_OBJECT(list->data));\
666
		}\
jehan's avatar
jehan committed
667 668 669 670 671 672 673
		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) {
674

675
	belle_sdp_bandwidth_t* bandwidth = BELLE_SDP_BANDWIDTH(belle_sdp_base_description_get_bandwidth(base_description, type));
676 677 678 679 680 681 682 683
	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
684 685
}
void belle_sdp_base_description_add_bandwidth(belle_sdp_base_description_t* base_description, const belle_sdp_bandwidth_t* bandwidth) {
686

687
	base_description->bandwidths = belle_sip_list_append(base_description->bandwidths,(void *)belle_sip_object_ref((void *)bandwidth));
jehan's avatar
jehan committed
688 689 690 691 692 693 694 695 696 697 698 699 700
}
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
701
	if (media_description->media) belle_sip_object_unref(BELLE_SIP_OBJECT((media_description->media)));
jehan's avatar
jehan committed
702 703 704
}

void belle_sdp_media_description_clone(belle_sdp_media_description_t *media_description, const belle_sdp_media_description_t *orig){
705
	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
706
}
Ghislain MARY's avatar
Ghislain MARY committed
707

708
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) {
709
	belle_sip_list_t* attributes;
Ghislain MARY's avatar
Ghislain MARY committed
710 711 712 713 714 715
	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;
716 717

	for(attributes=media_description->base_description.attributes;attributes!=NULL;attributes=attributes->next){
Ghislain MARY's avatar
Ghislain MARY committed
718 719 720 721
		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;
722
	}
Ghislain MARY's avatar
Ghislain MARY committed
723
	return error;
jehan's avatar
jehan committed
724
}
725

jehan's avatar
jehan committed
726
BELLE_SDP_NEW(media_description,belle_sdp_base_description)
jehan's avatar
jehan committed
727
belle_sdp_media_description_t* belle_sdp_media_description_create(const char* media_type
728 729 730 731
																 ,int media_port
																 ,int port_count
																 ,const char* protocol
																 ,belle_sip_list_t* static_media_formats) {
jehan's avatar
jehan committed
732 733 734 735
	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
736 737
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) {
738
	belle_sip_error("belle_sdp_media_description_add_dynamic_payloads not implemented yet");
jehan's avatar
jehan committed
739
}
740
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
741 742
	return belle_sdp_base_description_get_attribute(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),name);
}
jehan's avatar
jehan committed
743 744 745
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
746 747 748 749 750
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) {
751
	return belle_sdp_base_description_get_bandwidth_value(BELLE_SIP_CAST(media_description,belle_sdp_base_description_t),name);
jehan's avatar
jehan committed
752 753 754 755 756 757 758 759 760 761 762 763 764 765
}
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;
}
766 767 768 769 770 771 772 773

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
774 775 776
/*
 * rfc 3551
 * PT   encoding    media type  clock rate   channels
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798
					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
799 800

  PT      encoding    media type  clock rate
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816
					   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
817 818 819 820 821


 *
 * */

822
const struct static_payload static_payload_list [] ={
jehan's avatar
jehan committed
823
	/*audio*/
824 825 826 827 828
	{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
829
	{7,1,"LPC",8000},
830 831
	{8,1,"PCMA",8000},
	{9,1,"G722",8000},
jehan's avatar
jehan committed
832 833 834 835 836 837 838 839 840 841
	{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*/
842 843 844 845 846 847 848
	{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}
849
};
850

Simon Morlat's avatar
Simon Morlat committed
851
static const size_t payload_list_elements=sizeof(static_payload_list)/sizeof(struct static_payload);
852 853 854 855

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

Simon Morlat's avatar
Simon Morlat committed
857
	for (iterator = static_payload_list,i=0;i<payload_list_elements;i++,iterator++) {
858 859
		if (iterator->number == param->media_format &&
			strcasecmp(iterator->type,param->type)==0 &&
860 861 862 863 864 865 866 867
			iterator->channel_count==param->channel_count &&
			iterator->rate==param->rate ) {
			return TRUE;
		}
	}
	return FALSE;
}

868
static int mime_parameter_fill_from_static(belle_sdp_mime_parameter_t *mime_parameter,int format) {
869
	const struct static_payload* iterator;
870
	int i;
871

Simon Morlat's avatar
Simon Morlat committed
872
	for (iterator = static_payload_list,i=0;i<payload_list_elements;i++,iterator++) {
873 874 875 876
		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);
877
			break;
878 879 880 881
		}
	}
	return 0;
}
882

883
static int mime_parameter_fill_from_rtpmap(belle_sdp_mime_parameter_t *mime_parameter, const char *rtpmap, int is_audio){
884 885 886 887 888 889 890 891 892 893 894
	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));
895
		}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*/
896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913
		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);
914 915
		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);
916 917 918
			/* the return value may depend on how %n is interpreted by the libc: see manpage*/
			if (nb == 1 || nb==2 ){
				if (pt==tmppt){
919
					tmp=belle_sdp_attribute_get_value(attr)+scanned;
920 921 922
					if (strlen(tmp)>0)
						return tmp;
				}
923
			}else belle_sip_warning("sdp has a strange a= line (%s) nb=%i",belle_sdp_attribute_get_value(attr),nb);
924 925
		}
	}
jehan's avatar
jehan committed
926 927
	return NULL;
}
928 929 930 931 932 933 934 935 936 937 938 939 940

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;
941
	int is_audio=0;
942

943 944 945 946
	if (!media) {
		belle_sip_error("belle_sdp_media_description_build_mime_parameters: no media");
		return NULL;
	}
947
	if (strcasecmp(belle_sdp_media_get_media_type(media),"audio")==0) is_audio=1;
jehan's avatar
jehan committed
948
	ptime = belle_sdp_media_description_get_attribute_value(media_description,"ptime");
949
	ptime?ptime_as_int=atoi(ptime):-1;
jehan's avatar
jehan committed
950
	max_ptime = belle_sdp_media_description_get_attribute_value(media_description,"maxptime");
951 952 953 954 955 956 957 958
	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);
959

960 961 962 963 964
		/*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) {
965
			mime_parameter_fill_from_rtpmap(mime_parameter,rtpmap,is_audio);
966 967
		}else{
			mime_parameter_fill_from_static(mime_parameter,belle_sdp_mime_parameter_get_media_format(mime_parameter));
968 969 970 971 972 973 974 975 976 977 978 979
		}
		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
980
#define MAX_FMTP_LENGTH 512
981

Simon Morlat's avatar
Simon Morlat committed
982
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) {
983
	belle_sdp_media_t* media = belle_sdp_media_description_get_media(media_description);
Simon Morlat's avatar
Simon Morlat committed
984
	char atribute_value [MAX_FMTP_LENGTH];
985 986 987
	int current_ptime=0;
	int current_max_ptime=0;

988 989
	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))));
990 991 992 993 994 995 996 997 998 999 1000

	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");
	}

1001
#ifndef BELLE_SDP_FORCE_RTP_MAP /* defined to for RTP map even for static codec*/
1002
	if (!mime_parameter_is_static(mime_parameter)) {
1003
		/*dynamic payload*/
1004
#endif
1005
		if (belle_sdp_mime_parameter_get_channel_count(mime_parameter)>1) {
Simon Morlat's avatar
Simon Morlat committed
1006
			snprintf(atribute_value,MAX_FMTP_LENGTH,"%i %s/%i/%i"
1007 1008 1009 1010 1011
					,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 {