- 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: https://origsvn.digium.com/svn/asterisk/trunk@48200 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
Olle Johansson
2006-12-02 12:05:40 +00:00
parent eef9f7958b
commit c23bc46089
4 changed files with 177 additions and 75 deletions

View File

@@ -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)
static void check_rtp_timeout(struct sip_pvt *dialog, 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;
}
/* 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);

View File

@@ -95,12 +95,6 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
;language=en ; Default language setting for all users/peers
; This may also be set for individual users/peers
;relaxdtmf=yes ; Relax dtmf handling
;rtptimeout=60 ; Terminate call if 60 seconds of no RTP or RTCP activity
; when we're not on hold. This is to be able to hangup
; a call in the case of a phone disappearing from the net,
; like a powerloss or grandma tripping over a cable.
;rtpholdtimeout=300 ; Terminate call if 300 seconds of no RTP or RTCP activity
; when we're on hold (must be > rtptimeout)
;trustrpid = no ; If Remote-Party-ID should be trusted
;sendrpid = yes ; If Remote-Party-ID should be sent
;progressinband=never ; If we should generate in-band ringing always
@@ -162,6 +156,21 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
;
;regcontext=sipregistrations
;
;--------------------------- RTP timers ----------------------------------------------------
; These timers are currently used for both audio and video streams. The RTP timeouts
; are only applied to the audio channel.
; The settings are settable in the global section as well as per device
;
;rtptimeout=60 ; Terminate call if 60 seconds of no RTP or RTCP activity
; on the audio channel
; when we're not on hold. This is to be able to hangup
; a call in the case of a phone disappearing from the net,
; like a powerloss or grandma tripping over a cable.
;rtpholdtimeout=300 ; Terminate call if 300 seconds of no RTP or RTCP activity
; on the audio channel
; when we're on hold (must be > rtptimeout)
;rtpkeepalive=<secs> ; Send keepalives in the RTP stream to keep NAT open
; (default is off - zero)
;--------------------------- SIP DEBUGGING ---------------------------------------------------
;sipdebug = yes ; Turn on SIP debugging by default, from
; the moment the channel loads this configuration
@@ -206,8 +215,9 @@ srvlookup=yes ; Enable DNS SRV lookups on outbound calls
;
; This setting is available in the [general] section as well as in device configurations.
; Setting this to yes, enables T.38 fax (UDPTL) passthrough on SIP to SIP calls, provided
; both parties have T38 support enabled in their Asterisk configuration (either general or
; peer/user/friend sections)
; both parties have T38 support enabled in their Asterisk configuration
; This has to be enabled in the general section for all devices to work. You can then
; disable it on a per device basis.
;
; t38pt_udptl = yes ; Default false
;

View File

@@ -219,6 +219,21 @@ struct ast_codec_pref *ast_rtp_codec_getpref(struct ast_rtp *rtp);
int ast_rtp_codec_getformat(int pt);
/*! \brief Set rtp timeout */
void ast_rtp_set_rtptimeout(struct ast_rtp *rtp, int timeout);
/*! \brief Set rtp hold timeout */
void ast_rtp_set_rtpholdtimeout(struct ast_rtp *rtp, int timeout);
/*! \brief set RTP keepalive interval */
void ast_rtp_set_rtpkeepalive(struct ast_rtp *rtp, int period);
/*! \brief Get RTP keepalive interval */
int ast_rtp_get_rtpkeepalive(struct ast_rtp *rtp);
/*! \brief Get rtp hold timeout */
int ast_rtp_get_rtpholdtimeout(struct ast_rtp *rtp);
/*! \brief Get rtp timeout */
int ast_rtp_get_rtptimeout(struct ast_rtp *rtp);
/* \brief Put RTP timeout timers on hold during another transaction, like T.38 */
void ast_rtp_set_rtptimers_onhold(struct ast_rtp *rtp);
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif

View File

@@ -128,6 +128,11 @@ struct ast_rtp {
double rxtransit; /*!< Relative transit time for previous packet */
int lasttxformat;
int lastrxformat;
int rtptimeout; /*!< RTP timeout time (negative or zero means disabled, negative value means temporarily disabled) */
int rtpholdtimeout; /*!< RTP timeout when on hold (negative or zero means disabled, negative value means temporarily disabled). */
int rtpkeepalive; /*!< Send RTP comfort noice packets for keepalive */
/* DTMF Reception Variables */
char resp;
unsigned int lasteventendseqn;
@@ -521,6 +526,53 @@ unsigned int ast_rtcp_calc_interval(struct ast_rtp *rtp)
return interval;
}
/* \brief Put RTP timeout timers on hold during another transaction, like T.38 */
void ast_rtp_set_rtptimers_onhold(struct ast_rtp *rtp)
{
rtp->rtptimeout = (-1) * rtp->rtptimeout;
rtp->rtpholdtimeout = (-1) * rtp->rtpholdtimeout;
}
/*! \brief Set rtp timeout */
void ast_rtp_set_rtptimeout(struct ast_rtp *rtp, int timeout)
{
rtp->rtptimeout = timeout;
}
/*! \brief Set rtp hold timeout */
void ast_rtp_set_rtpholdtimeout(struct ast_rtp *rtp, int timeout)
{
rtp->rtpholdtimeout = timeout;
}
/*! \brief set RTP keepalive interval */
void ast_rtp_set_rtpkeepalive(struct ast_rtp *rtp, int period)
{
rtp->rtpkeepalive = period;
}
/*! \brief Get rtp timeout */
int ast_rtp_get_rtptimeout(struct ast_rtp *rtp)
{
if (rtp->rtptimeout < 0) /* We're not checking, but remembering the setting (during T.38 transmission) */
return 0;
return rtp->rtptimeout;
}
/*! \brief Get rtp hold timeout */
int ast_rtp_get_rtpholdtimeout(struct ast_rtp *rtp)
{
if (rtp->rtptimeout < 0) /* We're not checking, but remembering the setting (during T.38 transmission) */
return 0;
return rtp->rtpholdtimeout;
}
/*! \brief Get RTP keepalive interval */
int ast_rtp_get_rtpkeepalive(struct ast_rtp *rtp)
{
return rtp->rtpkeepalive;
}
void ast_rtp_set_data(struct ast_rtp *rtp, void *data)
{
rtp->data = data;