@ -1056,7 +1056,6 @@ static int sipdebug_text;
/*! \brief T38 States for a call */
enum t38state {
T38_DISABLED = 0 , /*!< Not enabled */
T38_LOCAL_DIRECT , /*!< Offered from local */
T38_LOCAL_REINVITE , /*!< Offered from local - REINVITE */
T38_PEER_DIRECT , /*!< Offered from peer */
T38_PEER_REINVITE , /*!< Offered from peer - REINVITE */
@ -1070,6 +1069,7 @@ struct t38properties {
int peercapability ; /*!< Peers T38 capability */
int jointcapability ; /*!< Supported T38 capability at both ends */
enum t38state state ; /*!< T.38 state */
unsigned int direct : 1 ; /*!< Whether the T38 came from the initial invite or not */
} ;
/*! \brief Parameters to know status of transfer */
@ -1798,7 +1798,7 @@ static void add_codec_to_sdp(const struct sip_pvt *p, int codec, int sample_rate
static void add_noncodec_to_sdp ( const struct sip_pvt * p , int format , int sample_rate ,
struct ast_str * * m_buf , struct ast_str * * a_buf ,
int debug ) ;
static enum sip_result add_sdp ( struct sip_request * resp , struct sip_pvt * p , int oldsdp );
static enum sip_result add_sdp ( struct sip_request * resp , struct sip_pvt * p , int oldsdp , int add_audio , int add_t38 );
static void do_setnat ( struct sip_pvt * p , int natflags ) ;
static void stop_media_flows ( struct sip_pvt * p ) ;
@ -3219,7 +3219,6 @@ static int sip_queryoption(struct ast_channel *chan, int option, void *data, int
/* Now if T38 support is enabled we need to look and see what the current state is to get what we want to report back */
if ( ast_test_flag ( & p - > t38 . t38support , SIP_PAGE2_T38SUPPORT ) ) {
switch ( p - > t38 . state ) {
case T38_LOCAL_DIRECT :
case T38_LOCAL_REINVITE :
case T38_PEER_DIRECT :
case T38_PEER_REINVITE :
@ -3960,6 +3959,10 @@ static void change_t38_state(struct sip_pvt *p, int state)
if ( old = = state )
return ;
if ( state = = T38_PEER_DIRECT ) {
p - > t38 . direct = 1 ;
}
p - > t38 . state = state ;
ast_debug ( 2 , " T38 state changed to %d on channel %s \n " , p - > t38 . state , chan ? chan - > name : " <none> " ) ;
@ -4303,9 +4306,6 @@ static int sip_call(struct ast_channel *ast, char *dest, int timeout)
} else if ( ! strcasecmp ( ast_var_name ( current ) , " SIPTRANSFER_REPLACES " ) ) {
/* We're replacing a call. */
p - > options - > replaces = ast_var_value ( current ) ;
} else if ( ! strcasecmp ( ast_var_name ( current ) , " T38CALL " ) ) {
p - > t38 . state = T38_LOCAL_DIRECT ;
ast_debug ( 1 , " T38State change to %d on channel %s \n " , p - > t38 . state , ast - > name ) ;
}
}
@ -5077,11 +5077,9 @@ static int sip_answer(struct ast_channel *ast)
ast_debug ( 1 , " SIP answering channel: %s \n " , ast - > name ) ;
if ( p - > t38 . state = = T38_PEER_DIRECT ) {
change_t38_state ( p , T38_ENABLED ) ;
res = transmit_response_with_t38_sdp ( p , " 200 OK " , & p - > initreq , XMIT_CRITICAL ) ;
} else {
ast_rtp_new_source ( p - > rtp ) ;
res = transmit_response_with_sdp ( p , " 200 OK " , & p - > initreq , XMIT_CRITICAL , FALSE ) ;
}
ast_rtp_new_source ( p - > rtp ) ;
res = transmit_response_with_sdp ( p , " 200 OK " , & p - > initreq , XMIT_CRITICAL , FALSE ) ;
}
sip_pvt_unlock ( p ) ;
return res ;
@ -5118,9 +5116,13 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
p - > invitestate = INV_EARLY_MEDIA ;
transmit_response_with_sdp ( p , " 183 Session Progress " , & p - > initreq , XMIT_UNRELIABLE , FALSE ) ;
ast_set_flag ( & p - > flags [ 0 ] , SIP_PROGRESS_SENT ) ;
} else if ( p - > t38 . state = = T38_ENABLED & & ! p - > t38 . direct ) {
change_t38_state ( p , T38_DISABLED ) ;
transmit_reinvite_with_sdp ( p , FALSE , FALSE ) ;
} else {
p - > lastrtptx = time ( NULL ) ;
res = ast_rtp_write ( p - > rtp , frame ) ;
}
p - > lastrtptx = time ( NULL ) ;
res = ast_rtp_write ( p - > rtp , frame ) ;
}
sip_pvt_unlock ( p ) ;
}
@ -5171,8 +5173,16 @@ static int sip_write(struct ast_channel *ast, struct ast_frame *frame)
we simply forget the frames if we get modem frames before the bridge is up .
Fax will re - transmit .
*/
if ( p - > udptl & & ast - > _state = = AST_STATE_UP )
res = ast_udptl_write ( p - > udptl , frame ) ;
if ( ast - > _state = = AST_STATE_UP ) {
if ( ast_test_flag ( & p - > flags [ 1 ] , SIP_PAGE2_T38SUPPORT ) & & p - > t38 . state = = T38_DISABLED ) {
if ( ! p - > pendinginvite ) {
change_t38_state ( p , T38_LOCAL_REINVITE ) ;
transmit_reinvite_with_sdp ( p , TRUE , FALSE ) ;
}
} else if ( p - > udptl & & p - > t38 . state = = T38_ENABLED ) {
res = ast_udptl_write ( p - > udptl , frame ) ;
}
}
sip_pvt_unlock ( p ) ;
}
break ;
@ -5589,10 +5599,6 @@ static struct ast_channel *sip_new(struct sip_pvt *i, int state, const char *tit
if ( i - > rtp )
ast_jb_configure ( tmp , & global_jbconf ) ;
/* If the INVITE contains T.38 SDP information set the proper channel variable so a created outgoing call will also have T.38 */
if ( i - > udptl & & i - > t38 . state = = T38_PEER_DIRECT )
pbx_builtin_setvar_helper ( tmp , " _T38CALL " , " 1 " ) ;
/* Set channel variables for this call from configuration */
for ( v = i - > chanvars ; v ; v = v - > next )
pbx_builtin_setvar_helper ( tmp , v - > name , v - > value ) ;
@ -7099,7 +7105,7 @@ static int process_sdp(struct sip_pvt *p, struct sip_request *req, int t38action
/* Remote party offers T38, we need to update state */
if ( t38action = = SDP_T38_ACCEPT ) {
if ( p - > t38 . state = = T38_LOCAL_ DIRECT | | p - > t38 . state = = T38_LOCAL_ REINVITE)
if ( p - > t38 . state = = T38_LOCAL_ REINVITE)
change_t38_state ( p , T38_ENABLED ) ;
} else if ( t38action = = SDP_T38_INITIATE ) {
if ( p - > owner & & p - > lastinvite ) {
@ -8176,92 +8182,6 @@ static int t38_get_rate(int t38cap)
}
}
/*! \brief Add T.38 Session Description Protocol message */
static int add_t38_sdp ( struct sip_request * resp , struct sip_pvt * p )
{
int len = 0 ;
int x = 0 ;
struct sockaddr_in udptlsin ;
struct ast_str * m_modem = ast_str_alloca ( 1024 ) ;
struct ast_str * a_modem = ast_str_alloca ( 1024 ) ;
struct sockaddr_in udptldest = { 0 , } ;
int debug ;
debug = sip_debug_test_pvt ( p ) ;
len = 0 ;
if ( ! p - > udptl ) {
ast_log ( LOG_WARNING , " No way to add SDP without an UDPTL structure \n " ) ;
return - 1 ;
}
if ( ! p - > sessionid ) {
p - > sessionid = ( int ) ast_random ( ) ;
p - > sessionversion = p - > sessionid ;
} else
p - > sessionversion + + ;
/* Our T.38 end is */
ast_udptl_get_us ( p - > udptl , & udptlsin ) ;
/* Determine T.38 UDPTL destination */
if ( p - > udptlredirip . sin_addr . s_addr ) {
udptldest . sin_port = p - > udptlredirip . sin_port ;
udptldest . sin_addr = p - > udptlredirip . sin_addr ;
} else {
udptldest . sin_addr = p - > ourip . sin_addr ;
udptldest . sin_port = udptlsin . sin_port ;
}
if ( debug )
ast_debug ( 1 , " T.38 UDPTL is at %s port %d \n " , ast_inet_ntoa ( p - > ourip . sin_addr ) , ntohs ( udptlsin . sin_port ) ) ;
/* We break with the "recommendation" and send our IP, in order that our
peer doesn ' t have to ast_gethostbyname ( ) us */
if ( debug ) {
ast_debug ( 1 , " Our T38 capability (%d), peer T38 capability (%d), joint capability (%d) \n " ,
p - > t38 . capability ,
p - > t38 . peercapability ,
p - > t38 . jointcapability ) ;
}
ast_str_append ( & m_modem , 0 , " v=0 \r \n " ) ;
ast_str_append ( & m_modem , 0 , " o=%s %d %d IN IP4 %s \r \n " , ast_strlen_zero ( global_sdpowner ) ? " - " : global_sdpowner , p - > sessionid , p - > sessionversion , ast_inet_ntoa ( udptldest . sin_addr ) ) ;
ast_str_append ( & m_modem , 0 , " s=%s \r \n " , ast_strlen_zero ( global_sdpsession ) ? " - " : global_sdpsession ) ;
ast_str_append ( & m_modem , 0 , " c=IN IP4 %s \r \n " , ast_inet_ntoa ( udptldest . sin_addr ) ) ;
ast_str_append ( & m_modem , 0 , " t=0 0 \r \n " ) ;
ast_str_append ( & m_modem , 0 , " m=image %d udptl t38 \r \n " , ntohs ( udptldest . sin_port ) ) ;
if ( ( p - > t38 . jointcapability & T38FAX_VERSION ) = = T38FAX_VERSION_0 )
ast_str_append ( & a_modem , 0 , " a=T38FaxVersion:0 \r \n " ) ;
if ( ( p - > t38 . jointcapability & T38FAX_VERSION ) = = T38FAX_VERSION_1 )
ast_str_append ( & a_modem , 0 , " a=T38FaxVersion:1 \r \n " ) ;
if ( ( x = t38_get_rate ( p - > t38 . jointcapability ) ) )
ast_str_append ( & a_modem , 0 , " a=T38MaxBitRate:%d \r \n " , x ) ;
if ( ( p - > t38 . jointcapability & T38FAX_FILL_BIT_REMOVAL ) = = T38FAX_FILL_BIT_REMOVAL )
ast_str_append ( & a_modem , 0 , " a=T38FaxFillBitRemoval \r \n " ) ;
if ( ( p - > t38 . jointcapability & T38FAX_TRANSCODING_MMR ) = = T38FAX_TRANSCODING_MMR )
ast_str_append ( & a_modem , 0 , " a=T38FaxTranscodingMMR \r \n " ) ;
if ( ( p - > t38 . jointcapability & T38FAX_TRANSCODING_JBIG ) = = T38FAX_TRANSCODING_JBIG )
ast_str_append ( & a_modem , 0 , " a=T38FaxTranscodingJBIG \r \n " ) ;
ast_str_append ( & a_modem , 0 , " a=T38FaxRateManagement:%s \r \n " , ( p - > t38 . jointcapability & T38FAX_RATE_MANAGEMENT_LOCAL_TCF ) ? " localTCF " : " transferredTCF " ) ;
x = ast_udptl_get_local_max_datagram ( p - > udptl ) ;
ast_str_append ( & a_modem , 0 , " a=T38FaxMaxBuffer:%d \r \n " , x ) ;
ast_str_append ( & a_modem , 0 , " a=T38FaxMaxDatagram:%d \r \n " , x ) ;
if ( p - > t38 . jointcapability ! = T38FAX_UDP_EC_NONE )
ast_str_append ( & a_modem , 0 , " a=T38FaxUdpEC:%s \r \n " , ( p - > t38 . jointcapability & T38FAX_UDP_EC_REDUNDANCY ) ? " t38UDPRedundancy " : " t38UDPFEC " ) ;
len = m_modem - > used + a_modem - > used ;
add_header ( resp , " Content-Type " , " application/sdp " ) ;
add_header_contentLength ( resp , len ) ;
add_line ( resp , m_modem - > str ) ;
add_line ( resp , a_modem - > str ) ;
/* Update lastrtprx when we send our SDP */
p - > lastrtprx = p - > lastrtptx = time ( NULL ) ;
return 0 ;
}
/*! \brief Add RFC 2833 DTMF offer to SDP */
static void add_noncodec_to_sdp ( const struct sip_pvt * p , int format , int sample_rate ,
struct ast_str * * m_buf , struct ast_str * * a_buf ,
@ -8331,7 +8251,7 @@ static void get_our_media_address(struct sip_pvt *p, int needvideo,
is used in Session - Timers where RE - INVITEs are used for refreshing SIP sessions
without modifying the media session in any way .
*/
static enum sip_result add_sdp ( struct sip_request * resp , struct sip_pvt * p , int oldsdp )
static enum sip_result add_sdp ( struct sip_request * resp , struct sip_pvt * p , int oldsdp , int add_audio , int add_t38 )
{
int len = 0 ;
int alreadysent = 0 ;
@ -8340,8 +8260,10 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
struct sockaddr_in vsin ;
struct sockaddr_in tsin ;
struct sockaddr_in dest ;
struct sockaddr_in udptlsin ;
struct sockaddr_in vdest = { 0 , } ;
struct sockaddr_in tdest = { 0 , } ;
struct sockaddr_in udptldest = { 0 , } ;
/* SDP fields */
char * version = " v=0 \r \n " ; /* Protocol version */
@ -8350,16 +8272,18 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
char connection [ 256 ] ; /* Connection data */
char * stime = " t=0 0 \r \n " ; /* Time the session is active */
char bandwidth [ 256 ] = " " ; /* Max bitrate */
char * hold ;
char * hold = " " ;
struct ast_str * m_audio = ast_str_alloca ( 256 ) ; /* Media declaration line for audio */
struct ast_str * m_video = ast_str_alloca ( 256 ) ; /* Media declaration line for video */
struct ast_str * m_text = ast_str_alloca ( 256 ) ; /* Media declaration line for text */
struct ast_str * m_modem = ast_str_alloca ( 256 ) ; /* Media declaration line for modem */
struct ast_str * a_audio = ast_str_alloca ( 1024 ) ; /* Attributes for audio */
struct ast_str * a_video = ast_str_alloca ( 1024 ) ; /* Attributes for video */
struct ast_str * a_text = ast_str_alloca ( 1024 ) ; /* Attributes for text */
struct ast_str * a_modem = ast_str_alloca ( 1024 ) ; /* Attributes for modem */
int x ;
int capability ;
int capability = 0 ;
int needaudio = FALSE ;
int needvideo = FALSE ;
int needtext = FALSE ;
@ -8390,183 +8314,232 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
p - > sessionversion + + ;
}
capability = p - > jointcapability ;
get_our_media_address ( p , needvideo , & sin , & vsin , & tsin , & dest , & vdest ) ;
/* XXX note, Video and Text are negated - 'true' means 'no' */
ast_debug ( 1 , " ** Our capability: %s Video flag: %s Text flag: %s \n " , ast_getformatname_multiple ( codecbuf , sizeof ( codecbuf ) , capability ) ,
p - > novideo ? " True " : " False " , p - > notext ? " True " : " False " ) ;
ast_debug ( 1 , " ** Our prefcodec: %s \n " , ast_getformatname_multiple ( codecbuf , sizeof ( codecbuf ) , p - > prefcodec ) ) ;
snprintf ( owner , sizeof ( owner ) , " o=%s %d %d IN IP4 %s \r \n " , ast_strlen_zero ( global_sdpowner ) ? " - " : global_sdpowner , p - > sessionid , p - > sessionversion , ast_inet_ntoa ( dest . sin_addr ) ) ;
snprintf ( connection , sizeof ( connection ) , " c=IN IP4 %s \r \n " , ast_inet_ntoa ( dest . sin_addr ) ) ;
if ( add_audio ) {
capability = p - > jointcapability ;
/* XXX note, Video and Text are negated - 'true' means 'no' */
ast_debug ( 1 , " ** Our capability: %s Video flag: %s Text flag: %s \n " , ast_getformatname_multiple ( codecbuf , sizeof ( codecbuf ) , capability ) ,
p - > novideo ? " True " : " False " , p - > notext ? " True " : " False " ) ;
ast_debug ( 1 , " ** Our prefcodec: %s \n " , ast_getformatname_multiple ( codecbuf , sizeof ( codecbuf ) , p - > prefcodec ) ) ;
# ifdef WHEN_WE_HAVE_T38_FOR_OTHER_TRANSPORTS
if ( ast_test_flag ( & p - > t38 . t38support , SIP_PAGE2_T38SUPPORT_RTP ) ) {
ast_str_append ( & m_audio , 0 , " %d " , 191 ) ;
ast_str_append ( & a_audio , 0 , " a=rtpmap:%d %s/%d \r \n " , 191 , " t38 " , 8000 ) ;
}
if ( ast_test_flag ( & p - > t38 . t38support , SIP_PAGE2_T38SUPPORT_RTP ) ) {
ast_str_append ( & m_audio , 0 , " %d " , 191 ) ;
ast_str_append ( & a_audio , 0 , " a=rtpmap:%d %s/%d \r \n " , 191 , " t38 " , 8000 ) ;
}
# endif
/* Check if we need audio */
if ( capability & AST_FORMAT_AUDIO_MASK )
needaudio = TRUE ;
/* Check if we need audio */
if ( capability & AST_FORMAT_AUDIO_MASK )
needaudio = TRUE ;
/* Check if we need video in this call */
if ( ( capability & AST_FORMAT_VIDEO_MASK ) & & ! p - > novideo ) {
if ( p - > vrtp ) {
needvideo = TRUE ;
ast_debug ( 2 , " This call needs video offers! \n " ) ;
} else
ast_debug ( 2 , " This call needs video offers, but there's no video support enabled! \n " ) ;
}
/* Check if we need video in this call */
if ( ( capability & AST_FORMAT_VIDEO_MASK ) & & ! p - > novideo ) {
if ( p - > vrtp ) {
needvideo = TRUE ;
ast_debug ( 2 , " This call needs video offers! \n " ) ;
} else
ast_debug ( 2 , " This call needs video offers, but there's no video support enabled! \n " ) ;
}
/* Get our media addresses */
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 . sin_addr ) , ntohs ( sin . sin_port ) ) ;
if ( debug )
ast_verbose ( " Audio is at %s port %d \n " , ast_inet_ntoa ( p - > ourip . sin_addr ) , 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 ) {
ast_str_append ( & m_video , 0 , " m=video %d RTP/AVP " , ntohs ( vdest . 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 ) {
ast_str_append ( & m_video , 0 , " m=video %d RTP/AVP " , ntohs ( vdest . sin_port ) ) ;
/* Build max bitrate string */
if ( p - > maxcallbitrate )
snprintf ( bandwidth , sizeof ( bandwidth ) , " b=CT:%d \r \n " , p - > maxcallbitrate ) ;
if ( debug )
ast_verbose ( " Video is at %s port %d \n " , ast_inet_ntoa ( p - > ourip . sin_addr ) , ntohs ( vsin . sin_port ) ) ;
}
/* Build max bitrate string */
if ( p - > maxcallbitrate )
snprintf ( bandwidth , sizeof ( bandwidth ) , " b=CT:%d \r \n " , p - > maxcallbitrate ) ;
if ( debug )
ast_verbose ( " Video is at %s port %d \n " , ast_inet_ntoa ( p - > ourip . sin_addr ) , ntohs ( vsin . sin_port ) ) ;
}
/* Check if we need text in this call */
if ( ( capability & AST_FORMAT_TEXT_MASK ) & & ! p - > notext ) {
if ( sipdebug_text )
ast_verbose ( " We think we can do text \n " ) ;
if ( p - > trtp ) {
/* Check if we need text in this call */
if ( ( capability & AST_FORMAT_TEXT_MASK ) & & ! p - > notext ) {
if ( sipdebug_text )
ast_verbose ( " And we have a text rtp object \n " ) ;
needtext = TRUE ;
ast_debug ( 2 , " This call needs text offers! \n " ) ;
} else
ast_debug ( 2 , " 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 . sin_addr ;
tdest . sin_port = tsin . sin_port ;
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 ;
ast_debug ( 2 , " This call needs text offers! \n " ) ;
} else
ast_debug ( 2 , " This call needs text offers, but there's no text support enabled ! \n " ) ;
}
ast_str_append ( & m_text , 0 , " m=text %d RTP/AVP " , ntohs ( tdest . sin_port ) ) ;
/* 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 . sin_addr ;
tdest . sin_port = tsin . sin_port ;
}
ast_str_append ( & m_text , 0 , " m=text %d RTP/AVP " , ntohs ( tdest . sin_port ) ) ;
if ( debug ) /* XXX should I use tdest below ? */
ast_verbose ( " Text is at %s port %d \n " , ast_inet_ntoa ( p - > ourip . sin_addr ) , ntohs ( tsin . sin_port ) ) ;
if ( debug ) /* XXX should I use tdest below ? */
ast_verbose ( " Text is at %s port %d \n " , ast_inet_ntoa ( p - > ourip . sin_addr ) , ntohs ( tsin . sin_port ) ) ;
}
}
/* Start building generic SDP headers */
/* Start building generic SDP headers */
/* We break with the "recommendation" and send our IP, in order that our
peer doesn ' t have to ast_gethostbyname ( ) us */
/* We break with the "recommendation" and send our IP, in order that our
peer doesn ' t have to ast_gethostbyname ( ) us */
snprintf ( owner , sizeof ( owner ) , " o=%s %d %d IN IP4 %s \r \n " , ast_strlen_zero ( global_sdpowner ) ? " - " : global_sdpowner , p - > sessionid , p - > sessionversion , ast_inet_ntoa ( dest . sin_addr ) ) ;
snprintf ( connection , sizeof ( connection ) , " c=IN IP4 %s \r \n " , ast_inet_ntoa ( dest . sin_addr ) ) ;
ast_str_append ( & m_audio , 0 , " m=audio %d RTP/AVP " , ntohs ( dest . sin_port ) ) ;
ast_str_append ( & m_audio , 0 , " m=audio %d RTP/AVP " , ntohs ( dest . sin_port ) ) ;
if ( ast_test_flag ( & p - > flags [ 1 ] , SIP_PAGE2_CALL_ONHOLD ) = = SIP_PAGE2_CALL_ONHOLD_ONEDIR )
hold = " a=recvonly \r \n " ;
else if ( ast_test_flag ( & p - > flags [ 1 ] , SIP_PAGE2_CALL_ONHOLD ) = = SIP_PAGE2_CALL_ONHOLD_INACTIVE )
hold = " a=inactive \r \n " ;
else
hold = " a=sendrecv \r \n " ;
if ( ast_test_flag ( & p - > flags [ 1 ] , SIP_PAGE2_CALL_ONHOLD ) = = SIP_PAGE2_CALL_ONHOLD_ONEDIR )
hold = " a=recvonly \r \n " ;
else if ( ast_test_flag ( & p - > flags [ 1 ] , SIP_PAGE2_CALL_ONHOLD ) = = SIP_PAGE2_CALL_ONHOLD_INACTIVE )
hold = " a=inactive \r \n " ;
else
hold = " a=sendrecv \r \n " ;
/* Now, start adding audio codecs. These are added in this order:
- First what was requested by the calling channel
- Then preferences in order from sip . conf device config for this peer / user
- Then other codecs in capabilities , including video
*/
/* Now, start adding audio codecs. These are added in this order:
- First what was requested by the calling channel
- Then preferences in order from sip . conf device config for this peer / user
- Then other codecs in capabilities , including video
*/
/* Prefer the audio codec we were requested to use, first, no matter what
Note that p - > prefcodec can include video codecs , so mask them out
*/
if ( capability & p - > prefcodec ) {
int codec = p - > prefcodec & AST_FORMAT_AUDIO_MASK ;
/* Prefer the audio codec we were requested to use, first, no matter what
Note that p - > prefcodec can include video codecs , so mask them out
*/
if ( capability & p - > prefcodec ) {
int codec = p - > prefcodec & AST_FORMAT_AUDIO_MASK ;
add_codec_to_sdp ( p , codec , SDP_SAMPLE_RATE ( codec ) ,
& m_audio , & a_audio ,
debug , & min_audio_packet_size ) ;
alreadysent | = codec ;
}
add_codec_to_sdp ( p , codec , SDP_SAMPLE_RATE ( codec ) ,
& m_audio , & a_audio ,
debug , & min_audio_packet_size ) ;
alreadysent | = codec ;
}
/* Start by sending our preferred audio/video codecs */
for ( x = 0 ; x < 32 ; x + + ) {
int codec ;
/* Start by sending our preferred audio/video codecs */
for ( x = 0 ; x < 32 ; x + + ) {
int codec ;
if ( ! ( codec = ast_codec_pref_index ( & p - > prefs , x ) ) )
break ;
if ( ! ( codec = ast_codec_pref_index ( & p - > prefs , x ) ) )
break ;
if ( ! ( capability & codec ) )
continue ;
if ( ! ( capability & codec ) )
continue ;
if ( alreadysent & codec )
if ( alreadysent & codec )
continue ;
add_codec_to_sdp ( p , codec , SDP_SAMPLE_RATE ( codec ) ,
& m_audio , & a_audio ,
debug , & min_audio_packet_size ) ;
alreadysent | = codec ;
}
add_codec_to_sdp ( p , codec , SDP_SAMPLE_RATE ( codec ) ,
& m_audio , & a_audio ,
debug , & min_audio_packet_size ) ;
alreadysent | = codec ;
}
/* Now send any other common audio and video codecs, and non-codec formats: */
for ( x = 1 ; x < = ( needtext ? AST_FORMAT_TEXT_MASK : ( needvideo ? AST_FORMAT_VIDEO_MASK : AST_FORMAT_AUDIO_MASK ) ) ; x < < = 1 ) {
if ( ! ( capability & x ) ) /* Codec not requested */
continue ;
/* Now send any other common audio and video codecs, and non-codec formats: */
for ( x = 1 ; x < = ( needtext ? AST_FORMAT_TEXT_MASK : ( needvideo ? AST_FORMAT_VIDEO_MASK : AST_FORMAT_AUDIO_MASK ) ) ; x < < = 1 ) {
if ( ! ( capability & x ) ) /* Codec not requested */
continue ;
if ( alreadysent & x ) /* Already added to SDP */
continue ;
if ( alreadysent & x ) /* Already added to SDP */
continue ;
if ( x & AST_FORMAT_AUDIO_MASK )
add_codec_to_sdp ( p , x , SDP_SAMPLE_RATE ( x ) ,
& m_audio , & a_audio , debug , & min_audio_packet_size ) ;
else if ( x & AST_FORMAT_VIDEO_MASK )
add_vcodec_to_sdp ( p , x , 90000 ,
& m_video , & a_video , debug , & min_video_packet_size ) ;
else if ( x & AST_FORMAT_TEXT_MASK )
add_tcodec_to_sdp ( p , x , 1000 ,
& m_text , & a_text , debug , & min_text_packet_size ) ;
}
if ( x & AST_FORMAT_AUDIO_MASK )
add_codec_to_sdp ( p , x , SDP_SAMPLE_RATE ( x ) ,
& m_audio , & a_audio , debug , & min_audio_packet_size ) ;
else if ( x & AST_FORMAT_VIDEO_MASK )
add_vcodec_to_sdp ( p , x , 90000 ,
& m_video , & a_video , debug , & min_video_packet_size ) ;
else if ( x & AST_FORMAT_TEXT_MASK )
add_tcodec_to_sdp ( p , x , 1000 ,
& m_text , & a_text , debug , & min_text_packet_size ) ;
}
/* Now add DTMF RFC2833 telephony-event as a codec */
for ( x = 1 ; x < = AST_RTP_MAX ; x < < = 1 ) {
if ( ! ( p - > jointnoncodeccapability & x ) )
continue ;
/* Now add DTMF RFC2833 telephony-event as a codec */
for ( x = 1 ; x < = AST_RTP_MAX ; x < < = 1 ) {
if ( ! ( p - > jointnoncodeccapability & x ) )
continue ;
add_noncodec_to_sdp ( p , x , 8000 , & m_audio , & a_audio , debug ) ;
}
ast_debug ( 3 , " -- Done with adding codecs to SDP \n " ) ;
add_noncodec_to_sdp ( p , x , 8000 , & m_audio , & a_audio , debug ) ;
if ( ! p - > owner | | ! ast_internal_timing_enabled ( p - > owner ) )
ast_str_append ( & a_audio , 0 , " a=silenceSupp:off - - - - \r \n " ) ;
if ( min_audio_packet_size )
ast_str_append ( & a_audio , 0 , " 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_str_append ( & a_video , 0 , " 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_str_append ( & a_text , 0 , " a=ptime:%d \r \n " , min_text_packet_size ) ;
}
ast_debug ( 3 , " -- Done with adding codecs to SDP \n " ) ;
if ( add_t38 ) {
ast_udptl_get_us ( p - > udptl , & udptlsin ) ;
if ( ! p - > owner | | ! ast_internal_timing_enabled ( p - > owner ) )
ast_str_append ( & a_audio , 0 , " a=silenceSupp:off - - - - \r \n " ) ;
/* Determine T.38 UDPTL destination */
if ( p - > udptlredirip . sin_addr . s_addr ) {
udptldest . sin_port = p - > udptlredirip . sin_port ;
udptldest . sin_addr = p - > udptlredirip . sin_addr ;
} else {
udptldest . sin_addr = p - > ourip . sin_addr ;
udptldest . sin_port = udptlsin . sin_port ;
}
if ( min_audio_packet_size )
ast_str_append ( & a_audio , 0 , " a=ptime:%d \r \n " , min_audio_packet_size ) ;
if ( debug )
ast_debug ( 1 , " T.38 UDPTL is at %s port %d \n " , ast_inet_ntoa ( p - > ourip . sin_addr ) , ntohs ( udptlsin . sin_port ) ) ;
/* XXX don't think you can have ptime for video */
if ( min_video_packet_size )
ast_str_append ( & a_video , 0 , " a=ptime:%d \r \n " , min_video_packet_size ) ;
/* We break with the "recommendation" and send our IP, in order that our
peer doesn ' t have to ast_gethostbyname ( ) us */
if ( debug ) {
ast_debug ( 1 , " Our T38 capability (%d), peer T38 capability (%d), joint capability (%d) \n " ,
p - > t38 . capability ,
p - > t38 . peercapability ,
p - > t38 . jointcapability ) ;
}
ast_str_append ( & m_modem , 0 , " m=image %d udptl t38 \r \n " , ntohs ( udptldest . sin_port ) ) ;
if ( ( p - > t38 . jointcapability & T38FAX_VERSION ) = = T38FAX_VERSION_0 )
ast_str_append ( & a_modem , 0 , " a=T38FaxVersion:0 \r \n " ) ;
if ( ( p - > t38 . jointcapability & T38FAX_VERSION ) = = T38FAX_VERSION_1 )
ast_str_append ( & a_modem , 0 , " a=T38FaxVersion:1 \r \n " ) ;
if ( ( x = t38_get_rate ( p - > t38 . jointcapability ) ) )
ast_str_append ( & a_modem , 0 , " a=T38MaxBitRate:%d \r \n " , x ) ;
if ( ( p - > t38 . jointcapability & T38FAX_FILL_BIT_REMOVAL ) = = T38FAX_FILL_BIT_REMOVAL )
ast_str_append ( & a_modem , 0 , " a=T38FaxFillBitRemoval \r \n " ) ;
if ( ( p - > t38 . jointcapability & T38FAX_TRANSCODING_MMR ) = = T38FAX_TRANSCODING_MMR )
ast_str_append ( & a_modem , 0 , " a=T38FaxTranscodingMMR \r \n " ) ;
if ( ( p - > t38 . jointcapability & T38FAX_TRANSCODING_JBIG ) = = T38FAX_TRANSCODING_JBIG )
ast_str_append ( & a_modem , 0 , " a=T38FaxTranscodingJBIG \r \n " ) ;
ast_str_append ( & a_modem , 0 , " a=T38FaxRateManagement:%s \r \n " , ( p - > t38 . jointcapability & T38FAX_RATE_MANAGEMENT_LOCAL_TCF ) ? " localTCF " : " transferredTCF " ) ;
x = ast_udptl_get_local_max_datagram ( p - > udptl ) ;
ast_str_append ( & a_modem , 0 , " a=T38FaxMaxBuffer:%d \r \n " , x ) ;
ast_str_append ( & a_modem , 0 , " a=T38FaxMaxDatagram:%d \r \n " , x ) ;
if ( p - > t38 . jointcapability ! = T38FAX_UDP_EC_NONE )
ast_str_append ( & a_modem , 0 , " a=T38FaxUdpEC:%s \r \n " , ( p - > t38 . jointcapability & T38FAX_UDP_EC_REDUNDANCY ) ? " t38UDPRedundancy " : " t38UDPFEC " ) ;
}
/* XXX don't think you can have ptime for text */
if ( min_text_packet_size )
ast_str_append ( & a_text , 0 , " a=ptime:%d \r \n " , min_text_packet_size ) ;
if ( m_audio - > len - m_audio - > used < 2 | | m_video - > len - m_video - > used < 2 | |
m_text - > len - m_text - > used < 2 | | a_text - > len - a_text - > used < 2 | |
a_audio - > len - a_audio - > used < 2 | | a_video - > len - a_video - > used < 2 )
m_text - > len - m_text - > used < 2 | | a_text - > len - a_text - > used < 2 | |
a_audio - > len - a_audio - > used < 2 | | a_video - > len - a_video - > used < 2 )
ast_log ( LOG_WARNING , " SIP SDP may be truncated due to undersized buffer!! \n " ) ;
if ( needaudio )
@ -8584,6 +8557,8 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
len + = m_video - > used + a_video - > used + strlen ( bandwidth ) + strlen ( hold ) ;
if ( needtext ) /* only if text response is appropriate */
len + = m_text - > used + a_text - > used + strlen ( hold ) ;
if ( add_t38 )
len + = m_modem - > used + a_modem - > used ;
add_header ( resp , " Content-Type " , " application/sdp " ) ;
add_header_contentLength ( resp , len ) ;
@ -8609,6 +8584,10 @@ static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p, int
add_line ( resp , a_text - > str ) ;
add_line ( resp , hold ) ; /* Repeat hold for the text stream */
}
if ( add_t38 ) {
add_line ( resp , m_modem - > str ) ;
add_line ( resp , a_modem - > str ) ;
}
/* Update lastrtprx when we send our SDP */
p - > lastrtprx = p - > lastrtptx = time ( NULL ) ; /* XXX why both ? */
@ -8631,7 +8610,7 @@ static int transmit_response_with_t38_sdp(struct sip_pvt *p, char *msg, struct s
respprep ( & resp , p , msg , req ) ;
if ( p - > udptl ) {
ast_udptl_offered_from_local ( p - > udptl , 0 ) ;
add_ t38_ sdp( & resp , p ) ;
add_ sdp( & resp , p , 0 , 0 , 1 ) ;
} else
ast_log ( LOG_ERROR , " Can't add SDP to response, since we have no UDPTL session allocated. Call-ID %s \n " , p - > callid ) ;
if ( retrans & & ! p - > pendinginvite )
@ -8673,8 +8652,12 @@ static int transmit_response_with_sdp(struct sip_pvt *p, const char *msg, const
ast_debug ( 1 , " Setting framing from config on incoming call \n " ) ;
ast_rtp_codec_setpref ( p - > rtp , & p - > prefs ) ;
}
try_suggested_sip_codec ( p ) ;
add_sdp ( & resp , p , oldsdp ) ;
try_suggested_sip_codec ( p ) ;
if ( p - > t38 . state = = T38_PEER_DIRECT | | p - > t38 . state = = T38_ENABLED ) {
add_sdp ( & resp , p , oldsdp , TRUE , TRUE ) ;
} else {
add_sdp ( & resp , p , oldsdp , TRUE , FALSE ) ;
}
} else
ast_log ( LOG_ERROR , " Can't add SDP to response, since we have no RTP session allocated. Call-ID %s \n " , p - > callid ) ;
if ( reliable & & ! p - > pendinginvite )
@ -8754,9 +8737,9 @@ static int transmit_reinvite_with_sdp(struct sip_pvt *p, int t38version, int old
if ( p - > do_history )
append_history ( p , " ReInv " , " Re-invite sent " ) ;
if ( t38version )
add_ t38_ sdp( & req , p ) ;
add_ sdp( & req , p , oldsdp , FALSE , TRUE ) ;
else
add_sdp ( & req , p , oldsdp );
add_sdp ( & req , p , oldsdp , TRUE , FALSE );
/* Use this as the basis */
initialize_initreq ( p , & req ) ;
@ -9139,12 +9122,12 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init)
ast_channel_unlock ( chan ) ;
}
if ( sdp ) {
if ( p - > udptl & & ( p - > t38 . state = = T38_LOCAL_DIRECT | | p - > t38 . state = = T38_LOCAL_REINVITE ) ) {
if ( p - > udptl & & p - > t38 . state = = T38_LOCAL_REINVITE ) {
ast_udptl_offered_from_local ( p - > udptl , 1 ) ;
ast_debug ( 1 , " T38 is in state %d on channel %s \n " , p - > t38 . state , p - > owner ? p - > owner - > name : " <none> " ) ;
add_ t38_ sdp( & req , p ) ;
add_ sdp( & req , p , FALSE , FALSE , TRUE ) ;
} else if ( p - > rtp )
add_sdp ( & req , p , FALSE );
add_sdp ( & req , p , FALSE , TRUE , FALSE );
} else {
add_header_contentLength ( & req , 0 ) ;
}
@ -15223,20 +15206,6 @@ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, stru
/* Trigger a reinvite back to audio */
transmit_reinvite_with_sdp ( p , FALSE , FALSE ) ;
} else if ( p - > udptl & & p - > t38 . state = = T38_LOCAL_DIRECT ) {
/* We tried to send T.38 out in an initial INVITE and the remote side rejected it,
right now we can ' t fall back to audio so totally abort .
*/
/* Try to reset RTP timers */
ast_rtp_set_rtptimers_onhold ( p - > rtp ) ;
ast_log ( LOG_ERROR , " Got error on T.38 initial invite. Bailing out. \n " ) ;
change_t38_state ( p , T38_DISABLED ) ;
/* The dialog is now terminated */
if ( p - > owner & & ! req - > ignore )
ast_queue_control ( p - > owner , AST_CONTROL_CONGESTION ) ;
p - > needdestroy = 1 ;
sip_alreadygone ( p ) ;
} else {
/* We can't set up this call, so give up */
if ( p - > owner & & ! req - > ignore )