[asterisk-commits] loren: branch loren/sdp-parser r275546 - /team/loren/sdp-parser/channels/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Sun Jul 11 02:21:08 CDT 2010
Author: loren
Date: Sun Jul 11 02:21:04 2010
New Revision: 275546
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=275546
Log:
current version of sdp parsing code
Modified:
team/loren/sdp-parser/channels/chan_sip.c
Modified: team/loren/sdp-parser/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/loren/sdp-parser/channels/chan_sip.c?view=diff&rev=275546&r1=275545&r2=275546
==============================================================================
--- team/loren/sdp-parser/channels/chan_sip.c (original)
+++ team/loren/sdp-parser/channels/chan_sip.c Sun Jul 11 02:21:04 2010
@@ -273,7 +273,7 @@
#include "asterisk/xml.h"
#include "sip/include/dialog.h"
#include "sip/include/dialplan_functions.h"
-
+#include "sip/include/sdp_parser.h"
/*** DOCUMENTATION
<application name="SIPDtmfMode" language="en_US">
@@ -7468,1189 +7468,6 @@
return determine_firstline_parts(req);
}
-/*!
- \brief Determine whether a SIP message contains an SDP in its body
- \param req the SIP request to process
- \return 1 if SDP found, 0 if not found
-
- Also updates req->sdp_start and req->sdp_count to indicate where the SDP
- lives in the message body.
-*/
-static int find_sdp(struct sip_request *req)
-{
- const char *content_type;
- const char *content_length;
- const char *search;
- char *boundary;
- unsigned int x;
- int boundaryisquoted = FALSE;
- int found_application_sdp = FALSE;
- int found_end_of_headers = FALSE;
-
- content_length = get_header(req, "Content-Length");
-
- if (!ast_strlen_zero(content_length)) {
- if (sscanf(content_length, "%30u", &x) != 1) {
- ast_log(LOG_WARNING, "Invalid Content-Length: %s\n", content_length);
- return 0;
- }
-
- /* Content-Length of zero means there can't possibly be an
- SDP here, even if the Content-Type says there is */
- if (x == 0)
- return 0;
- }
-
- content_type = get_header(req, "Content-Type");
-
- /* if the body contains only SDP, this is easy */
- if (!strncasecmp(content_type, "application/sdp", 15)) {
- req->sdp_start = 0;
- req->sdp_count = req->lines;
- return req->lines ? 1 : 0;
- }
-
- /* if it's not multipart/mixed, there cannot be an SDP */
- if (strncasecmp(content_type, "multipart/mixed", 15))
- return 0;
-
- /* if there is no boundary marker, it's invalid */
- if ((search = strcasestr(content_type, ";boundary=")))
- search += 10;
- else if ((search = strcasestr(content_type, "; boundary=")))
- search += 11;
- else
- return 0;
-
- if (ast_strlen_zero(search))
- return 0;
-
- /* If the boundary is quoted with ", remove quote */
- if (*search == '\"') {
- search++;
- boundaryisquoted = TRUE;
- }
-
- /* make a duplicate of the string, with two extra characters
- at the beginning */
- boundary = ast_strdupa(search - 2);
- boundary[0] = boundary[1] = '-';
- /* Remove final quote */
- if (boundaryisquoted)
- boundary[strlen(boundary) - 1] = '\0';
-
- /* search for the boundary marker, the empty line delimiting headers from
- sdp part and the end boundry if it exists */
-
- for (x = 0; x < (req->lines); x++) {
- const char *line = REQ_OFFSET_TO_STR(req, line[x]);
- if (!strncasecmp(line, boundary, strlen(boundary))){
- if (found_application_sdp && found_end_of_headers) {
- req->sdp_count = (x - 1) - req->sdp_start;
- return 1;
- }
- found_application_sdp = FALSE;
- }
- if (!strcasecmp(line, "Content-Type: application/sdp"))
- found_application_sdp = TRUE;
-
- if (ast_strlen_zero(line)) {
- if (found_application_sdp && !found_end_of_headers){
- req->sdp_start = x;
- found_end_of_headers = TRUE;
- }
- }
- }
- if (found_application_sdp && found_end_of_headers) {
- req->sdp_count = x - req->sdp_start;
- return TRUE;
- }
- return FALSE;
-}
-
-
-static int get_ip_and_port_from_sdp(struct sip_request *req, const enum media_type media, struct sockaddr_in *sin)
-{
- const char *m;
- const char *c;
- int miterator = req->sdp_start;
- int citerator = req->sdp_start;
- int x = 0;
- int numberofports;
- int len;
- char host[258] = ""; /*Initialize to empty so we will know if we have any input */
- struct ast_hostent audiohp;
- struct hostent *hp;
-
- c = get_sdp_iterate(&citerator, req, "c");
- if (sscanf(c, "IN IP4 %256s", host) != 1) {
- ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
- /* Continue since there may be a valid host in a c= line specific to the audio stream */
- }
- /* We only want the m and c lines for audio */
- for (m = get_sdp_iterate(&miterator, req, "m"); !ast_strlen_zero(m); m = get_sdp_iterate(&miterator, req, "m")) {
- if ((media == SDP_AUDIO && ((sscanf(m, "audio %30u/%30u RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
- (sscanf(m, "audio %30u RTP/AVP %n", &x, &len) == 1 && len > 0))) ||
- (media == SDP_VIDEO && ((sscanf(m, "video %30u/%30u RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
- (sscanf(m, "video %30u RTP/AVP %n", &x, &len) == 1 && len > 0)))) {
- /* See if there's a c= line for this media stream.
- * XXX There is no guarantee that we'll be grabbing the c= line for this
- * particular media stream here. However, this is the same logic used in process_sdp.
- */
- c = get_sdp_iterate(&citerator, req, "c");
- if (!ast_strlen_zero(c)) {
- sscanf(c, "IN IP4 %256s", host);
- }
- break;
- }
- }
-
- if (ast_strlen_zero(host) || x == 0) {
- ast_log(LOG_WARNING, "Failed to read an alternate host or port in SDP. Expect %s problems\n", media == SDP_AUDIO ? "audio" : "video");
- return -1;
- }
-
- hp = ast_gethostbyname(host, &audiohp);
- if (!hp) {
- ast_log(LOG_WARNING, "Could not look up IP address of alternate hostname. Expect %s problems\n", media == SDP_AUDIO? "audio" : "video");
- return -1;
- }
-
- memcpy(&sin->sin_addr, hp->h_addr, sizeof(sin->sin_addr));
- sin->sin_port = htons(x);
- return 0;
-}
-
-/*! \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.
- Must be called after find_sdp().
-*/
-static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action)
-{
- /* Iterators for SDP parsing */
- int start = req->sdp_start;
- int next = start;
- int iterator = start;
-
- /* Temporary vars for SDP parsing */
- char type = '\0';
- const char *value = NULL;
- const char *m = NULL; /* SDP media offer */
- const char *nextm = NULL;
- int len = -1;
-
- /* Host information */
- struct ast_hostent sessionhp;
- struct ast_hostent audiohp;
- struct ast_hostent videohp;
- struct ast_hostent texthp;
- struct ast_hostent imagehp;
- struct hostent *hp = NULL; /*!< RTP Audio host IP */
- struct hostent *vhp = NULL; /*!< RTP video host IP */
- struct hostent *thp = NULL; /*!< RTP text host IP */
- struct hostent *ihp = NULL; /*!< UDPTL host ip */
- int portno = -1; /*!< RTP Audio port number */
- int vportno = -1; /*!< RTP Video port number */
- int tportno = -1; /*!< RTP Text port number */
- int udptlportno = -1; /*!< UDPTL Image port number */
- struct sockaddr_in sin; /*!< media socket address */
- struct sockaddr_in vsin; /*!< video socket address */
- struct sockaddr_in isin; /*!< image socket address */
- struct sockaddr_in tsin; /*!< text socket address */
-
- /* Peer capability is the capability in the SDP, non codec is RFC2833 DTMF (101) */
- format_t peercapability = 0, vpeercapability = 0, tpeercapability = 0;
- int peernoncodeccapability = 0, vpeernoncodeccapability = 0, tpeernoncodeccapability = 0;
-
- struct ast_rtp_codecs newaudiortp, newvideortp, newtextrtp;
- format_t newjointcapability; /* Negotiated capability */
- format_t newpeercapability;
- int newnoncodeccapability;
-
- const char *codecs;
- int codec;
-
- /* SRTP */
- int secure_audio = FALSE;
- int secure_video = FALSE;
-
- /* Others */
- int sendonly = -1;
- int vsendonly = -1;
- int numberofports;
- int numberofmediastreams = 0;
- int last_rtpmap_codec = 0;
- int red_data_pt[10]; /* For T.140 red */
- int red_num_gen = 0; /* For T.140 red */
- char red_fmtp[100] = "empty"; /* For T.140 red */
- int debug = sip_debug_test_pvt(p);
-
- /* START UNKNOWN */
- char buf[SIPBUFSIZE];
- /* END UNKNOWN */
-
- /* Initial check */
- if (!p->rtp) {
- ast_log(LOG_ERROR, "Got SDP but have no RTP session allocated.\n");
- return -1;
- }
-
- /* Make sure that the codec structures are all cleared out */
- ast_rtp_codecs_payloads_clear(&newaudiortp, NULL);
- ast_rtp_codecs_payloads_clear(&newvideortp, NULL);
- ast_rtp_codecs_payloads_clear(&newtextrtp, NULL);
-
- /* Update our last rtprx when we receive an SDP, too */
- p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */
-
- memset(p->offered_media, 0, sizeof(p->offered_media));
-
-
- /* default: novideo and notext set */
- p->novideo = TRUE;
- p->notext = TRUE;
-
- if (p->vrtp) {
- ast_rtp_codecs_payloads_clear(&newvideortp, NULL);
- }
-
- if (p->trtp) {
- ast_rtp_codecs_payloads_clear(&newtextrtp, NULL);
- }
-
- /* Scan for the first media stream (m=) line to limit scanning of globals */
- nextm = get_sdp_iterate(&next, req, "m");
- if (ast_strlen_zero(nextm)) {
- ast_log(LOG_WARNING, "Insufficient information for SDP (m= not found)\n");
- return -1;
- }
-
- /* Scan session level SDP parameters (lines before first media stream) */
- while ((type = get_sdp_line(&iterator, next - 1, req, &value)) != '\0') {
- int processed = FALSE;
- switch (type) {
- case 'o':
- /* If we end up receiving SDP that doesn't actually modify the session we don't want to treat this as a fatal
- * error. We just want to ignore the SDP and let the rest of the packet be handled as normal.
- */
- if (!process_sdp_o(value, p))
- return (p->session_modify == FALSE) ? 0 : -1;
- break;
- case 'c':
- if (process_sdp_c(value, &sessionhp)) {
- processed = TRUE;
- hp = &sessionhp.hp;
- vhp = hp;
- thp = hp;
- ihp = hp;
- }
- break;
- case 'a':
- if (process_sdp_a_sendonly(value, &sendonly)) {
- processed = TRUE;
- vsendonly = sendonly;
- }
- else if (process_sdp_a_audio(value, p, &newaudiortp, &last_rtpmap_codec))
- processed = TRUE;
- else if (process_sdp_a_video(value, p, &newvideortp, &last_rtpmap_codec))
- processed = TRUE;
- else if (process_sdp_a_text(value, p, &newtextrtp, red_fmtp, &red_num_gen, red_data_pt, &last_rtpmap_codec))
- processed = TRUE;
- else if (process_sdp_a_image(value, p))
- processed = TRUE;
- break;
- }
-
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Processing session-level SDP %c=%s... %s\n", type, value, (processed == TRUE)? "OK." : "UNSUPPORTED.");
- }
-
-
-
- /* Scan media stream (m=) specific parameters loop */
- while (!ast_strlen_zero(nextm)) {
- int audio = FALSE;
- int video = FALSE;
- int image = FALSE;
- int text = FALSE;
- char protocol[5] = {0,};
- int x;
-
- numberofports = 1;
- len = -1;
- start = next;
- m = nextm;
- iterator = next;
- nextm = get_sdp_iterate(&next, req, "m");
-
- /* Search for audio media definition */
- if ((sscanf(m, "audio %30u/%30u RTP/%4s %n", &x, &numberofports, protocol, &len) == 3 && len > 0) ||
- (sscanf(m, "audio %30u RTP/%4s %n", &x, protocol, &len) == 2 && len > 0)) {
- if (!strcmp(protocol, "SAVP")) {
- secure_audio = 1;
- } else if (strcmp(protocol, "AVP")) {
- ast_log(LOG_WARNING, "unknown SDP media protocol in offer: %s\n", protocol);
- continue;
- }
- audio = TRUE;
- p->offered_media[SDP_AUDIO].offered = TRUE;
- numberofmediastreams++;
- portno = x;
-
- /* Scan through the RTP payload types specified in a "m=" line: */
- codecs = m + len;
- ast_copy_string(p->offered_media[SDP_AUDIO].codecs, codecs, sizeof(p->offered_media[SDP_AUDIO].codecs));
- for (; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) {
- if (sscanf(codecs, "%30u%n", &codec, &len) != 1) {
- ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs);
- return -1;
- }
- if (debug)
- ast_verbose("Found RTP audio format %d\n", codec);
-
- ast_rtp_codecs_payloads_set_m_type(&newaudiortp, NULL, codec);
- }
- /* Search for video media definition */
- } else if ((sscanf(m, "video %30u/%30u RTP/%4s %n", &x, &numberofports, protocol, &len) == 3 && len > 0) ||
- (sscanf(m, "video %30u RTP/%4s %n", &x, protocol, &len) == 2 && len >= 0)) {
- if (!strcmp(protocol, "SAVP")) {
- secure_video = 1;
- } else if (strcmp(protocol, "AVP")) {
- ast_log(LOG_WARNING, "unknown SDP media protocol in offer: %s\n", protocol);
- continue;
- }
- video = TRUE;
- p->novideo = FALSE;
- p->offered_media[SDP_VIDEO].offered = TRUE;
- numberofmediastreams++;
- vportno = x;
-
- /* Scan through the RTP payload types specified in a "m=" line: */
- codecs = m + len;
- ast_copy_string(p->offered_media[SDP_VIDEO].codecs, codecs, sizeof(p->offered_media[SDP_VIDEO].codecs));
- for (; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) {
- if (sscanf(codecs, "%30u%n", &codec, &len) != 1) {
- ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs);
- return -1;
- }
- if (debug)
- ast_verbose("Found RTP video format %d\n", codec);
- ast_rtp_codecs_payloads_set_m_type(&newvideortp, NULL, codec);
- }
- /* Search for text media definition */
- } else if ((sscanf(m, "text %30u/%30u RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) ||
- (sscanf(m, "text %30u RTP/AVP %n", &x, &len) == 1 && len > 0)) {
- text = TRUE;
- p->notext = FALSE;
- p->offered_media[SDP_TEXT].offered = TRUE;
- numberofmediastreams++;
- tportno = x;
-
- /* Scan through the RTP payload types specified in a "m=" line: */
- codecs = m + len;
- ast_copy_string(p->offered_media[SDP_TEXT].codecs, codecs, sizeof(p->offered_media[SDP_TEXT].codecs));
- for (; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) {
- if (sscanf(codecs, "%30u%n", &codec, &len) != 1) {
- ast_log(LOG_WARNING, "Error in codec string '%s'\n", codecs);
- return -1;
- }
- if (debug)
- ast_verbose("Found RTP text format %d\n", codec);
- ast_rtp_codecs_payloads_set_m_type(&newtextrtp, NULL, codec);
- }
- /* Search for image media definition */
- } else if (p->udptl && ((sscanf(m, "image %30u udptl t38%n", &x, &len) == 1 && len > 0) ||
- (sscanf(m, "image %30u UDPTL t38%n", &x, &len) == 1 && len > 0) )) {
- image = TRUE;
- if (debug)
- ast_verbose("Got T.38 offer in SDP in dialog %s\n", p->callid);
- p->offered_media[SDP_IMAGE].offered = TRUE;
- udptlportno = x;
- numberofmediastreams++;
-
- if (p->t38.state != T38_ENABLED) {
- memset(&p->t38.their_parms, 0, sizeof(p->t38.their_parms));
- }
- } else {
- ast_log(LOG_WARNING, "Unsupported SDP media type in offer: %s\n", m);
- continue;
- }
-
- /* Check for number of ports */
- if (numberofports > 1)
- ast_log(LOG_WARNING, "SDP offered %d ports for media, not supported by Asterisk. Will try anyway...\n", numberofports);
-
- /* Media stream specific parameters */
- while ((type = get_sdp_line(&iterator, next - 1, req, &value)) != '\0') {
- int processed = FALSE;
-
- switch (type) {
- case 'c':
- if (audio) {
- if (process_sdp_c(value, &audiohp)) {
- processed = TRUE;
- hp = &audiohp.hp;
- }
- } else if (video) {
- if (process_sdp_c(value, &videohp)) {
- processed = TRUE;
- vhp = &videohp.hp;
- }
- } else if (text) {
- if (process_sdp_c(value, &texthp)) {
- processed = TRUE;
- thp = &texthp.hp;
- }
- } else if (image) {
- if (process_sdp_c(value, &imagehp)) {
- processed = TRUE;
- ihp = &imagehp.hp;
- }
- }
- break;
- case 'a':
- /* Audio specific scanning */
- if (audio) {
- if (process_sdp_a_sendonly(value, &sendonly))
- processed = TRUE;
- else if (process_crypto(p, p->rtp, &p->srtp, value))
- processed = TRUE;
- else if (process_sdp_a_audio(value, p, &newaudiortp, &last_rtpmap_codec))
- processed = TRUE;
- }
- /* Video specific scanning */
- else if (video) {
- if (process_sdp_a_sendonly(value, &vsendonly))
- processed = TRUE;
- else if (process_crypto(p, p->vrtp, &p->vsrtp, value))
- processed = TRUE;
- else if (process_sdp_a_video(value, p, &newvideortp, &last_rtpmap_codec))
- processed = TRUE;
- }
- /* Text (T.140) specific scanning */
- else if (text) {
- if (process_sdp_a_text(value, p, &newtextrtp, red_fmtp, &red_num_gen, red_data_pt, &last_rtpmap_codec))
- processed = TRUE;
- else if (process_crypto(p, p->trtp, &p->tsrtp, value))
- processed = TRUE;
- }
- /* Image (T.38 FAX) specific scanning */
- else if (image) {
- if (process_sdp_a_image(value, p))
- processed = TRUE;
- }
- break;
- }
-
- if (option_debug > 2)
- ast_log(LOG_DEBUG, "Processing media-level (%s) SDP %c=%s... %s\n",
- (audio == TRUE)? "audio" : (video == TRUE)? "video" : "image",
- type, value,
- (processed == TRUE)? "OK." : "UNSUPPORTED.");
- }
- }
-
-
- /* Sanity checks */
- if (!hp && !vhp && !thp && !ihp) {
- ast_log(LOG_WARNING, "Insufficient information in SDP (c=)...\n");
- return -1;
- }
-
- 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 */
- ast_log(LOG_WARNING, "Failing due to no acceptable offer found\n");
- return -2;
- }
-
- if (numberofmediastreams > 3) {
- /* We have too many fax, audio and/or video and/or text media streams, fail this offer */
- ast_log(LOG_WARNING, "Faling due to too many media streams\n");
- return -3;
- }
-
- if (secure_audio && !(p->srtp && (ast_test_flag(p->srtp, SRTP_CRYPTO_OFFER_OK)))) {
- ast_log(LOG_WARNING, "Can't provide secure audio requested in SDP offer\n");
- return -4;
- }
-
- if (!secure_audio && p->srtp) {
- ast_log(LOG_WARNING, "We are requesting SRTP, but they responded without it!\n");
- return -4;
- }
-
- if (secure_video && !(p->vsrtp && (ast_test_flag(p->vsrtp, SRTP_CRYPTO_OFFER_OK)))) {
- ast_log(LOG_WARNING, "Can't provide secure video requested in SDP offer\n");
- return -4;
- }
-
- if (!p->novideo && !secure_video && p->vsrtp) {
- ast_log(LOG_WARNING, "We are requesting SRTP, but they responded without it!\n");
- return -4;
- }
-
- if (!(secure_audio || secure_video) && ast_test_flag(&p->flags[1], SIP_PAGE2_USE_SRTP)) {
- ast_log(LOG_WARNING, "Matched device setup to use SRTP, but request was not!\n");
- return -4;
- }
-
- if (udptlportno == -1) {
- change_t38_state(p, T38_DISABLED);
- }
-
- /* Now gather all of the codecs that we are asked for: */
- ast_rtp_codecs_payload_formats(&newaudiortp, &peercapability, &peernoncodeccapability);
- ast_rtp_codecs_payload_formats(&newvideortp, &vpeercapability, &vpeernoncodeccapability);
- ast_rtp_codecs_payload_formats(&newtextrtp, &tpeercapability, &tpeernoncodeccapability);
-
- newjointcapability = p->capability & (peercapability | vpeercapability | tpeercapability);
- newpeercapability = (peercapability | vpeercapability | tpeercapability);
- newnoncodeccapability = p->noncodeccapability & peernoncodeccapability;
-
- if (debug) {
- /* shame on whoever coded this.... */
- char s1[SIPBUFSIZE], s2[SIPBUFSIZE], s3[SIPBUFSIZE], s4[SIPBUFSIZE], s5[SIPBUFSIZE];
-
- ast_verbose("Capabilities: us - %s, peer - audio=%s/video=%s/text=%s, combined - %s\n",
- ast_getformatname_multiple(s1, SIPBUFSIZE, p->capability),
- ast_getformatname_multiple(s2, SIPBUFSIZE, peercapability),
- ast_getformatname_multiple(s3, SIPBUFSIZE, vpeercapability),
- ast_getformatname_multiple(s4, SIPBUFSIZE, tpeercapability),
- ast_getformatname_multiple(s5, SIPBUFSIZE, newjointcapability));
- }
- if (debug) {
- struct ast_str *s1 = ast_str_alloca(SIPBUFSIZE);
- struct ast_str *s2 = ast_str_alloca(SIPBUFSIZE);
- struct ast_str *s3 = ast_str_alloca(SIPBUFSIZE);
-
- ast_verbose("Non-codec capabilities (dtmf): us - %s, peer - %s, combined - %s\n",
- ast_rtp_lookup_mime_multiple2(s1, p->noncodeccapability, 0, 0),
- ast_rtp_lookup_mime_multiple2(s2, peernoncodeccapability, 0, 0),
- ast_rtp_lookup_mime_multiple2(s3, newnoncodeccapability, 0, 0));
- }
- if (!newjointcapability && (portno != -1)) {
- ast_log(LOG_NOTICE, "No compatible codecs, not accepting this offer!\n");
- /* Do NOT Change current setting */
- return -1;
- }
-
- /* Setup audio address and port */
- if (p->rtp) {
- if (portno > 0) {
- sin.sin_family = AF_INET;
- sin.sin_port = htons(portno);
- memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
- ast_rtp_instance_set_remote_address(p->rtp, &sin);
- if (debug)
- ast_verbose("Peer audio RTP is at port %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port));
- /* We are now ready to change the sip session and p->rtp and p->vrtp with the offered codecs, since
- they are acceptable */
- p->jointcapability = newjointcapability; /* Our joint codec profile for this call */
- p->peercapability = newpeercapability; /* The other sides capability in latest offer */
- p->jointnoncodeccapability = newnoncodeccapability; /* DTMF capabilities */
-
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_PREFERRED_CODEC)) { /* respond with single most preferred joint codec, limiting the other side's choice */
- p->jointcapability = ast_codec_choose(&p->prefs, p->jointcapability, 1);
- }
-
- ast_rtp_codecs_payloads_copy(&newaudiortp, ast_rtp_instance_get_codecs(p->rtp), p->rtp);
-
- if (ast_test_flag(&p->flags[0], SIP_DTMF) == SIP_DTMF_AUTO) {
- ast_clear_flag(&p->flags[0], SIP_DTMF);
- if (newnoncodeccapability & AST_RTP_DTMF) {
- /* XXX Would it be reasonable to drop the DSP at this point? XXX */
- ast_set_flag(&p->flags[0], SIP_DTMF_RFC2833);
- /* Since RFC2833 is now negotiated we need to change some properties of the RTP stream */
- ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF, 1);
- ast_rtp_instance_set_prop(p->rtp, AST_RTP_PROPERTY_DTMF_COMPENSATE, ast_test_flag(&p->flags[1], SIP_PAGE2_RFC2833_COMPENSATE));
- } else {
- ast_set_flag(&p->flags[0], SIP_DTMF_INBAND);
- }
- }
- } else if (udptlportno > 0) {
- if (debug)
- ast_verbose("Got T.38 Re-invite without audio. Keeping RTP active during T.38 session.\n");
- } else {
- ast_rtp_instance_stop(p->rtp);
- if (debug)
- ast_verbose("Peer doesn't provide audio\n");
- }
- }
-
- /* Setup video address and port */
- if (p->vrtp) {
- if (vportno > 0) {
- vsin.sin_family = AF_INET;
- vsin.sin_port = htons(vportno);
- memcpy(&vsin.sin_addr, vhp->h_addr, sizeof(vsin.sin_addr));
- ast_rtp_instance_set_remote_address(p->vrtp, &vsin);
- if (debug)
- ast_verbose("Peer video RTP is at port %s:%d\n", ast_inet_ntoa(vsin.sin_addr), ntohs(vsin.sin_port));
- ast_rtp_codecs_payloads_copy(&newvideortp, ast_rtp_instance_get_codecs(p->vrtp), p->vrtp);
- } else {
- ast_rtp_instance_stop(p->vrtp);
- if (debug)
- ast_verbose("Peer doesn't provide video\n");
- }
- }
-
- /* Setup text address and port */
- if (p->trtp) {
- if (tportno > 0) {
- tsin.sin_family = AF_INET;
- tsin.sin_port = htons(tportno);
- memcpy(&tsin.sin_addr, thp->h_addr, sizeof(tsin.sin_addr));
- ast_rtp_instance_set_remote_address(p->trtp, &tsin);
- if (debug)
- ast_verbose("Peer T.140 RTP is at port %s:%d\n", ast_inet_ntoa(tsin.sin_addr), ntohs(tsin.sin_port));
- if ((p->jointcapability & AST_FORMAT_T140RED)) {
- p->red = 1;
- ast_rtp_red_init(p->trtp, 300, red_data_pt, 2);
- } else {
- p->red = 0;
- }
- ast_rtp_codecs_payloads_copy(&newtextrtp, ast_rtp_instance_get_codecs(p->trtp), p->trtp);
- } else {
- ast_rtp_instance_stop(p->trtp);
- if (debug)
- ast_verbose("Peer doesn't provide T.140\n");
- }
- }
- /* Setup image address and port */
- if (p->udptl) {
- if (udptlportno > 0) {
- isin.sin_family = AF_INET;
- isin.sin_port = htons(udptlportno);
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_SYMMETRICRTP) && ast_test_flag(&p->flags[1], SIP_PAGE2_UDPTL_DESTINATION)) {
- struct sockaddr_in remote_address = { 0, };
- ast_rtp_instance_get_remote_address(p->rtp, &remote_address);
- if (remote_address.sin_addr.s_addr) {
- memcpy(&isin, &remote_address, sizeof(isin));
- if (debug) {
- ast_log(LOG_DEBUG, "Peer T.38 UDPTL is set behind NAT and with destination, destination address now %s\n", ast_inet_ntoa(isin.sin_addr));
- }
- }
- } else {
- memcpy(&isin.sin_addr, ihp->h_addr, sizeof(isin.sin_addr));
- }
- ast_udptl_set_peer(p->udptl, &isin);
- if (debug)
- ast_debug(1,"Peer T.38 UDPTL is at port %s:%d\n", ast_inet_ntoa(isin.sin_addr), ntohs(isin.sin_port));
-
- /* verify the far max ifp can be calculated. this requires far max datagram to be set. */
- if (!ast_udptl_get_far_max_datagram(p->udptl)) {
- /* setting to zero will force a default if none was provided by the SDP */
- ast_udptl_set_far_max_datagram(p->udptl, 0);
- }
-
- /* Remote party offers T38, we need to update state */
- if ((t38action == SDP_T38_ACCEPT) &&
- (p->t38.state == T38_LOCAL_REINVITE)) {
- change_t38_state(p, T38_ENABLED);
- } else if ((t38action == SDP_T38_INITIATE) &&
- p->owner && p->lastinvite) {
- change_t38_state(p, T38_PEER_REINVITE); /* T38 Offered in re-invite from remote party */
- /* If fax detection is enabled then send us off to the fax extension */
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_FAX_DETECT_T38)) {
- ast_channel_lock(p->owner);
- if (strcmp(p->owner->exten, "fax")) {
- const char *target_context = S_OR(p->owner->macrocontext, p->owner->context);
- ast_channel_unlock(p->owner);
- if (ast_exists_extension(p->owner, target_context, "fax", 1, p->owner->cid.cid_num)) {
- ast_verbose(VERBOSE_PREFIX_2 "Redirecting '%s' to fax extension due to peer T.38 re-INVITE\n", p->owner->name);
- pbx_builtin_setvar_helper(p->owner, "FAXEXTEN", p->owner->exten);
- if (ast_async_goto(p->owner, target_context, "fax", 1)) {
- ast_log(LOG_NOTICE, "Failed to async goto '%s' into fax of '%s'\n", p->owner->name, target_context);
- }
- } else {
- ast_log(LOG_NOTICE, "T.38 re-INVITE detected but no fax extension\n");
- }
- } else {
- ast_channel_unlock(p->owner);
- }
- }
- }
- } else {
- ast_udptl_stop(p->udptl);
- if (debug)
- ast_debug(1, "Peer doesn't provide T.38 UDPTL\n");
- }
- }
-
- if ((portno == -1) && (p->t38.state != T38_DISABLED)) {
- ast_debug(3, "Have T.38 but no audio, accepting offer anyway\n");
- return 0;
- }
-
- /* Ok, we're going with this offer */
- ast_debug(2, "We're settling with these formats: %s\n", ast_getformatname_multiple(buf, SIPBUFSIZE, p->jointcapability));
-
- if (!p->owner) /* There's no open channel owning us so we can return here. For a re-invite or so, we proceed */
- return 0;
-
- ast_debug(4, "We have an owner, now see if we need to change this call\n");
-
- if (!(p->owner->nativeformats & p->jointcapability) && (p->jointcapability & AST_FORMAT_AUDIO_MASK)) {
- if (debug) {
- char s1[SIPBUFSIZE], s2[SIPBUFSIZE];
- ast_debug(1, "Oooh, we need to change our audio formats since our peer supports only %s and not %s\n",
- ast_getformatname_multiple(s1, SIPBUFSIZE, p->jointcapability),
- ast_getformatname_multiple(s2, SIPBUFSIZE, p->owner->nativeformats));
- }
- p->owner->nativeformats = ast_codec_choose(&p->prefs, p->jointcapability, 1) | (p->capability & vpeercapability) | (p->capability & tpeercapability);
- ast_set_read_format(p->owner, p->owner->readformat);
- ast_set_write_format(p->owner, p->owner->writeformat);
- }
-
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) && sin.sin_addr.s_addr && (!sendonly || sendonly == -1)) {
- ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
- /* Activate a re-invite */
- ast_queue_frame(p->owner, &ast_null_frame);
- /* Queue Manager Unhold event */
- append_history(p, "Unhold", "%s", req->data->str);
- if (sip_cfg.callevents)
- ast_manager_event(p->owner, EVENT_FLAG_CALL, "Hold",
- "Status: Off\r\n"
- "Channel: %s\r\n"
- "Uniqueid: %s\r\n",
- p->owner->name,
- p->owner->uniqueid);
- if (sip_cfg.notifyhold)
- sip_peer_hold(p, FALSE);
- ast_clear_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD); /* Clear both flags */
- } else if (!sin.sin_addr.s_addr || (sendonly && sendonly != -1)) {
- int already_on_hold = ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD);
- ast_queue_control_data(p->owner, AST_CONTROL_HOLD,
- S_OR(p->mohsuggest, NULL),
- !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
- if (sendonly)
- ast_rtp_instance_stop(p->rtp);
- /* RTCP needs to go ahead, even if we're on hold!!! */
- /* Activate a re-invite */
- ast_queue_frame(p->owner, &ast_null_frame);
- /* Queue Manager Hold event */
- append_history(p, "Hold", "%s", req->data->str);
- if (sip_cfg.callevents && !ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD)) {
- ast_manager_event(p->owner, EVENT_FLAG_CALL, "Hold",
- "Status: On\r\n"
- "Channel: %s\r\n"
- "Uniqueid: %s\r\n",
- p->owner->name,
- p->owner->uniqueid);
- }
- if (sendonly == 1) /* One directional hold (sendonly/recvonly) */
- ast_set_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_ONEDIR);
- else if (sendonly == 2) /* Inactive stream */
- ast_set_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_INACTIVE);
- else
- ast_set_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD_ACTIVE);
- if (sip_cfg.notifyhold && !already_on_hold)
- sip_peer_hold(p, TRUE);
- }
-
- return 0;
-}
-
-static int process_sdp_o(const char *o, struct sip_pvt *p)
-{
- char *o_copy;
- char *token;
- int64_t rua_version;
-
- /* 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. */
-
- p->session_modify = TRUE;
-
- if (ast_strlen_zero(o)) {
- ast_log(LOG_WARNING, "SDP syntax error. SDP without an o= line\n");
- return FALSE;
- }
-
- o_copy = ast_strdupa(o);
- token = strsep(&o_copy, " "); /* Skip username */
- if (!o_copy) {
- ast_log(LOG_WARNING, "SDP syntax error in o= line username\n");
- return FALSE;
- }
- token = strsep(&o_copy, " "); /* Skip session-id */
- if (!o_copy) {
- ast_log(LOG_WARNING, "SDP syntax error in o= line session-id\n");
- return FALSE;
- }
- token = strsep(&o_copy, " "); /* Version */
- if (!o_copy) {
- ast_log(LOG_WARNING, "SDP syntax error in o= line\n");
- return FALSE;
- }
- if (!sscanf(token, "%30" SCNd64, &rua_version)) {
- ast_log(LOG_WARNING, "SDP syntax error in o= line version\n");
- return FALSE;
- }
-
- /* we need to check the SDP version number the other end sent us;
- * our rules for deciding what to accept are a bit complex.
- *
- * 1) if 'ignoresdpversion' has been set for this dialog, then
- * we will just accept whatever they sent and assume it is
- * a modification of the session, even if it is not
- * 2) otherwise, if this is the first SDP we've seen from them
- * we accept it
- * 3) otherwise, if the new SDP version number is higher than the
- * old one, we accept it
- * 4) otherwise, if this SDP is in response to us requesting a switch
- * to T.38, we accept the SDP, but also generate a warning message
- * that this peer should have the 'ignoresdpversion' option set,
- * because it is not following the SDP offer/answer RFC; if we did
- * not request a switch to T.38, then we stop parsing the SDP, as it
- * has not changed from the previous version
- */
-
- if (ast_test_flag(&p->flags[1], SIP_PAGE2_IGNORESDPVERSION) ||
- (p->sessionversion_remote < 0) ||
- (p->sessionversion_remote < rua_version)) {
- p->sessionversion_remote = rua_version;
- } else {
- if (p->t38.state == T38_LOCAL_REINVITE) {
- p->sessionversion_remote = rua_version;
- ast_log(LOG_WARNING, "Call %s responded to our T.38 reinvite without changing SDP version; 'ignoresdpversion' should be set for this peer.\n", p->callid);
- } else {
- p->session_modify = FALSE;
- ast_debug(2, "Call %s responded to our reinvite without changing SDP version; ignoring SDP.\n", p->callid);
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-static int process_sdp_c(const char *c, struct ast_hostent *ast_hp)
-{
- char host[258];
- struct hostent *hp;
-
- /* Check for Media-description-level-address */
- if (sscanf(c, "IN IP4 %255s", host) != 1) {
- ast_log(LOG_WARNING, "Invalid host in c= line, '%s'\n", c);
- return FALSE;
- } else {
- if (!(hp = ast_gethostbyname(host, ast_hp))) {
- ast_log(LOG_WARNING, "Unable to lookup RTP Audio host in c= line, '%s'\n", c);
- return FALSE;
- }
- return TRUE;
- }
- return FALSE;
-}
-
-static int process_sdp_a_sendonly(const char *a, int *sendonly)
-{
- int found = FALSE;
-
- if (!strcasecmp(a, "sendonly")) {
- if (*sendonly == -1)
- *sendonly = 1;
- found = TRUE;
- } else if (!strcasecmp(a, "inactive")) {
- if (*sendonly == -1)
- *sendonly = 2;
- found = TRUE;
- } else if (!strcasecmp(a, "sendrecv")) {
- if (*sendonly == -1)
- *sendonly = 0;
- found = TRUE;
- }
- return found;
-}
-
-static int process_sdp_a_audio(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newaudiortp, int *last_rtpmap_codec)
-{
- int found = FALSE;
- int codec;
- char mimeSubtype[128];
- char fmtp_string[64];
- unsigned int sample_rate;
- int debug = sip_debug_test_pvt(p);
-
- if (!strncasecmp(a, "ptime", 5)) {
- char *tmp = strrchr(a, ':');
- long int framing = 0;
- if (tmp) {
- tmp++;
- framing = strtol(tmp, NULL, 10);
- if (framing == LONG_MIN || framing == LONG_MAX) {
- framing = 0;
- ast_debug(1, "Can't read framing from SDP: %s\n", a);
- }
- }
- if (framing && p->autoframing) {
- struct ast_codec_pref *pref = &ast_rtp_instance_get_codecs(p->rtp)->pref;
- int codec_n;
- for (codec_n = 0; codec_n < AST_RTP_MAX_PT; codec_n++) {
- struct ast_rtp_payload_type format = ast_rtp_codecs_payload_lookup(ast_rtp_instance_get_codecs(p->rtp), codec_n);
- if (!format.asterisk_format || !format.code) /* non-codec or not found */
- continue;
- if (option_debug)
- ast_log(LOG_DEBUG, "Setting framing for %s to %ld\n", ast_getformatname(format.code), framing);
- ast_codec_pref_setsize(pref, format.code, framing);
- }
- ast_rtp_codecs_packetization_set(ast_rtp_instance_get_codecs(p->rtp), p->rtp, pref);
- }
- found = TRUE;
- } else if (sscanf(a, "rtpmap: %30u %127[^/]/%30u", &codec, mimeSubtype, &sample_rate) == 3) {
- /* We have a rtpmap to handle */
- if (*last_rtpmap_codec < SDP_MAX_RTPMAP_CODECS) {
- if (ast_rtp_codecs_payloads_set_rtpmap_type_rate(newaudiortp, NULL, codec, "audio", mimeSubtype,
- ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0, sample_rate) != -1) {
- if (debug)
- ast_verbose("Found audio description format %s for ID %d\n", mimeSubtype, codec);
- //found_rtpmap_codecs[last_rtpmap_codec] = codec;
- (*last_rtpmap_codec)++;
- found = TRUE;
- } else {
- ast_rtp_codecs_payloads_unset(newaudiortp, NULL, codec);
- if (debug)
- ast_verbose("Found unknown media description format %s for ID %d\n", mimeSubtype, codec);
- }
- } else {
- if (debug)
- ast_verbose("Discarded description format %s for ID %d\n", mimeSubtype, codec);
- }
- } else if (sscanf(a, "fmtp: %30u %63s", &codec, fmtp_string) == 2) {
- struct ast_rtp_payload_type payload;
-
- payload = ast_rtp_codecs_payload_lookup(newaudiortp, codec);
- if (payload.code && payload.asterisk_format) {
- unsigned int bit_rate;
-
- switch (payload.code) {
- case AST_FORMAT_SIREN7:
- if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) {
- if (bit_rate != 32000) {
- ast_log(LOG_WARNING, "Got Siren7 offer at %d bps, but only 32000 bps supported; ignoring.\n", bit_rate);
- ast_rtp_codecs_payloads_unset(newaudiortp, NULL, codec);
- } else {
- found = TRUE;
- }
- }
- break;
- case AST_FORMAT_SIREN14:
- if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) {
- if (bit_rate != 48000) {
- ast_log(LOG_WARNING, "Got Siren14 offer at %d bps, but only 48000 bps supported; ignoring.\n", bit_rate);
- ast_rtp_codecs_payloads_unset(newaudiortp, NULL, codec);
- } else {
- found = TRUE;
- }
- }
- break;
- case AST_FORMAT_G719:
- if (sscanf(fmtp_string, "bitrate=%30u", &bit_rate) == 1) {
- if (bit_rate != 64000) {
- ast_log(LOG_WARNING, "Got G.719 offer at %d bps, but only 64000 bps supported; ignoring.\n", bit_rate);
- ast_rtp_codecs_payloads_unset(newaudiortp, NULL, codec);
- } else {
- found = TRUE;
- }
- }
- }
- }
- }
-
- return found;
-}
-
-static int process_sdp_a_video(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newvideortp, int *last_rtpmap_codec)
-{
- int found = FALSE;
- int codec;
- char mimeSubtype[128];
- unsigned int sample_rate;
- int debug = sip_debug_test_pvt(p);
-
- if (sscanf(a, "rtpmap: %30u %127[^/]/%30u", &codec, mimeSubtype, &sample_rate) == 3) {
- /* We have a rtpmap to handle */
- if (*last_rtpmap_codec < SDP_MAX_RTPMAP_CODECS) {
- /* Note: should really look at the '#chans' params too */
- if (!strncasecmp(mimeSubtype, "H26", 3) || !strncasecmp(mimeSubtype, "MP4", 3)) {
- if (ast_rtp_codecs_payloads_set_rtpmap_type_rate(newvideortp, NULL, codec, "video", mimeSubtype, 0, sample_rate) != -1) {
- if (debug)
- ast_verbose("Found video description format %s for ID %d\n", mimeSubtype, codec);
- //found_rtpmap_codecs[last_rtpmap_codec] = codec;
- (*last_rtpmap_codec)++;
- found = TRUE;
- } else {
- ast_rtp_codecs_payloads_unset(newvideortp, NULL, codec);
- if (debug)
- ast_verbose("Found unknown media description format %s for ID %d\n", mimeSubtype, codec);
- }
- }
- } else {
- if (debug)
- ast_verbose("Discarded description format %s for ID %d\n", mimeSubtype, codec);
- }
- }
-
- return found;
-}
-
-static int process_sdp_a_text(const char *a, struct sip_pvt *p, struct ast_rtp_codecs *newtextrtp, char *red_fmtp, int *red_num_gen, int *red_data_pt, int *last_rtpmap_codec)
-{
- int found = FALSE;
- int codec;
- char mimeSubtype[128];
- unsigned int sample_rate;
- char *red_cp;
- int debug = sip_debug_test_pvt(p);
-
- if (sscanf(a, "rtpmap: %30u %127[^/]/%30u", &codec, mimeSubtype, &sample_rate) == 3) {
- /* We have a rtpmap to handle */
- if (*last_rtpmap_codec < SDP_MAX_RTPMAP_CODECS) {
- if (!strncasecmp(mimeSubtype, "T140", 4)) { /* Text */
- if (p->trtp) {
- /* ast_verbose("Adding t140 mimeSubtype to textrtp struct\n"); */
- ast_rtp_codecs_payloads_set_rtpmap_type_rate(newtextrtp, NULL, codec, "text", mimeSubtype, 0, sample_rate);
- found = TRUE;
- }
- } else if (!strncasecmp(mimeSubtype, "RED", 3)) { /* Text with Redudancy */
- if (p->trtp) {
- ast_rtp_codecs_payloads_set_rtpmap_type_rate(newtextrtp, NULL, codec, "text", mimeSubtype, 0, sample_rate);
- sprintf(red_fmtp, "fmtp:%d ", codec);
- if (debug)
- ast_verbose("RED submimetype has payload type: %d\n", codec);
- found = TRUE;
- }
- }
- } else {
- if (debug)
[... 124 lines stripped ...]
More information about the asterisk-commits
mailing list