[asterisk-commits] kpfleming: branch kpfleming/sofiasdp r131128 - in /team/kpfleming/sofiasdp: c...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Jul 15 18:05:32 CDT 2008


Author: kpfleming
Date: Tue Jul 15 18:05:31 2008
New Revision: 131128

URL: http://svn.digium.com/view/asterisk?view=rev&rev=131128
Log:
more progress... doesn't actually setup media streams yet, but getting close

along the way, fix the naming of all the T.140RED related stuff that was added to rtp.c to use "ast_" prefixes for API functions and structure definitions


Modified:
    team/kpfleming/sofiasdp/channels/chan_sip.c
    team/kpfleming/sofiasdp/include/asterisk/rtp.h
    team/kpfleming/sofiasdp/main/rtp.c

Modified: team/kpfleming/sofiasdp/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/team/kpfleming/sofiasdp/channels/chan_sip.c?view=diff&rev=131128&r1=131127&r2=131128
==============================================================================
--- team/kpfleming/sofiasdp/channels/chan_sip.c (original)
+++ team/kpfleming/sofiasdp/channels/chan_sip.c Tue Jul 15 18:05:31 2008
@@ -5169,7 +5169,7 @@
 		if (p) {
 			sip_pvt_lock(p);
 			if (p->red) {
-				red_buffer_t140(p->trtp, frame);
+				ast_red_buffer_t140(p->trtp, frame);
 			} else {
 				if (p->trtp) {
 					/* Activate text early media */
@@ -6537,6 +6537,26 @@
 	return FALSE;
 }
 
+static int connection_usable(const sdp_connection_t *conn)
+{
+	if (!conn) {
+		return -1;
+	}
+	/* must be an 'IN' type connection */
+	if (conn->c_nettype != sdp_net_in) {
+		return 0;
+	}
+	/* must be an IPv4 address (for now) */
+	if (conn->c_addrtype != sdp_addr_ip4) {
+		return 0;
+	}
+	if (!conn->c_address) {
+		return 0;
+	}
+
+	return 1;
+}
+
 /*! \brief Process SIP SDP offer, select formats and activate RTP channels
 	If offer is rejected, we will not change any properties of the call
  	Return 0 on success, a negative value on errors.
@@ -6544,44 +6564,228 @@
 */
 static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action)
 {
+	int res = -1;		/* assume failure... */
 	unsigned int x;
-	char *c;
-	su_home_t *su_home = su_home_create();
-	sdp_parser_t *sdp;
+	su_home_t *su_home = NULL;
+	sdp_parser_t *sdp = NULL;
 	sdp_session_t *session;
-	sdp_printer_t *printer;
-
-	/* reassemble the SDP into a continuous string; we know all of these lines
-	   were originally consecutive and that they ended with '\r\n' pairs, so
-	   we can safely put it back without having to worry about memory allocation
-	*/
+	sdp_media_t *media;
+	struct ast_rtp *newaudiortp, *newvideortp, *newtextrtp;	/* Buffers for stream handling */
+	int numberofmediastreams = 0;
+	int debug = sip_debug_test_pvt(p);
+	struct ast_str *parsebuf;
+	sdp_rtpmap_t *rtpmap;
+
+	if (!p->rtp) {
+		ast_log(LOG_ERROR, "Got SDP but have no RTP session allocated.\n");
+		goto exit;
+	}
+
+	/* TODO: if this technique survives, switch to threadstorage mode for this buffer */
+	parsebuf = ast_str_alloca(req->line[req->sdp_end] - req->line[req->sdp_start] + 80);
+
 	for (x = req->sdp_start; x <= req->sdp_end; x++) {
-		c = req->line[x] + strlen(req->line[x]);
-		*c++ = '\r';
-		*c++ = '\n';
-	}
-
-	sdp = sdp_parse(su_home, req->line[req->sdp_start], req->line[req->sdp_end] + strlen(req->line[req->sdp_end]) + 1 - req->line[req->sdp_start], 0);
+		ast_str_append(&parsebuf, 0, "%s\r\n", req->line[x]);
+	}
+
+	if (!(su_home = su_home_create())) {
+		goto exit;
+	}
+
+	if (debug) {
+		ast_log(LOG_DEBUG, "Parsing SDP:\n%s\n", parsebuf->str);
+	}
+
+	sdp = sdp_parse(su_home, parsebuf->str, parsebuf->used, 0);
 
 	if (!(session = sdp_session(sdp))) {
 		ast_log(LOG_WARNING, "SDP parsing failed: %s\n", sdp_parsing_error(sdp));
-		sdp_parser_free(sdp);
-		su_home_unref(su_home);
-		return -1;
-	}
-
-	printer = sdp_print(su_home, session, NULL, 0, 0);
-
-	if (sdp_message(printer)) {
-		ast_log(LOG_DEBUG, "Parsed and regenerated SDP is:\n%s\n", sdp_message(printer));
-	}
-
-	sdp_printer_free(printer);
+		goto exit_free;
+	}
+
+	/* Sanity check the SDP. It's certainly possible for us to receive an SDP that
+	   is entirely RFC compliant and logical, but useless.
+	*/
+
+	/* must have an origin */
+	if (!session->sdp_origin) {
+		ast_log(LOG_WARNING, "SDP syntax error. SDP without an o= line\n");
+		goto exit_free;
+	}
+
+	/* must have at least one media stream */
+	if (!session->sdp_media) {
+		ast_log(LOG_WARNING, "SDP does not contain any media streams\n");
+		goto exit_free;
+	}
+
+	/* sanity check media streams */
+	for (media = session->sdp_media; media; media = media->m_next) {
+		sdp_connection_t *conn;
+
+		/* does it have a usable connection? */
+		for (conn = media->m_connections; conn; conn = conn->c_next) {
+			if (connection_usable(conn)) {
+				break;
+			}
+		}
+
+		/* if not, and there is no session-level usable connection, we can't
+		   support this stream
+		*/
+		if (!conn && !connection_usable(session->sdp_connection)) {
+			ast_log(LOG_WARNING, "Media stream has no usable connection information\n");
+			goto exit_free;
+		}
+
+		/* ensure that the stream's type is supported */
+		switch (media->m_type) {
+		case sdp_media_audio:
+			break;
+		case sdp_media_video:
+			break;
+		case sdp_media_image:
+			break;
+		default:
+			if (strcasecmp(media->m_type_name, "text")) {
+				ast_log(LOG_WARNING, "Media stream is not a supported type (%s)\n", media->m_type_name);
+				goto exit_free;
+			}
+			break;
+		}
+
+		/* we can't handle streams that use more than one port */
+		if (media->m_number_of_ports > 1) {
+			ast_log(LOG_WARNING, "Media stream needs %d set of ports; only one is supported\n", (int) media->m_number_of_ports);
+		}
+
+		switch (media->m_proto) {
+		case sdp_proto_rtp:
+			for (rtpmap = media->m_rtpmaps; rtpmap; rtpmap = rtpmap->rm_next) {
+				if (rtpmap->rm_any) {
+					ast_log(LOG_WARNING, "Media stream uses an RTP map of 'any'; not supported\n");
+					goto exit_free;
+				}
+			}
+			break;
+		case sdp_proto_udptl:
+			/* TODO: anything to check here? */
+			break;
+		case sdp_proto_tcp:
+		case sdp_proto_srtp:
+		case sdp_proto_udp:
+		case sdp_proto_tls:
+		default:
+			ast_log(LOG_WARNING, "Media stream uses an unsupported protocol (%s)\n", media->m_proto_name);
+			goto exit_free;
+		}
+
+		/* this media stream is sane and can be supported */
+		numberofmediastreams++;
+	}
+
+	if (numberofmediastreams > 3) {
+		/* We have too many media streams, fail this offer */
+		ast_log(LOG_WARNING, "Too many media streams offered (%d)\n", numberofmediastreams);
+		res = -3;
+		goto exit_free;
+	} else if (numberofmediastreams == 0) {
+		ast_log(LOG_WARNING, "No compatible media streams offered\n");
+		res = -2;
+		goto exit_free;
+	}
+
+	/* Initialize the temporary RTP structures we use to evaluate the offer from the peer */
+#ifdef LOW_MEMORY
+	newaudiortp = ast_threadstorage_get(&ts_audio_rtp, ast_rtp_alloc_size());
+#else
+	newaudiortp = alloca(ast_rtp_alloc_size());
+#endif
+	memset(newaudiortp, 0, ast_rtp_alloc_size());
+	ast_rtp_new_init(newaudiortp);
+	ast_rtp_pt_clear(newaudiortp);
+
+#ifdef LOW_MEMORY
+	newvideortp = ast_threadstorage_get(&ts_video_rtp, ast_rtp_alloc_size());
+#else
+	newvideortp = alloca(ast_rtp_alloc_size());
+#endif
+	memset(newvideortp, 0, ast_rtp_alloc_size());
+	ast_rtp_new_init(newvideortp);
+	ast_rtp_pt_clear(newvideortp);
+
+#ifdef LOW_MEMORY
+	newtextrtp = ast_threadstorage_get(&ts_text_rtp, ast_rtp_alloc_size());
+#else
+	newtextrtp = alloca(ast_rtp_alloc_size());
+#endif
+	memset(newtextrtp, 0, ast_rtp_alloc_size());
+	ast_rtp_new_init(newtextrtp);
+	ast_rtp_pt_clear(newtextrtp);
+
+	/* Update our last rtprx when we receive an SDP, too */
+	p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */
+
+	/* Store the SDP version number of remote UA. This will allow us to 
+	distinguish between session modifications and session refreshes. If 
+	the remote UA does not send an incremented SDP version number in a 
+	subsequent RE-INVITE then that means its not changing media session. 
+	The RE-INVITE may have been sent to update connected party, remote  
+	target or to refresh the session (Session-Timers).  Asterisk must not 
+	change media session and increment its own version number in answer 
+	SDP in this case. */ 
+	
+	if (p->sessionversion_remote < 0 || p->sessionversion_remote != session->sdp_origin->o_version) {
+ 		p->sessionversion_remote = session->sdp_origin->o_version;
+		p->session_modify = TRUE;
+	} else if (p->sessionversion_remote == session->sdp_origin->o_version) {
+		p->session_modify = FALSE;
+		ast_debug(2, "SDP version number same as previous SDP\n");
+		res = 0;
+		goto exit_free;
+	}
+
+	/* default: novideo and notext set */
+	p->novideo = TRUE;
+	p->notext = TRUE;
+
+	/* process the media streams */
+	for (media = session->sdp_media; media; media = media->m_next) {
+		switch (media->m_type) {
+		case sdp_media_audio:
+			for (rtpmap = media->m_rtpmaps; rtpmap; rtpmap = rtpmap->rm_next) {
+				if (debug)
+					ast_verbose("Found RTP audio format %d\n", rtpmap->rm_pt);
+				ast_rtp_set_m_type(newaudiortp, rtpmap->rm_pt);
+			}
+			break;
+		case sdp_media_video:
+			for (rtpmap = media->m_rtpmaps; rtpmap; rtpmap = rtpmap->rm_next) {
+				if (debug)
+					ast_verbose("Found RTP video format %d\n", rtpmap->rm_pt);
+				ast_rtp_set_m_type(newvideortp, rtpmap->rm_pt);
+			}
+			break;
+		case sdp_media_image:
+			for (rtpmap = media->m_rtpmaps; rtpmap; rtpmap = rtpmap->rm_next) {
+				if (debug)
+					ast_verbose("Found RTP text format %d\n", rtpmap->rm_pt);
+				ast_rtp_set_m_type(newtextrtp, rtpmap->rm_pt);
+			}
+			break;
+		default:
+			/* must be "text", because we filtered out everything else already */
+			break;
+		}
+	}
+
+exit_free:
 	sdp_parser_free(sdp);
 
 	su_home_unref(su_home);
 
-	return -1;
+exit:
+	return res;
 
 #if 0
 	const char *m;		/* SDP media offer */
@@ -6620,12 +6824,9 @@
 	int iterator;
 	int sendonly = -1;
 	int numberofports;
-	struct ast_rtp *newaudiortp, *newvideortp, *newtextrtp;	/* Buffers for codec handling */
 	int newjointcapability;				/* Negotiated capability */
 	int newpeercapability;
 	int newnoncodeccapability;
-	int numberofmediastreams = 0;
-	int debug = sip_debug_test_pvt(p);
 		
 	int found_rtpmap_codecs[SDP_MAX_RTPMAP_CODECS];
 	int last_rtpmap_codec=0;
@@ -6639,122 +6840,6 @@
 
 	char *red_cp; 				/* For T.140 red */
 	char red_fmtp[100] = "empty";		/* For T.140 red */
-
-	if (!p->rtp) {
-		ast_log(LOG_ERROR, "Got SDP but have no RTP session allocated.\n");
-		return -1;
-	}
-
-	/* Initialize the temporary RTP structures we use to evaluate the offer from the peer */
-#ifdef LOW_MEMORY
-	newaudiortp = ast_threadstorage_get(&ts_audio_rtp, ast_rtp_alloc_size());
-#else
-	newaudiortp = alloca(ast_rtp_alloc_size());
-#endif
-	memset(newaudiortp, 0, ast_rtp_alloc_size());
-	ast_rtp_new_init(newaudiortp);
-	ast_rtp_pt_clear(newaudiortp);
-
-#ifdef LOW_MEMORY
-	newvideortp = ast_threadstorage_get(&ts_video_rtp, ast_rtp_alloc_size());
-#else
-	newvideortp = alloca(ast_rtp_alloc_size());
-#endif
-	memset(newvideortp, 0, ast_rtp_alloc_size());
-	ast_rtp_new_init(newvideortp);
-	ast_rtp_pt_clear(newvideortp);
-
-#ifdef LOW_MEMORY
-	newtextrtp = ast_threadstorage_get(&ts_text_rtp, ast_rtp_alloc_size());
-#else
-	newtextrtp = alloca(ast_rtp_alloc_size());
-#endif
-	memset(newtextrtp, 0, ast_rtp_alloc_size());
-	ast_rtp_new_init(newtextrtp);
-	ast_rtp_pt_clear(newtextrtp);
-
-	/* Update our last rtprx when we receive an SDP, too */
-	p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */
-
-	/* Store the SDP version number of remote UA. This will allow us to 
-	distinguish between session modifications and session refreshes. If 
-	the remote UA does not send an incremented SDP version number in a 
-	subsequent RE-INVITE then that means its not changing media session. 
-	The RE-INVITE may have been sent to update connected party, remote  
-	target or to refresh the session (Session-Timers).  Asterisk must not 
-	change media session and increment its own version number in answer 
-	SDP in this case. */ 
-	
-	o = get_sdp(req, "o");
-	if (ast_strlen_zero(o)) {
-		ast_log(LOG_WARNING, "SDP sytax error. SDP without an o= line\n");
-		return -1;
-	}
-
-	o_copy = ast_strdupa(o);
-	token = strsep(&o_copy, " ");  /* Skip username   */
-	if (!o_copy) { 
-		ast_log(LOG_WARNING, "SDP sytax error in o= line username\n");
-		return -1;
-	}
-	token = strsep(&o_copy, " ");  /* Skip session-id */
-	if (!o_copy) { 
-		ast_log(LOG_WARNING, "SDP sytax error in o= line session-id\n");
-		return -1;
-	}
-	token = strsep(&o_copy, " ");  /* Version         */
-	if (!o_copy) { 
-		ast_log(LOG_WARNING, "SDP sytax error in o= line\n");
-		return -1;
-	}
-	if (!sscanf(token, "%d", &rua_version)) {
-		ast_log(LOG_WARNING, "SDP sytax error in o= line version\n");
-		return -1;
-	}
-
-	if (p->sessionversion_remote < 0 || p->sessionversion_remote != rua_version) {
- 		p->sessionversion_remote = rua_version;
-		p->session_modify = TRUE;
-	} else if (p->sessionversion_remote == rua_version) {
-		p->session_modify = FALSE;
-		ast_debug(2, "SDP version number same as previous SDP\n");
-		return 0;
-	} 
-
-	/* Try to find first media stream */
-	m = get_sdp(req, "m");
-	destiterator = req->sdp_start;
-	c = get_sdp_iterate(&destiterator, req, "c");
-	if (ast_strlen_zero(m) || ast_strlen_zero(c)) {
-		ast_log(LOG_WARNING, "Insufficient information for SDP (m = '%s', c = '%s')\n", m, c);
-		return -1;
-	}
-
-	/* Check for IPv4 address (not IPv6 yet) */
-	if (sscanf(c, "IN IP4 %256s", host) != 1) {
-		ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
-		return -1;
-	}
-
-	/* XXX This could block for a long time, and block the main thread! XXX */
-	hp = ast_gethostbyname(host, &audiohp);
-	if (!hp) {
-		ast_log(LOG_WARNING, "Unable to lookup host in c= line, '%s'\n", c);
-		return -1;
-	}
-	vhp = hp;	/* Copy to video address as default too */
-	thp = hp;	/* Copy to text address as default too */
-	
-	iterator = req->sdp_start;
-	/* default: novideo and notext set */
-	p->novideo = TRUE;
-	p->notext = TRUE;
-
-	if (p->vrtp)
-		ast_rtp_pt_clear(newvideortp);  /* Must be cleared in case no m=video line exists */
- 
-	if (p->trtp)
-		ast_rtp_pt_clear(newtextrtp);  /* Must be cleared in case no m=text line exists */
 
 	/* Find media streams in this SDP offer */
 	while ((m = get_sdp_iterate(&iterator, req, "m"))[0] != '\0') {
@@ -6851,14 +6936,6 @@
 
 		}
 	}
-	if (portno == -1 && vportno == -1 && udptlportno == -1  && tportno == -1)
-		/* No acceptable offer found in SDP  - we have no ports */
-		/* Do not change RTP or VRTP if this is a re-invite */
-		return -2;
-
-	if (numberofmediastreams > 3)
-		/* We have too many fax, audio and/or video and/or text media streams, fail this offer */
-		return -3;
 
 	/* RTP addresses and ports for audio and video */
 	sin.sin_family = AF_INET;

Modified: team/kpfleming/sofiasdp/include/asterisk/rtp.h
URL: http://svn.digium.com/view/asterisk/team/kpfleming/sofiasdp/include/asterisk/rtp.h?view=diff&rev=131128&r1=131127&r2=131128
==============================================================================
--- team/kpfleming/sofiasdp/include/asterisk/rtp.h (original)
+++ team/kpfleming/sofiasdp/include/asterisk/rtp.h Tue Jul 15 18:05:31 2008
@@ -82,7 +82,7 @@
 
 struct ast_rtp;
 /*! T.140 Redundancy structure*/
-struct rtp_red;
+struct ast_rtp_red;
 
 /*! \brief This is the structure that binds a channel (SIP/Jingle/H.323) to the RTP subsystem 
 */
@@ -338,21 +338,18 @@
 /* \brief Put RTP timeout timers on hold during another transaction, like T.38 */
 void ast_rtp_set_rtptimers_onhold(struct ast_rtp *rtp);
 
-/*! \brief Initalize t.140 redudancy 
+/*! \brief Initalize T.140 redundancy 
  * \param ti time between each t140red frame is sent
  * \param red_pt payloadtype for RTP packet
  * \param pt payloadtype numbers for each generation including primary data
  * \param num_gen number of redundant generations, primary data excluded
  */
-int rtp_red_init(struct ast_rtp *rtp, int ti, int *pt, int num_gen);
-
-void red_init(struct rtp_red *red, const struct ast_frame *f);
-
+int ast_rtp_red_init(struct ast_rtp *rtp, int ti, int *pt, int num_gen);
+
+void ast_red_init(struct ast_rtp_red *red, const struct ast_frame *f);
 
 /*! \brief Buffer t.140 data */
-void red_buffer_t140(struct ast_rtp *rtp, struct ast_frame *f);
-
-
+void ast_red_buffer_t140(struct ast_rtp *rtp, struct ast_frame *f);
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }

Modified: team/kpfleming/sofiasdp/main/rtp.c
URL: http://svn.digium.com/view/asterisk/team/kpfleming/sofiasdp/main/rtp.c?view=diff&rev=131128&r1=131127&r2=131128
==============================================================================
--- team/kpfleming/sofiasdp/main/rtp.c (original)
+++ team/kpfleming/sofiasdp/main/rtp.c Tue Jul 15 18:05:31 2008
@@ -179,13 +179,10 @@
 	struct sockaddr_in strict_rtp_address;  /*!< Remote address information for strict RTP purposes */
 
 	int set_marker_bit:1;           /*!< Whether to set the marker bit or not */
-	struct rtp_red *red;
+	struct ast_rtp_red *red;
 };
 
-static struct ast_frame *red_t140_to_red(struct rtp_red *red);
-static int red_write(const void *data);
- 
-struct rtp_red {
+struct ast_rtp_red {
 	struct ast_frame t140;  /*!< Primary data  */
 	struct ast_frame t140red;   /*!< Redundant t140*/
 	unsigned char pt[RED_MAX_GENERATION];  /*!< Payload types for redundancy data */
@@ -208,6 +205,7 @@
 static unsigned int ast_rtcp_calc_interval(struct ast_rtp *rtp);
 static int ast_rtp_senddigit_continuation(struct ast_rtp *rtp);
 int ast_rtp_senddigit_end(struct ast_rtp *rtp, char digit);
+static struct ast_frame *red_t140_to_red(struct ast_rtp_red *red);
 
 #define FLAG_3389_WARNING		(1 << 0)
 #define FLAG_NAT_ACTIVE			(3 << 1)
@@ -4765,7 +4763,7 @@
 	__ast_rtp_reload(0);
 }
 
-/*! \brief Write t140 redundacy frame 
+/*! \brief Write T.140 redundancy frame 
  * \param data primary data to be buffered
  */
 static int red_write(const void *data)
@@ -4780,7 +4778,8 @@
 /*! \brief Construct a redundant frame 
  * \param red redundant data structure
  */
-static struct ast_frame *red_t140_to_red(struct rtp_red *red) {
+static struct ast_frame *red_t140_to_red(struct ast_rtp_red *red)
+{
 	unsigned char *data = red->t140red.data.ptr;
 	int len = 0;
 	int i;
@@ -4817,19 +4816,19 @@
 	return &red->t140red;
 }
 
-/*! \brief Initialize t140 redundancy 
+/*! \brief Initialize T.140 redundancy 
  * \param rtp
  * \param ti buffer t140 for ti (msecs) before sending redundant frame
  * \param red_data_pt Payloadtypes for primary- and generation-data
  * \param num_gen numbers of generations (primary generation not encounted)
  *
 */
-int rtp_red_init(struct ast_rtp *rtp, int ti, int *red_data_pt, int num_gen)
-{
-	struct rtp_red *r;
+int ast_rtp_red_init(struct ast_rtp *rtp, int ti, int *red_data_pt, int num_gen)
+{
+	struct ast_rtp_red *r;
 	int x;
 	
-	if (!(r = ast_calloc(1, sizeof(struct rtp_red))))
+	if (!(r = ast_calloc(1, sizeof(*r))))
 		return -1;
 
 	r->t140.frametype = AST_FRAME_TEXT;
@@ -4859,14 +4858,15 @@
 	return 0;
 }
 
-/*! \brief Buffer t140 from chan_sip
+/*! \brief Buffer T.140 data
  * \param rtp
  * \param f frame
  */
-void red_buffer_t140(struct ast_rtp *rtp, struct ast_frame *f)
+void ast_red_buffer_t140(struct ast_rtp *rtp, struct ast_frame *f)
 {
 	if (f->datalen > -1) {
-		struct rtp_red *red = rtp->red;
+		struct ast_rtp_red *red = rtp->red;
+
 		memcpy(&red->buf_data[red->t140.datalen], f->data.ptr, f->datalen); 
 		red->t140.datalen += f->datalen;
 		red->t140.ts = f->ts;




More information about the asterisk-commits mailing list