diff options
author | oej <oej@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-12-02 12:05:40 +0000 |
---|---|---|
committer | oej <oej@f38db490-d61c-443f-a65b-d21fe96a405b> | 2006-12-02 12:05:40 +0000 |
commit | 10d3f3f5ba29d3d173709db55f2cd02d7fd0677b (patch) | |
tree | 09ffb0a36d6c9a88e86937e5c2cff44de6ff208f /channels/chan_sip.c | |
parent | be7b4bb5fe310740d73d85cdc6c9f3aa65d3a844 (diff) |
- Disable RTP timeouts during T.38 transmission
- Encapsulate RTP timers to the RTP structure, so we have one set for video and one for audio
- Document RTP keepalive configuration option
- Cleanup and document the monitor support function to hangup on RTP timeouts
- Add RTP keepalive to SIP show settings
Imported from 1.4 with modifications for trunk.
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@48200 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'channels/chan_sip.c')
-rw-r--r-- | channels/chan_sip.c | 161 |
1 files changed, 93 insertions, 68 deletions
diff --git a/channels/chan_sip.c b/channels/chan_sip.c index e3f82edce..26fd403aa 100644 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -961,8 +961,6 @@ struct sip_pvt { time_t lastrtprx; /*!< Last RTP received */ time_t lastrtptx; /*!< Last RTP sent */ int rtptimeout; /*!< RTP timeout time */ - int rtpholdtimeout; /*!< RTP timeout when on hold */ - int rtpkeepalive; /*!< Send RTP packets for keepalive */ struct sockaddr_in recv; /*!< Received as */ struct in_addr ourip; /*!< Our IP */ struct ast_channel *owner; /*!< Who owns us (if we have an owner) */ @@ -2726,17 +2724,21 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer) if (dialog->rtp) { ast_rtp_setdtmf(dialog->rtp, ast_test_flag(&dialog->flags[0], SIP_DTMF) != SIP_DTMF_INFO); ast_rtp_setdtmfcompensate(dialog->rtp, ast_test_flag(&dialog->flags[1], SIP_PAGE2_RFC2833_COMPENSATE)); + ast_rtp_set_rtptimeout(dialog->rtp, peer->rtptimeout); + ast_rtp_set_rtpholdtimeout(dialog->rtp, peer->rtpholdtimeout); + ast_rtp_set_rtpkeepalive(dialog->rtp, peer->rtpkeepalive); + /* Set Frame packetization */ + ast_rtp_codec_setpref(dialog->rtp, &dialog->prefs); + dialog->autoframing = peer->autoframing; } if (dialog->vrtp) { ast_rtp_setdtmf(dialog->vrtp, 0); ast_rtp_setdtmfcompensate(dialog->vrtp, 0); + ast_rtp_set_rtptimeout(dialog->vrtp, peer->rtptimeout); + ast_rtp_set_rtpholdtimeout(dialog->vrtp, peer->rtpholdtimeout); + ast_rtp_set_rtpkeepalive(dialog->vrtp, peer->rtpkeepalive); } - /* Set Frame packetization */ - if (dialog->rtp) { - ast_rtp_codec_setpref(dialog->rtp, &dialog->prefs); - dialog->autoframing = peer->autoframing; - } ast_string_field_set(dialog, peername, peer->username); ast_string_field_set(dialog, authname, peer->username); ast_string_field_set(dialog, username, peer->username); @@ -2774,8 +2776,6 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer) dialog->noncodeccapability &= ~AST_RTP_DTMF; ast_string_field_set(dialog, context, peer->context); dialog->rtptimeout = peer->rtptimeout; - dialog->rtpholdtimeout = peer->rtpholdtimeout; - dialog->rtpkeepalive = peer->rtpkeepalive; if (peer->call_limit) ast_set_flag(&dialog->flags[0], SIP_CALL_LIMIT); dialog->maxcallbitrate = peer->maxcallbitrate; @@ -4299,16 +4299,19 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si ast_rtp_setdtmf(p->rtp, ast_test_flag(&p->flags[0], SIP_DTMF) != SIP_DTMF_INFO); ast_rtp_setdtmfcompensate(p->rtp, ast_test_flag(&p->flags[1], SIP_PAGE2_RFC2833_COMPENSATE)); ast_rtp_settos(p->rtp, global_tos_audio); + ast_rtp_set_rtptimeout(p->rtp, global_rtptimeout); + ast_rtp_set_rtpholdtimeout(p->rtp, global_rtpholdtimeout); + ast_rtp_set_rtpkeepalive(p->rtp, global_rtpkeepalive); if (p->vrtp) { ast_rtp_settos(p->vrtp, global_tos_video); ast_rtp_setdtmf(p->vrtp, 0); ast_rtp_setdtmfcompensate(p->vrtp, 0); + ast_rtp_set_rtptimeout(p->vrtp, global_rtptimeout); + ast_rtp_set_rtpholdtimeout(p->vrtp, global_rtpholdtimeout); + ast_rtp_set_rtpkeepalive(p->vrtp, global_rtpkeepalive); } if (p->udptl) ast_udptl_settos(p->udptl, global_tos_audio); - p->rtptimeout = global_rtptimeout; - p->rtpholdtimeout = global_rtpholdtimeout; - p->rtpkeepalive = global_rtpkeepalive; p->maxcallbitrate = default_maxcallbitrate; } @@ -10427,6 +10430,7 @@ static int sip_show_settings(int fd, int argc, char *argv[]) ast_cli(fd, " T1 minimum: %d\n", global_t1min); ast_cli(fd, " Relax DTMF: %s\n", global_relaxdtmf ? "Yes" : "No"); ast_cli(fd, " Compact SIP headers: %s\n", compactheaders ? "Yes" : "No"); + ast_cli(fd, " RTP Keepalive: %d %s\n", global_rtpkeepalive, global_rtpkeepalive ? "" : "(Disabled)" ); ast_cli(fd, " RTP Timeout: %d %s\n", global_rtptimeout, global_rtptimeout ? "" : "(Disabled)" ); ast_cli(fd, " RTP Hold Timeout: %d %s\n", global_rtpholdtimeout, global_rtpholdtimeout ? "" : "(Disabled)"); ast_cli(fd, " MWI NOTIFY mime type: %s\n", default_notifymime); @@ -11823,6 +11827,9 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru if (bridgepvt->udptl) { if (p->t38.state == T38_PEER_REINVITE) { sip_handle_t38_reinvite(bridgepeer, p, 0); + ast_rtp_set_rtptimers_onhold(p->rtp); + if (p->vrtp) + ast_rtp_set_rtptimers_onhold(p->vrtp); /* Turn off RTP timers while we send fax */ } else if (p->t38.state == T38_DISABLED && bridgepeer && (bridgepvt->t38.state == T38_ENABLED)) { ast_log(LOG_WARNING, "RTP re-inivte after T38 session not handled yet !\n"); /* Insted of this we should somehow re-invite the other side of the bridge to RTP */ @@ -14912,52 +14919,66 @@ static int does_peer_need_mwi(struct sip_peer *peer) /*! \brief helper function for the monitoring thread */ -static void check_rtp_timeout(struct sip_pvt *sip, time_t t) -{ - if (sip->rtp && sip->owner && - (sip->owner->_state == AST_STATE_UP) && - !sip->redirip.sin_addr.s_addr) { - if (sip->lastrtptx && - sip->rtpkeepalive && - (t > sip->lastrtptx + sip->rtpkeepalive)) { - /* Need to send an empty RTP packet */ - sip->lastrtptx = time(NULL); - ast_rtp_sendcng(sip->rtp, 0); - } - if (sip->lastrtprx && - (sip->rtptimeout || sip->rtpholdtimeout) && - (t > sip->lastrtprx + sip->rtptimeout)) { - /* Might be a timeout now -- see if we're on hold */ - struct sockaddr_in sin; - ast_rtp_get_peer(sip->rtp, &sin); - if (sin.sin_addr.s_addr || - (sip->rtpholdtimeout && - (t > sip->lastrtprx + sip->rtpholdtimeout))) { - /* Needs a hangup */ - if (sip->rtptimeout) { - while (sip->owner && ast_channel_trylock(sip->owner)) { - sip_pvt_unlock(sip); - usleep(1); - sip_pvt_lock(sip); - } - if (sip->owner) { - if (!(ast_rtp_get_bridged(sip->rtp))) { - ast_log(LOG_NOTICE, - "Disconnecting call '%s' for lack of RTP activity in %ld seconds\n", - sip->owner->name, - (long) (t - sip->lastrtprx)); - /* Issue a softhangup */ - ast_softhangup_nolock(sip->owner, AST_SOFTHANGUP_DEV); - } else - ast_log(LOG_NOTICE, "'%s' will not be disconnected in %ld seconds because it is directly bridged to another RTP stream\n", sip->owner->name, (long) (t - sip->lastrtprx)); - ast_channel_unlock(sip->owner); - /* forget the timeouts for this call, since a hangup - has already been requested and we don't want to - repeatedly request hangups - */ - sip->rtptimeout = 0; - sip->rtpholdtimeout = 0; - } +static void check_rtp_timeout(struct sip_pvt *dialog, time_t t) +{ + /* 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 (dialog->owner->_state != AST_STATE_UP || dialog->redirip.sin_addr.s_addr) + return; + + /* If we have no timers set, return now */ + if (ast_rtp_get_rtpkeepalive(dialog->rtp) == 0 || (ast_rtp_get_rtptimeout(dialog->rtp) == 0 && ast_rtp_get_rtpholdtimeout(dialog->rtp) == 0)) + return; + + /* Check AUDIO RTP keepalives */ + if (dialog->lastrtptx && ast_rtp_get_rtpkeepalive(dialog->rtp) && + (t > dialog->lastrtptx + ast_rtp_get_rtpkeepalive(dialog->rtp))) { + /* Need to send an empty RTP packet */ + dialog->lastrtptx = time(NULL); + ast_rtp_sendcng(dialog->rtp, 0); + } + + /*! \todo Check video RTP keepalives + + Do we need to move the lastrtptx to the RTP structure to have one for audio and one + for video? It really does belong to the RTP structure. + */ + + /* Check AUDIO RTP timers */ + if (dialog->lastrtprx && (ast_rtp_get_rtptimeout(dialog->rtp) || ast_rtp_get_rtpholdtimeout(dialog->rtp)) && + (t > dialog->lastrtprx + ast_rtp_get_rtptimeout(dialog->rtp))) { + + /* Might be a timeout now -- see if we're on hold */ + struct sockaddr_in sin; + ast_rtp_get_peer(dialog->rtp, &sin); + if (sin.sin_addr.s_addr || (ast_rtp_get_rtpholdtimeout(dialog->rtp) && + (t > dialog->lastrtprx + ast_rtp_get_rtpholdtimeout(dialog->rtp)))) { + /* Needs a hangup */ + if (dialog->rtptimeout) { + while (dialog->owner && ast_channel_trylock(dialog->owner)) { + sip_pvt_unlock(dialog); + usleep(1); + sip_pvt_lock(dialog); + } + if (!(ast_rtp_get_bridged(dialog->rtp))) { + ast_log(LOG_NOTICE, "Disconnecting call '%s' for lack of RTP activity in %ld seconds\n", + dialog->owner->name, (long) (t - dialog->lastrtprx)); + /* Issue a softhangup */ + ast_softhangup_nolock(dialog->owner, AST_SOFTHANGUP_DEV); + } else + ast_log(LOG_NOTICE, "'%s' will not be disconnected in %ld seconds because it is directly bridged to another RTP stream\n", dialog->owner->name, (long) (t - dialog->lastrtprx)); + ast_channel_unlock(dialog->owner); + /* forget the timeouts for this call, since a hangup + has already been requested and we don't want to + repeatedly request hangups + */ + ast_rtp_set_rtptimeout(dialog->rtp, 0); + ast_rtp_set_rtpholdtimeout(dialog->rtp, 0); + if (dialog->vrtp) { + ast_rtp_set_rtptimeout(dialog->vrtp, 0); + ast_rtp_set_rtpholdtimeout(dialog->vrtp, 0); } } } @@ -14971,7 +14992,7 @@ static void check_rtp_timeout(struct sip_pvt *sip, time_t t) static void *do_monitor(void *data) { int res; - struct sip_pvt *sip; + struct sip_pvt *dialog; struct sip_peer *peer = NULL; time_t t; int fastrestart = FALSE; @@ -14999,6 +15020,7 @@ static void *do_monitor(void *data) if (sipsock > -1) sipsock_read_id = ast_io_change(io, sipsock_read_id, sipsock, NULL, 0, NULL); } + /* Check for dialogs needing to be killed */ dialoglist_lock(); restartsearch: @@ -15007,18 +15029,20 @@ restartsearch: of time since the last time we did it (when MWI is being sent, we can get back to this point every millisecond or less) */ - for (sip = dialoglist; !fastrestart && sip; sip = sip->next) { - sip_pvt_lock(sip); + for (dialog = dialoglist; !fastrestart && dialog; dialog = dialog->next) { + sip_pvt_lock(dialog); /* Check RTP timeouts and kill calls if we have a timeout set and do not get RTP */ - check_rtp_timeout(sip, t); + check_rtp_timeout(dialog, t); /* If we have sessions that needs to be destroyed, do it now */ - if (ast_test_flag(&sip->flags[0], SIP_NEEDDESTROY) && !sip->packets && - !sip->owner) { - sip_pvt_unlock(sip); - __sip_destroy(sip, TRUE, FALSE); + /* Check if we have outstanding requests not responsed to or an active call + - if that's the case, wait with destruction */ + if (ast_test_flag(&dialog->flags[0], SIP_NEEDDESTROY) && !dialog->packets && + !dialog->owner) { + sip_pvt_unlock(dialog); + __sip_destroy(dialog, TRUE, FALSE); goto restartsearch; } - sip_pvt_unlock(sip); + sip_pvt_unlock(dialog); } dialoglist_unlock(); @@ -15027,7 +15051,8 @@ restartsearch: res = ast_sched_wait(sched); if ((res < 0) || (res > 1000)) res = 1000; - /* If we might need to send more mailboxes, don't wait long at all.*/ + + /* If we might need to send more mailbox notifications, don't wait long at all.*/ if (fastrestart) res = 1; res = ast_io_wait(io, res); |