diff -ur asterisk-1.2.7.1-non-jorrit/channels/chan_sip.c asterisk-1.2.7.1/channels/chan_sip.c --- asterisk-1.2.7.1-non-jorrit/channels/chan_sip.c 2006-05-19 11:42:44.000000000 +0200 +++ asterisk-1.2.7.1/channels/chan_sip.c 2006-06-19 14:53:18.000000000 +0200 @@ -657,6 +657,7 @@ char lastmsg[256]; /*!< Last Message sent/received */ int amaflags; /*!< AMA Flags */ int pendinginvite; /*!< Any pending invite */ + int codecweight; /*!< Weight of the codec */ #ifdef OSP_SUPPORT int osphandle; /*!< OSP Handle for call */ time_t ospstart; /*!< OSP Start time */ @@ -785,6 +786,7 @@ int pokeexpire; /*!< When to expire poke (qualify= checking) */ int lastms; /*!< How long last response took (in ms), or -1 for no response */ int maxms; /*!< Max ms we will accept for the host to be up, 0 to not monitor */ + int codecweight; /*!< whose codec preference weighs more */ struct timeval ps; /*!< Ping send time */ struct sockaddr_in defaddr; /*!< Default IP address, used until registration */ @@ -898,6 +900,7 @@ static int sip_do_reload(void); static int expire_register(void *data); static int callevents = 0; +static int opt_evade_transcoding = 0; static struct ast_channel *sip_request_call(const char *type, const struct ast_codec_pref *format, void *data, int *cause); static int sip_devicestate(void *data); @@ -922,6 +925,7 @@ static const struct cfsubscription_types *find_subscription_type(enum subscriptiontype subtype); static int transmit_state_notify(struct sip_pvt *p, int state, int full, int substate); static char *gettag(struct sip_request *req, char *header, char *tagbuf, int tagbufsize); +static int sip_evade_transcoding(struct ast_channel *c0, struct ast_channel *c1); /*! \brief Definition of this channel for PBX channel registration */ static const struct ast_channel_tech sip_tech = { @@ -944,6 +948,7 @@ .bridge = ast_rtp_bridge, .send_text = sip_sendtext, .fixup_codecs = sip_fixup_codecs, + .evade_transcoding = sip_evade_transcoding, }; /*! @@ -1862,6 +1867,7 @@ ast_copy_flags(r, peer, SIP_FLAGS_TO_COPY); r->userprefs = peer->prefs; + r->codecweight = peer->codecweight; if (r->rtp) { ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE)); ast_rtp_setnat(r->rtp, (ast_test_flag(r, SIP_NAT) & SIP_NAT_ROUTE)); @@ -4442,7 +4448,7 @@ ast_build_string(&m_video_next, &m_video_left, "m=video %d RTP/AVP", ntohs(vdest.sin_port)); /* Prefer the codec we were requested to use, first, no matter what */ - pref_codec = ast_codec_pref_index_audio(capability, 0); + /*pref_codec = ast_codec_pref_index_audio(capability, 0); if (pref_codec) { add_codec_to_sdp(p, pref_codec, 8000, &m_audio_next, &m_audio_left, @@ -4457,7 +4463,7 @@ &a_video_next, &a_video_left, debug); alreadysent |= pref_codec; - } + }*/ /* Start by sending our preferred codecs */ for (x = 0; x < 32; x++) { @@ -10296,6 +10302,8 @@ char *supported; char *required; unsigned int required_profile = 0; + struct ast_channel *bridged = NULL; + /* Find out what they support */ if (!p->sipoptions) { supported = get_header(req, "Supported"); @@ -10516,6 +10524,10 @@ break; case AST_STATE_UP: /* Here we have reINVITE request - try to renegotiate codecs with */ + bridged = ast_bridged_channel(p->owner); + if (bridged) + sip_evade_transcoding(bridged, p->owner); + transmit_response_with_sdp(p, "200 OK", req, 1); break; default: @@ -12128,6 +12140,7 @@ peer->rtpkeepalive = global_rtpkeepalive; peer->maxms = default_qualify; peer->prefs = global_prefs; + peer->codecweight = 0; oldha = peer->ha; peer->ha = NULL; peer->addr.sin_family = AF_INET; @@ -12291,6 +12304,8 @@ ast_log(LOG_WARNING, "Qualification of peer '%s' should be 'yes', 'no', or a number of milliseconds at line %d of sip.conf\n", peer->name, v->lineno); peer->maxms = 0; } + } else if (!strcasecmp(v->name, "codecweight")) { + peer->codecweight = atoi(v->value); } /* else if (strcasecmp(v->name,"type")) * ast_log(LOG_WARNING, "Ignoring %s\n", v->name); @@ -12587,6 +12602,8 @@ } } else if (!strcasecmp(v->name, "callevents")) { callevents = ast_true(v->value); + } else if (!strcasecmp(v->name, "evadetranscoding")) { + opt_evade_transcoding = ast_true(v->value); } /* else if (strcasecmp(v->name,"type")) * ast_log(LOG_WARNING, "Ignoring %s\n", v->name); @@ -13303,4 +13320,93 @@ return (char *) desc; } +static int sip_evade_transcoding(struct ast_channel *c0, struct ast_channel *c1) { + struct sip_pvt *p0 = c0->tech_pvt; + struct sip_pvt *p1 = c1->tech_pvt; + struct ast_codec_pref pref0; + struct ast_codec_pref pref1; + struct ast_channel *pref_chan; + struct ast_channel *other_chan; + int i; + int audio_codec; + int video_codec; + int codec_picked = 0; + + if (!opt_evade_transcoding) /* don't bother */ + return 0; + + /* which channel has the preferred codecs? */ + if (p0->codecweight >= p1->codecweight) { + pref_chan = c0; + other_chan = c1; + } else { + pref_chan = c1; + other_chan = c0; + } + + /* + * find a non-transcoding path for audio + */ + for (i = 0; i < 32; i++) { + if (!(audio_codec = ast_codec_pref_index_audio(&pref_chan->nativeformats, i))) + break; + + if (audio_codec & other_chan->nativeformats.audio_bits) { + ast_codec_pref_init(&pref0); + ast_codec_pref_append(&pref0, audio_codec); + codec_picked++; + break; + } + } + + /* if we couldn't find any path, then forget it */ + if (!codec_picked) + return 0; + + memcpy(&pref1, &pref0, sizeof(pref0)); + + /* add the video codecs back to the structure */ + for (i = 0; i < 32; i++) { + if (!(video_codec = ast_codec_pref_index_video(&c0->nativeformats, i))) + break; + + ast_codec_pref_append(&pref0, video_codec); + } + for (i = 0; i < 32; i++) { + if (!(video_codec = ast_codec_pref_index_video(&c1->nativeformats, i))) + break; + + ast_codec_pref_append(&pref1, video_codec); + } + + if (!ast_codec_pref_eq_noorder(&c0->nativeformats, &pref0)) { + memcpy(&c0->nativeformats, &pref0, sizeof(pref0)); + memcpy(&p0->formats, &pref0, sizeof(pref0)); + + /* Transmit reinvite if there's been a change in codec */ + if (AST_STATE_UP == c0->_state && p0->pendinginvite == 0 && audio_codec != c0->lastreadformat) { + transmit_reinvite_with_sdp(p0); + } + + /* dodge some warnings */ + ast_set_read_format(c0, audio_codec); + ast_set_write_format(c0, audio_codec); + } + + if (!ast_codec_pref_eq_noorder(&c1->nativeformats, &pref1)) { + memcpy(&c1->nativeformats, &pref1, sizeof(pref1)); + memcpy(&p1->formats, &pref1, sizeof(pref1)); + + /* Transmit reinvite if there's been a change in codec */ + if (AST_STATE_UP == c1->_state && p1->pendinginvite == 0 && audio_codec != c1->lastreadformat) { + transmit_reinvite_with_sdp(p1); + } + + /* dodge some warnings */ + ast_set_read_format(c1, audio_codec); + ast_set_write_format(c1, audio_codec); + } + + return 0; +} diff -ur asterisk-1.2.7.1-non-jorrit/include/asterisk/channel.h asterisk-1.2.7.1/include/asterisk/channel.h --- asterisk-1.2.7.1-non-jorrit/include/asterisk/channel.h 2006-05-19 11:42:44.000000000 +0200 +++ asterisk-1.2.7.1/include/asterisk/channel.h 2006-06-15 15:18:23.000000000 +0200 @@ -246,6 +246,9 @@ /*! Try to fixup codecs */ void (*fixup_codecs)(struct ast_channel *chan, const struct ast_codec_pref *peer_codecs); + + /*! Try to evade transcoding */ + int (*evade_transcoding)(struct ast_channel *c0, struct ast_channel *c1); }; struct ast_channel_spy_list; diff -ur asterisk-1.2.7.1-non-jorrit/res/res_features.c asterisk-1.2.7.1/res/res_features.c --- asterisk-1.2.7.1-non-jorrit/res/res_features.c 2006-05-19 11:42:45.000000000 +0200 +++ asterisk-1.2.7.1/res/res_features.c 2006-06-16 15:25:59.000000000 +0200 @@ -1296,6 +1296,9 @@ if (ast_codec_pref_intersect(&chan->nativeformats, &peer->nativeformats)) { + if (peer->tech->evade_transcoding) + peer->tech->evade_transcoding(chan, peer); + if (chan->tech->fixup_codecs && ast_codec_pref_intersect(&chan->nativeformats, &peer->nativeformats) != ast_codec_pref_bits(&chan->nativeformats)) {