Index: channels/chan_sip.c =================================================================== --- channels/chan_sip.c (revisiĆ³n: 193045) +++ channels/chan_sip.c (copia de trabajo) @@ -4269,10 +4269,29 @@ return ""; } +/*! \brief Lookup 'name' in the SDP between the 'start' line + * and until the 'stop' line. Returns the matching line, and 'start' + * is updated with the next line number. + */ +static const char *get_sdp_iterate_until(int *start, int stop, struct sip_request *req, const char *name) +{ + int len = strlen(name); + + if(stop > req->sdp_end || stop < req->sdp_start) stop = req->sdp_end; + + while (*start < stop) { + const char *r = get_body_by_line(req->line[(*start)++], name, len); + if (r[0] != '\0') + return r; + } + + return ""; +} + /*! \brief Get a line from an SDP message body */ static const char *get_sdp(struct sip_request *req, const char *name) { - int dummy = 0; + int dummy = req->sdp_start; return get_sdp_iterate(&dummy, req, name); } @@ -4856,7 +4875,7 @@ /*! \brief Parse multiline SIP headers into one header This is enabled if pedanticsipchecking is enabled */ -static int lws2sws(char *msgbuf, int len) +static int lws2sws(char *msgbuf, int len) { int h = 0, t = 0; int lws = 0; @@ -5117,9 +5136,10 @@ */ static int process_sdp(struct sip_pvt *p, struct sip_request *req) { - const char *m; /* SDP media offer */ - const char *c; - const char *a; + const char *m = NULL; /* SDP media offer */ + const char *nextm = NULL; + const char *c = NULL; + const char *a = NULL; char host[258]; int len = -1; int portno = -1; /*!< RTP Audio port number */ @@ -5136,13 +5156,18 @@ struct sockaddr_in vsin; /*!< Video socket address */ const char *codecs; - struct hostent *hp; /*!< RTP Audio host IP */ + struct hostent *hp = NULL; /*!< RTP Audio host IP */ struct hostent *vhp = NULL; /*!< RTP video host IP */ struct ast_hostent audiohp; struct ast_hostent videohp; int codec; - int destiterator = 0; - int iterator; + + /* iterators for SDP parsing */ + int start = req->sdp_start; + int next = req->sdp_start; + int aiterator = req->sdp_start; + int citerator = req->sdp_start; + int sendonly = -1; int numberofports; struct ast_rtp *newaudiortp, *newvideortp; /* Buffers for codec handling */ @@ -5182,47 +5207,59 @@ /* Update our last rtprx when we receive an SDP, too */ p->lastrtprx = p->lastrtptx = time(NULL); /* XXX why both ? */ +/**************/ +/**************/ + /* Scan for the first media stream (m=) line */ + nextm = get_sdp_iterate(&next, req, "m"); - /* 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); + if(ast_strlen_zero(nextm)) { + ast_log(LOG_WARNING, "Insufficient information for SDP (m = '%s')\n", m); 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; - } + ast_set_flag(&p->flags[0], SIP_NOVIDEO); - /* 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; + /* Scan global SDP parameters (lines before first media stream) */ + c = get_sdp_iterate_until(&citerator, next, req, "c"); + if(!ast_strlen_zero(c)) { + /* 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 */ } - vhp = hp; /* Copy to video address as default too */ - - iterator = req->sdp_start; - ast_set_flag(&p->flags[0], SIP_NOVIDEO); - /* Find media streams in this SDP offer */ - while ((m = get_sdp_iterate(&iterator, req, "m"))[0] != '\0') { + /* Scan media stream (m=) parameters loop */ + while(!ast_strlen_zero(nextm)) { + start = next; + citerator = start; + aiterator = start; + m = nextm; + nextm = get_sdp_iterate(&next, req, "m"); + + /* parse media stream (m=) line */ int x; int audio = FALSE; - + int video = FALSE; + int image = FALSE; numberofports = 1; len = -1; if ((sscanf(m, "audio %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) || (sscanf(m, "audio %d RTP/AVP %n", &x, &len) == 1 && len > 0)) { + /* Found audio stream in this media definition */ audio = TRUE; numberofmediastreams++; - /* Found audio stream in this media definition */ portno = x; + /* Scan through the RTP payload types specified in a "m=" line: */ for (codecs = m + len; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) { if (sscanf(codecs, "%d%n", &codec, &len) != 1) { @@ -5235,10 +5272,12 @@ } } else if ((sscanf(m, "video %d/%d RTP/AVP %n", &x, &numberofports, &len) == 2 && len > 0) || (sscanf(m, "video %d RTP/AVP %n", &x, &len) == 1 && len >= 0)) { - /* If it is not audio - is it video ? */ + /* Found video stream in this media definition */ + video = TRUE; ast_clear_flag(&p->flags[0], SIP_NOVIDEO); numberofmediastreams++; vportno = x; + /* Scan through the RTP payload types specified in a "m=" line: */ for (codecs = m + len; !ast_strlen_zero(codecs); codecs = ast_skip_blanks(codecs + len)) { if (sscanf(codecs, "%d%n", &codec, &len) != 1) { @@ -5251,6 +5290,8 @@ } } else if (p->udptl && ( (sscanf(m, "image %d udptl t38%n", &x, &len) == 1 && len > 0) || (sscanf(m, "image %d UDPTL t38%n", &x, &len) == 1 && len >= 0) )) { + /* Found image stream in this media definition */ + image = TRUE; if (debug) ast_verbose("Got T.38 offer in SDP in dialog %s\n", p->callid); udptlportno = x; @@ -5268,30 +5309,287 @@ } } else ast_log(LOG_WARNING, "Unsupported SDP media type in offer: %s\n", m); + if (numberofports > 1) ast_log(LOG_WARNING, "SDP offered %d ports for media, not supported by Asterisk. Will try anyway...\n", numberofports); + + + /* Check for Media-description-level-address for audio or video */ + if(audio || video) { + c = get_sdp_iterate_until(&citerator, next, req, "c"); + if (!ast_strlen_zero(c)) { + if (sscanf(c, "IN IP4 %256s", host) != 1) { + ast_log(LOG_WARNING, "Invalid secondary host in c= line, '%s'\n", c); + } else { + /* XXX This could block for a long time, and block the main thread! XXX */ + if (audio) { + if ( !(hp = ast_gethostbyname(host, &audiohp))) { + ast_log(LOG_WARNING, "Unable to lookup RTP Audio host in secondary c= line, '%s'\n", c); + return -2; + } + } else if (video) { + if ( !(vhp = ast_gethostbyname(host, &videohp))) { + ast_log(LOG_WARNING, "Unable to lookup RTP video host in secondary c= line, '%s'\n", c); + return -2; + } + } + } + } + } + + /* media stream specific parameters */ + while ((a = get_sdp_iterate_until(&aiterator, next, req, "a"))[0] != '\0') { + + /* Unsupported scanning if debug */ + if (option_debug > 1) { + int breakout = FALSE; + + /* If we're debugging, check for unsupported sdp options */ + if (!strncasecmp(a, "rtcp:", (size_t) 5)) { + if (debug) + ast_verbose("Got unsupported a:rtcp in SDP offer \n"); + breakout = TRUE; + } else if (!strncasecmp(a, "fmtp:", (size_t) 5)) { + /* Format parameters: Not supported */ + /* Note: This is used for codec parameters, like bitrate for + G722 and video formats for H263 and H264 + See RFC2327 for an example */ + if (debug) + ast_verbose("Got unsupported a:fmtp in SDP offer \n"); + breakout = TRUE; + } else if (!strncasecmp(a, "framerate:", (size_t) 10)) { + /* Video stuff: Not supported */ + if (debug) + ast_verbose("Got unsupported a:framerate in SDP offer \n"); + breakout = TRUE; + } else if (!strncasecmp(a, "maxprate:", (size_t) 9)) { + /* Video stuff: Not supported */ + if (debug) + ast_verbose("Got unsupported a:maxprate in SDP offer \n"); + breakout = TRUE; + } else if (!strncasecmp(a, "crypto:", (size_t) 7)) { + /* SRTP stuff, not yet supported */ + if (debug) + ast_verbose("Got unsupported a:crypto in SDP offer \n"); + breakout = TRUE; + } + if (breakout) /* We have a match, skip to next header */ + continue; + } + + /* Audio and video specific scanning */ + if(audio || video) { + char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */ + if (!strcasecmp(a, "sendonly")) { + if (sendonly == -1) + sendonly = 1; + continue; + } else if (!strcasecmp(a, "inactive")) { + if (sendonly == -1) + sendonly = 2; + continue; + } else if (!strcasecmp(a, "sendrecv")) { + if (sendonly == -1) + sendonly = 0; + continue; + } else if (strlen(a) > 5 && !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; + if (option_debug) + ast_log(LOG_DEBUG, "Can't read framing from SDP: %s\n", a); + } + } + if (framing && p->autoframing) { + struct ast_codec_pref *pref = ast_rtp_codec_getpref(p->rtp); + int codec_n; + int format = 0; + for (codec_n = 0; codec_n < MAX_RTP_PT; codec_n++) { + format = ast_rtp_codec_getformat(codec_n); + if (!format) /* non-codec or not found */ + continue; + if (option_debug) + ast_log(LOG_DEBUG, "Setting framing for %d to %ld\n", format, framing); + ast_codec_pref_setsize(pref, format, framing); + } + ast_rtp_codec_setpref(p->rtp, pref); + } + continue; + } else if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) == 2) { + /* We have a rtpmap to handle */ + int found = FALSE; + + if (last_rtpmap_codec < SDP_MAX_RTPMAP_CODECS) { + /* Note: should really look at the 'freq' and '#chans' params too */ + if(audio) { + if(ast_rtp_set_rtpmap_type(newaudiortp, codec, "audio", mimeSubtype, + ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0) != -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 if (video) { + if(p->vrtp && ast_rtp_set_rtpmap_type(newvideortp, codec, "video", mimeSubtype, 0) != -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 { + if (debug) + ast_verbose("Discarded description format %s for ID %d\n", mimeSubtype, codec); + } + + if (!found) { + /* Remove this codec since it's an unknown media type for us */ + if (audio) + ast_rtp_unset_m_type(newaudiortp, codec); + else if (video) + ast_rtp_unset_m_type(newvideortp, codec); + if (debug) + ast_verbose("Found unknown media description format %s for ID %d\n", mimeSubtype, codec); + } + } + + /* image (T.38 FAX) specific scanning */ + } else if (image) { + if (udptlportno != -1) { + int found = 0, x; + old = 0; + /* Scan trough the a= lines for T38 attributes and set apropriate fileds */ + if ((sscanf(a, "T38FaxMaxBuffer:%d", &x) == 1)) { + found = 1; + if (option_debug > 2) + ast_log(LOG_DEBUG, "MaxBufferSize:%d\n",x); + } else if ((sscanf(a, "T38MaxBitRate:%d", &x) == 1) || (sscanf(a, "T38FaxMaxRate:%d", &x) == 1)) { + found = 1; + if (option_debug > 2) + ast_log(LOG_DEBUG,"T38MaxBitRate: %d\n",x); + switch (x) { + case 14400: + peert38capability |= T38FAX_RATE_14400 | T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400; + break; + case 12000: + peert38capability |= T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400; + break; + case 9600: + peert38capability |= T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400; + break; + case 7200: + peert38capability |= T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400; + break; + case 4800: + peert38capability |= T38FAX_RATE_4800 | T38FAX_RATE_2400; + break; + case 2400: + peert38capability |= T38FAX_RATE_2400; + break; + } + } else if ((sscanf(a, "T38FaxVersion:%d", &x) == 1)) { + found = 1; + if (option_debug > 2) + ast_log(LOG_DEBUG, "FaxVersion: %d\n",x); + if (x == 0) + peert38capability |= T38FAX_VERSION_0; + else if (x == 1) + peert38capability |= T38FAX_VERSION_1; + } else if ((sscanf(a, "T38FaxMaxDatagram:%d", &x) == 1) || (sscanf(a, "T38MaxDatagram:%d", &x) == 1)) { + found = 1; + if (option_debug > 2) + ast_log(LOG_DEBUG, "FaxMaxDatagram: %d\n",x); + ast_udptl_set_far_max_datagram(p->udptl, x); + ast_udptl_set_local_max_datagram(p->udptl, x); + } else if ((strncmp(a, "T38FaxFillBitRemoval", 20) == 0)) { + found = 1; + if ((sscanf(a, "T38FaxFillBitRemoval:%d", &x) == 1)) { + if (option_debug > 2) + ast_log(LOG_DEBUG, "FillBitRemoval: %d\n",x); + if (x == 1) + peert38capability |= T38FAX_FILL_BIT_REMOVAL; + } else { + if (option_debug > 2) + ast_log(LOG_DEBUG, "FillBitRemoval\n"); + peert38capability |= T38FAX_FILL_BIT_REMOVAL; + } + } else if ((strncmp(a, "T38FaxTranscodingMMR", 20) == 0)) { + found = 1; + if ((sscanf(a, "T38FaxTranscodingMMR:%d", &x) == 1)) { + if (option_debug > 2) + ast_log(LOG_DEBUG, "Transcoding MMR: %d\n",x); + if (x == 1) + peert38capability |= T38FAX_TRANSCODING_MMR; + } else { + if (option_debug > 2) + ast_log(LOG_DEBUG, "Transcoding MMR\n"); + peert38capability |= T38FAX_TRANSCODING_MMR; + } + } else if ((strncmp(a, "T38FaxTranscodingJBIG", 21) == 0)) { + found = 1; + if ((sscanf(a, "T38FaxTranscodingJBIG:%d", &x) == 1)) { + if (option_debug > 2) + ast_log(LOG_DEBUG, "Transcoding JBIG: %d\n",x); + if (x == 1) + peert38capability |= T38FAX_TRANSCODING_JBIG; + } else { + if (option_debug > 2) + ast_log(LOG_DEBUG, "Transcoding JBIG\n"); + peert38capability |= T38FAX_TRANSCODING_JBIG; + } + } else if ((sscanf(a, "T38FaxRateManagement:%255s", s) == 1)) { + found = 1; + if (option_debug > 2) + ast_log(LOG_DEBUG, "RateManagement: %s\n", s); + if (!strcasecmp(s, "localTCF")) + peert38capability |= T38FAX_RATE_MANAGEMENT_LOCAL_TCF; + else if (!strcasecmp(s, "transferredTCF")) + peert38capability |= T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF; + } else if ((sscanf(a, "T38FaxUdpEC:%255s", s) == 1)) { + found = 1; + if (option_debug > 2) + ast_log(LOG_DEBUG, "UDP EC: %s\n", s); + if (!strcasecmp(s, "t38UDPRedundancy")) { + peert38capability |= T38FAX_UDP_EC_REDUNDANCY; + ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_REDUNDANCY); + } else if (!strcasecmp(s, "t38UDPFEC")) { + peert38capability |= T38FAX_UDP_EC_FEC; + ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_FEC); + } else { + peert38capability |= T38FAX_UDP_EC_NONE; + ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_NONE); + } + } - /* Check for Media-description-level-address for audio */ - c = get_sdp_iterate(&destiterator, req, "c"); - if (!ast_strlen_zero(c)) { - if (sscanf(c, "IN IP4 %256s", host) != 1) { - ast_log(LOG_WARNING, "Invalid secondary host in c= line, '%s'\n", c); - } else { - /* XXX This could block for a long time, and block the main thread! XXX */ - if (audio) { - if ( !(hp = ast_gethostbyname(host, &audiohp))) { - ast_log(LOG_WARNING, "Unable to lookup RTP Audio host in secondary c= line, '%s'\n", c); - return -2; + if (found) { /* Some cisco equipment returns nothing beside c= and m= lines in 200 OK T38 SDP */ + p->t38.peercapability = peert38capability; + p->t38.jointcapability = (peert38capability & 255); /* Put everything beside supported speeds settings */ + peert38capability &= (T38FAX_RATE_14400 | T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400); + p->t38.jointcapability |= (peert38capability & p->t38.capability); /* Put the lower of our's and peer's speed */ } - } else if (!(vhp = ast_gethostbyname(host, &videohp))) { - ast_log(LOG_WARNING, "Unable to lookup RTP video host in secondary c= line, '%s'\n", c); - return -2; + if (debug) + ast_log(LOG_DEBUG, "Our T38 capability = (%d), peer T38 capability (%d), joint T38 capability (%d)\n", + p->t38.capability, + p->t38.peercapability, + p->t38.jointcapability); + } else { + p->t38.state = T38_DISABLED; + if (option_debug > 2) + ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : ""); } } - } } + + /* Sanity checks */ if (portno == -1 && vportno == -1 && udptlportno == -1) /* No acceptable offer found in SDP - we have no ports */ /* Do not change RTP or VRTP if this is a re-invite */ @@ -5332,7 +5630,7 @@ } } - + /* Setup RTP port number */ if (p->rtp) { if (portno > 0) { sin.sin_port = htons(portno); @@ -5350,260 +5648,11 @@ } } } + /* Setup video port number */ if (vportno != -1) vsin.sin_port = htons(vportno); - /* Next, scan through each "a=rtpmap:" line, noting each - * specified RTP payload type (with corresponding MIME subtype): - */ - /* XXX This needs to be done per media stream, since it's media stream specific */ - iterator = req->sdp_start; - while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') { - char* mimeSubtype = ast_strdupa(a); /* ensures we have enough space */ - if (option_debug > 1) { - int breakout = FALSE; - - /* If we're debugging, check for unsupported sdp options */ - if (!strncasecmp(a, "rtcp:", (size_t) 5)) { - if (debug) - ast_verbose("Got unsupported a:rtcp in SDP offer \n"); - breakout = TRUE; - } else if (!strncasecmp(a, "fmtp:", (size_t) 5)) { - /* Format parameters: Not supported */ - /* Note: This is used for codec parameters, like bitrate for - G722 and video formats for H263 and H264 - See RFC2327 for an example */ - if (debug) - ast_verbose("Got unsupported a:fmtp in SDP offer \n"); - breakout = TRUE; - } else if (!strncasecmp(a, "framerate:", (size_t) 10)) { - /* Video stuff: Not supported */ - if (debug) - ast_verbose("Got unsupported a:framerate in SDP offer \n"); - breakout = TRUE; - } else if (!strncasecmp(a, "maxprate:", (size_t) 9)) { - /* Video stuff: Not supported */ - if (debug) - ast_verbose("Got unsupported a:maxprate in SDP offer \n"); - breakout = TRUE; - } else if (!strncasecmp(a, "crypto:", (size_t) 7)) { - /* SRTP stuff, not yet supported */ - if (debug) - ast_verbose("Got unsupported a:crypto in SDP offer \n"); - breakout = TRUE; - } - if (breakout) /* We have a match, skip to next header */ - continue; - } - if (!strcasecmp(a, "sendonly")) { - if (sendonly == -1) - sendonly = 1; - continue; - } else if (!strcasecmp(a, "inactive")) { - if (sendonly == -1) - sendonly = 2; - continue; - } else if (!strcasecmp(a, "sendrecv")) { - if (sendonly == -1) - sendonly = 0; - continue; - } else if (strlen(a) > 5 && !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; - if (option_debug) - ast_log(LOG_DEBUG, "Can't read framing from SDP: %s\n", a); - } - } - if (framing && p->autoframing) { - struct ast_codec_pref *pref = ast_rtp_codec_getpref(p->rtp); - int codec_n; - int format = 0; - for (codec_n = 0; codec_n < MAX_RTP_PT; codec_n++) { - format = ast_rtp_codec_getformat(codec_n); - if (!format) /* non-codec or not found */ - continue; - if (option_debug) - ast_log(LOG_DEBUG, "Setting framing for %d to %ld\n", format, framing); - ast_codec_pref_setsize(pref, format, framing); - } - ast_rtp_codec_setpref(p->rtp, pref); - } - continue; - } else if (sscanf(a, "rtpmap: %u %[^/]/", &codec, mimeSubtype) == 2) { - /* We have a rtpmap to handle */ - int found = FALSE; - /* We should propably check if this is an audio or video codec - so we know where to look */ - - if (last_rtpmap_codec < SDP_MAX_RTPMAP_CODECS) { - /* Note: should really look at the 'freq' and '#chans' params too */ - if(ast_rtp_set_rtpmap_type(newaudiortp, codec, "audio", mimeSubtype, - ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0) != -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 if (p->vrtp) { - if(ast_rtp_set_rtpmap_type(newvideortp, codec, "video", mimeSubtype, 0) != -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 { - if (debug) - ast_verbose("Discarded description format %s for ID %d\n", mimeSubtype, codec); - } - - if (!found) { - /* Remove this codec since it's an unknown media type for us */ - /* XXX This is buggy since the media line for audio and video can have the - same numbers. We need to check as described above, but for testing this works... */ - ast_rtp_unset_m_type(newaudiortp, codec); - ast_rtp_unset_m_type(newvideortp, codec); - if (debug) - ast_verbose("Found unknown media description format %s for ID %d\n", mimeSubtype, codec); - } - } - } - - if (udptlportno != -1) { - int found = 0, x; - - old = 0; - - /* Scan trough the a= lines for T38 attributes and set apropriate fileds */ - iterator = req->sdp_start; - while ((a = get_sdp_iterate(&iterator, req, "a"))[0] != '\0') { - if ((sscanf(a, "T38FaxMaxBuffer:%d", &x) == 1)) { - found = 1; - if (option_debug > 2) - ast_log(LOG_DEBUG, "MaxBufferSize:%d\n",x); - } else if ((sscanf(a, "T38MaxBitRate:%d", &x) == 1) || (sscanf(a, "T38FaxMaxRate:%d", &x) == 1)) { - found = 1; - if (option_debug > 2) - ast_log(LOG_DEBUG,"T38MaxBitRate: %d\n",x); - switch (x) { - case 14400: - peert38capability |= T38FAX_RATE_14400 | T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400; - break; - case 12000: - peert38capability |= T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400; - break; - case 9600: - peert38capability |= T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400; - break; - case 7200: - peert38capability |= T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400; - break; - case 4800: - peert38capability |= T38FAX_RATE_4800 | T38FAX_RATE_2400; - break; - case 2400: - peert38capability |= T38FAX_RATE_2400; - break; - } - } else if ((sscanf(a, "T38FaxVersion:%d", &x) == 1)) { - found = 1; - if (option_debug > 2) - ast_log(LOG_DEBUG, "FaxVersion: %d\n",x); - if (x == 0) - peert38capability |= T38FAX_VERSION_0; - else if (x == 1) - peert38capability |= T38FAX_VERSION_1; - } else if ((sscanf(a, "T38FaxMaxDatagram:%d", &x) == 1) || (sscanf(a, "T38MaxDatagram:%d", &x) == 1)) { - found = 1; - if (option_debug > 2) - ast_log(LOG_DEBUG, "FaxMaxDatagram: %d\n",x); - ast_udptl_set_far_max_datagram(p->udptl, x); - ast_udptl_set_local_max_datagram(p->udptl, x); - } else if ((strncmp(a, "T38FaxFillBitRemoval", 20) == 0)) { - found = 1; - if ((sscanf(a, "T38FaxFillBitRemoval:%d", &x) == 1)) { - if (option_debug > 2) - ast_log(LOG_DEBUG, "FillBitRemoval: %d\n",x); - if (x == 1) - peert38capability |= T38FAX_FILL_BIT_REMOVAL; - } else { - if (option_debug > 2) - ast_log(LOG_DEBUG, "FillBitRemoval\n"); - peert38capability |= T38FAX_FILL_BIT_REMOVAL; - } - } else if ((strncmp(a, "T38FaxTranscodingMMR", 20) == 0)) { - found = 1; - if ((sscanf(a, "T38FaxTranscodingMMR:%d", &x) == 1)) { - if (option_debug > 2) - ast_log(LOG_DEBUG, "Transcoding MMR: %d\n",x); - if (x == 1) - peert38capability |= T38FAX_TRANSCODING_MMR; - } else { - if (option_debug > 2) - ast_log(LOG_DEBUG, "Transcoding MMR\n"); - peert38capability |= T38FAX_TRANSCODING_MMR; - } - } else if ((strncmp(a, "T38FaxTranscodingJBIG", 21) == 0)) { - found = 1; - if ((sscanf(a, "T38FaxTranscodingJBIG:%d", &x) == 1)) { - if (option_debug > 2) - ast_log(LOG_DEBUG, "Transcoding JBIG: %d\n",x); - if (x == 1) - peert38capability |= T38FAX_TRANSCODING_JBIG; - } else { - if (option_debug > 2) - ast_log(LOG_DEBUG, "Transcoding JBIG\n"); - peert38capability |= T38FAX_TRANSCODING_JBIG; - } - } else if ((sscanf(a, "T38FaxRateManagement:%255s", s) == 1)) { - found = 1; - if (option_debug > 2) - ast_log(LOG_DEBUG, "RateManagement: %s\n", s); - if (!strcasecmp(s, "localTCF")) - peert38capability |= T38FAX_RATE_MANAGEMENT_LOCAL_TCF; - else if (!strcasecmp(s, "transferredTCF")) - peert38capability |= T38FAX_RATE_MANAGEMENT_TRANSFERED_TCF; - } else if ((sscanf(a, "T38FaxUdpEC:%255s", s) == 1)) { - found = 1; - if (option_debug > 2) - ast_log(LOG_DEBUG, "UDP EC: %s\n", s); - if (!strcasecmp(s, "t38UDPRedundancy")) { - peert38capability |= T38FAX_UDP_EC_REDUNDANCY; - ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_REDUNDANCY); - } else if (!strcasecmp(s, "t38UDPFEC")) { - peert38capability |= T38FAX_UDP_EC_FEC; - ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_FEC); - } else { - peert38capability |= T38FAX_UDP_EC_NONE; - ast_udptl_set_error_correction_scheme(p->udptl, UDPTL_ERROR_CORRECTION_NONE); - } - } - } - if (found) { /* Some cisco equipment returns nothing beside c= and m= lines in 200 OK T38 SDP */ - p->t38.peercapability = peert38capability; - p->t38.jointcapability = (peert38capability & 255); /* Put everything beside supported speeds settings */ - peert38capability &= (T38FAX_RATE_14400 | T38FAX_RATE_12000 | T38FAX_RATE_9600 | T38FAX_RATE_7200 | T38FAX_RATE_4800 | T38FAX_RATE_2400); - p->t38.jointcapability |= (peert38capability & p->t38.capability); /* Put the lower of our's and peer's speed */ - } - if (debug) - ast_log(LOG_DEBUG, "Our T38 capability = (%d), peer T38 capability (%d), joint T38 capability (%d)\n", - p->t38.capability, - p->t38.peercapability, - p->t38.jointcapability); - } else { - p->t38.state = T38_DISABLED; - if (option_debug > 2) - ast_log(LOG_DEBUG, "T38 state changed to %d on channel %s\n", p->t38.state, p->owner ? p->owner->name : ""); - } - /* Now gather all of the codecs that we are asked for: */ ast_rtp_get_current_formats(newaudiortp, &peercapability, &peernoncodeccapability); ast_rtp_get_current_formats(newvideortp, &vpeercapability, &vpeernoncodeccapability);