@ -510,6 +510,7 @@ static const struct cfsip_options {
# define DEFAULT_TOS_SIP 0 /*!< Call signalling packets should be marked as DSCP CS3, but the default is 0 to be compatible with previous versions. */
# define DEFAULT_TOS_AUDIO 0 /*!< Audio packets should be marked as DSCP EF (Expedited Forwarding), but the default is 0 to be compatible with previous versions. */
# define DEFAULT_TOS_VIDEO 0 /*!< Video packets should be marked as DSCP AF41, but the default is 0 to be compatible with previous versions. */
# define DEFAULT_TOS_TEXT 0 /*!< Text packets should be marked as XXXX XXXX, but the default is 0 to be compatible with previous versions. */
# define DEFAULT_ALLOW_EXT_DOM TRUE
# define DEFAULT_REALM "asterisk"
# define DEFAULT_NOTIFYRINGING TRUE
@ -563,6 +564,7 @@ static int global_mwitime; /*!< Time between MWI checks for peers */
static unsigned int global_tos_sip ; /*!< IP type of service for SIP packets */
static unsigned int global_tos_audio ; /*!< IP type of service for audio RTP packets */
static unsigned int global_tos_video ; /*!< IP type of service for video RTP packets */
static unsigned int global_tos_text ; /*!< IP type of service for text RTP packets */
static int compactheaders ; /*!< send compact sip headers */
static int recordhistory ; /*!< Record SIP history. Off by default */
static int dumphistory ; /*!< Dump history to verbose before destroying SIP dialog */
@ -794,10 +796,14 @@ struct sip_auth {
# define SIP_PAGE2_CALL_ONHOLD_INACTIVE (1 << 24) /*!< 24: Inactive */
# define SIP_PAGE2_RFC2833_COMPENSATE (1 << 25) /*!< 25: ???? */
# define SIP_PAGE2_BUGGY_MWI (1 << 26) /*!< 26: Buggy CISCO MWI fix */
# define SIP_PAGE2_NOTEXT (1 << 27) /*!< 26: Text not supported */
# define SIP_PAGE2_TEXTSUPPORT (1 << 28) /*!< 27: Global text enable */
# define SIP_PAGE2_DEBUG_TEXT (1 << 29) /*!< 28: Global text debug */
# define SIP_PAGE2_FLAGS_TO_COPY \
( SIP_PAGE2_ALLOWSUBSCRIBE | SIP_PAGE2_ALLOWOVERLAP | SIP_PAGE2_VIDEOSUPPORT | \
SIP_PAGE2_T38SUPPORT | SIP_PAGE2_RFC2833_COMPENSATE | SIP_PAGE2_BUGGY_MWI )
SIP_PAGE2_T38SUPPORT | SIP_PAGE2_RFC2833_COMPENSATE | SIP_PAGE2_BUGGY_MWI | \
SIP_PAGE2_TEXTSUPPORT )
/* SIP packet flags */
# define SIP_PKT_DEBUG (1 << 0) /*!< Debug this packet */
@ -833,6 +839,7 @@ static int global_t38_capability = T38FAX_VERSION_0 | T38FAX_RATE_2400 | T38FAX_
# define sipdebug ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG)
# define sipdebug_config ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONFIG)
# define sipdebug_console ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_CONSOLE)
# define sipdebug_text ast_test_flag(&global_flags[1], SIP_PAGE2_DEBUG_TEXT)
/*! \brief T38 States for a call */
enum t38state {
@ -976,6 +983,7 @@ struct sip_pvt {
struct sockaddr_in sa ; /*!< Our peer */
struct sockaddr_in redirip ; /*!< Where our RTP should be going if not to us */
struct sockaddr_in vredirip ; /*!< Where our Video RTP should be going if not to us */
struct sockaddr_in tredirip ; /*!< Where our Text RTP should be going if not to us */
time_t lastrtprx ; /*!< Last RTP received */
time_t lastrtptx ; /*!< Last RTP sent */
int rtptimeout ; /*!< RTP timeout time */
@ -1010,6 +1018,7 @@ struct sip_pvt {
struct sip_registry * registry ; /*!< If this is a REGISTER dialog, to which registry */
struct ast_rtp * rtp ; /*!< RTP Session */
struct ast_rtp * vrtp ; /*!< Video RTP session */
struct ast_rtp * trtp ; /*!< Text RTP session */
struct sip_pkt * packets ; /*!< Packets scheduled for re-transmission */
struct sip_history_head * history ; /*!< History of this SIP dialog */
struct ast_variable * chanvars ; /*!< Channel variables to set for inbound call */
@ -1545,9 +1554,10 @@ static int handle_response_register(struct sip_pvt *p, int resp, char *rest, str
static void handle_response ( struct sip_pvt * p , int resp , char * rest , struct sip_request * req , int seqno ) ;
/*----- RTP interface functions */
static int sip_set_rtp_peer ( struct ast_channel * chan , struct ast_rtp * rtp , struct ast_rtp * vrtp , int codecs , int nat_active ) ;
static int sip_set_rtp_peer ( struct ast_channel * chan , struct ast_rtp * rtp , struct ast_rtp * vrtp , struct ast_rtp * trtp , int codecs , int nat_active ) ;
static enum ast_rtp_get_result sip_get_rtp_peer ( struct ast_channel * chan , struct ast_rtp * * rtp ) ;
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_frame * sip_rtp_read ( struct ast_channel * ast , struct sip_pvt * p , int * faxdetect ) ;
@ -1571,6 +1581,7 @@ static const struct ast_channel_tech sip_tech = {
. read = sip_read ,
. write = sip_write ,
. write_video = sip_write ,
. write_text = sip_write ,
. indicate = sip_indicate ,
. transfer = sip_transfer ,
. fixup = sip_fixup ,
@ -1619,6 +1630,7 @@ static struct ast_rtp_protocol sip_rtp = {
type : " SIP " ,
get_rtp_info : sip_get_rtp_peer ,
get_vrtp_info : sip_get_vrtp_peer ,
get_trtp_info : sip_get_trtp_peer ,
set_rtp_peer : sip_set_rtp_peer ,
get_codec : sip_get_codec ,
} ;
@ -2839,6 +2851,11 @@ static void do_setnat(struct sip_pvt *p, int natflags)
ast_log ( LOG_DEBUG , " Setting NAT on UDPTL to %s \n " , mode ) ;
ast_udptl_setnat ( p - > udptl , natflags ) ;
}
if ( p - > trtp ) {
if ( option_debug )
ast_log ( LOG_DEBUG , " Setting NAT on TRTP to %s \n " , mode ) ;
ast_rtp_setnat ( p - > trtp , natflags ) ;
}
}
/*! \brief Create address structure from peer reference.
@ -2860,6 +2877,10 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
ast_rtp_destroy ( dialog - > vrtp ) ;
dialog - > vrtp = NULL ;
}
if ( ! ast_test_flag ( & dialog - > flags [ 1 ] , SIP_PAGE2_TEXTSUPPORT ) & & dialog - > trtp ) {
ast_rtp_destroy ( dialog - > trtp ) ;
dialog - > trtp = NULL ;
}
dialog - > prefs = peer - > prefs ;
if ( ast_test_flag ( & dialog - > flags [ 1 ] , SIP_PAGE2_T38SUPPORT ) ) {
dialog - > t38 . capability = global_t38_capability ;
@ -2898,6 +2919,13 @@ static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
ast_rtp_set_rtpholdtimeout ( dialog - > vrtp , peer - > rtpholdtimeout ) ;
ast_rtp_set_rtpkeepalive ( dialog - > vrtp , peer - > rtpkeepalive ) ;
}
if ( dialog - > trtp ) {
ast_rtp_setdtmf ( dialog - > trtp , 0 ) ;
ast_rtp_setdtmfcompensate ( dialog - > trtp , 0 ) ;
ast_rtp_set_rtptimeout ( dialog - > trtp , peer - > rtptimeout ) ;
ast_rtp_set_rtpholdtimeout ( dialog - > trtp , peer - > rtpholdtimeout ) ;
ast_rtp_set_rtpkeepalive ( dialog - > trtp , peer - > rtpkeepalive ) ;
}
ast_string_field_set ( dialog , peername , peer - > username ) ;
ast_string_field_set ( dialog , authname , peer - > username ) ;
@ -3181,6 +3209,8 @@ static void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
ast_rtp_destroy ( p - > rtp ) ;
if ( p - > vrtp )
ast_rtp_destroy ( p - > vrtp ) ;
if ( p - > trtp )
ast_rtp_destroy ( p - > trtp ) ;
if ( p - > udptl )
ast_udptl_destroy ( p - > udptl ) ;
if ( p - > refer )
@ -3644,10 +3674,13 @@ static int sip_hangup(struct ast_channel *ast)
if ( ! p - > pendinginvite ) {
char * audioqos = " " ;
char * videoqos = " " ;
char * textqos = " " ;
if ( p - > rtp )
audioqos = ast_rtp_get_quality ( p - > rtp ) ;
if ( p - > vrtp )
videoqos = ast_rtp_get_quality ( p - > vrtp ) ;
if ( p - > trtp )
textqos = ast_rtp_get_quality ( p - > trtp ) ;
/* Send a hangup */
transmit_request_with_auth ( p , SIP_BYE , 0 , XMIT_RELIABLE , 1 ) ;
@ -3657,11 +3690,15 @@ static int sip_hangup(struct ast_channel *ast)
append_history ( p , " RTCPaudio " , " Quality:%s " , audioqos ) ;
if ( p - > vrtp )
append_history ( p , " RTCPvideo " , " Quality:%s " , videoqos ) ;
if ( p - > trtp )
append_history ( p , " RTCPtext " , " Quality:%s " , textqos ) ;
}
if ( p - > rtp & & oldowner )
pbx_builtin_setvar_helper ( oldowner , " RTPAUDIOQOS " , audioqos ) ;
if ( p - > vrtp & & oldowner )
pbx_builtin_setvar_helper ( oldowner , " RTPVIDEOQOS " , videoqos ) ;
if ( p - > trtp & & oldowner )
pbx_builtin_setvar_helper ( oldowner , " RTPTEXTQOS " , textqos ) ;
} else {
/* Note we will need a BYE when this all settles out
but we can ' t send one while we have " INVITE " outstanding . */
@ -3779,6 +3816,23 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
sip_pvt_unlock ( p ) ;
}
break ;
case AST_FRAME_TEXT :
if ( p ) {
sip_pvt_lock ( p ) ;
if ( p - > trtp ) {
/* Activate text early media */
if ( ( ast - > _state ! = AST_STATE_UP ) & &
! ast_test_flag ( & p - > flags [ 0 ] , SIP_PROGRESS_SENT ) & &
! ast_test_flag ( & p - > flags [ 0 ] , SIP_OUTGOING ) ) {
transmit_response_with_sdp ( p , " 183 Session Progress " , & p - > initreq , XMIT_UNRELIABLE ) ;
ast_set_flag ( & p - > flags [ 0 ] , SIP_PROGRESS_SENT ) ;
}
p - > lastrtptx = time ( NULL ) ;
res = ast_rtp_write ( p - > trtp , frame ) ;
}
sip_pvt_unlock ( p ) ;
}
break ;
case AST_FRAME_IMAGE :
return 0 ;
break ;
@ -4010,7 +4064,10 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
struct ast_variable * v = NULL ;
int fmt ;
int what ;
int video ;
int text ;
int needvideo = 0 ;
int needtext = 0 ;
{
const char * my_name ; /* pick a good name */
@ -4040,15 +4097,22 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
/* Select our native format based on codec preference until we receive
something from another device to the contrary . */
if ( i - > jointcapability ) /* The joint capabilities of us and peer */
if ( i - > jointcapability ) { /* The joint capabilities of us and peer */
what = i - > jointcapability ;
else if ( i - > capability ) /* Our configured capability for this peer */
video = i - > jointcapability & AST_FORMAT_VIDEO_MASK ;
text = i - > jointcapability & AST_FORMAT_TEXT_MASK ;
} else if ( i - > capability ) { /* Our configured capability for this peer */
what = i - > capability ;
else
video = i - > capability & AST_FORMAT_VIDEO_MASK ;
text = i - > capability & AST_FORMAT_TEXT_MASK ;
} else {
what = global_capability ; /* Global codec support */
video = global_capability & AST_FORMAT_VIDEO_MASK ;
text = global_capability & AST_FORMAT_TEXT_MASK ;
}
/* Set the native formats for audio and merge in video */
tmp - > nativeformats = ast_codec_choose ( & i - > prefs , what , 1 ) | ( i - > jointcapability & AST_FORMAT_VIDEO_MASK ) ;
tmp - > nativeformats = ast_codec_choose ( & i - > prefs , what , 1 ) | video | text ;
if ( option_debug > 2 ) {
char buf [ BUFSIZ ] ;
ast_log ( LOG_DEBUG , " *** Our native formats are %s \n " , ast_getformatname_multiple ( buf , BUFSIZ , tmp - > nativeformats ) ) ;
@ -4073,6 +4137,13 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
needvideo = i - > jointcapability & AST_FORMAT_VIDEO_MASK ; /* Inbound call */
}
if ( i - > trtp ) {
if ( i - > prefcodec )
needtext = i - > prefcodec & AST_FORMAT_TEXT_MASK ; /* Outbound call */
else
needtext = i - > jointcapability & AST_FORMAT_TEXT_MASK ; /* Inbound call */
}
if ( option_debug > 2 ) {
if ( needvideo )
ast_log ( LOG_DEBUG , " This channel can handle video! HOLLYWOOD next! \n " ) ;
@ -4096,6 +4167,9 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
tmp - > fds [ 2 ] = ast_rtp_fd ( i - > vrtp ) ;
tmp - > fds [ 3 ] = ast_rtcp_fd ( i - > vrtp ) ;
}
if ( needtext & & i - > trtp ) {
tmp - > fds [ 4 ] = ast_rtp_fd ( i - > trtp ) ;
}
if ( i - > udptl ) {
tmp - > fds [ 5 ] = ast_udptl_fd ( i - > udptl ) ;
}
@ -4314,6 +4388,19 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p
case 3 :
f = ast_rtcp_read ( p - > vrtp ) ; /* RTCP Control Channel for video */
break ;
case 4 :
f = ast_rtp_read ( p - > trtp ) ; /* RTP Text */
if ( sipdebug_text ) {
int i ;
unsigned char * arr = f - > data ;
for ( i = 0 ; i < f - > datalen ; i + + )
ast_verbose ( " %c " , ( arr [ i ] > ' ' & & arr [ i ] < ' } ' ) ? arr [ i ] : ' . ' ) ;
ast_verbose ( " -> " ) ;
for ( i = 0 ; i < f - > datalen ; i + + )
ast_verbose ( " %02X " , arr [ i ] ) ;
ast_verbose ( " \n " ) ;
}
break ;
case 5 :
f = ast_udptl_read ( p - > udptl ) ; /* UDPTL for T.38 */
break ;
@ -4331,7 +4418,7 @@ static struct ast_frame *sip_rtp_read(struct ast_channel *ast, struct sip_pvt *p
if ( f - > subclass ! = ( p - > owner - > nativeformats & AST_FORMAT_AUDIO_MASK ) ) {
if ( option_debug )
ast_log ( LOG_DEBUG , " Oooh, format changed to %d \n " , f - > subclass ) ;
p - > owner - > nativeformats = ( p - > owner - > nativeformats & AST_FORMAT_VIDEO_MASK ) | f - > subclass ;
p - > owner - > nativeformats = ( p - > owner - > nativeformats & ( AST_FORMAT_VIDEO_MASK | AST_FORMAT_TEXT_MASK ) ) | f - > subclass ;
ast_set_read_format ( p - > owner , p - > owner - > readformat ) ;
ast_set_write_format ( p - > owner , p - > owner - > writeformat ) ;
}
@ -4475,11 +4562,15 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
/* If the global videosupport flag is on, we always create a RTP interface for video */
if ( ast_test_flag ( & p - > flags [ 1 ] , SIP_PAGE2_VIDEOSUPPORT ) )
p - > vrtp = ast_rtp_new_with_bindaddr ( sched , io , 1 , 0 , bindaddr . sin_addr ) ;
if ( ast_test_flag ( & p - > flags [ 1 ] , SIP_PAGE2_TEXTSUPPORT ) )
p - > trtp = ast_rtp_new_with_bindaddr ( sched , io , 1 , 0 , bindaddr . sin_addr ) ;
if ( ast_test_flag ( & p - > flags [ 1 ] , SIP_PAGE2_T38SUPPORT ) )
p - > udptl = ast_udptl_new_with_bindaddr ( sched , io , 0 , bindaddr . sin_addr ) ;
if ( ! p - > rtp | | ( ast_test_flag ( & p - > flags [ 1 ] , SIP_PAGE2_VIDEOSUPPORT ) & & ! p - > vrtp ) ) {
ast_log ( LOG_WARNING , " Unable to create RTP audio %s session: %s \n " ,
ast_test_flag ( & p - > flags [ 1 ] , SIP_PAGE2_VIDEOSUPPORT ) ? " and video " : " " , strerror ( errno ) ) ;
if ( ! p - > rtp | | ( ast_test_flag ( & p - > flags [ 1 ] , SIP_PAGE2_VIDEOSUPPORT ) & & ! p - > vrtp )
| | ( ast_test_flag ( & p - > flags [ 1 ] , SIP_PAGE2_TEXTSUPPORT ) & & ! p - > trtp ) ) {
ast_log ( LOG_WARNING , " Unable to create RTP audio %s%ssession: %s \n " ,
ast_test_flag ( & p - > flags [ 1 ] , SIP_PAGE2_VIDEOSUPPORT ) ? " and video " : " " ,
ast_test_flag ( & p - > flags [ 1 ] , SIP_PAGE2_TEXTSUPPORT ) ? " and text " : " " , strerror ( errno ) ) ;
ast_mutex_destroy ( & p - > pvt_lock ) ;
if ( p - > chanvars ) {
ast_variables_destroy ( p - > chanvars ) ;
@ -4502,6 +4593,11 @@ static struct sip_pvt *sip_alloc(ast_string_field callid, struct sockaddr_in *si
ast_rtp_set_rtpholdtimeout ( p - > vrtp , global_rtpholdtimeout ) ;
ast_rtp_set_rtpkeepalive ( p - > vrtp , global_rtpkeepalive ) ;
}
if ( p - > trtp ) {
ast_rtp_settos ( p - > trtp , global_tos_text ) ;
ast_rtp_setdtmf ( p - > trtp , 0 ) ;
ast_rtp_setdtmfcompensate ( p - > trtp , 0 ) ;
}
if ( p - > udptl )
ast_udptl_settos ( p - > udptl , global_tos_audio ) ;
p - > maxcallbitrate = default_maxcallbitrate ;
@ -4944,6 +5040,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
int len = - 1 ;
int portno = - 1 ; /*!< RTP Audio port number */
int vportno = - 1 ; /*!< RTP Video port number */
int tportno = - 1 ; /*!< RTP Text port number */
int udptlportno = - 1 ;
int peert38capability = 0 ;
char s [ 256 ] ;
@ -4952,20 +5049,24 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
/* Peer capability is the capability in the SDP, non codec is RFC2833 DTMF (101) */
int peercapability = 0 , peernoncodeccapability = 0 ;
int vpeercapability = 0 , vpeernoncodeccapability = 0 ;
int tpeercapability = 0 , tpeernoncodeccapability = 0 ;
struct sockaddr_in sin ; /*!< media socket address */
struct sockaddr_in vsin ; /*!< Video socket address */
struct sockaddr_in tsin ; /*!< Text socket address */
const char * codecs ;
struct hostent * hp ; /*!< RTP Audio host IP */
struct hostent * vhp = NULL ; /*!< RTP video host IP */
struct hostent * thp = NULL ; /*!< RTP text host IP */
struct ast_hostent audiohp ;
struct ast_hostent videohp ;
struct ast_hostent texthp ;
int codec ;
int destiterator = 0 ;
int iterator ;
int sendonly = 0 ;
int numberofports ;
struct ast_rtp * newaudiortp , * newvideortp ; /* Buffers for codec handling */
struct ast_rtp * newaudiortp , * newvideortp , * newtextrtp ; /* Buffers for codec handling */
int newjointcapability ; /* Negotiated capability */
int newpeercapability ;
int newnoncodeccapability ;
@ -4991,6 +5092,11 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
ast_rtp_new_init ( newvideortp ) ;
ast_rtp_pt_clear ( newvideortp ) ;
newtextrtp = alloca ( ast_rtp_alloc_size ( ) ) ;
memset ( newtextrtp , 0 , ast_rtp_alloc_size ( ) ) ;
ast_rtp_new_init ( newtextrtp ) ;
ast_rtp_pt_clear ( newtextrtp ) ;
/* Update our last rtprx when we receive an SDP, too */
p - > lastrtprx = p - > lastrtptx = time ( NULL ) ; /* XXX why both ? */
@ -5017,15 +5123,24 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
return - 1 ;
}
vhp = hp ; /* Copy to video address as default too */
thp = hp ; /* Copy to video address as default too */
iterator = req - > sdp_start ;
ast_set_flag ( & p - > flags [ 0 ] , SIP_NOVIDEO ) ;
ast_set_flag ( & p - > flags [ 1 ] , SIP_PAGE2_NOTEXT ) ;
if ( p - > vrtp )
ast_rtp_pt_clear ( newvideortp ) ; /* Must be cleared in case no m=video line exists */
if ( p - > trtp )
ast_rtp_pt_clear ( newtextrtp ) ; /* Must be cleared in case no m=text line exists */
/* Find media streams in this SDP offer */
while ( ( m = get_sdp_iterate ( & iterator , req , " m " ) ) [ 0 ] ! = ' \0 ' ) {
int x ;
int audio = FALSE ;
int video = FALSE ;
int text = FALSE ;
numberofports = 1 ;
if ( ( sscanf ( m , " audio %d/%d RTP/AVP %n " , & x , & numberofports , & len ) = = 2 ) | |
@ -5046,7 +5161,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
}
} else if ( ( sscanf ( m , " video %d/%d RTP/AVP %n " , & x , & numberofports , & len ) = = 2 ) | |
( sscanf ( m , " video %d RTP/AVP %n " , & x , & len ) = = 1 ) ) {
/* If it is not audio - is it video ? */
video = TRUE ;
ast_clear_flag ( & p - > flags [ 0 ] , SIP_NOVIDEO ) ;
numberofmediastreams + + ;
vportno = x ;
@ -5060,6 +5175,22 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
ast_verbose ( " Found RTP video format %d \n " , codec ) ;
ast_rtp_set_m_type ( newvideortp , codec ) ;
}
} else if ( ( sscanf ( m , " text %d/%d RTP/AVP %n " , & x , & numberofports , & len ) = = 2 ) | |
( sscanf ( m , " text %d RTP/AVP %n " , & x , & len ) = = 1 ) ) {
text = TRUE ;
ast_clear_flag ( & p - > flags [ 1 ] , SIP_PAGE2_NOTEXT ) ;
numberofmediastreams + + ;
tportno = x ;
/* Scan through the RTP payload types specified in a "m=" line: */
for ( codecs = m + len ; ! ast_strlen_zero ( codecs ) ; codecs = ast_skip_blanks ( codecs + len ) ) {
if ( sscanf ( codecs , " %d%n " , & codec , & len ) ! = 1 ) {
ast_log ( LOG_WARNING , " Error in codec string '%s' \n " , codecs ) ;
return - 1 ;
}
if ( debug )
ast_verbose ( " Found RTP text format %d \n " , codec ) ;
ast_rtp_set_m_type ( newtextrtp , codec ) ;
}
} else if ( p - > udptl & & ( ( sscanf ( m , " image %d udptl t38%n " , & x , & len ) = = 1 ) | |
( sscanf ( m , " image %d UDPTL t38%n " , & x , & len ) = = 1 ) ) ) {
if ( debug )
@ -5092,27 +5223,35 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
if ( audio ) {
if ( ! ( hp = ast_gethostbyname ( host , & audiohp ) ) )
ast_log ( LOG_WARNING , " Unable to lookup RTP Audio host in secondary c= line, '%s' \n " , c ) ;
} else if ( ! ( vhp = ast_gethostbyname ( host , & videohp ) ) )
ast_log ( LOG_WARNING , " Unable to lookup RTP video host in secondary c= line, '%s' \n " , c ) ;
} else if ( video ) {
if ( ! ( vhp = ast_gethostbyname ( host , & videohp ) ) )
ast_log ( LOG_WARNING , " Unable to lookup RTP video host in secondary c= line, '%s' \n " , c ) ;
} else if ( text ) {
if ( ! ( thp = ast_gethostbyname ( host , & texthp ) ) )
ast_log ( LOG_WARNING , " Unable to lookup RTP text host in secondary c= line, '%s' \n " , c ) ;
}
}
}
}
if ( portno = = - 1 & & vportno = = - 1 & & udptlportno = = - 1 )
if ( portno = = - 1 & & vportno = = - 1 & & udptlportno = = - 1 & & tportno = = - 1 )
/* No acceptable offer found in SDP - we have no ports */
/* Do not change RTP or VRTP if this is a re-invite */
return - 2 ;
if ( numberofmediastreams > 2 )
/* We have too many fax, audio and/or video media streams, fail this offer */
if ( numberofmediastreams > 3 )
/* We have too many fax, audio and/or video and/or text media streams, fail this offer */
return - 3 ;
/* RTP addresses and ports for audio and video */
sin . sin_family = AF_INET ;
vsin . sin_family = AF_INET ;
tsin . sin_family = AF_INET ;
memcpy ( & sin . sin_addr , hp - > h_addr , sizeof ( sin . sin_addr ) ) ;
if ( vhp )
memcpy ( & vsin . sin_addr , vhp - > h_addr , sizeof ( vsin . sin_addr ) ) ;
if ( thp )
memcpy ( & tsin . sin_addr , thp - > h_addr , sizeof ( tsin . sin_addr ) ) ;
/* Setup UDPTL port number */
if ( p - > udptl ) {
@ -5146,11 +5285,15 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
}
}
}
/* Setup video port number */
/* Setup video port number , assumes we have audio */
if ( vportno ! = - 1 )
vsin . sin_port = htons ( vportno ) ;
/* Next, scan through each "a=rtpmap:" line, noting each
/* Setup text port number, assumes we have audio */
if ( tportno ! = - 1 )
tsin . sin_port = htons ( tportno ) ;
/* Next, scan through each "a=xxxx:" line, noting each
* specified RTP payload type ( with corresponding MIME subtype ) :
*/
/* XXX This needs to be done per media stream, since it's media stream specific */
@ -5240,10 +5383,18 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
last_rtpmap_codec + + ;
/* Note: should really look at the 'freq' and '#chans' params too */
ast_rtp_set_rtpmap_type ( newaudiortp , codec , " audio " , mimeSubtype ,
ast_test_flag ( & p - > flags [ 0 ] , SIP_G726_NONSTANDARD ) ? AST_RTP_OPT_G726_NONSTANDARD : 0 ) ;
if ( p - > vrtp )
ast_rtp_set_rtpmap_type ( newvideortp , codec , " video " , mimeSubtype , 0 ) ;
/* Note: This should all be done in the context of the m= above */
if ( ! strncasecmp ( mimeSubtype , " H26 " , 3 ) ) { /* Video */
/* Not going to do anything here for the moment, but we will soon */
} else if ( ! strncasecmp ( mimeSubtype , " T140 " , 4 ) ) { /* Text */
if ( p - > trtp ) {
/* ast_verbose("Adding t140 mimeSubtype to textrtp struct\n"); */
ast_rtp_set_rtpmap_type ( newtextrtp , codec , " text " , mimeSubtype , 0 ) ;
}
} else { /* Must be audio?? */
ast_rtp_set_rtpmap_type ( newaudiortp , codec , " audio " , mimeSubtype ,
ast_test_flag ( & p - > flags [ 0 ] , SIP_G726_NONSTANDARD ) ? AST_RTP_OPT_G726_NONSTANDARD : 0 ) ;
}
}
}
@ -5360,21 +5511,23 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
/* Now gather all of the codecs that we are asked for: */
ast_rtp_get_current_formats ( newaudiortp , & peercapability , & peernoncodeccapability ) ;
ast_rtp_get_current_formats ( newvideortp , & vpeercapability , & vpeernoncodeccapability ) ;
newjointcapability = p - > capability & ( peercapability | vpeercapability ) ;
newpeercapability = ( peercapability | vpeercapability ) ;
ast_rtp_get_current_formats ( newtextrtp , & tpeercapability , & tpeernoncodeccapability ) ;
newjointcapability = p - > capability & ( peercapability | vpeercapability | tpeercapability ) ;
newpeercapability = ( peercapability | vpeercapability | tpeercapability ) ;
newnoncodeccapability = p - > noncodeccapability & peernoncodeccapability ;
if ( debug ) {
/* shame on whoever coded this.... */
char s1 [ BUFSIZ ] , s2 [ BUFSIZ ] , s3 [ BUFSIZ ] , s4 [ BUFSIZ ] ;
char s1 [ BUFSIZ ] , s2 [ BUFSIZ ] , s3 [ BUFSIZ ] , s4 [ BUFSIZ ] , s5 [ BUFSIZ ] ;
ast_verbose ( " Capabilities: us - %s, peer - audio=%s/video=%s , combined - %s\n " ,
ast_verbose ( " Capabilities: us - %s, peer - audio=%s/video=%s /text=%s , combined - %s\n " ,
ast_getformatname_multiple ( s1 , BUFSIZ , p - > capability ) ,
ast_getformatname_multiple ( s2 , BUFSIZ , newpeercapability ) ,
ast_getformatname_multiple ( s3 , BUFSIZ , vpeercapability ) ,
ast_getformatname_multiple ( s4 , BUFSIZ , newjointcapability ) ) ;
ast_getformatname_multiple ( s4 , BUFSIZ , tpeercapability ) ,
ast_getformatname_multiple ( s5 , BUFSIZ , newjointcapability ) ) ;
ast_verbose ( " Non-codec capabilities (dtmf): us - %s, peer - %s, combined - %s \n " ,
ast_rtp_lookup_mime_multiple ( s1 , BUFSIZ , p - > noncodeccapability , 0 , 0 ) ,
@ -5403,6 +5556,8 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
ast_rtp_pt_copy ( p - > rtp , newaudiortp ) ;
if ( p - > vrtp )
ast_rtp_pt_copy ( p - > vrtp , newvideortp ) ;
if ( p - > trtp )
ast_rtp_pt_copy ( p - > trtp , newtextrtp ) ;
if ( ast_test_flag ( & p - > flags [ 0 ] , SIP_DTMF ) = = SIP_DTMF_AUTO ) {
ast_clear_flag ( & p - > flags [ 0 ] , SIP_DTMF ) ;
@ -5431,6 +5586,13 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
ast_verbose ( " Peer video RTP is at port %s:%d \n " , ast_inet_ntoa ( vsin . sin_addr ) , ntohs ( vsin . sin_port ) ) ;
}
/* Setup text port number */
if ( p - > trtp & & tsin . sin_port ) {
ast_rtp_set_peer ( p - > trtp , & tsin ) ;
if ( debug )
ast_verbose ( " Peer text RTP is at port %s:%d \n " , ast_inet_ntoa ( tsin . sin_addr ) , ntohs ( tsin . sin_port ) ) ;
}
/* Ok, we're going with this offer */
if ( option_debug > 1 ) {
char buf [ BUFSIZ ] ;
@ -5450,7 +5612,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req)
ast_getformatname_multiple ( s1 , BUFSIZ , p - > jointcapability ) ,
ast_getformatname_multiple ( s2 , BUFSIZ , p - > owner - > nativeformats ) ) ;
}
p - > owner - > nativeformats = ast_codec_choose ( & p - > prefs , p - > jointcapability , 1 ) | ( p - > capability & vpeercapability ) ;
p - > owner - > nativeformats = ast_codec_choose ( & p - > prefs , p - > jointcapability , 1 ) | ( p - > capability & vpeercapability ) | ( p - > capability & tpeercapability ) ;
ast_set_read_format ( p - > owner , p - > owner - > readformat ) ;
ast_set_write_format ( p - > owner , p - > owner - > writeformat ) ;
}
@ -6187,6 +6349,52 @@ static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate
* min_packet_size = fmt . cur_ms ;
}
/*! \brief Add video codec offer to SDP offer/answer body in INVITE or 200 OK */
/* This is different to the audio one now so we can add more caps later */
static void add_vcodec_to_sdp ( const struct sip_pvt * p , int codec , int sample_rate ,
char * * m_buf , size_t * m_size , char * * a_buf , size_t * a_size ,
int debug , int * min_packet_size )
{
int rtp_code ;
if ( ! p - > vrtp )
return ;
if ( debug )
ast_verbose ( " Adding video codec 0x%x (%s) to SDP \n " , codec , ast_getformatname ( codec ) ) ;
if ( ( rtp_code = ast_rtp_lookup_code ( p - > vrtp , 1 , codec ) ) = = - 1 )
return ;
ast_build_string ( m_buf , m_size , " %d " , rtp_code ) ;
ast_build_string ( a_buf , a_size , " a=rtpmap:%d %s/%d \r \n " , rtp_code ,
ast_rtp_lookup_mime_subtype ( 1 , codec , 0 ) , sample_rate ) ;
/* Add fmtp code here */
}
/*! \brief Add text codec offer to SDP offer/answer body in INVITE or 200 OK */
static void add_tcodec_to_sdp ( const struct sip_pvt * p , int codec , int sample_rate ,
char * * m_buf , size_t * m_size , char * * a_buf , size_t * a_size ,
int debug , int * min_packet_size )
{
int rtp_code ;
if ( ! p - > trtp )
return ;
if ( debug )
ast_verbose ( " Adding text codec 0x%x (%s) to SDP \n " , codec , ast_getformatname ( codec ) ) ;
if ( ( rtp_code = ast_rtp_lookup_code ( p - > trtp , 1 , codec ) ) = = - 1 )
return ;
ast_build_string ( m_buf , m_size , " %d " , rtp_code ) ;
ast_build_string ( a_buf , a_size , " a=rtpmap:%d %s/%d \r \n " , rtp_code ,
ast_rtp_lookup_mime_subtype ( 1 , codec , 0 ) , sample_rate ) ;
/* Add fmtp code here */
}
/*! \brief Get Max T.38 Transmission rate from T38 capabilities */
static int t38_get_rate ( int t38cap )
{
@ -6344,12 +6552,14 @@ static void add_noncodec_to_sdp(const struct sip_pvt *p, int format, int sample_
/*! \brief Set all IP media addresses for this call
\ note called from add_sdp ( )
*/
static void get_our_media_address ( struct sip_pvt * p , int needvideo , struct sockaddr_in * sin , struct sockaddr_in * vsin , struct sockaddr_in * dest, struct sockaddr_in * vdest )
static void get_our_media_address ( struct sip_pvt * p , int needvideo , struct sockaddr_in * sin , struct sockaddr_in * vsin , struct sockaddr_in * tsin, struct sockaddr_in * dest, struct sockaddr_in * vdest )
{
/* First, get our address */
ast_rtp_get_us ( p - > rtp , sin ) ;
if ( p - > vrtp )
ast_rtp_get_us ( p - > vrtp , vsin ) ;
if ( p - > trtp )
ast_rtp_get_us ( p - > trtp , tsin ) ;
/* Now, try to figure out where we want them to send data */
/* Is this a re-invite to move the media out, then use the original offer from caller */
@ -6383,8 +6593,10 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
struct sockaddr_in sin ;
struct sockaddr_in vsin ;
struct sockaddr_in tsin ;
struct sockaddr_in dest ;
struct sockaddr_in vdest = { 0 , } ;
struct sockaddr_in tdest = { 0 , } ;
/* SDP fields */
char * version = " v=0 \r \n " ; /* Protocol version */
@ -6396,25 +6608,34 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
char * hold ;
char m_audio [ 256 ] ; /* Media declaration line for audio */
char m_video [ 256 ] ; /* Media declaration line for video */
char m_text [ 256 ] ; /* Media declaration line for text */
char a_audio [ 1024 ] ; /* Attributes for audio */
char a_video [ 1024 ] ; /* Attributes for video */
char a_text [ 1024 ] ; /* Attributes for text */
char * m_audio_next = m_audio ;
char * m_video_next = m_video ;
char * m_text_next = m_text ;
size_t m_audio_left = sizeof ( m_audio ) ;
size_t m_video_left = sizeof ( m_video ) ;
size_t m_text_left = sizeof ( m_text ) ;
char * a_audio_next = a_audio ;
char * a_video_next = a_video ;
char * a_text_next = a_text ;
size_t a_audio_left = sizeof ( a_audio ) ;
size_t a_video_left = sizeof ( a_video ) ;
size_t a_text_left = sizeof ( a_text ) ;
int x ;
int capability ;
int needvideo = FALSE ;
int needtext = FALSE ;
int debug = sip_debug_test_pvt ( p ) ;
int min_audio_packet_size = 0 ;
int min_video_packet_size = 0 ;
int min_text_packet_size = 0 ;
m_video [ 0 ] = ' \0 ' ; /* Reset the video media string if it's not needed */
m_text [ 0 ] = ' \0 ' ; /* Reset the video media string if it's not needed */
if ( ! p - > rtp ) {
ast_log ( LOG_WARNING , " No way to add SDP without an RTP structure \n " ) ;
@ -6434,7 +6655,8 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
if ( option_debug > 1 ) {
char codecbuf [ BUFSIZ ] ;
ast_log ( LOG_DEBUG , " ** Our capability: %s Video flag: %s \n " , ast_getformatname_multiple ( codecbuf , sizeof ( codecbuf ) , capability ) , ast_test_flag ( & p - > flags [ 0 ] , SIP_NOVIDEO ) ? " True " : " False " ) ;
ast_log ( LOG_DEBUG , " ** Our capability: %s Video flag: %s Text flag: %s \n " , ast_getformatname_multiple ( codecbuf , sizeof ( codecbuf ) , capability ) ,
ast_test_flag ( & p - > flags [ 0 ] , SIP_NOVIDEO ) ? " True " : " False " , ast_test_flag ( & p - > flags [ 1 ] , SIP_PAGE2_NOTEXT ) ? " True " : " False " ) ;
ast_log ( LOG_DEBUG , " ** Our prefcodec: %s \n " , ast_getformatname_multiple ( codecbuf , sizeof ( codecbuf ) , p - > prefcodec ) ) ;
}
@ -6456,8 +6678,11 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
}
/* Get our media addresses */
get_our_media_address ( p , needvideo , & sin , & vsin , & dest, & vdest ) ;
get_our_media_address ( p , needvideo , & sin , & vsin , & tsin, & dest, & vdest ) ;
if ( debug )
ast_verbose ( " Audio is at %s port %d \n " , ast_inet_ntoa ( p - > ourip ) , ntohs ( sin . sin_port ) ) ;
/* Ok, we need video. Let's add what we need for video and set codecs.
Video is handled differently than audio since we can not transcode . */
if ( needvideo ) {
@ -6470,8 +6695,36 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
ast_verbose ( " Video is at %s port %d \n " , ast_inet_ntoa ( p - > ourip ) , ntohs ( vsin . sin_port ) ) ;
}
if ( debug )
ast_verbose ( " Audio is at %s port %d \n " , ast_inet_ntoa ( p - > ourip ) , ntohs ( sin . sin_port ) ) ;
/* Check if we need text in this call */
if ( ( capability & AST_FORMAT_TEXT_MASK ) & & ! ast_test_flag ( & p - > flags [ 1 ] , SIP_PAGE2_NOTEXT ) ) {
if ( sipdebug_text ) ast_verbose ( " We think we can do text \n " ) ;
if ( p - > trtp ) {
if ( sipdebug_text ) ast_verbose ( " And we have a text rtp object \n " ) ;
needtext = TRUE ;
if ( option_debug > 1 )
ast_log ( LOG_DEBUG , " This call needs text offers! \n " ) ;
} else if ( option_debug > 1 )
ast_log ( LOG_DEBUG , " This call needs text offers, but there's no text support enabled ! \n " ) ;
}
/* Ok, we need text. Let's add what we need for text and set codecs.
Text is handled differently than audio since we can not transcode . */
if ( needtext ) {
if ( sipdebug_text ) ast_verbose ( " Lets set up the text sdp \n " ) ;
/* Determine text destination */
if ( p - > tredirip . sin_addr . s_addr ) {
tdest . sin_addr = p - > tredirip . sin_addr ;
tdest . sin_port = p - > tredirip . sin_port ;
} else {
tdest . sin_addr = p - > ourip ;
tdest . sin_port = tsin . sin_port ;
}
ast_build_string ( & m_text_next , & m_text_left , " m=text %d RTP/AVP " , ntohs ( tdest . sin_port ) ) ;
if ( debug )
ast_verbose ( " Text is at %s port %d \n " , ast_inet_ntoa ( p - > ourip ) , ntohs ( tsin . sin_port ) ) ;
}
/* Start building generic SDP headers */
@ -6529,7 +6782,7 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
}
/* Now send any other common audio and video codecs, and non-codec formats: */
for ( x = 1 ; x < = ( need video ? AST_FORMAT_MAX_VIDEO : AST_FORMAT_MAX_AUDIO ) ; x < < = 1 ) {
for ( x = 1 ; x < = ( need text ? AST_FORMAT_MAX_TEXT : ( need video ? AST_FORMAT_MAX_VIDEO : AST_FORMAT_MAX_AUDIO ) ) ; x < < = 1 ) {
if ( ! ( capability & x ) ) /* Codec not requested */
continue ;
@ -6541,11 +6794,16 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
& m_audio_next , & m_audio_left ,
& a_audio_next , & a_audio_left ,
debug , & min_audio_packet_size ) ;
else
add_ codec_to_sdp( p , x , 90000 ,
else if ( x < = AST_FORMAT_MAX_VIDEO )
add_ v codec_to_sdp( p , x , 90000 ,
& m_video_next , & m_video_left ,
& a_video_next , & a_video_left ,
debug , & min_video_packet_size ) ;
else if ( x < = AST_FORMAT_MAX_TEXT )
add_tcodec_to_sdp ( p , x , 1000 ,
& m_text_next , & m_text_left ,
& a_text_next , & a_text_left ,
debug , & min_text_packet_size ) ;
}
/* Now add DTMF RFC2833 telephony-event as a codec */
@ -6565,21 +6823,32 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
if ( ! p - > owner | | ! ast_internal_timing_enabled ( p - > owner ) )
ast_build_string ( & a_audio_next , & a_audio_left , " a=silenceSupp:off - - - - \r \n " ) ;
if ( min_audio_packet_size )
ast_build_string ( & a_audio_next , & a_audio_left , " a=ptime:%d \r \n " , min_audio_packet_size ) ;
if ( min_video_packet_size )
ast_build_string ( & a_video_next , & a_video_left , " a=ptime:%d \r \n " , min_video_packet_size ) ;
if ( ( m_audio_left < 2 ) | | ( m_video_left < 2 ) | | ( a_audio_left = = 0 ) | | ( a_video_left = = 0 ) )
ast_log ( LOG_WARNING , " SIP SDP may be truncated due to undersized buffer!! \n " ) ;
ast_build_string ( & m_audio_next , & m_audio_left , " \r \n " ) ;
if ( needvideo )
ast_build_string ( & m_video_next , & m_video_left , " \r \n " ) ;
len = strlen ( version ) + strlen ( subject ) + strlen ( owner ) + strlen ( connection ) + strlen ( stime ) + strlen ( m_audio ) + strlen ( a_audio ) + strlen ( hold ) ;
if ( needvideo ) /* only if video response is appropriate */
len + = strlen ( m_video ) + strlen ( a_video ) + strlen ( bandwidth ) + strlen ( hold ) ;
if ( min_audio_packet_size )
ast_build_string ( & a_audio_next , & a_audio_left , " a=ptime:%d \r \n " , min_audio_packet_size ) ;
/* XXX don't think you can have ptime for video */
if ( min_video_packet_size )
ast_build_string ( & a_video_next , & a_video_left , " a=ptime:%d \r \n " , min_video_packet_size ) ;
/* XXX don't think you can have ptime for text */
if ( min_text_packet_size )
ast_build_string ( & a_text_next , & a_text_left , " a=ptime:%d \r \n " , min_text_packet_size ) ;
if ( ( m_audio_left < 2 ) | | ( m_video_left < 2 ) | | ( m_text_left < 2 ) | |
( a_audio_left = = 0 ) | | ( a_video_left = = 0 ) | | ( a_text_left = = 0 ) )
ast_log ( LOG_WARNING , " SIP SDP may be truncated due to undersized buffer!! \n " ) ;
ast_build_string ( & m_audio_next , & m_audio_left , " \r \n " ) ;
if ( needvideo )
ast_build_string ( & m_video_next , & m_video_left , " \r \n " ) ;
if ( needtext )
ast_build_string ( & m_text_next , & m_text_left , " \r \n " ) ;
len = strlen ( version ) + strlen ( subject ) + strlen ( owner ) + strlen ( connection ) + strlen ( stime ) + strlen ( m_audio ) + strlen ( a_audio ) + strlen ( hold ) ;
if ( needvideo ) /* only if video response is appropriate */
len + = strlen ( m_video ) + strlen ( a_video ) + strlen ( bandwidth ) + strlen ( hold ) ;
if ( needtext ) /* only if text response is appropriate */
len + = strlen ( m_text ) + strlen ( a_text ) + strlen ( hold ) ;
add_header ( resp , " Content-Type " , " application/sdp " ) ;
add_header_contentLength ( resp , len ) ;
@ -6598,6 +6867,11 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
add_line ( resp , a_video ) ;
add_line ( resp , hold ) ; /* Repeat hold for the video stream */
}
if ( needtext ) { /* only if text response is appropriate */
add_line ( resp , m_text ) ;
add_line ( resp , a_text ) ;
add_line ( resp , hold ) ; /* Repeat hold for the text stream */
}
/* Update lastrtprx when we send our SDP */
p - > lastrtprx = p - > lastrtptx = time ( NULL ) ; /* XXX why both ? */
@ -9359,6 +9633,11 @@ static enum check_auth_result check_user_ok(struct sip_pvt *p, char *of,
ast_rtp_destroy ( p - > vrtp ) ;
p - > vrtp = NULL ;
}
/* If we do not support text, remove text from call structure */
if ( ! ast_test_flag ( & p - > flags [ 1 ] , SIP_PAGE2_TEXTSUPPORT ) & & p - > trtp ) {
ast_rtp_destroy ( p - > trtp ) ;
p - > trtp = NULL ;
}
}
unref_user ( user ) ;
return res ;
@ -9473,6 +9752,10 @@ static enum check_auth_result check_peer_ok(struct sip_pvt *p, char *of,
ast_rtp_destroy ( p - > vrtp ) ;
p - > vrtp = NULL ;
}
if ( ( ! ast_test_flag ( & p - > flags [ 1 ] , SIP_PAGE2_TEXTSUPPORT ) | | ! ( p - > capability & AST_FORMAT_TEXT_MASK ) ) & & p - > trtp ) {
ast_rtp_destroy ( p - > trtp ) ;
p - > trtp = NULL ;
}
if ( ( ast_test_flag ( & p - > flags [ 0 ] , SIP_DTMF ) = = SIP_DTMF_RFC2833 ) | |
( ast_test_flag ( & p - > flags [ 0 ] , SIP_DTMF ) = = SIP_DTMF_AUTO ) )
p - > noncodeccapability | = AST_RTP_DTMF ;
@ -9962,6 +10245,7 @@ static int _sip_show_peers(int fd, int *total, struct mansession *s, const struc
" Dynamic: %s \r \n "
" Natsupport: %s \r \n "
" VideoSupport: %s \r \n "
" TextSupport: %s \r \n "
" ACL: %s \r \n "
" Status: %s \r \n "
" RealtimeDevice: %s \r \n \r \n " ,
@ -9972,6 +10256,7 @@ static int _sip_show_peers(int fd, int *total, struct mansession *s, const struc
ast_test_flag ( & iterator - > flags [ 1 ] , SIP_PAGE2_DYNAMIC ) ? " yes " : " no " , /* Dynamic or not? */
ast_test_flag ( & iterator - > flags [ 0 ] , SIP_NAT_ROUTE ) ? " yes " : " no " , /* NAT=yes? */
ast_test_flag ( & iterator - > flags [ 1 ] , SIP_PAGE2_VIDEOSUPPORT ) ? " yes " : " no " , /* VIDEOSUPPORT=yes? */
ast_test_flag ( & iterator - > flags [ 1 ] , SIP_PAGE2_TEXTSUPPORT ) ? " yes " : " no " , /* TEXTSUPPORT=yes? */
iterator - > ha ? " yes " : " no " , /* permit/deny */
status ,
realtimepeers ? ( ast_test_flag ( & iterator - > flags [ 0 ] , SIP_REALTIME ) ? " yes " : " no " ) : " no " ) ;
@ -10392,6 +10677,7 @@ static int _sip_show_peer(int type, int fd, struct mansession *s, const struct m
ast_cli ( fd , " PromiscRedir : %s \n " , ast_test_flag ( & peer - > flags [ 0 ] , SIP_PROMISCREDIR ) ? " Yes " : " No " ) ;
ast_cli ( fd , " User=Phone : %s \n " , ast_test_flag ( & peer - > flags [ 0 ] , SIP_USEREQPHONE ) ? " Yes " : " No " ) ;
ast_cli ( fd , " Video Support: %s \n " , ast_test_flag ( & peer - > flags [ 1 ] , SIP_PAGE2_VIDEOSUPPORT ) ? " Yes " : " No " ) ;
ast_cli ( fd , " Text Support : %s \n " , ast_test_flag ( & peer - > flags [ 1 ] , SIP_PAGE2_TEXTSUPPORT ) ? " Yes " : " No " ) ;
ast_cli ( fd , " Trust RPID : %s \n " , ast_test_flag ( & peer - > flags [ 0 ] , SIP_TRUSTRPID ) ? " Yes " : " No " ) ;
ast_cli ( fd , " Send RPID : %s \n " , ast_test_flag ( & peer - > flags [ 0 ] , SIP_SENDRPID ) ? " Yes " : " No " ) ;
ast_cli ( fd , " Subscriptions: %s \n " , ast_test_flag ( & peer - > flags [ 1 ] , SIP_PAGE2_ALLOWSUBSCRIBE ) ? " Yes " : " No " ) ;
@ -10479,6 +10765,7 @@ static int _sip_show_peer(int type, int fd, struct mansession *s, const struct m
astman_append ( s , " SIP-PromiscRedir: %s \r \n " , ( ast_test_flag ( & peer - > flags [ 0 ] , SIP_PROMISCREDIR ) ? " Y " : " N " ) ) ;
astman_append ( s , " SIP-UserPhone: %s \r \n " , ( ast_test_flag ( & peer - > flags [ 0 ] , SIP_USEREQPHONE ) ? " Y " : " N " ) ) ;
astman_append ( s , " SIP-VideoSupport: %s \r \n " , ( ast_test_flag ( & peer - > flags [ 1 ] , SIP_PAGE2_VIDEOSUPPORT ) ? " Y " : " N " ) ) ;
astman_append ( s , " SIP-TextSupport: %s \r \n " , ( ast_test_flag ( & peer - > flags [ 1 ] , SIP_PAGE2_TEXTSUPPORT ) ? " Y " : " N " ) ) ;
/* - is enumerated */
astman_append ( s , " SIP-DTMFmode: %s \r \n " , dtmfmode2str ( ast_test_flag ( & peer - > flags [ 0 ] , SIP_DTMF ) ) ) ;
@ -10628,6 +10915,7 @@ static int sip_show_settings(int fd, int argc, char *argv[])
ast_cli ( fd , " SIP Port: %d \n " , ntohs ( bindaddr . sin_port ) ) ;
ast_cli ( fd , " Bindaddress: %s \n " , ast_inet_ntoa ( bindaddr . sin_addr ) ) ;
ast_cli ( fd , " Videosupport: %s \n " , ast_test_flag ( & global_flags [ 1 ] , SIP_PAGE2_VIDEOSUPPORT ) ? " Yes " : " No " ) ;
ast_cli ( fd , " Textsupport: %s \n " , ast_test_flag ( & global_flags [ 1 ] , SIP_PAGE2_TEXTSUPPORT ) ? " Yes " : " No " ) ;
ast_cli ( fd , " AutoCreatePeer: %s \n " , autocreatepeer ? " Yes " : " No " ) ;
ast_cli ( fd , " MatchAuthUsername: %s \n " , global_match_auth_username ? " Yes " : " No " ) ;
ast_cli ( fd , " Allow unknown access: %s \n " , global_allowguest ? " Yes " : " No " ) ;
@ -10652,6 +10940,7 @@ static int sip_show_settings(int fd, int argc, char *argv[])
ast_cli ( fd , " IP ToS SIP: %s \n " , ast_tos2str ( global_tos_sip ) ) ;
ast_cli ( fd , " IP ToS RTP audio: %s \n " , ast_tos2str ( global_tos_audio ) ) ;
ast_cli ( fd , " IP ToS RTP video: %s \n " , ast_tos2str ( global_tos_video ) ) ;
ast_cli ( fd , " IP ToS RTP text: %s \n " , ast_tos2str ( global_tos_text ) ) ;
ast_cli ( fd , " T38 fax pt UDPTL: %s \n " , ast_test_flag ( & global_flags [ 1 ] , SIP_PAGE2_T38SUPPORT_UDPTL ) ? " Yes " : " No " ) ;
# ifdef WHEN_WE_HAVE_T38_FOR_OTHER_TRANSPORTS
ast_cli ( fd , " T38 fax pt RTP: %s \n " , ast_test_flag ( & global_flags [ 1 ] , SIP_PAGE2_T38SUPPORT_RTP ) ? " Yes " : " No " ) ;
@ -11262,6 +11551,7 @@ static int sip_do_debug(int fd, int argc, char *argv[])
return RESULT_SHOWUSAGE ;
}
ast_set_flag ( & global_flags [ 1 ] , SIP_PAGE2_DEBUG_CONSOLE ) ;
ast_set_flag ( & global_flags [ 1 ] , SIP_PAGE2_DEBUG_TEXT ) ; /*! \note this can be a special debug command - "sip debug text" or something */
memset ( & debugaddr , 0 , sizeof ( debugaddr ) ) ;
ast_cli ( fd , " SIP Debugging %senabled \n " , oldsipdebug ? " re- " : " " ) ;
return RESULT_SUCCESS ;
@ -11329,6 +11619,7 @@ static int sip_no_debug(int fd, int argc, char *argv[])
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
ast_clear_flag ( & global_flags [ 1 ] , SIP_PAGE2_DEBUG_CONSOLE ) ;
ast_clear_flag ( & global_flags [ 1 ] , SIP_PAGE2_DEBUG_TEXT ) ;
ast_cli ( fd , " SIP Debugging Disabled \n " ) ;
return RESULT_SUCCESS ;
}
@ -12510,6 +12801,8 @@ static void stop_media_flows(struct sip_pvt *p)
ast_rtp_stop ( p - > rtp ) ;
if ( p - > vrtp )
ast_rtp_stop ( p - > vrtp ) ;
if ( p - > trtp )
ast_rtp_stop ( p - > trtp ) ;
if ( p - > udptl )
ast_udptl_stop ( p - > udptl ) ;
}
@ -14487,7 +14780,7 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req)
/* Get RTCP quality before end of call */
if ( ! ast_test_flag ( & p - > flags [ 0 ] , SIP_NO_HISTORY ) | | p - > owner ) {
char * audioqos , * videoqos ;
char * audioqos , * videoqos , * textqos ;
if ( p - > rtp ) {
audioqos = ast_rtp_get_quality ( p - > rtp ) ;
if ( ! ast_test_flag ( & p - > flags [ 0 ] , SIP_NO_HISTORY ) )
@ -14502,6 +14795,13 @@ static int handle_request_bye(struct sip_pvt *p, struct sip_request *req)
if ( p - > owner )
pbx_builtin_setvar_helper ( p - > owner , " RTPVIDEOQOS " , videoqos ) ;
}
if ( p - > trtp ) {
textqos = ast_rtp_get_quality ( p - > trtp ) ;
if ( ! ast_test_flag ( & p - > flags [ 0 ] , SIP_NO_HISTORY ) )
append_history ( p , " RTCPtext " , " Quality:%s " , textqos ) ;
if ( p - > owner )
pbx_builtin_setvar_helper ( p - > owner , " RTPTEXTQOS " , textqos ) ;
}
}
stop_media_flows ( p ) ; /* Immediately stop RTP, VRTP and UDPTL as applicable */
@ -15697,6 +15997,7 @@ static struct ast_channel *sip_request_call(const char *type, int format, void *
printf ( " Setting up to call extension '%s' at '%s' \n " , ext ? ext : " <none> " , host ) ;
# endif
p - > prefcodec = oldformat ; /* Format for this call */
p - > jointcapability = oldformat ;
sip_pvt_lock ( p ) ;
tmpc = sip_new ( p , AST_STATE_DOWN , host ) ; /* Place the call */
sip_pvt_unlock ( p ) ;
@ -15819,6 +16120,10 @@ static int handle_common_options(struct ast_flags *flags, struct ast_flags *mask
ast_set_flag ( & mask [ 1 ] , SIP_PAGE2_VIDEOSUPPORT ) ;
ast_set2_flag ( & flags [ 1 ] , ast_true ( v - > value ) , SIP_PAGE2_VIDEOSUPPORT ) ;
res = 1 ;
} else if ( ! strcasecmp ( v - > name , " textsupport " ) ) {
ast_set_flag ( & mask [ 1 ] , SIP_PAGE2_TEXTSUPPORT ) ;
ast_set2_flag ( & flags [ 1 ] , ast_true ( v - > value ) , SIP_PAGE2_TEXTSUPPORT ) ;
res = 1 ;
} else if ( ! strcasecmp ( v - > name , " allowoverlap " ) ) {
ast_set_flag ( & mask [ 1 ] , SIP_PAGE2_ALLOWOVERLAP ) ;
ast_set2_flag ( & flags [ 1 ] , ast_true ( v - > value ) , SIP_PAGE2_ALLOWOVERLAP ) ;
@ -16517,6 +16822,7 @@ static int reload_config(enum channelreloadreason reason)
global_tos_sip = DEFAULT_TOS_SIP ;
global_tos_audio = DEFAULT_TOS_AUDIO ;
global_tos_video = DEFAULT_TOS_VIDEO ;
global_tos_text = DEFAULT_TOS_TEXT ;
externhost [ 0 ] = ' \0 ' ; /* External host name (for behind NAT DynDNS support) */
externexpire = 0 ; /* Expiration for DNS re-issuing */
externrefresh = 10 ;
@ -16584,6 +16890,7 @@ static int reload_config(enum channelreloadreason reason)
memcpy ( & global_jbconf , & default_jbconf , sizeof ( struct ast_jb_conf ) ) ;
ast_clear_flag ( & global_flags [ 1 ] , SIP_PAGE2_VIDEOSUPPORT ) ;
ast_clear_flag ( & global_flags [ 1 ] , SIP_PAGE2_TEXTSUPPORT ) ;
/* Read the [general] config section of sip.conf (or from realtime config) */
for ( v = ast_variable_browse ( cfg , " general " ) ; v ; v = v - > next ) {
@ -16806,6 +17113,9 @@ static int reload_config(enum channelreloadreason reason)
} else if ( ! strcasecmp ( v - > name , " tos_video " ) ) {
if ( ast_str2tos ( v - > value , & global_tos_video ) )
ast_log ( LOG_WARNING , " Invalid tos_video value at line %d, recommended value is 'af41'. See doc/ip-tos.txt. \n " , v - > lineno ) ;
} else if ( ! strcasecmp ( v - > name , " tos_text " ) ) {
if ( ast_str2tos ( v - > value , & global_tos_text ) )
ast_log ( LOG_WARNING , " Invalid tos_text value at line %d, recommended value is 'af41'. See doc/ip-tos.txt. \n " , v - > lineno ) ;
} else if ( ! strcasecmp ( v - > name , " bindport " ) ) {
if ( sscanf ( v - > value , " %d " , & ourport ) = = 1 ) {
bindaddr . sin_port = htons ( ourport ) ;
@ -17208,8 +17518,33 @@ static enum ast_rtp_get_result sip_get_vrtp_peer(struct ast_channel *chan, struc
return res ;
}
/*! \brief Returns null if we can't reinvite text (part of RTP interface) */
static enum ast_rtp_get_result sip_get_trtp_peer ( struct ast_channel * chan , struct ast_rtp * * rtp )
{
struct sip_pvt * p = NULL ;
enum ast_rtp_get_result res = AST_RTP_TRY_PARTIAL ;
if ( ! ( p = chan - > tech_pvt ) )
return AST_RTP_GET_FAILED ;
sip_pvt_lock ( p ) ;
if ( ! ( p - > trtp ) ) {
sip_pvt_unlock ( p ) ;
return AST_RTP_GET_FAILED ;
}
* rtp = p - > trtp ;
if ( ast_test_flag ( & p - > flags [ 0 ] , SIP_CAN_REINVITE ) )
res = AST_RTP_TRY_NATIVE ;
sip_pvt_unlock ( p ) ;
return res ;
}
/*! \brief Set the RTP peer for this call */
static int sip_set_rtp_peer ( struct ast_channel * chan , struct ast_rtp * rtp , struct ast_rtp * vrtp , int codecs , int nat_active )
static int sip_set_rtp_peer ( struct ast_channel * chan , struct ast_rtp * rtp , struct ast_rtp * vrtp , struct ast_rtp * trtp , int codecs , int nat_active )
{
struct sip_pvt * p ;
int changed = 0 ;
@ -17249,6 +17584,12 @@ static int sip_set_rtp_peer(struct ast_channel *chan, struct ast_rtp *rtp, struc
memset ( & p - > vredirip , 0 , sizeof ( p - > vredirip ) ) ;
changed = 1 ;
}
if ( trtp ) {
changed | = ast_rtp_get_peer ( trtp , & p - > tredirip ) ;
} else if ( p - > tredirip . sin_addr . s_addr | | ntohs ( p - > tredirip . sin_port ) ! = 0 ) {
memset ( & p - > tredirip , 0 , sizeof ( p - > tredirip ) ) ;
changed = 1 ;
}
if ( codecs & & ( p - > redircodecs ! = codecs ) ) {
p - > redircodecs = codecs ;
changed = 1 ;