⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sdp.c.svn-base

📁 Session Description Protocol parse code
💻 SVN-BASE
字号:
/* Copyright (C) 2005, REDSonic, inc. * Author:  Wills Yin <wills_yin@redsonic.com> */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include "sdp.h"/* * This converts string containing a Network Time Protocol timestamp to * a time_t: */#define NTP_TIME_DIFFERENCE 2208988800UL#define NETWORK_TIME_TO_TIME_T(_ntp_time_value_)                      \	(((_ntp_time_value_) >= NTP_TIME_DIFFERENCE)                  \		? (time_t) ((_ntp_time_value_) - NTP_TIME_DIFFERENCE) \		: (time_t) (_ntp_time_value_))/*  * Struct for session-level and media-level "a" fields:  * Exap: a=recvonly; a=cat:Action. */typedef struct  sdp_attr_s  {	char*        field;	char*        value;	struct sdp_attr_s * next;}sdp_attr_t;typedef struct  sdp_repeat_s {	long         interval;	long         act_dur;	long*        offsets;	struct sdp_repeat_s* next;}sdp_repeat_t;/* * A struct for a "t" "r" "z" field. */typedef struct  sdp_time_s {	time_t       start;	time_t       end;	sdp_repeat_t*  repeat;/* The repreat times */}sdp_time_t;/* * The struct for session-level and media-level "c" fields:  */typedef struct sdp_conn_s {	/*	 * A string containing the type of network the session or media is on:	 */	char*        network_type;	/*	 * A string containing address type of the address the session or media	 * is coming from:	 */	char*        addr_type;	/*	 * A string containing a dotted IP address (e.g., "127.0.0.1") of the	 * machine the session or media is coming from:	 */	char*        address;	/* Time To Live */	int          ttl;}sdp_conn_t;/* * Struct for media description "m" fields:  */typedef struct sdp_media_s {	/* A string containing the media type (e.g., "audio"): */	char*        type;	/* The port number of where the media will be sent: */	int          port;	/*	 * A string containing the name of the protocol to be used to deliver	 * the stream (e.g., "RTP/AVP"):	 */	char*        tran_pro;	/* A string containing the media formats: */	int          format;	/* A string containing a description of the media: */	char*        desc;	/*	 * This will store connection information for this specific piece of	 * media if there was no session-level "c" field or if the connection	 * used for this media differs from that used by the rest of the	 * session:	 */	sdp_conn_t*  conn;	/*	 * This will store a suggested maximum bandwidth limit for this media	 * if there was no session-level "b" field or if the bandwidth limits	 * differ for this media differ than those for the entire session	 */	int          bandwidth;	/*	 * A list of attribute structs containing the media-level	 * attributes for this piece of media:	 */	sdp_attr_t*  attrs;		struct sdp_media_s* next;}sdp_media_t;struct  sdp_desc_s {	/* o= filed */	char*        user_name;	char*        session_id;	char*        network_type;	char*        addr_type;	char*        addr;	/* s= field */	char*        session_name;	/* i= field */	char*        desc;	/* u= field */	char*        uri;	/* e= field */	char*        email;	/* p= field */	char*        phone;	/* c= field session level */	sdp_conn_t*  conn;      	/* b= field */	int          bandwidth;	/* t= r= z= playtime field */	sdp_time_t*  time;	/* a= field session level */	sdp_attr_t*  attrs;	/* m level fields */	int          num_media;	sdp_media_t* media;	sdp_desc_t*  next;};static void sdp_conn_free( sdp_conn_t* conn){	if (!conn) return;	SAFE_FREE(conn->network_type);	SAFE_FREE(conn->addr_type);	SAFE_FREE(conn->addr_type);	SAFE_FREE(conn->address);	free(conn);}static void sdp_attr_free(sdp_attr_t* attr){	if (!attr) return;	SAFE_FREE(attr->field);	SAFE_FREE(attr->value);	free(attr);}static void sdp_media_free( sdp_media_t* media){	if (!media) return;	SAFE_FREE(media->type);	SAFE_FREE(media->tran_pro);	SAFE_FREE(media->desc);	sdp_conn_free(media->conn);	DESTROY_LIST(media->attrs, sdp_attr_t, sdp_attr_free);	free(media);}static void sdp_repeat_free(sdp_repeat_t*  repeat){	if (!repeat) return;	SAFE_FREE(repeat->offsets);	free(repeat);}static int sdp_get_line(const char* src, char* dest, int* start, int total){	int i;	if (!src || !dest) 	       return -1;		for(i = 0; (*start) < total; i++, (*start)++) {		dest[i] = src[*start];		if (dest[i] == '\n')			break;	}	*start += 1;	if (i >= 1 && dest[i-1] == '\r')		i--;	dest[i] = '\0';	return i;}static char* sdp_strcspn(char** strLine, char* delim){	char *p, *q;	if (!(*strLine) || !delim)		return NULL;	p = *strLine;	q = p + strcspn(*strLine, delim);	if (*q == '\0')		*strLine = '\0';	else {		*q       = '\0';		*strLine = q + 1;	}	return p;}static int sdp_owner_create(sdp_desc_t* sdp, char* buf, char* delim){	int   i;	char *p, *value;	char *fields[5];	if (!sdp || !buf || !delim)		return -1;	p = buf;	for (i = 0; i < 5; i++) {		value = sdp_strcspn(&p, delim);		if (value)			fields[i] = strdup(value);		else 			fields[i] = NULL;	}	sdp->user_name    = fields[0];	sdp->session_id   = fields[1];	sdp->network_type = fields[2];	sdp->addr_type    = fields[3];	sdp->addr         = fields[4];	return 0;}static int sdp_conn_create(sdp_conn_t** conn, char* buf, char* delim){	int   i;	char *p, *value;	char *fields[5];	if (!buf || !delim)		return -1;	p = buf;	if (!(*conn) && !(*conn = malloc(sizeof(sdp_conn_t))))		return -1;	bzero(*conn, sizeof(sdp_conn_t));	for (i = 0; i< 3; i++) {		value = sdp_strcspn(&p, delim);		if (value)			fields[i] = strdup(value);		else			fields[i] = NULL;	}	if ((p = strchr(fields[2], '/')) != NULL) {		*p++ ='\0';		(*conn)->ttl= atoi(p);	}	(*conn)->network_type = fields[0];	(*conn)->addr_type    = fields[1];	(*conn)->address      = fields[2];	return 0;}static int sdp_media_create(sdp_media_t** media, char* buf, char* delim){	int   i;	char *p, *value;	char *fields[5];	if (!buf || !delim)		return -1;	p = buf;	if (!(*media) && !(*media = malloc(sizeof(sdp_media_t))))		return -1;	bzero(*media, sizeof(sdp_media_t));	for (i = 0; i< 4; i++) {		value = sdp_strcspn(&p, delim);		if (value)			fields[i] = strdup(value);		else			fields[i] = NULL;	}	(*media)->type         = fields[0];	(*media)->port         = atoi(fields[1]);	(*media)->tran_pro     = fields[2];	(*media)->format       = atoi(fields[3]);	if (fields[1] != NULL)		free(fields[1]);	if (fields[3] != NULL)		free(fields[3]);	return 0;}static int sdp_time_create(sdp_time_t**  time, char* buf, char* delim){	int   i;	char *p, *value;	char *fields[5];	if (!buf || !delim)		return -1;	p = buf;	if (!(*time) && !(*time = malloc(sizeof(sdp_time_t))))		return -1;	bzero(*time, sizeof(sdp_time_t));	for (i = 0; i< 2; i++) {		value = sdp_strcspn(&p, delim);		if (value)			fields[i] = strdup(value);		else			fields[i] = NULL;	}	if (fields[0] != NULL) {		unsigned long start = strtoul(fields[0], NULL, 10);		if (start)			(*time)->start = NETWORK_TIME_TO_TIME_T(start);		else			(*time)->start = 0;		free(fields[0]);	}	if (fields[1] != NULL) {		unsigned long end = strtoul(fields[1], NULL, 10);		if (end)			(*time)->end = NETWORK_TIME_TO_TIME_T(end);		else			(*time)->end = 0;		free(fields[1]);	}	return 0;}static int sdp_attr_create(sdp_attr_t**  attr, char* buf, char* delim){	int   i;	char *p, *value;	char *fields[5];	if (!buf || !delim)		return -1;	p = buf;	if (!(*attr) && !(*attr = malloc(sizeof(sdp_attr_t))))		return -1;	bzero(*attr, sizeof(sdp_attr_t));	for (i = 0; i< 2; i++) {		value = sdp_strcspn(&p, delim);		if (value)			fields[i] = strdup(value);		else			fields[i] = NULL;	}	(*attr)->field  = fields[0];	(*attr)->value  = fields[1];	return 0;}static sdp_media_t* sdp_get_media(sdp_desc_t* sdp, int index){	int i;	sdp_media_t *m;	if (!sdp || index >= sdp->num_media)		return NULL;	for (i = 0, m = sdp->media; 			m && i < index;			i++, m = m->next);	return m;}void sdp_destroy(sdp_desc_t* sdp){	sdp_desc_t *p, *q;	if (sdp == NULL) return;	p = sdp;	while (p) {	    q = p->next;	    SAFE_FREE(p->user_name);	    SAFE_FREE(p->session_id);	    SAFE_FREE(p->network_type);	    SAFE_FREE(p->addr_type);	    SAFE_FREE(p->addr);	    SAFE_FREE(p->session_name);	    SAFE_FREE(p->desc);	    SAFE_FREE(p->uri);	    SAFE_FREE(p->email);	    SAFE_FREE(p->phone);		    sdp_conn_free(p->conn);	    if (p->time) {		DESTROY_LIST(p->time->repeat, sdp_repeat_t, sdp_repeat_free);		SAFE_FREE(p->time);	    }	    DESTROY_LIST(p->attrs, sdp_attr_t,  sdp_attr_free);	    DESTROY_LIST(p->media, sdp_media_t, sdp_media_free);	    free(p);	    p = q;	}}sdp_desc_t* sdp_parse(const char* payload, int total){	char  line[1024];	int   linelen, offset, next_offset;	int   count = 0;	int   session_level = 1;	sdp_desc_t*   sdp;	sdp_media_t*  media = NULL;	if (payload == NULL) 		return NULL;	if ( (sdp = malloc(sizeof(sdp_desc_t))) == NULL) 		return NULL;	bzero(sdp, sizeof(sdp_desc_t));	if (payload[0] != 'v' || payload[1] != '=') {	    fprintf(stderr,  "SDP bad packet\n");        	    goto error_exit;	}	next_offset =  offset = 0;	while ( offset < total) {		char  delim, type;		char *buf;		/*		 * Find the end of the line.		 */		linelen = sdp_get_line(payload, line, &next_offset, total);		/*		 * Line must contain at least e.g. "v=".		 */		buf = line;		if (linelen < 2) break;		type  = line[0];		delim = line[1];		if (delim != '=') {			offset = next_offset;			continue;		}		buf += 2;				/*		 * Attributes.		 */		switch (type) {		case 'v':			++count;			if ( count == 2) {				sdp->next = sdp_parse(payload + offset, total - offset);				return sdp;			}			break;		case 'o':			sdp_owner_create(sdp, buf, " ");			break;		case 's':			if (buf[0] == '\0')				sdp->session_name = NULL;			else 				sdp->session_name = strdup(buf);			break;		case 'i':		{			char *desc;			if (buf[0] == '\0')				desc = NULL;			else 				desc = strdup(&buf[0]);			if (session_level == 1)				sdp->desc   = desc;			else 				media->desc = desc;			break;		}		case 'u':		case 'e':		case 'p':			break;		case 'c':			if (session_level == 1) 				sdp_conn_create(&sdp->conn, buf, " ");			else 				sdp_conn_create(&media->conn, buf, " ");			break;		case 'b':			break;		case 't':			sdp_time_create(&sdp->time, buf, " ");			break;		case 'r':			break;		case 'm':			media = NULL;			sdp_media_create(&media, buf, " ");			LINK_INTO_LIST(sdp->media, media, sdp_media_t); 			sdp->num_media++;			session_level = 0;			break;		case 'k':			break;		case 'a':		{			sdp_attr_t* attr = NULL;			sdp_attr_create(&attr, buf, ":");			if (session_level == 1)				LINK_INTO_LIST(sdp->attrs, attr, sdp_attr_t);			else 				LINK_INTO_LIST(media->attrs, attr, sdp_attr_t);			break;		}		case 'z':			break;		default:			break;		}		offset = next_offset;	}	return sdp;error_exit:	sdp_destroy(sdp);	return NULL;}const char* sdp_get_attr(sdp_desc_t* sdp, const char* key, int index){	sdp_attr_t*    p;	sdp_media_t*   media; 	if (!sdp || !key || (index >= sdp->num_media))		return NULL;	media = sdp_get_media(sdp, index);	/*         * Search order:the the media level -> session level           */	p = sdp->attrs;	while (p) {		if (p->field && strcasecmp(p->field, key) == 0)			return p->value;		p = p->next;	}	p = media->attrs;	while (p) {		if (p->field && strcasecmp(p->field, key) == 0)			return p->value;		p = p->next;	}	return NULL;}const char* sdp_get_mediaAddr(sdp_desc_t* sdp, int index){	sdp_media_t*   media; 	if (!sdp || index >= sdp->num_media)		return NULL;	media = sdp_get_media(sdp, index);	if (media && media->conn) 		return media->conn->address;	else if (sdp->conn)		return sdp->conn->address;	else		return NULL;}const char* sdp_get_mediaProt(sdp_desc_t* sdp, int index){	sdp_media_t*   media; 	if (!sdp || index >= sdp->num_media)		return NULL;	media = sdp_get_media(sdp, index);	if (media && media->tran_pro && !strcasecmp(media->tran_pro, "RTP/AVP"))		return "rtp";	else		return NULL;}int sdp_get_mediaPort(sdp_desc_t* sdp, int index){	sdp_media_t*   media; 	if (!sdp || index >= sdp->num_media)		return -1;	media = sdp_get_media(sdp, index);	return media ? media->port : -1;}int sdp_get_mediaCodec(sdp_desc_t* sdp, int index){	sdp_media_t*   media; 	if (!sdp || index >= sdp->num_media)		return -1;	media = sdp_get_media(sdp, index);	return media ? media->format : -1;}const char* sdp_get_mediaType(sdp_desc_t* sdp, int index){	sdp_media_t*   media; 	if (!sdp || index >= sdp->num_media)		return NULL;	media = sdp_get_media(sdp, index);	return media ? media->type : 0;}const char* sdp_get_sessionName(sdp_desc_t* sdp){	return sdp ? sdp->session_name : NULL ;}const char* sdp_get_mediaDesc(sdp_desc_t* sdp, int index){	sdp_media_t*   media; 	if (!sdp || index >= sdp->num_media)		return NULL;	media = sdp_get_media(sdp, index);	if (media && media->desc)		return media->desc;	else if (sdp->desc)		return sdp->desc;	else		return NULL;}time_t sdp_get_startTime(sdp_desc_t* sdp){	if (!sdp || !sdp->time)		return 0;	return sdp->time->start;}time_t sdp_get_endTime(sdp_desc_t* sdp){	if (!sdp || !sdp->time)		return 0;	return sdp->time->end;}int         sdp_get_mediaNum(sdp_desc_t* sdp){	return sdp ? sdp->num_media : 0;}const char* sdp_get_mediaMimetype(sdp_desc_t* sdp, int index){	return NULL;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -