Index: channels/chan_skinny.c =================================================================== --- channels/chan_skinny.c (revision 56124) +++ channels/chan_skinny.c (working copy) @@ -781,6 +781,7 @@ static char mailbox[AST_MAX_EXTENSION]; static int amaflags = 0; static int callnums = 1; +static int canreinvite = 0; #define SKINNY_DEVICE_UNKNOWN -1 #define SKINNY_DEVICE_NONE 0 @@ -916,6 +917,7 @@ /* int lastout; */ /* Unused */ int cxmode; int nat; + int canreinvite; int outgoing; int alreadygone; @@ -963,6 +965,7 @@ int immediate; int hookstate; int nat; + int canreinvite; struct ast_codec_pref prefs; struct skinny_subchannel *sub; @@ -1053,7 +1056,7 @@ .fixup = skinny_fixup, .send_digit_begin = skinny_senddigit_begin, .send_digit_end = skinny_senddigit_end, -/* .bridge = ast_rtp_bridge, */ + .bridge = ast_rtp_bridge, }; static void *get_button_template(struct skinnysession *s, struct button_definition_template *btn) @@ -1733,24 +1736,88 @@ static enum ast_rtp_get_result skinny_get_rtp_peer(struct ast_channel *c, struct ast_rtp **rtp) { struct skinny_subchannel *sub = NULL; + struct skinny_line *l; + enum ast_rtp_get_result res = AST_RTP_TRY_NATIVE; - if (!(sub = c->tech_pvt) || !(sub->rtp)) + if (skinnydebug) + ast_verbose("skinny_get_rtp_peer() Channel = %s\n", c->name); + + if (!(sub = c->tech_pvt)) return AST_RTP_GET_FAILED; + ast_mutex_lock(&sub->lock); + + if (!(sub->rtp)){ + ast_mutex_unlock(&sub->lock); + return AST_RTP_GET_FAILED; + } + *rtp = sub->rtp; - return AST_RTP_TRY_NATIVE; + l = sub->parent; + + if (!l->canreinvite || l->nat) + res = AST_RTP_TRY_PARTIAL; + + ast_mutex_unlock(&sub->lock); + + return res; } static int skinny_set_rtp_peer(struct ast_channel *c, struct ast_rtp *rtp, struct ast_rtp *vrtp, int codecs, int nat_active) { struct skinny_subchannel *sub; + struct skinny_line *l; + struct skinny_device *d; + struct skinnysession *s; + + struct ast_format_list fmt; + struct sockaddr_in them; + struct skinny_req *req; + sub = c->tech_pvt; - if (sub) { - /* transmit_modify_with_sdp(sub, rtp); @@FIXME@@ if needed */ + + if (c->_state != AST_STATE_UP) return 0; + + if (!sub) + return -1; + + ast_mutex_lock(&c->lock); + + l = sub->parent; + d = l->parent; + s = d->session; + + /* transmit_modify_with_sdp(sub, rtp); @@FIXME@@ if needed */ + if (rtp){ + ast_rtp_get_peer(rtp, &them); + if (skinnydebug) + ast_verbose("Peerip = %s:%d\n", ast_inet_ntoa(them.sin_addr), ntohs(them.sin_port)); + if (!(req = req_alloc(sizeof(struct start_media_transmission_message), START_MEDIA_TRANSMISSION_MESSAGE))) + return -1; + + fmt = ast_codec_pref_getsize(&l->prefs, ast_best_codec(l->capability)); + + if (skinnydebug) + ast_verbose("Setting payloadType to '%d' (%d ms)\n", fmt.bits, fmt.cur_ms); + + req->data.startmedia.conferenceId = htolel(0); + req->data.startmedia.passThruPartyId = htolel(sub->callid); + req->data.startmedia.remoteIp = htolel(them.sin_addr.s_addr); + req->data.startmedia.remotePort = htolel(ntohs(them.sin_port)); + req->data.startmedia.packetSize = htolel(fmt.cur_ms); + req->data.startmedia.payloadType = htolel(codec_ast2skinny(fmt.bits)); + req->data.startmedia.qualifier.precedence = htolel(127); + req->data.startmedia.qualifier.vad = htolel(0); + req->data.startmedia.qualifier.packets = htolel(0); + req->data.startmedia.qualifier.bitRate = htolel(0); + transmit_response(s, req); + + return 0; } - return -1; + /* Need a return here to break the bridge */ + return 0; } static struct ast_rtp_protocol skinny_rtp = { @@ -2046,6 +2113,8 @@ ast_parse_allow_disallow(&d->prefs, &d->capability, v->value, 0); } else if (!strcasecmp(v->name, "version")) { ast_copy_string(d->version_id, v->value, sizeof(d->version_id)); + } else if (!strcasecmp(v->name, "canreinvite")) { + canreinvite = ast_true(v->value); } else if (!strcasecmp(v->name, "nat")) { nat = ast_true(v->value); } else if (!strcasecmp(v->name, "callerid")) { @@ -2165,6 +2234,7 @@ /* ASSUME we're onhook at this point */ l->hookstate = SKINNY_ONHOOK; l->nat = nat; + l->canreinvite = canreinvite; l->next = d->lines; d->lines = l; @@ -2728,6 +2798,7 @@ d->lastcallreference = sub->callid; sub->cxmode = SKINNY_CX_INACTIVE; sub->nat = l->nat; + sub->canreinvite = l->canreinvite; sub->parent = l; sub->onhold = 0; @@ -3633,31 +3704,33 @@ return 0; } - if (skinnydebug) { + if (skinnydebug) ast_verbose("ipaddr = %s:%d\n", ast_inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); - ast_verbose("ourip = %s:%d\n", ast_inet_ntoa(d->ourip), ntohs(us.sin_port)); - } + - if (!(req = req_alloc(sizeof(struct start_media_transmission_message), START_MEDIA_TRANSMISSION_MESSAGE))) - return -1; - fmt = ast_codec_pref_getsize(&l->prefs, ast_best_codec(l->capability)); + if (!(l->canreinvite) || (l->nat)){ + if (!(req = req_alloc(sizeof(struct start_media_transmission_message), START_MEDIA_TRANSMISSION_MESSAGE))) + return -1; - if (skinnydebug) - ast_verbose("Setting payloadType to '%d' (%d ms)\n", fmt.bits, fmt.cur_ms); + fmt = ast_codec_pref_getsize(&l->prefs, ast_best_codec(l->capability)); - req->data.startmedia.conferenceId = htolel(0); - req->data.startmedia.passThruPartyId = htolel(sub->callid); - req->data.startmedia.remoteIp = htolel(d->ourip.s_addr); - req->data.startmedia.remotePort = htolel(ntohs(us.sin_port)); - req->data.startmedia.packetSize = htolel(fmt.cur_ms); - req->data.startmedia.payloadType = htolel(codec_ast2skinny(fmt.bits)); - req->data.startmedia.qualifier.precedence = htolel(127); - req->data.startmedia.qualifier.vad = htolel(0); - req->data.startmedia.qualifier.packets = htolel(0); - req->data.startmedia.qualifier.bitRate = htolel(0); - transmit_response(s, req); + if (skinnydebug) + ast_verbose("Setting payloadType to '%d' (%d ms)\n", fmt.bits, fmt.cur_ms); + req->data.startmedia.conferenceId = htolel(0); + req->data.startmedia.passThruPartyId = htolel(sub->callid); + req->data.startmedia.remoteIp = htolel(d->ourip.s_addr); + req->data.startmedia.remotePort = htolel(ntohs(us.sin_port)); + req->data.startmedia.packetSize = htolel(fmt.cur_ms); + req->data.startmedia.payloadType = htolel(codec_ast2skinny(fmt.bits)); + req->data.startmedia.qualifier.precedence = htolel(127); + req->data.startmedia.qualifier.vad = htolel(0); + req->data.startmedia.qualifier.packets = htolel(0); + req->data.startmedia.qualifier.bitRate = htolel(0); + transmit_response(s, req); + } + return 1; } @@ -4451,6 +4524,8 @@ keep_alive = atoi(v->value); } else if (!strcasecmp(v->name, "dateformat")) { ast_copy_string(date_format, v->value, sizeof(date_format)); + } else if (!strcasecmp(v->name, "canreinvite")) { + canreinvite = ast_true(v->value); } else if (!strcasecmp(v->name, "allow")) { ast_parse_allow_disallow(&default_prefs, &default_capability, v->value, 1); } else if (!strcasecmp(v->name, "disallow")) {