--- channels/chan_sip.c.orig 2011-12-08 14:04:26.811531771 +0100 +++ channels/chan_sip.c 2011-12-08 16:51:58.145534831 +0100 @@ -1081,6 +1081,7 @@ static int global_match_auth_username; static int global_relaxdtmf; /*!< Relax DTMF */ static int global_prematuremediafilter; /*!< Enable/disable premature frames in a call (causing 183 early media) */ static int global_relaxdtmf; /*!< Relax DTMF */ +static int global_rtpprodhack; /*!< Prod an RTP stream immediately to get things going */ static int global_rtptimeout; /*!< Time out call if no RTP */ static int global_rtpholdtimeout; /*!< Time out call if no RTP during hold */ static int global_rtpkeepalive; /*!< Send RTP keepalives */ @@ -2643,6 +2644,9 @@ static enum ast_rtp_get_result sip_get_v 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_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p, int *faxdetect); +static void _sip_rtp_prod(const char *function, struct sip_pvt *p); +#define sip_rtp_prod(p) _sip_rtp_prod(__PRETTY_FUNCTION__, p) + /*------ T38 Support --------- */ static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans); @@ -6492,6 +6496,7 @@ static int sip_answer(struct ast_channel ast_rtp_new_source(p->rtp); res = transmit_response_with_sdp(p, "200 OK", &p->initreq, XMIT_CRITICAL, FALSE); ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED); + sip_rtp_prod(p); /* explicitly sip_pvt_lock'ed */ } sip_pvt_unlock(p); return res; @@ -6867,6 +6872,7 @@ static int sip_indicate(struct ast_chann p->invitestate = INV_EARLY_MEDIA; transmit_provisional_response(p, "183 Session Progress", &p->initreq, TRUE); ast_set_flag(&p->flags[0], SIP_PROGRESS_SENT); + sip_rtp_prod(p); /* explicitly sip_pvt_lock'ed */ break; } res = -1; @@ -7424,6 +7430,19 @@ static struct ast_frame *sip_read(struct return fr; } +/*! \brief Poke media session. This is sometimes required to break through a + * stand off where both parties are waiting for the other one to send. + * This is especially an issue when both: + * (a) we're behind NAT and our peer is not, and + * (b) we're an asterisk and we like to wait for incoming RTP before replying + */ +static void _sip_rtp_prod(char const *function, struct sip_pvt *dialog) +{ + if (global_rtpprodhack) { + ast_verb(3, "Prodding channel '%s' RTP (triggered by %s)\n", dialog->owner->name, function); + ast_rtp_sendcng(dialog->rtp, 0); + } +} /*! \brief Generate 32 byte random string for callid's etc */ static char *generate_random_string(char *buf, size_t size) @@ -18379,6 +18398,7 @@ static void handle_response_invite(struc ast_queue_control(p->owner, AST_CONTROL_RINGING); } } + sip_rtp_prod(p); /* sip_pvt_locked in handle_request_do */ check_pendings(p); break; @@ -18467,6 +18487,7 @@ static void handle_response_invite(struc p->invitestate = INV_TERMINATED; ast_set_flag(&p->flags[1], SIP_PAGE2_DIALOG_ESTABLISHED); xmitres = transmit_request(p, SIP_ACK, seqno, XMIT_UNRELIABLE, TRUE); + sip_rtp_prod(p); /* sip_pvt_locked in handle_request_do */ check_pendings(p); break; @@ -23179,8 +23200,8 @@ static void check_rtp_timeout(struct sip /* If we have no RTP or no active owner, no need to check timers */ if (!dialog->rtp || !dialog->owner) return; - /* If the call is not in UP state or redirected outside Asterisk, no need to check timers */ + /* If the call is not in UP state or redirected outside Asterisk, no need to check timers */ if (dialog->owner->_state != AST_STATE_UP || dialog->redirip.sin_addr.s_addr) return; @@ -25345,6 +25366,7 @@ static int reload_config(enum channelrel sip_cfg.allowguest = DEFAULT_ALLOWGUEST; global_callcounter = DEFAULT_CALLCOUNTER; global_match_auth_username = FALSE; /*!< Match auth username if available instead of From: Default off. */ + global_rtpprodhack = 0; global_rtptimeout = 0; global_rtpholdtimeout = 0; global_rtpkeepalive = DEFAULT_RTPKEEPALIVE; @@ -25533,6 +25555,8 @@ static int reload_config(enum channelrel global_relaxdtmf = ast_true(v->value); } else if (!strcasecmp(v->name, "vmexten")) { ast_copy_string(default_vmexten, v->value, sizeof(default_vmexten)); + } else if (!strcasecmp(v->name, "rtpprodhack")) { + global_rtpprodhack = ast_true(v->value); } else if (!strcasecmp(v->name, "rtptimeout")) { if ((sscanf(v->value, "%30d", &global_rtptimeout) != 1) || (global_rtptimeout < 0)) { ast_log(LOG_WARNING, "'%s' is not a valid RTP hold time at line %d. Using default.\n", v->value, v->lineno);