Exemple #1
0
GF_Err SDP_CheckConnection(GF_SDPConnection *conn)
{
	if (!conn) return GF_BAD_PARAM;
	if (!conn->host || !conn->add_type || !conn->net_type) return GF_REMOTE_SERVICE_ERROR;
	if (gf_sk_is_multicast_address(conn->host)) {
		if (conn->TTL < 0 || conn->TTL > 255) return GF_REMOTE_SERVICE_ERROR;
	} else {
		conn->TTL = -1;
		conn->add_count = 0;
	}
	return GF_OK;
}
Exemple #2
0
GF_Err PNC_InitRTP(GF_RTPChannel **chan, char *dest, int port, unsigned short mtu_size)
{
	GF_Err res;
	GF_RTSPTransport tr;

	*chan = gf_rtp_new();
	res = gf_rtp_set_ports(*chan, 0);
	if (res) {
		fprintf(stderr, "Cannot set RTP ports: %s\n", gf_error_to_string(res));
		gf_rtp_del(*chan);
		return res;
	}

	tr.destination = dest;
	tr.IsUnicast = gf_sk_is_multicast_address(dest) ? 0 : 1;
	tr.Profile="RTP/AVP";//RTSP_PROFILE_RTP_AVP;
	tr.IsRecord = 0;
	tr.Append = 0;
	tr.source = "0.0.0.0";
	tr.SSRC=rand();

	tr.port_first		= port;
	tr.port_last		 = port+1;
	if (tr.IsUnicast) {
		tr.client_port_first = port;
		tr.client_port_last = port+1;
	} else {
		tr.source = dest;
		tr.client_port_first = 0;
		tr.client_port_last  = 0;
	}

	res = gf_rtp_setup_transport(*chan, &tr, dest);
	if (res) {
		fprintf(stderr, "Cannot setup RTP transport %s\n", gf_error_to_string(res));
		gf_rtp_del(*chan);
		return res;
	}

	res = gf_rtp_initialize(*chan, 0, 1, mtu_size, 0, 0, NULL);
	if (res) {
		fprintf(stderr, "Cannot initialize RTP transport %s\n", gf_error_to_string(res));
		gf_rtp_del(*chan);
		return res;
	}
	return GF_OK;
}
Exemple #3
0
static GF_Err rtp_stream_init_channel(GF_RTPStreamer *rtp, u32 path_mtu, const char * dest, int port, int ttl, const char *ifce_addr)
{
	GF_RTSPTransport tr;
	GF_Err res;

	rtp->channel = gf_rtp_new();
	gf_rtp_set_ports(rtp->channel, 0);
	memset(&tr, 0, sizeof(GF_RTSPTransport));

	tr.IsUnicast = gf_sk_is_multicast_address(dest) ? 0 : 1;
	tr.Profile="RTP/AVP";
	tr.destination = (char *)dest;
	tr.source = "0.0.0.0";
	tr.IsRecord = 0;
	tr.Append = 0;
	tr.SSRC = rand();
	tr.TTL = ttl;

	tr.port_first = port;
	tr.port_last = port+1;
	if (tr.IsUnicast) {
		tr.client_port_first = port;
		tr.client_port_last  = port+1;
	} else {
		tr.source = (char *)dest;
	}

	res = gf_rtp_setup_transport(rtp->channel, &tr, dest);
	if (res !=0) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("Cannot setup RTP transport info: %s\n", gf_error_to_string(res) ));
		return res;
	}

	res = gf_rtp_initialize(rtp->channel, 0, 1, path_mtu, 0, 0, (char *)ifce_addr);
	if (res !=0) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_RTP, ("Cannot initialize RTP sockets: %s\n", gf_error_to_string(res) ));
		return res;
	}
	return GF_OK;
} 
Exemple #4
0
GF_EXPORT
GF_Err gf_sk_setup_multicast(GF_Socket *sock, const char *multi_IPAdd, u16 MultiPortNumber, u32 TTL, Bool NoBind, char *local_interface_ip)
{
	s32 ret;
	u32 flag;
	struct ip_mreq M_req;
	u32 optval;
#ifdef GPAC_HAS_IPV6
	struct sockaddr *addr;
	struct addrinfo *res, *aip;
	Bool is_ipv6 = 0;
	u32 type;
#endif
	unsigned long local_add_id;

	if (!sock || sock->socket) return GF_BAD_PARAM;

	if (TTL > 255) TTL = 255;

	/*check the address*/
	if (!gf_sk_is_multicast_address(multi_IPAdd)) return GF_BAD_PARAM;

	/*turn on MobileIP*/
	if (local_interface_ip && MobileIPAdd && !strcmp(MobileIPAdd, local_interface_ip) ) {
		if (gf_net_mobileip_ctrl(1)==GF_OK) {
			sock->flags |= GF_SOCK_IS_MIP;
		} else {
			local_interface_ip = NULL;
		}
	}


#ifdef GPAC_HAS_IPV6
	is_ipv6 = gf_net_is_ipv6(multi_IPAdd) || gf_net_is_ipv6(local_interface_ip) ? 1 : 0;
	type = (sock->flags & GF_SOCK_IS_TCP) ? SOCK_STREAM : SOCK_DGRAM;

	if (is_ipv6) {

		res = gf_sk_get_ipv6_addr(local_interface_ip, MultiPortNumber, AF_UNSPEC, AI_PASSIVE, type);
		if (!res) {
			if (local_interface_ip) {
				res = gf_sk_get_ipv6_addr(NULL, MultiPortNumber, AF_UNSPEC, AI_PASSIVE, type);
				local_interface_ip = NULL;
			}
			if (!res) return GF_IP_CONNECTION_FAILURE;
		}

		/*for all interfaces*/
		for (aip=res; aip!=NULL; aip=aip->ai_next) {
			if (type != (u32) aip->ai_socktype) continue;
			sock->socket = socket(aip->ai_family, aip->ai_socktype, aip->ai_protocol);
			if (sock->socket == INVALID_SOCKET) {
				sock->socket = NULL_SOCKET;
				continue;
			}

			if ((aip->ai_family!=PF_INET) && aip->ai_next && (aip->ai_next->ai_family==PF_INET) && !gf_net_is_ipv6(multi_IPAdd)) continue;

			/*enable address reuse*/
			optval = 1;
			setsockopt(sock->socket, SOL_SOCKET, SO_REUSEADDR, (const char *) &optval, sizeof(optval));
#ifdef SO_REUSEPORT
			optval = 1;
			setsockopt(sock->socket, SOL_SOCKET, SO_REUSEPORT, SSO_CAST &optval, sizeof(optval));
#endif

			/*TODO: copy over other properties (recption buffer size & co)*/
			if (sock->flags & GF_SOCK_NON_BLOCKING) gf_sk_set_block_mode(sock, 1);

			memcpy(&sock->dest_addr, aip->ai_addr, aip->ai_addrlen);
			sock->dest_addr_len = (u32) aip->ai_addrlen;

			if (!NoBind) {
				ret = bind(sock->socket, aip->ai_addr, (int) aip->ai_addrlen);
				if (ret == SOCKET_ERROR) {
					closesocket(sock->socket);
					sock->socket = NULL_SOCKET;
					continue;
				}
			}
			if (aip->ai_family==PF_INET6) sock->flags |= GF_SOCK_IS_IPV6;
			else sock->flags &= ~GF_SOCK_IS_IPV6;
			break;
		}
		freeaddrinfo(res);
		if (!sock->socket) return GF_IP_CONNECTION_FAILURE;


		if (!gf_sk_ipv6_set_remote_address(sock, multi_IPAdd, MultiPortNumber))
			return GF_IP_CONNECTION_FAILURE;

		addr = (struct sockaddr *)&sock->dest_addr;
		if (addr->sa_family == AF_INET) {
			M_req.imr_multiaddr.s_addr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
			M_req.imr_interface.s_addr = INADDR_ANY;
			ret = setsockopt(sock->socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &M_req, sizeof(M_req));
			if (ret == SOCKET_ERROR) return GF_IP_CONNECTION_FAILURE;
			/*set TTL*/
			ret = setsockopt(sock->socket, IPPROTO_IP, IP_MULTICAST_TTL, (char *) &TTL, sizeof(TTL));
			if (ret == SOCKET_ERROR) return GF_IP_CONNECTION_FAILURE;
			/*Disable loopback*/
			flag = 1;
			ret = setsockopt(sock->socket, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &flag, sizeof(flag));
			if (ret == SOCKET_ERROR) return GF_IP_CONNECTION_FAILURE;
		}

		if (addr->sa_family == AF_INET6) {
			struct ipv6_mreq M_reqV6;

			memcpy(&M_reqV6.ipv6mr_multiaddr, &(((struct sockaddr_in6 *)addr)->sin6_addr), sizeof(struct in6_addr));
			M_reqV6.ipv6mr_interface = 0;

			/*set TTL*/
			ret = setsockopt(sock->socket, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *) &TTL, sizeof(TTL));
			if (ret == SOCKET_ERROR) return GF_IP_CONNECTION_FAILURE;
			/*Disable loopback*/
			flag = 1;
			ret = setsockopt(sock->socket, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, (char *) &flag, sizeof(flag));
			if (ret == SOCKET_ERROR) return GF_IP_CONNECTION_FAILURE;

			ret = setsockopt(sock->socket, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (char *) &M_reqV6, sizeof(M_reqV6));
			if (ret == SOCKET_ERROR) return GF_IP_CONNECTION_FAILURE;
		}
		sock->flags |= GF_SOCK_IS_MULTICAST | GF_SOCK_HAS_PEER;
		return GF_OK;
	}
#endif

	//IPv4 setup
	sock->socket = socket(AF_INET, (sock->flags & GF_SOCK_IS_TCP) ? SOCK_STREAM : SOCK_DGRAM, 0);
	if (sock->flags & GF_SOCK_NON_BLOCKING) gf_sk_set_block_mode(sock, 1);
	sock->flags &= ~GF_SOCK_IS_IPV6;

	/*enable address reuse*/
	optval = 1;
	ret = setsockopt(sock->socket, SOL_SOCKET, SO_REUSEADDR, SSO_CAST &optval, sizeof(optval));
#ifdef SO_REUSEPORT
	optval = 1;
	setsockopt(sock->socket, SOL_SOCKET, SO_REUSEPORT, SSO_CAST &optval, sizeof(optval));
#endif

	if (local_interface_ip) local_add_id = inet_addr(local_interface_ip);
	else local_add_id = htonl(INADDR_ANY);

	if (!NoBind) {
		struct sockaddr_in local_address;

		local_address.sin_family = AF_INET;
		local_address.sin_addr.s_addr = local_add_id;
		local_address.sin_port = htons( MultiPortNumber);

		ret = bind(sock->socket, (struct sockaddr *) &local_address, sizeof(local_address));
		if (ret == SOCKET_ERROR) {
			/*retry without specifying the local add*/
			local_address.sin_addr.s_addr = local_add_id = htonl(INADDR_ANY);
			local_interface_ip = NULL;
			ret = bind(sock->socket, (struct sockaddr *) &local_address, sizeof(local_address));
			if (ret == SOCKET_ERROR) return GF_IP_CONNECTION_FAILURE;
		}
		/*setup local interface*/
		if (local_interface_ip) {
			ret = setsockopt(sock->socket, IPPROTO_IP, IP_MULTICAST_IF, (char *) &local_add_id, sizeof(local_add_id));
			if (ret == SOCKET_ERROR) return GF_IP_CONNECTION_FAILURE;
		}
	}

	/*now join the multicast*/
	M_req.imr_multiaddr.s_addr = inet_addr(multi_IPAdd);
	M_req.imr_interface.s_addr = local_add_id;

	ret = setsockopt(sock->socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *) &M_req, sizeof(M_req));
	if (ret == SOCKET_ERROR) {
		GF_LOG(GF_LOG_ERROR, GF_LOG_NETWORK, ("[core] cannot join multicast: error %d\n", LASTSOCKERROR));
		return GF_IP_CONNECTION_FAILURE;
	}
	/*set the Time To Live*/
	ret = setsockopt(sock->socket, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&TTL, sizeof(TTL));
	if (ret == SOCKET_ERROR) return GF_IP_CONNECTION_FAILURE;
	/*Disable loopback*/
	flag = 1;
	ret = setsockopt(sock->socket, IPPROTO_IP, IP_MULTICAST_LOOP, (char *) &flag, sizeof(flag));
//	if (ret == SOCKET_ERROR) return GF_IP_CONNECTION_FAILURE;

#ifdef GPAC_HAS_IPV6
	((struct sockaddr_in *) &sock->dest_addr)->sin_family = AF_INET;
	((struct sockaddr_in *) &sock->dest_addr)->sin_addr.s_addr = M_req.imr_multiaddr.s_addr;
	((struct sockaddr_in *) &sock->dest_addr)->sin_port = htons( MultiPortNumber);
	sock->dest_addr_len = sizeof(struct sockaddr);
#else
	sock->dest_addr.sin_family = AF_INET;
	sock->dest_addr.sin_addr.s_addr = M_req.imr_multiaddr.s_addr;
	sock->dest_addr.sin_port = htons( MultiPortNumber);
#endif

	sock->flags |= GF_SOCK_IS_MULTICAST | GF_SOCK_HAS_PEER;
	return GF_OK;
}
Exemple #5
0
RTPStream *RP_NewStream(RTPClient *rtp, GF_SDPMedia *media, GF_SDPInfo *sdp, RTPStream *input_stream)
{
	GF_RTSPRange *range;
	RTPStream *tmp;
	GF_RTPMap *map;
	u32 i, ESID, ODID, ssrc, rtp_seq, rtp_time;
	Bool force_bcast = 0;
	Double Start, End;
	Float CurrentTime;
	u16 rvc_predef = 0;
	char *rvc_config_att = NULL;
	u32 s_port_first, s_port_last;
	GF_X_Attribute *att;
	Bool is_migration = 0;
	char *ctrl;
	GF_SDPConnection *conn;
	GF_RTSPTransport trans;
	u32 mid, prev_stream, base_stream;

	//extract all relevant info from the GF_SDPMedia
	Start = 0.0;
	End = -1.0;
	CurrentTime = 0.0f;
	ODID = 0;
	ESID = 0;
	ctrl = NULL;
	range = NULL;
	s_port_first = s_port_last = 0;
	ssrc = rtp_seq = rtp_time = 0;
	mid = prev_stream = base_stream = 0;
	i=0;
	while ((att = (GF_X_Attribute*)gf_list_enum(media->Attributes, &i))) {
		if (!stricmp(att->Name, "control")) ctrl = att->Value;
		else if (!stricmp(att->Name, "gpac-broadcast")) force_bcast = 1;
		else if (!stricmp(att->Name, "mpeg4-esid") && att->Value) ESID = atoi(att->Value);
		else if (!stricmp(att->Name, "mpeg4-odid") && att->Value) ODID = atoi(att->Value);
		else if (!stricmp(att->Name, "range") && !range) range = gf_rtsp_range_parse(att->Value);
		else if (!stricmp(att->Name, "x-stream-state") ) {
			sscanf(att->Value, "server-port=%u-%u;ssrc=%X;npt=%g;seq=%u;rtptime=%u",
			       &s_port_first, &s_port_last, &ssrc, &CurrentTime, &rtp_seq, &rtp_time);
			is_migration = 1;
		}
		else if (!stricmp(att->Name, "x-server-port") ) {
			sscanf(att->Value, "%u-%u", &s_port_first, &s_port_last);
		} else if (!stricmp(att->Name, "rvc-config-predef")) {
			rvc_predef = atoi(att->Value);
		} else if (!stricmp(att->Name, "rvc-config")) {
			rvc_config_att = att->Value;
		} else if (!stricmp(att->Name, "mid")) {
			sscanf(att->Value, "L%d", &mid);
		} else if (!stricmp(att->Name, "depend")) {
			char buf[3000];
			memset(buf, 0, 3000);
			sscanf(att->Value, "%*d lay L%d %*s %s", &base_stream, buf);
			if (!strlen(buf))
				sscanf(att->Value, "%*d lay %s", buf);
			sscanf(buf, "L%d", &prev_stream);
		}
	}

	if (range) {
		Start = range->start;
		End = range->end;
		gf_rtsp_range_del(range);
	}

	/*check connection*/
	conn = sdp->c_connection;
	if (conn && (!conn->host || !strcmp(conn->host, "0.0.0.0"))) conn = NULL;

	if (!conn) conn = (GF_SDPConnection*)gf_list_get(media->Connections, 0);
	if (conn && (!conn->host || !strcmp(conn->host, "0.0.0.0"))) conn = NULL;

	if (!conn) {
		/*RTSP RFC recommends an empty "c= " line but some server don't send it. Use session info (o=)*/
		if (!sdp->o_net_type || !sdp->o_add_type || strcmp(sdp->o_net_type, "IN")) return NULL;
		if (strcmp(sdp->o_add_type, "IP4") && strcmp(sdp->o_add_type, "IP6")) return NULL;
	} else {
		if (strcmp(conn->net_type, "IN")) return NULL;
		if (strcmp(conn->add_type, "IP4") && strcmp(conn->add_type, "IP6")) return NULL;
	}
	/*do we support transport*/
	if (strcmp(media->Profile, "RTP/AVP") && strcmp(media->Profile, "RTP/AVP/TCP")
	        && strcmp(media->Profile, "RTP/SAVP") && strcmp(media->Profile, "RTP/SAVP/TCP")
	   ) return NULL;

	/*check RTP map. For now we only support 1 RTPMap*/
	if (media->fmt_list || (gf_list_count(media->RTPMaps) > 1)) return NULL;

	/*check payload type*/
	map = (GF_RTPMap*)gf_list_get(media->RTPMaps, 0);

	/*this is an ESD-URL setup, we likely have namespace conflicts so overwrite given ES_ID
	by the app one (client side), but keep control (server side) if provided*/
	if (input_stream) {
		ESID = input_stream->ES_ID;
		if (!ctrl) ctrl = input_stream->control;
		tmp = input_stream;
	} else {
		tmp = RP_FindChannel(rtp, NULL, ESID, NULL, 0);
		if (tmp) return NULL;

		GF_SAFEALLOC(tmp, RTPStream);
		tmp->owner = rtp;
	}

	/*create an RTP channel*/
	tmp->rtp_ch = gf_rtp_new();
	if (ctrl) tmp->control = gf_strdup(ctrl);
	tmp->ES_ID = ESID;
	tmp->OD_ID = ODID;
	tmp->mid = mid;
	tmp->prev_stream = prev_stream;
	tmp->base_stream = base_stream;

	memset(&trans, 0, sizeof(GF_RTSPTransport));
	trans.Profile = media->Profile;
	trans.source = conn ? conn->host : sdp->o_address;
	trans.IsUnicast = gf_sk_is_multicast_address(trans.source) ? 0 : 1;
	if (!trans.IsUnicast) {
		trans.port_first = media->PortNumber;
		trans.port_last = media->PortNumber + 1;
		trans.TTL = conn ? conn->TTL : 0;
	} else {
		trans.client_port_first = media->PortNumber;
		trans.client_port_last = media->PortNumber + 1;
		trans.port_first = s_port_first ? s_port_first : trans.client_port_first;
		trans.port_last = s_port_last ? s_port_last : trans.client_port_last;
	}

	if (gf_rtp_setup_transport(tmp->rtp_ch, &trans, NULL) != GF_OK) {
		RP_DeleteStream(tmp);
		return NULL;
	}
	/*setup depacketizer*/
	tmp->depacketizer = gf_rtp_depacketizer_new(media, rtp_sl_packet_cbk, tmp);
	if (!tmp->depacketizer) {
		RP_DeleteStream(tmp);
		return NULL;
	}
	/*setup channel*/
	gf_rtp_setup_payload(tmp->rtp_ch, map);

//	tmp->status = NM_Disconnected;

	ctrl = (char *) gf_modules_get_option((GF_BaseInterface *) gf_term_get_service_interface(rtp->service), "Streaming", "DisableRTCP");
	if (!ctrl || stricmp(ctrl, "yes")) tmp->flags |= RTP_ENABLE_RTCP;

	/*setup NAT keep-alive*/
	ctrl = (char *) gf_modules_get_option((GF_BaseInterface *) gf_term_get_service_interface(rtp->service), "Streaming", "NATKeepAlive");
	if (ctrl) gf_rtp_enable_nat_keepalive(tmp->rtp_ch, atoi(ctrl));

	tmp->range_start = Start;
	tmp->range_end = End;
	if (End != -1.0) tmp->flags |= RTP_HAS_RANGE;

	if (force_bcast) tmp->flags |= RTP_FORCE_BROADCAST;

	if (is_migration) {
		tmp->current_start = (Double) CurrentTime;
		tmp->check_rtp_time = RTP_SET_TIME_RTP;
		gf_rtp_set_info_rtp(tmp->rtp_ch, rtp_seq, rtp_time, ssrc);
		tmp->status = RTP_SessionResume;
	}

	if (rvc_predef) {
		tmp->depacketizer->sl_map.rvc_predef = rvc_predef ;
	} else if (rvc_config_att) {
		char *rvc_data=NULL;
		u32 rvc_size;
		Bool is_gz = 0;
		if (!strncmp(rvc_config_att, "data:application/rvc-config+xml", 32) && strstr(rvc_config_att, "base64") ) {
			char *data = strchr(rvc_config_att, ',');
			if (data) {
				rvc_size = (u32) strlen(data) * 3 / 4 + 1;
				rvc_data = gf_malloc(sizeof(char) * rvc_size);
				rvc_size = gf_base64_decode(data, (u32) strlen(data), rvc_data, rvc_size);
				rvc_data[rvc_size] = 0;
			}
			if (!strncmp(rvc_config_att, "data:application/rvc-config+xml+gz", 35)) is_gz = 1;
		} else if (!strnicmp(rvc_config_att, "http://", 7) || !strnicmp(rvc_config_att, "https://", 8) ) {
			char *mime;
			if (gf_dm_get_file_memory(rvc_config_att, &rvc_data, &rvc_size, &mime) == GF_OK) {
				if (mime && strstr(mime, "+gz")) is_gz = 1;
				if (mime) gf_free(mime);
			}
		}
		if (rvc_data) {
			if (is_gz) {
#ifdef GPAC_DISABLE_ZLIB
				fprintf(stderr, "Error: no zlib support - RVC not supported in RTP\n");
				return NULL;
#endif
				gf_gz_decompress_payload(rvc_data, rvc_size, &tmp->depacketizer->sl_map.rvc_config, &tmp->depacketizer->sl_map.rvc_config_size);
				gf_free(rvc_data);
			} else {
				tmp->depacketizer->sl_map.rvc_config = rvc_data;
				tmp->depacketizer->sl_map.rvc_config_size = rvc_size;
			}
		}
	}

	return tmp;
}
Exemple #6
0
GF_EXPORT
GF_Err gf_sdp_info_parse(GF_SDPInfo *sdp, char *sdp_text, u32 text_size)
{
	GF_SDPBandwidth *bw;
	GF_SDPConnection *conn;
	GF_SDPMedia *media;
	GF_SDPTiming *timing;
	u32 i;
	s32 pos, LinePos;
	char LineBuf[3000], comp[3000];

	media = NULL;
	timing = NULL;

	if (!sdp) return GF_BAD_PARAM;

	//Clean SDP info
	gf_sdp_info_reset(sdp);

	LinePos = 0;
	while (1) {
		LinePos = gf_token_get_line(sdp_text, LinePos, text_size, LineBuf, 3000);
		if (LinePos <= 0) break;
		if (!strcmp(LineBuf, "\r\n") || !strcmp(LineBuf, "\n") || !strcmp(LineBuf, "\r")) continue;


		switch (LineBuf[0]) {
		case 'v':
			pos = gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000);
			sdp->Version = atoi(comp);
			break;
		case 'o':
			pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000);
			sdp->o_username = gf_strdup(comp);
			pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
			sdp->o_session_id = gf_strdup(comp);
			pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
			sdp->o_version = gf_strdup(comp);
			
			pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
			sdp->o_net_type = gf_strdup(comp);

			pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
			sdp->o_add_type = gf_strdup(comp);

			pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
			sdp->o_address = gf_strdup(comp);
			break;
		case 's':
			pos = gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000);
			sdp->s_session_name = gf_strdup(comp);
			break;
		case 'i':
			pos = gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000);
			sdp->i_description = gf_strdup(comp);
			break;
		case 'u':
			pos = gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000);
			sdp->u_uri = gf_strdup(comp);
			break;
		case 'e':
			pos = gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000);
			sdp->e_email = gf_strdup(comp);
			break;
		case 'p':
			pos = gf_token_get(LineBuf, 2, "\t\r\n", comp, 3000);
			sdp->p_phone = gf_strdup(comp);
			break;
		case 'c':
			//if at session level, only 1 is allowed for all SDP
			if (sdp->c_connection) break;
			
			conn = gf_sdp_conn_new();

			pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000);
			conn->net_type = gf_strdup(comp);
			
			pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
			conn->add_type = gf_strdup(comp);

			pos = gf_token_get(LineBuf, pos, " /\r\n", comp, 3000);
			conn->host = gf_strdup(comp);
			if (gf_sk_is_multicast_address(conn->host)) {
				//a valid SDP will have TTL if address is multicast
				pos = gf_token_get(LineBuf, pos, "/\r\n", comp, 3000);
				if (pos > 0) {
					conn->TTL = atoi(comp);
					//multiple address indication is only valid for media
					pos = gf_token_get(LineBuf, pos, "/\r\n", comp, 3000);
				}
				if (pos > 0) {
					if (!media) {
						gf_sdp_conn_del(conn);
						break;
					}
					conn->add_count = atoi(comp);
				}
			}
			if (!media) 
				sdp->c_connection = conn;
			else 
				gf_list_add(media->Connections, conn);

			break;
		case 'b':
			pos = gf_token_get(LineBuf, 2, ":\r\n", comp, 3000);
			if (strcmp(comp, "CT") && strcmp(comp, "AS") && (comp[0] != 'X')) break;

			bw = (GF_SDPBandwidth*)gf_malloc(sizeof(GF_SDPBandwidth));
			bw->name = gf_strdup(comp);
			pos = gf_token_get(LineBuf, pos, ":\r\n", comp, 3000);
			bw->value = atoi(comp);
			if (media) {
				gf_list_add(media->Bandwidths, bw);
			} else {
				gf_list_add(sdp->b_bandwidth, bw);
			}
			break;

		case 't':
			if (media) break;
			//create a new time structure for each entry
			GF_SAFEALLOC(timing, GF_SDPTiming);
			pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000);
			timing->StartTime = atoi(comp);
			pos = gf_token_get(LineBuf, pos, "\r\n", comp, 3000);
			timing->StopTime = atoi(comp);
			gf_list_add(sdp->Timing, timing);
			break;
		case 'r':
			if (media) break;
			pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000);
			timing->RepeatInterval = SDP_MakeSeconds(comp);
			pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
			timing->ActiveDuration = SDP_MakeSeconds(comp);
			while (1) {
				pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
				if (pos <= 0) break;
				timing->OffsetFromStart[timing->NbRepeatOffsets] = SDP_MakeSeconds(comp);
				timing->NbRepeatOffsets += 1;
			}
			break;
		case 'z':
			if (media) break;
			pos = 2;
			while (1) {
				pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
				if (pos <= 0) break;
				timing->AdjustmentTime[timing->NbZoneOffsets] = atoi(comp);
				pos = gf_token_get(LineBuf, pos, " \t\r\n", comp, 3000);
				timing->AdjustmentOffset[timing->NbZoneOffsets] = SDP_MakeSeconds(comp);
				timing->NbZoneOffsets += 1;
			}
			break;
		case 'k':
			pos = gf_token_get(LineBuf, 2, ":\t\r\n", comp, 3000);
			if (media) {
				media->k_method = gf_strdup(comp);
			} else {
				sdp->k_method = gf_strdup(comp);
			}
			pos = gf_token_get(LineBuf, pos, ":\r\n", comp, 3000);
			if (pos > 0) {
				if (media) {
					media->k_key = gf_strdup(comp);
				} else {
					sdp->k_key = gf_strdup(comp);
				}
			}
			break;
		case 'a':
			SDP_ParseAttribute(sdp, LineBuf+2, media);
			break;
		case 'm':
			pos = gf_token_get(LineBuf, 2, " \t\r\n", comp, 3000);
			if (strcmp(comp, "audio") 
				&& strcmp(comp, "data") 
				&& strcmp(comp, "control") 
				&& strcmp(comp, "video") 
				&& strcmp(comp, "text") 
				&& strcmp(comp, "application")) {
				return GF_SERVICE_ERROR;
			}
			media = gf_sdp_media_new();
			//media type
			if (!strcmp(comp, "video")) media->Type = 1;
			else if (!strcmp(comp, "audio")) media->Type = 2;
			else if (!strcmp(comp, "text")) media->Type = 3;
			else if (!strcmp(comp, "data")) media->Type = 4;
			else if (!strcmp(comp, "control")) media->Type = 5;
			else media->Type = 0;
			//port numbers			
			gf_token_get(LineBuf, pos, " ", comp, 3000);
			if (!strstr(comp, "/")) {
				pos = gf_token_get(LineBuf, pos, " \r\n", comp, 3000);
				media->PortNumber = atoi(comp);
				media->NumPorts = 0;
			} else {
				pos = gf_token_get(LineBuf, pos, " /\r\n", comp, 3000);
				media->PortNumber = atoi(comp);
				pos = gf_token_get(LineBuf, pos, " \r\n", comp, 3000);
				media->NumPorts = atoi(comp);
			}
			//transport Profile
			pos = gf_token_get(LineBuf, pos, " \r\n", comp, 3000);
			media->Profile = gf_strdup(comp);
			pos = gf_token_get(LineBuf, pos, " \r\n", comp, 3000);
			media->fmt_list = gf_strdup(comp);

			gf_list_add(sdp->media_desc, media);
			break;
		}
	}
	//finally rewrite the fmt_list for all media, and remove dynamic payloads 
	//from the list
	i=0;
	while ((media = (GF_SDPMedia*)gf_list_enum(sdp->media_desc, &i))) {
		pos = 0;
		LinePos = 1;
		strcpy(LineBuf, "");
		while (1) {
			if (!media->fmt_list) break;
			pos = gf_token_get(media->fmt_list, pos, " ", comp, 3000);
			if (pos <= 0) break;
			if (!SDP_IsDynamicPayload(media, comp)) {
				if (!LinePos) {
					strcat(LineBuf, " ");
				} else {
					LinePos = 0;
				}
				strcat(LineBuf, comp);
			}
			gf_free(media->fmt_list);
			media->fmt_list = NULL;
			if (strlen(LineBuf)) {
				media->fmt_list = gf_strdup(LineBuf);
			}
		}
	}
	return GF_OK;
}