Index: asterisk-1.6.2.7/channels/chan_sip.c =================================================================== --- asterisk-1.6.2.7.orig/channels/chan_sip.c 2010-05-25 14:53:01.000000000 +0100 +++ asterisk-1.6.2.7/channels/chan_sip.c 2010-05-25 18:33:36.000000000 +0100 @@ -2637,6 +2637,7 @@ static enum ast_rtp_get_result sip_get_vrtp_peer(struct ast_channel *chan, struct ast_rtp **rtp); static enum ast_rtp_get_result sip_get_trtp_peer(struct ast_channel *chan, struct ast_rtp **rtp); static int sip_get_codec(struct ast_channel *chan); +static struct ast_codec_pref *sip_get_codec_pref(struct ast_channel *chan); static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p, int *faxdetect); /*------ T38 Support --------- */ @@ -2770,6 +2771,7 @@ .get_trtp_info = sip_get_trtp_peer, .set_rtp_peer = sip_set_rtp_peer, .get_codec = sip_get_codec, + .get_codec_pref = sip_get_codec_pref, }; /*! @@ -10035,6 +10037,7 @@ { int len = 0; int alreadysent = 0; + int doing_directmedia = FALSE; struct sockaddr_in sin; struct sockaddr_in vsin; @@ -10096,6 +10099,11 @@ } if (add_audio) { + /* Remote IP address specified, and redircodecs has been set. + This sets the initial state for the type of SDP redirect to be done. + */ + doing_directmedia = (p->redirip.sin_addr.s_addr && p->redircodecs) ? TRUE : FALSE; + /* Check if we need video in this call */ if ((p->jointcapability & AST_FORMAT_VIDEO_MASK) && !p->novideo) { if (p->vrtp) { @@ -10126,12 +10134,25 @@ snprintf(connection, sizeof(connection), "c=IN IP4 %s\r\n", ast_inet_ntoa(dest.sin_addr)); if (add_audio) { + if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_ONEDIR) { + hold = "a=recvonly\r\n"; + doing_directmedia = FALSE; + } else if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_INACTIVE) { + hold = "a=inactive\r\n"; + doing_directmedia = FALSE; + } else + hold = "a=sendrecv\r\n"; + capability = p->jointcapability; /* XXX note, Video and Text are negated - 'true' means 'no' */ ast_debug(1, "** Our capability: %s Video flag: %s Text flag: %s\n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), capability), p->novideo ? "True" : "False", p->notext ? "True" : "False"); ast_debug(1, "** Our prefcodec: %s \n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), p->prefcodec)); + if( doing_directmedia ) { + capability &= p->redircodecs; + ast_debug(1, "** Our NATIVE-BRIDGE filtered capability: %s\n", ast_getformatname_multiple(codecbuf, sizeof(codecbuf), capability)); + } /* Check if we need audio */ if (capability & AST_FORMAT_AUDIO_MASK) @@ -10178,13 +10199,6 @@ ast_str_append(&m_audio, 0, "m=audio %d RTP/AVP", ntohs(dest.sin_port)); - if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_ONEDIR) - hold = "a=recvonly\r\n"; - else if (ast_test_flag(&p->flags[1], SIP_PAGE2_CALL_ONHOLD) == SIP_PAGE2_CALL_ONHOLD_INACTIVE) - hold = "a=inactive\r\n"; - else - hold = "a=sendrecv\r\n"; - /* Now, start adding audio codecs. These are added in this order: - First what was requested by the calling channel - Then preferences in order from sip.conf device config for this peer/user @@ -25735,6 +25749,13 @@ return p->jointcapability ? p->jointcapability : p->capability; } +/*! \brief Return SIP UA's codec prefs (part of the RTP interface) */ +static struct ast_codec_pref *sip_get_codec_pref(struct ast_channel *chan) +{ + struct sip_pvt *p = chan->tech_pvt; + return &(p->prefs); +} + /*! \brief Send a poke to all known peers */ static void sip_poke_all_peers(void) { Index: asterisk-1.6.2.7/main/rtp.c =================================================================== --- asterisk-1.6.2.7.orig/main/rtp.c 2010-05-25 16:23:04.000000000 +0100 +++ asterisk-1.6.2.7/main/rtp.c 2010-05-26 10:40:54.000000000 +0100 @@ -4562,6 +4562,47 @@ ast_channel_unlock(c1); return AST_BRIDGE_FAILED_NOWARN; } + /* If we can determine a preference, filter audio/video codecs to best choices */ + if( pr0->get_codec_pref && pr1->get_codec_pref ) { + int x, y, tmp1, tmp2, besta = 999, bestv = 999, commona = 0, commonv = 0; + struct ast_codec_pref *prefs0, *prefs1; + prefs0 = pr0->get_codec_pref(c0); + prefs1 = pr1->get_codec_pref(c1); + + for (x = 0; x < 32; x++) { + if (!(tmp1=ast_codec_pref_index(prefs0, x))) + break; + for (y = 0; y < 32; y++) { + int score; + if (!(tmp2=ast_codec_pref_index(prefs1, y))) + break; + + if (tmp1 != tmp2) /* Find codec common to both */ + continue; + if (!(codec0 & tmp1) || !(codec1 & tmp1)) /* Ensure codec is "current" */ + continue; + + score = (x^2) + (y^2); /* Do our best to dislike low prio codecs */ + if( tmp2 & AST_FORMAT_AUDIO_MASK && score < besta ) { + besta = score; + commona = tmp1; + } else if( tmp2 & AST_FORMAT_VIDEO_MASK && score < bestv ) { + bestv = score; + commonv = tmp1; + } + } + } + if( commona ) { + codec0 &= (commona | ~AST_FORMAT_AUDIO_MASK); + codec1 &= (commona | ~AST_FORMAT_AUDIO_MASK); + ast_verb(3, "Found common audio codec for native bridge %s\n", ast_getformatname(commona)); + } + if( commonv ) { + codec0 &= (commonv | ~AST_FORMAT_VIDEO_MASK); + codec1 &= (commonv | ~AST_FORMAT_VIDEO_MASK); + ast_verb(3, "Found common video codec for native bridge %s\n", ast_getformatname(commonv)); + } + } /* If either side can only do a partial bridge, then don't try for a true native bridge */ if (audio_p0_res == AST_RTP_TRY_PARTIAL || audio_p1_res == AST_RTP_TRY_PARTIAL) { Index: asterisk-1.6.2.7/include/asterisk/rtp.h =================================================================== --- asterisk-1.6.2.7.orig/include/asterisk/rtp.h 2010-05-25 18:14:47.000000000 +0100 +++ asterisk-1.6.2.7/include/asterisk/rtp.h 2010-05-25 18:16:29.000000000 +0100 @@ -102,6 +102,7 @@ /*! Set RTP peer */ int (* const set_rtp_peer)(struct ast_channel *chan, struct ast_rtp *peer, struct ast_rtp *vpeer, struct ast_rtp *tpeer, int codecs, int nat_active); int (* const get_codec)(struct ast_channel *chan); + struct ast_codec_pref * (* const get_codec_pref)(struct ast_channel *chan); const char * const type; AST_LIST_ENTRY(ast_rtp_protocol) list; };