2002-06-16 16:06:38 +00:00
/*
2005-09-14 20:46:50 +00:00
* Asterisk - - An open source telephony toolkit .
2002-06-16 16:06:38 +00:00
*
2006-01-03 22:16:23 +00:00
* Copyright ( C ) 1999 - 2006 , Digium , Inc .
2002-06-16 16:06:38 +00:00
*
2004-06-29 20:10:57 +00:00
* Mark Spencer < markster @ digium . com >
2002-06-16 16:06:38 +00:00
*
2005-09-14 20:46:50 +00:00
* See http : //www.asterisk.org for more information about
* the Asterisk project . Please do not directly contact
* any of the maintainers of this project for assistance ;
* the project provides a web site , mailing lists and IRC
* channels for your use .
*
2002-06-16 16:06:38 +00:00
* This program is free software , distributed under the terms of
2005-09-14 20:46:50 +00:00
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree .
*/
2005-10-12 20:45:18 +00:00
/*!
2005-10-24 20:12:06 +00:00
* \ file
2005-12-30 21:18:06 +00:00
*
2005-10-12 20:45:18 +00:00
* \ brief Supports RTP and RTCP with Symmetric RTP support for NAT traversal .
2005-12-30 21:18:06 +00:00
*
* \ author Mark Spencer < markster @ digium . com >
2005-09-14 20:46:50 +00:00
*
2005-12-30 21:18:06 +00:00
* \ note RTP is deffined in RFC 3550.
2002-06-16 16:06:38 +00:00
*/
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
# include <sys/time.h>
# include <signal.h>
# include <errno.h>
# include <unistd.h>
# include <netinet/in.h>
# include <sys/time.h>
# include <sys/socket.h>
# include <arpa/inet.h>
# include <fcntl.h>
2005-06-06 20:27:51 +00:00
# include "asterisk.h"
2005-06-06 22:12:19 +00:00
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
2005-06-06 20:27:51 +00:00
2005-04-21 06:02:45 +00:00
# include "asterisk/rtp.h"
# include "asterisk/frame.h"
# include "asterisk/logger.h"
# include "asterisk/options.h"
# include "asterisk/channel.h"
# include "asterisk/acl.h"
# include "asterisk/channel.h"
# include "asterisk/config.h"
# include "asterisk/lock.h"
# include "asterisk/utils.h"
# include "asterisk/cli.h"
# include "asterisk/unaligned.h"
2005-07-15 23:00:47 +00:00
# include "asterisk/utils.h"
2002-06-16 16:06:38 +00:00
2004-06-30 06:03:57 +00:00
# define MAX_TIMESTAMP_SKEW 640
2003-06-28 16:40:02 +00:00
# define RTP_MTU 1200
2006-01-03 09:30:19 +00:00
# define DEFAULT_DTMF_TIMEOUT 3000 /*!< samples */
2005-11-01 00:06:43 +00:00
static int dtmftimeout = DEFAULT_DTMF_TIMEOUT ;
2002-06-16 16:06:38 +00:00
2006-01-03 09:30:19 +00:00
static int rtpstart = 0 ; /*!< First port for RTP sessions (set in rtp.conf) */
static int rtpend = 0 ; /*!< Last port for RTP sessions (set in rtp.conf) */
static int rtpdebug = 0 ; /*!< Are we debugging? */
static struct sockaddr_in rtpdebugaddr ; /*!< Debug packets to/from this host */
2004-07-19 18:09:33 +00:00
# ifdef SO_NO_CHECK
2005-03-31 19:09:48 +00:00
static int nochecksums = 0 ;
2004-07-19 18:09:33 +00:00
# endif
2003-05-16 02:50:46 +00:00
2006-01-03 09:30:19 +00:00
/*! \brief The value of each payload format mapping: */
2003-03-12 06:00:18 +00:00
struct rtpPayloadType {
2006-01-03 09:30:19 +00:00
int isAstFormat ; /*!< whether the following code is an AST_FORMAT */
2004-10-30 01:52:12 +00:00
int code ;
2003-03-12 06:00:18 +00:00
} ;
2006-01-03 09:30:19 +00:00
# define MAX_RTP_PT 256
2003-03-12 06:00:18 +00:00
2005-09-07 20:33:30 +00:00
# define FLAG_3389_WARNING (1 << 0)
# define FLAG_NAT_ACTIVE (3 << 1)
# define FLAG_NAT_INACTIVE (0 << 1)
# define FLAG_NAT_INACTIVE_NOWARN (1 << 1)
2004-04-20 19:23:08 +00:00
2006-01-03 09:30:19 +00:00
/*! \brief RTP session description */
2002-06-16 16:06:38 +00:00
struct ast_rtp {
int s ;
char resp ;
struct ast_frame f ;
2003-06-28 16:40:02 +00:00
unsigned char rawdata [ 8192 + AST_FRIENDLY_OFFSET ] ;
2006-01-03 09:30:19 +00:00
unsigned int ssrc ; /*!< Synchronization source, RFC 3550, page 10. */
2002-06-16 16:06:38 +00:00
unsigned int lastts ;
2005-04-04 02:13:40 +00:00
unsigned int lastdigitts ;
2002-06-16 16:06:38 +00:00
unsigned int lastrxts ;
2003-06-28 16:40:02 +00:00
unsigned int lastividtimestamp ;
unsigned int lastovidtimestamp ;
2004-11-17 19:04:48 +00:00
unsigned int lasteventseqn ;
2005-07-12 23:36:00 +00:00
unsigned int lasteventendseqn ;
2003-02-05 19:26:49 +00:00
int lasttxformat ;
2003-02-16 06:00:12 +00:00
int lastrxformat ;
2002-06-16 16:06:38 +00:00
int dtmfcount ;
2003-08-14 21:55:31 +00:00
unsigned int dtmfduration ;
2003-03-07 06:00:13 +00:00
int nat ;
2005-09-07 20:33:30 +00:00
unsigned int flags ;
2006-01-03 09:30:19 +00:00
struct sockaddr_in us ; /*!< Socket representation of the local endpoint. */
struct sockaddr_in them ; /*!< Socket representation of the remote endpoint. */
2002-06-16 16:06:38 +00:00
struct timeval rxcore ;
struct timeval txcore ;
2004-03-15 16:20:01 +00:00
struct timeval dtmfmute ;
2002-08-09 17:17:54 +00:00
struct ast_smoother * smoother ;
2002-06-16 16:06:38 +00:00
int * ioid ;
2006-01-03 09:30:19 +00:00
unsigned short seqno ; /*!< Sequence number, RFC 3550, page 13. */
2004-10-19 21:07:10 +00:00
unsigned short rxseqno ;
2002-06-16 16:06:38 +00:00
struct sched_context * sched ;
struct io_context * io ;
void * data ;
ast_rtp_callback callback ;
2004-10-30 01:52:12 +00:00
struct rtpPayloadType current_RTP_PT [ MAX_RTP_PT ] ;
2006-01-03 09:30:19 +00:00
int rtp_lookup_code_cache_isAstFormat ; /*!< a cache for the result of rtp_lookup_code(): */
2004-10-30 01:52:12 +00:00
int rtp_lookup_code_cache_code ;
int rtp_lookup_code_cache_result ;
2003-06-28 16:40:02 +00:00
struct ast_rtcp * rtcp ;
} ;
2005-10-12 20:45:18 +00:00
/*!
* \ brief Structure defining an RTCP session .
*
* The concept " RTCP session " is not defined in RFC 3550 , but since
* this structure is analogous to ast_rtp , which tracks a RTP session ,
* it is logical to think of this as a RTCP session .
*
* RTCP packet is defined on page 9 of RFC 3550.
*
*/
2003-06-28 16:40:02 +00:00
struct ast_rtcp {
2006-01-03 09:30:19 +00:00
int s ; /*!< Socket */
struct sockaddr_in us ; /*!< Socket representation of the local endpoint. */
struct sockaddr_in them ; /*!< Socket representation of the remote endpoint. */
2002-06-16 16:06:38 +00:00
} ;
2006-01-03 09:30:19 +00:00
/*! \brief List of current sessions */
static AST_LIST_HEAD_STATIC ( protos , ast_rtp_protocol ) ;
2003-02-16 06:00:12 +00:00
2003-02-12 13:59:15 +00:00
int ast_rtp_fd ( struct ast_rtp * rtp )
{
return rtp - > s ;
}
2002-06-16 16:06:38 +00:00
2003-06-28 16:40:02 +00:00
int ast_rtcp_fd ( struct ast_rtp * rtp )
{
if ( rtp - > rtcp )
return rtp - > rtcp - > s ;
return - 1 ;
}
2002-06-16 16:06:38 +00:00
void ast_rtp_set_data ( struct ast_rtp * rtp , void * data )
{
rtp - > data = data ;
}
void ast_rtp_set_callback ( struct ast_rtp * rtp , ast_rtp_callback callback )
{
rtp - > callback = callback ;
}
2003-03-07 06:00:13 +00:00
void ast_rtp_setnat ( struct ast_rtp * rtp , int nat )
{
rtp - > nat = nat ;
}
2003-02-12 13:59:15 +00:00
static struct ast_frame * send_dtmf ( struct ast_rtp * rtp )
2002-06-16 16:06:38 +00:00
{
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2005-07-15 23:00:47 +00:00
if ( ast_tvcmp ( ast_tvnow ( ) , rtp - > dtmfmute ) < 0 ) {
2004-12-28 16:43:20 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Ignore potential DTMF echo from '%s' \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , rtp - > them . sin_addr ) ) ;
2004-03-15 16:20:01 +00:00
rtp - > resp = 0 ;
rtp - > dtmfduration = 0 ;
2006-01-31 17:18:58 +00:00
return & ast_null_frame ;
2004-03-15 16:20:01 +00:00
}
2004-12-28 16:43:20 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Sending dtmf: %d (%c), at %s \n " , rtp - > resp , rtp - > resp , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , rtp - > them . sin_addr ) ) ;
2004-12-09 14:54:13 +00:00
if ( rtp - > resp = = ' X ' ) {
rtp - > f . frametype = AST_FRAME_CONTROL ;
rtp - > f . subclass = AST_CONTROL_FLASH ;
} else {
rtp - > f . frametype = AST_FRAME_DTMF ;
rtp - > f . subclass = rtp - > resp ;
}
2002-06-16 16:06:38 +00:00
rtp - > f . datalen = 0 ;
2003-02-05 19:26:49 +00:00
rtp - > f . samples = 0 ;
2002-06-16 16:06:38 +00:00
rtp - > f . mallocd = 0 ;
rtp - > f . src = " RTP " ;
rtp - > resp = 0 ;
2003-08-14 21:55:31 +00:00
rtp - > dtmfduration = 0 ;
2003-02-12 13:59:15 +00:00
return & rtp - > f ;
2002-06-16 16:06:38 +00:00
}
2004-10-30 01:52:12 +00:00
static inline int rtp_debug_test_addr ( struct sockaddr_in * addr )
{
if ( rtpdebug = = 0 )
return 0 ;
if ( rtpdebugaddr . sin_addr . s_addr ) {
if ( ( ( ntohs ( rtpdebugaddr . sin_port ) ! = 0 )
& & ( rtpdebugaddr . sin_port ! = addr - > sin_port ) )
| | ( rtpdebugaddr . sin_addr . s_addr ! = addr - > sin_addr . s_addr ) )
return 0 ;
}
return 1 ;
}
2003-05-02 15:37:34 +00:00
static struct ast_frame * process_cisco_dtmf ( struct ast_rtp * rtp , unsigned char * data , int len )
{
unsigned int event ;
char resp = 0 ;
struct ast_frame * f = NULL ;
event = ntohl ( * ( ( unsigned int * ) ( data ) ) ) ;
event & = 0x001F ;
2006-01-03 09:30:19 +00:00
if ( option_debug > 2 | | rtpdebug )
ast_log ( LOG_DEBUG , " Cisco DTMF Digit: %08x (len = %d) \n " , event , len ) ;
2003-05-02 15:37:34 +00:00
if ( event < 10 ) {
resp = ' 0 ' + event ;
} else if ( event < 11 ) {
resp = ' * ' ;
} else if ( event < 12 ) {
resp = ' # ' ;
} else if ( event < 16 ) {
resp = ' A ' + ( event - 12 ) ;
2004-12-09 14:54:13 +00:00
} else if ( event < 17 ) {
resp = ' X ' ;
2003-05-02 15:37:34 +00:00
}
if ( rtp - > resp & & ( rtp - > resp ! = resp ) ) {
f = send_dtmf ( rtp ) ;
}
rtp - > resp = resp ;
rtp - > dtmfcount = dtmftimeout ;
return f ;
}
2005-10-12 20:45:18 +00:00
/*!
* \ brief Process RTP DTMF and events according to RFC 2833.
*
* RFC 2833 is " RTP Payload for DTMF Digits, Telephony Tones and Telephony Signals " .
*
* \ param rtp
* \ param data
* \ param len
* \ param seqno
* \ returns
*/
2005-07-12 23:36:00 +00:00
static struct ast_frame * process_rfc2833 ( struct ast_rtp * rtp , unsigned char * data , int len , unsigned int seqno )
2002-06-16 16:06:38 +00:00
{
unsigned int event ;
2003-08-14 21:55:31 +00:00
unsigned int event_end ;
unsigned int duration ;
2002-06-16 16:06:38 +00:00
char resp = 0 ;
2003-02-12 13:59:15 +00:00
struct ast_frame * f = NULL ;
2006-01-03 09:30:19 +00:00
2002-06-16 16:06:38 +00:00
event = ntohl ( * ( ( unsigned int * ) ( data ) ) ) ;
event > > = 24 ;
2003-08-14 21:55:31 +00:00
event_end = ntohl ( * ( ( unsigned int * ) ( data ) ) ) ;
event_end < < = 8 ;
event_end > > = 24 ;
duration = ntohl ( * ( ( unsigned int * ) ( data ) ) ) ;
duration & = 0xFFFF ;
2006-01-03 09:30:19 +00:00
if ( rtpdebug | | option_debug > 2 )
2005-05-16 13:22:34 +00:00
ast_log ( LOG_DEBUG , " - RTP 2833 Event: %08x (len = %d) \n " , event , len ) ;
2002-06-16 16:06:38 +00:00
if ( event < 10 ) {
resp = ' 0 ' + event ;
} else if ( event < 11 ) {
resp = ' * ' ;
} else if ( event < 12 ) {
resp = ' # ' ;
} else if ( event < 16 ) {
resp = ' A ' + ( event - 12 ) ;
2005-05-16 13:22:34 +00:00
} else if ( event < 17 ) { /* Event 16: Hook flash */
resp = ' X ' ;
2002-06-16 16:06:38 +00:00
}
if ( rtp - > resp & & ( rtp - > resp ! = resp ) ) {
2003-02-12 13:59:15 +00:00
f = send_dtmf ( rtp ) ;
2005-05-16 13:22:34 +00:00
} else if ( event_end & 0x80 ) {
2003-08-16 16:51:58 +00:00
if ( rtp - > resp ) {
2005-07-12 23:36:00 +00:00
if ( rtp - > lasteventendseqn ! = seqno ) {
f = send_dtmf ( rtp ) ;
rtp - > lasteventendseqn = seqno ;
}
2003-08-16 16:51:58 +00:00
rtp - > resp = 0 ;
}
2003-08-14 21:55:31 +00:00
resp = 0 ;
duration = 0 ;
2005-11-30 14:24:50 +00:00
} else if ( rtp - > resp & & rtp - > dtmfduration & & ( duration < rtp - > dtmfduration ) ) {
2003-08-14 21:55:31 +00:00
f = send_dtmf ( rtp ) ;
}
2003-08-16 16:51:58 +00:00
if ( ! ( event_end & 0x80 ) )
rtp - > resp = resp ;
2002-06-16 16:06:38 +00:00
rtp - > dtmfcount = dtmftimeout ;
2003-08-14 21:55:31 +00:00
rtp - > dtmfduration = duration ;
2003-02-12 13:59:15 +00:00
return f ;
2002-06-16 16:06:38 +00:00
}
2005-10-12 20:45:18 +00:00
/*!
* \ brief Process Comfort Noise RTP .
*
* This is incomplete at the moment .
*
2005-05-16 13:22:34 +00:00
*/
2003-02-16 06:00:12 +00:00
static struct ast_frame * process_rfc3389 ( struct ast_rtp * rtp , unsigned char * data , int len )
{
struct ast_frame * f = NULL ;
/* Convert comfort noise into audio with various codecs. Unfortunately this doesn't
totally help us out becuase we don ' t have an engine to keep it going and we are not
guaranteed to have it every 20 ms or anything */
2005-05-16 13:22:34 +00:00
if ( rtpdebug )
2005-06-02 00:49:41 +00:00
ast_log ( LOG_DEBUG , " - RTP 3389 Comfort noise event: Level %d (len = %d) \n " , rtp - > lastrxformat , len ) ;
2005-09-07 20:33:30 +00:00
if ( ! ( ast_test_flag ( rtp , FLAG_3389_WARNING ) ) ) {
2005-05-16 13:22:34 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2005-09-07 20:33:30 +00:00
ast_log ( LOG_NOTICE , " Comfort noise support incomplete in Asterisk (RFC 3389). Please turn off on client if possible. Client IP: %s \n " ,
ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , rtp - > them . sin_addr ) ) ;
ast_set_flag ( rtp , FLAG_3389_WARNING ) ;
2004-04-20 19:23:08 +00:00
}
2005-09-07 20:33:30 +00:00
2004-08-26 04:56:26 +00:00
/* Must have at least one byte */
if ( ! len )
return NULL ;
if ( len < 24 ) {
2004-09-09 02:33:14 +00:00
rtp - > f . data = rtp - > rawdata + AST_FRIENDLY_OFFSET ;
2004-08-26 04:56:26 +00:00
rtp - > f . datalen = len - 1 ;
2004-09-09 02:33:14 +00:00
rtp - > f . offset = AST_FRIENDLY_OFFSET ;
2004-08-26 04:56:26 +00:00
memcpy ( rtp - > f . data , data + 1 , len - 1 ) ;
} else {
2004-09-09 02:33:14 +00:00
rtp - > f . data = NULL ;
rtp - > f . offset = 0 ;
2004-08-26 04:56:26 +00:00
rtp - > f . datalen = 0 ;
2003-02-16 06:00:12 +00:00
}
2004-08-26 04:56:26 +00:00
rtp - > f . frametype = AST_FRAME_CNG ;
rtp - > f . subclass = data [ 0 ] & 0x7f ;
rtp - > f . datalen = len - 1 ;
rtp - > f . samples = 0 ;
rtp - > f . delivery . tv_usec = rtp - > f . delivery . tv_sec = 0 ;
f = & rtp - > f ;
2003-02-16 06:00:12 +00:00
return f ;
}
2002-06-16 16:06:38 +00:00
static int rtpread ( int * id , int fd , short events , void * cbdata )
{
struct ast_rtp * rtp = cbdata ;
2003-02-12 13:59:15 +00:00
struct ast_frame * f ;
f = ast_rtp_read ( rtp ) ;
if ( f ) {
if ( rtp - > callback )
rtp - > callback ( rtp , f , rtp - > data ) ;
}
return 1 ;
}
2003-06-28 16:40:02 +00:00
struct ast_frame * ast_rtcp_read ( struct ast_rtp * rtp )
{
2005-05-15 03:21:51 +00:00
socklen_t len ;
2003-06-28 16:40:02 +00:00
int hdrlen = 8 ;
int res ;
struct sockaddr_in sin ;
unsigned int rtcpdata [ 1024 ] ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-06-28 16:40:02 +00:00
2005-06-18 16:46:44 +00:00
if ( ! rtp | | ! rtp - > rtcp )
2006-01-31 17:18:58 +00:00
return & ast_null_frame ;
2003-06-28 16:40:02 +00:00
len = sizeof ( sin ) ;
res = recvfrom ( rtp - > rtcp - > s , rtcpdata , sizeof ( rtcpdata ) ,
0 , ( struct sockaddr * ) & sin , & len ) ;
if ( res < 0 ) {
2005-05-04 04:43:30 +00:00
if ( errno ! = EAGAIN )
2004-06-29 14:22:27 +00:00
ast_log ( LOG_WARNING , " RTP Read error: %s \n " , strerror ( errno ) ) ;
2003-06-28 16:40:02 +00:00
if ( errno = = EBADF )
CRASH ;
2006-01-31 17:18:58 +00:00
return & ast_null_frame ;
2003-06-28 16:40:02 +00:00
}
if ( res < hdrlen ) {
ast_log ( LOG_WARNING , " RTP Read too short \n " ) ;
2006-01-31 17:18:58 +00:00
return & ast_null_frame ;
2003-06-28 16:40:02 +00:00
}
if ( rtp - > nat ) {
/* Send to whoever sent to us */
if ( ( rtp - > rtcp - > them . sin_addr . s_addr ! = sin . sin_addr . s_addr ) | |
( rtp - > rtcp - > them . sin_port ! = sin . sin_port ) ) {
2005-08-12 18:59:43 +00:00
memcpy ( & rtp - > rtcp - > them , & sin , sizeof ( rtp - > rtcp - > them ) ) ;
2005-09-07 20:33:30 +00:00
if ( option_debug | | rtpdebug )
ast_log ( LOG_DEBUG , " RTCP NAT: Got RTCP from other end. Now sending to address %s:%d \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , rtp - > rtcp - > them . sin_addr ) , ntohs ( rtp - > rtcp - > them . sin_port ) ) ;
2003-06-28 16:40:02 +00:00
}
}
2003-08-12 16:51:44 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Got RTCP report of %d bytes \n " , res ) ;
2006-01-31 17:18:58 +00:00
return & ast_null_frame ;
2003-06-28 16:40:02 +00:00
}
2004-05-01 15:18:28 +00:00
static void calc_rxstamp ( struct timeval * tv , struct ast_rtp * rtp , unsigned int timestamp , int mark )
2004-03-13 03:52:14 +00:00
{
2005-07-15 23:00:47 +00:00
struct timeval ts = ast_samp2tv ( timestamp , 8000 ) ;
if ( ast_tvzero ( rtp - > rxcore ) | | mark ) {
rtp - > rxcore = ast_tvsub ( ast_tvnow ( ) , ts ) ;
2004-06-30 06:03:57 +00:00
/* Round to 20ms for nice, pretty timestamps */
2004-03-20 05:19:45 +00:00
rtp - > rxcore . tv_usec - = rtp - > rxcore . tv_usec % 20000 ;
2004-03-13 03:52:14 +00:00
}
2005-07-15 23:00:47 +00:00
* tv = ast_tvadd ( rtp - > rxcore , ts ) ;
2004-03-13 03:52:14 +00:00
}
2003-02-12 13:59:15 +00:00
struct ast_frame * ast_rtp_read ( struct ast_rtp * rtp )
{
2002-06-16 16:06:38 +00:00
int res ;
struct sockaddr_in sin ;
2005-05-15 03:21:51 +00:00
socklen_t len ;
2002-06-16 16:06:38 +00:00
unsigned int seqno ;
2004-12-28 16:45:03 +00:00
int version ;
2002-06-16 16:06:38 +00:00
int payloadtype ;
int hdrlen = 12 ;
2005-05-14 23:41:12 +00:00
int padding ;
2003-06-28 16:40:02 +00:00
int mark ;
2004-08-31 00:16:28 +00:00
int ext ;
2004-10-19 21:07:10 +00:00
int x ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2002-06-16 16:06:38 +00:00
unsigned int timestamp ;
unsigned int * rtpheader ;
2006-01-31 17:18:58 +00:00
static struct ast_frame * f ;
2003-03-12 06:00:18 +00:00
struct rtpPayloadType rtpPT ;
2002-06-16 16:06:38 +00:00
len = sizeof ( sin ) ;
2003-06-28 16:40:02 +00:00
/* Cache where the header will go */
2003-06-28 18:35:58 +00:00
res = recvfrom ( rtp - > s , rtp - > rawdata + AST_FRIENDLY_OFFSET , sizeof ( rtp - > rawdata ) - AST_FRIENDLY_OFFSET ,
2002-06-16 16:06:38 +00:00
0 , ( struct sockaddr * ) & sin , & len ) ;
2003-03-07 06:00:13 +00:00
2003-06-28 18:35:58 +00:00
rtpheader = ( unsigned int * ) ( rtp - > rawdata + AST_FRIENDLY_OFFSET ) ;
2002-06-16 16:06:38 +00:00
if ( res < 0 ) {
2005-05-04 04:43:30 +00:00
if ( errno ! = EAGAIN )
2004-06-06 17:44:47 +00:00
ast_log ( LOG_WARNING , " RTP Read error: %s \n " , strerror ( errno ) ) ;
2002-06-16 16:06:38 +00:00
if ( errno = = EBADF )
CRASH ;
2006-01-31 17:18:58 +00:00
return & ast_null_frame ;
2002-06-16 16:06:38 +00:00
}
if ( res < hdrlen ) {
ast_log ( LOG_WARNING , " RTP Read too short \n " ) ;
2006-01-31 17:18:58 +00:00
return & ast_null_frame ;
2002-06-16 16:06:38 +00:00
}
2004-04-15 20:12:46 +00:00
/* Ignore if the other side hasn't been given an address
yet . */
if ( ! rtp - > them . sin_addr . s_addr | | ! rtp - > them . sin_port )
2006-01-31 17:18:58 +00:00
return & ast_null_frame ;
2004-04-15 20:12:46 +00:00
2003-03-07 06:00:13 +00:00
if ( rtp - > nat ) {
/* Send to whoever sent to us */
2003-03-09 06:00:18 +00:00
if ( ( rtp - > them . sin_addr . s_addr ! = sin . sin_addr . s_addr ) | |
( rtp - > them . sin_port ! = sin . sin_port ) ) {
memcpy ( & rtp - > them , & sin , sizeof ( rtp - > them ) ) ;
2004-10-19 21:07:10 +00:00
rtp - > rxseqno = 0 ;
2005-09-07 20:33:30 +00:00
ast_set_flag ( rtp , FLAG_NAT_ACTIVE ) ;
if ( option_debug | | rtpdebug )
ast_log ( LOG_DEBUG , " RTP NAT: Got audio from other end. Now sending to address %s:%d \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , rtp - > them . sin_addr ) , ntohs ( rtp - > them . sin_port ) ) ;
2003-03-09 06:00:18 +00:00
}
2003-03-07 06:00:13 +00:00
}
2004-03-14 22:49:26 +00:00
2002-06-16 16:06:38 +00:00
/* Get fields */
seqno = ntohl ( rtpheader [ 0 ] ) ;
2004-12-28 16:45:03 +00:00
/* Check RTP version */
version = ( seqno & 0xC0000000 ) > > 30 ;
if ( version ! = 2 )
2006-01-31 17:18:58 +00:00
return & ast_null_frame ;
2004-12-28 16:45:03 +00:00
2002-06-16 16:06:38 +00:00
payloadtype = ( seqno & 0x7f0000 ) > > 16 ;
2005-05-14 23:41:12 +00:00
padding = seqno & ( 1 < < 29 ) ;
2003-06-28 16:40:02 +00:00
mark = seqno & ( 1 < < 23 ) ;
2004-08-31 00:16:28 +00:00
ext = seqno & ( 1 < < 28 ) ;
2002-06-16 16:06:38 +00:00
seqno & = 0xffff ;
timestamp = ntohl ( rtpheader [ 1 ] ) ;
2005-05-14 23:41:12 +00:00
if ( padding ) {
/* Remove padding bytes */
res - = rtp - > rawdata [ AST_FRIENDLY_OFFSET + res - 1 ] ;
}
2004-08-31 00:16:28 +00:00
if ( ext ) {
/* RTP Extension present */
hdrlen + = 4 ;
2004-08-31 14:03:18 +00:00
hdrlen + = ( ntohl ( rtpheader [ 3 ] ) & 0xffff ) < < 2 ;
2004-08-31 00:16:28 +00:00
}
2003-06-28 16:40:02 +00:00
2004-08-31 05:09:20 +00:00
if ( res < hdrlen ) {
ast_log ( LOG_WARNING , " RTP Read too short (%d, expecting %d) \n " , res , hdrlen ) ;
2006-01-31 17:18:58 +00:00
return & ast_null_frame ;
2004-08-31 05:09:20 +00:00
}
2004-10-30 01:52:12 +00:00
if ( rtp_debug_test_addr ( & sin ) )
2004-12-28 16:43:20 +00:00
ast_verbose ( " Got RTP packet from %s:%d (type %d, seq %d, ts %d, len %d) \n "
2004-10-30 01:52:12 +00:00
, ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , sin . sin_addr ) , ntohs ( sin . sin_port ) , payloadtype , seqno , timestamp , res - hdrlen ) ;
2006-01-24 10:36:45 +00:00
rtpPT = ast_rtp_lookup_pt ( rtp , payloadtype ) ;
2003-03-12 06:00:18 +00:00
if ( ! rtpPT . isAstFormat ) {
2004-12-28 16:43:20 +00:00
/* This is special in-band data that's not one of our codecs */
if ( rtpPT . code = = AST_RTP_DTMF ) {
2005-07-12 23:36:00 +00:00
/* It's special -- rfc2833 process it */
if ( rtp_debug_test_addr ( & sin ) ) {
unsigned char * data ;
unsigned int event ;
unsigned int event_end ;
unsigned int duration ;
data = rtp - > rawdata + AST_FRIENDLY_OFFSET + hdrlen ;
event = ntohl ( * ( ( unsigned int * ) ( data ) ) ) ;
event > > = 24 ;
event_end = ntohl ( * ( ( unsigned int * ) ( data ) ) ) ;
event_end < < = 8 ;
event_end > > = 24 ;
duration = ntohl ( * ( ( unsigned int * ) ( data ) ) ) ;
duration & = 0xFFFF ;
ast_verbose ( " Got rfc2833 RTP packet from %s:%d (type %d, seq %d, ts %d, len %d, mark %d, event %08x, end %d, duration %d) \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , sin . sin_addr ) , ntohs ( sin . sin_port ) , payloadtype , seqno , timestamp , res - hdrlen , ( mark ? 1 : 0 ) , event , ( ( event_end & 0x80 ) ? 1 : 0 ) , duration ) ;
}
2005-10-12 20:45:18 +00:00
if ( rtp - > lasteventseqn < = seqno | | rtp - > resp = = 0 | | ( rtp - > lasteventseqn > = 65530 & & seqno < = 6 ) ) {
f = process_rfc2833 ( rtp , rtp - > rawdata + AST_FRIENDLY_OFFSET + hdrlen , res - hdrlen , seqno ) ;
rtp - > lasteventseqn = seqno ;
} else
2004-12-28 16:43:20 +00:00
f = NULL ;
2005-10-12 20:45:18 +00:00
if ( f )
return f ;
else
2006-01-31 17:18:58 +00:00
return & ast_null_frame ;
2005-10-12 20:45:18 +00:00
} else if ( rtpPT . code = = AST_RTP_CISCO_DTMF ) {
/* It's really special -- process it the Cisco way */
if ( rtp - > lasteventseqn < = seqno | | rtp - > resp = = 0 | | ( rtp - > lasteventseqn > = 65530 & & seqno < = 6 ) ) {
f = process_cisco_dtmf ( rtp , rtp - > rawdata + AST_FRIENDLY_OFFSET + hdrlen , res - hdrlen ) ;
rtp - > lasteventseqn = seqno ;
} else
2004-12-28 16:43:20 +00:00
f = NULL ;
2006-03-31 17:46:03 +00:00
if ( f )
2004-12-28 16:43:20 +00:00
return f ;
else
2006-01-31 17:18:58 +00:00
return & ast_null_frame ;
2005-10-12 20:45:18 +00:00
} else if ( rtpPT . code = = AST_RTP_CN ) {
/* Comfort Noise */
f = process_rfc3389 ( rtp , rtp - > rawdata + AST_FRIENDLY_OFFSET + hdrlen , res - hdrlen ) ;
if ( f )
2004-12-28 16:43:20 +00:00
return f ;
else
2006-01-31 17:18:58 +00:00
return & ast_null_frame ;
2005-10-12 20:45:18 +00:00
} else {
2006-03-31 17:46:03 +00:00
ast_log ( LOG_NOTICE , " Unknown RTP codec %d received from '%s' \n " , payloadtype , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , rtp - > them . sin_addr ) ) ;
2006-01-31 17:18:58 +00:00
return & ast_null_frame ;
2005-10-12 20:45:18 +00:00
}
2003-03-12 06:00:18 +00:00
}
rtp - > f . subclass = rtpPT . code ;
2003-06-28 16:40:02 +00:00
if ( rtp - > f . subclass < AST_FORMAT_MAX_AUDIO )
rtp - > f . frametype = AST_FRAME_VOICE ;
else
rtp - > f . frametype = AST_FRAME_VIDEO ;
2003-03-12 06:00:18 +00:00
rtp - > lastrxformat = rtp - > f . subclass ;
2002-06-16 16:06:38 +00:00
if ( ! rtp - > lastrxts )
rtp - > lastrxts = timestamp ;
2004-10-19 21:07:10 +00:00
if ( rtp - > rxseqno ) {
for ( x = rtp - > rxseqno + 1 ; x < seqno ; x + + ) {
/* Queue empty frames */
rtp - > f . mallocd = 0 ;
rtp - > f . datalen = 0 ;
rtp - > f . data = NULL ;
rtp - > f . offset = 0 ;
rtp - > f . samples = 0 ;
rtp - > f . src = " RTPMissedFrame " ;
}
}
rtp - > rxseqno = seqno ;
2002-06-16 16:06:38 +00:00
if ( rtp - > dtmfcount ) {
#if 0
printf ( " dtmfcount was %d \n " , rtp - > dtmfcount ) ;
# endif
rtp - > dtmfcount - = ( timestamp - rtp - > lastrxts ) ;
if ( rtp - > dtmfcount < 0 )
rtp - > dtmfcount = 0 ;
#if 0
if ( dtmftimeout ! = rtp - > dtmfcount )
printf ( " dtmfcount is %d \n " , rtp - > dtmfcount ) ;
# endif
}
rtp - > lastrxts = timestamp ;
/* Send any pending DTMF */
if ( rtp - > resp & & ! rtp - > dtmfcount ) {
2004-12-28 16:43:20 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Sending pending DTMF \n " ) ;
2003-02-12 13:59:15 +00:00
return send_dtmf ( rtp ) ;
2002-06-16 16:06:38 +00:00
}
rtp - > f . mallocd = 0 ;
2003-06-28 18:35:58 +00:00
rtp - > f . datalen = res - hdrlen ;
2002-06-16 16:06:38 +00:00
rtp - > f . data = rtp - > rawdata + hdrlen + AST_FRIENDLY_OFFSET ;
rtp - > f . offset = hdrlen + AST_FRIENDLY_OFFSET ;
2003-06-28 16:40:02 +00:00
if ( rtp - > f . subclass < AST_FORMAT_MAX_AUDIO ) {
2005-05-14 23:57:44 +00:00
rtp - > f . samples = ast_codec_get_samples ( & rtp - > f ) ;
if ( rtp - > f . subclass = = AST_FORMAT_SLINEAR )
2005-04-03 22:57:18 +00:00
ast_frame_byteswap_be ( & rtp - > f ) ;
2004-05-01 15:18:28 +00:00
calc_rxstamp ( & rtp - > f . delivery , rtp , timestamp , mark ) ;
2003-06-28 16:40:02 +00:00
} else {
/* Video -- samples is # of samples vs. 90000 */
2003-06-29 03:24:39 +00:00
if ( ! rtp - > lastividtimestamp )
rtp - > lastividtimestamp = timestamp ;
2003-06-28 16:40:02 +00:00
rtp - > f . samples = timestamp - rtp - > lastividtimestamp ;
rtp - > lastividtimestamp = timestamp ;
2004-05-30 20:24:48 +00:00
rtp - > f . delivery . tv_sec = 0 ;
rtp - > f . delivery . tv_usec = 0 ;
2003-06-28 18:35:58 +00:00
if ( mark )
rtp - > f . subclass | = 0x1 ;
2002-06-16 16:06:38 +00:00
}
rtp - > f . src = " RTP " ;
2003-02-12 13:59:15 +00:00
return & rtp - > f ;
2002-06-16 16:06:38 +00:00
}
2004-06-29 20:10:57 +00:00
/* The following array defines the MIME Media type (and subtype) for each
of our codecs , or RTP - specific data type . */
2002-06-16 16:06:38 +00:00
static struct {
2006-01-03 09:30:19 +00:00
struct rtpPayloadType payloadType ;
char * type ;
char * subtype ;
2003-03-12 06:00:18 +00:00
} mimeTypes [ ] = {
2006-01-03 09:30:19 +00:00
{ { 1 , AST_FORMAT_G723_1 } , " audio " , " G723 " } ,
{ { 1 , AST_FORMAT_GSM } , " audio " , " GSM " } ,
{ { 1 , AST_FORMAT_ULAW } , " audio " , " PCMU " } ,
{ { 1 , AST_FORMAT_ALAW } , " audio " , " PCMA " } ,
{ { 1 , AST_FORMAT_G726 } , " audio " , " G726-32 " } ,
{ { 1 , AST_FORMAT_ADPCM } , " audio " , " DVI4 " } ,
{ { 1 , AST_FORMAT_SLINEAR } , " audio " , " L16 " } ,
{ { 1 , AST_FORMAT_LPC10 } , " audio " , " LPC " } ,
{ { 1 , AST_FORMAT_G729A } , " audio " , " G729 " } ,
{ { 1 , AST_FORMAT_SPEEX } , " audio " , " speex " } ,
{ { 1 , AST_FORMAT_ILBC } , " audio " , " iLBC " } ,
{ { 0 , AST_RTP_DTMF } , " audio " , " telephone-event " } ,
{ { 0 , AST_RTP_CISCO_DTMF } , " audio " , " cisco-telephone-event " } ,
{ { 0 , AST_RTP_CN } , " audio " , " CN " } ,
{ { 1 , AST_FORMAT_JPEG } , " video " , " JPEG " } ,
{ { 1 , AST_FORMAT_PNG } , " video " , " PNG " } ,
{ { 1 , AST_FORMAT_H261 } , " video " , " H261 " } ,
{ { 1 , AST_FORMAT_H263 } , " video " , " H263 " } ,
{ { 1 , AST_FORMAT_H263_PLUS } , " video " , " h263-1998 " } ,
2006-01-07 17:54:22 +00:00
{ { 1 , AST_FORMAT_H264 } , " video " , " H264 " } ,
2002-06-16 16:06:38 +00:00
} ;
2003-04-10 15:36:52 +00:00
/* Static (i.e., well-known) RTP payload types for our "AST_FORMAT..."s:
also , our own choices for dynamic payload types . This is our master
table for transmission */
2003-03-12 06:00:18 +00:00
static struct rtpPayloadType static_RTP_PT [ MAX_RTP_PT ] = {
2006-01-03 09:30:19 +00:00
[ 0 ] = { 1 , AST_FORMAT_ULAW } ,
2005-03-25 21:01:11 +00:00
# ifdef USE_DEPRECATED_G726
2006-01-03 09:30:19 +00:00
[ 2 ] = { 1 , AST_FORMAT_G726 } , /* Technically this is G.721, but if Cisco can do it, so can we... */
2005-03-25 21:01:11 +00:00
# endif
2006-01-03 09:30:19 +00:00
[ 3 ] = { 1 , AST_FORMAT_GSM } ,
[ 4 ] = { 1 , AST_FORMAT_G723_1 } ,
[ 5 ] = { 1 , AST_FORMAT_ADPCM } , /* 8 kHz */
[ 6 ] = { 1 , AST_FORMAT_ADPCM } , /* 16 kHz */
[ 7 ] = { 1 , AST_FORMAT_LPC10 } ,
[ 8 ] = { 1 , AST_FORMAT_ALAW } ,
[ 10 ] = { 1 , AST_FORMAT_SLINEAR } , /* 2 channels */
[ 11 ] = { 1 , AST_FORMAT_SLINEAR } , /* 1 channel */
[ 13 ] = { 0 , AST_RTP_CN } ,
[ 16 ] = { 1 , AST_FORMAT_ADPCM } , /* 11.025 kHz */
[ 17 ] = { 1 , AST_FORMAT_ADPCM } , /* 22.050 kHz */
[ 18 ] = { 1 , AST_FORMAT_G729A } ,
[ 19 ] = { 0 , AST_RTP_CN } , /* Also used for CN */
[ 26 ] = { 1 , AST_FORMAT_JPEG } ,
[ 31 ] = { 1 , AST_FORMAT_H261 } ,
[ 34 ] = { 1 , AST_FORMAT_H263 } ,
[ 103 ] = { 1 , AST_FORMAT_H263_PLUS } ,
[ 97 ] = { 1 , AST_FORMAT_ILBC } ,
2006-01-07 17:54:22 +00:00
[ 99 ] = { 1 , AST_FORMAT_H264 } ,
2006-01-03 09:30:19 +00:00
[ 101 ] = { 0 , AST_RTP_DTMF } ,
[ 110 ] = { 1 , AST_FORMAT_SPEEX } ,
[ 111 ] = { 1 , AST_FORMAT_G726 } ,
[ 121 ] = { 0 , AST_RTP_CISCO_DTMF } , /* Must be type 121 */
2003-03-12 06:00:18 +00:00
} ;
2003-03-13 06:00:20 +00:00
void ast_rtp_pt_clear ( struct ast_rtp * rtp )
{
2004-12-28 16:43:20 +00:00
int i ;
2005-09-07 20:33:30 +00:00
if ( ! rtp )
return ;
2003-03-12 06:00:18 +00:00
2004-12-28 16:43:20 +00:00
for ( i = 0 ; i < MAX_RTP_PT ; + + i ) {
rtp - > current_RTP_PT [ i ] . isAstFormat = 0 ;
rtp - > current_RTP_PT [ i ] . code = 0 ;
}
2003-03-12 06:00:18 +00:00
2004-12-28 16:43:20 +00:00
rtp - > rtp_lookup_code_cache_isAstFormat = 0 ;
rtp - > rtp_lookup_code_cache_code = 0 ;
rtp - > rtp_lookup_code_cache_result = 0 ;
2002-06-16 16:06:38 +00:00
}
2003-03-13 06:00:20 +00:00
void ast_rtp_pt_default ( struct ast_rtp * rtp )
{
2004-12-28 16:43:20 +00:00
int i ;
/* Initialize to default payload types */
for ( i = 0 ; i < MAX_RTP_PT ; + + i ) {
rtp - > current_RTP_PT [ i ] . isAstFormat = static_RTP_PT [ i ] . isAstFormat ;
rtp - > current_RTP_PT [ i ] . code = static_RTP_PT [ i ] . code ;
}
rtp - > rtp_lookup_code_cache_isAstFormat = 0 ;
rtp - > rtp_lookup_code_cache_code = 0 ;
rtp - > rtp_lookup_code_cache_result = 0 ;
2003-03-13 06:00:20 +00:00
}
2005-12-20 17:52:31 +00:00
static void ast_rtp_pt_copy ( struct ast_rtp * dest , struct ast_rtp * src )
{
int i ;
/* Copy payload types from source to destination */
for ( i = 0 ; i < MAX_RTP_PT ; + + i ) {
dest - > current_RTP_PT [ i ] . isAstFormat =
src - > current_RTP_PT [ i ] . isAstFormat ;
dest - > current_RTP_PT [ i ] . code =
src - > current_RTP_PT [ i ] . code ;
}
dest - > rtp_lookup_code_cache_isAstFormat = 0 ;
dest - > rtp_lookup_code_cache_code = 0 ;
dest - > rtp_lookup_code_cache_result = 0 ;
}
2006-01-03 09:30:19 +00:00
/*! \brief Get channel driver interface structure */
2005-12-20 17:52:31 +00:00
static struct ast_rtp_protocol * get_proto ( struct ast_channel * chan )
{
2006-01-03 17:08:35 +00:00
struct ast_rtp_protocol * cur = NULL ;
2005-12-20 17:52:31 +00:00
2006-01-03 09:30:19 +00:00
AST_LIST_LOCK ( & protos ) ;
AST_LIST_TRAVERSE ( & protos , cur , list ) {
2006-02-01 23:05:28 +00:00
if ( cur - > type = = chan - > tech - > type )
2006-01-03 17:08:35 +00:00
break ;
2005-12-20 17:52:31 +00:00
}
2006-01-03 09:30:19 +00:00
AST_LIST_UNLOCK ( & protos ) ;
2006-01-03 17:08:35 +00:00
return cur ;
2005-12-20 17:52:31 +00:00
}
int ast_rtp_make_compatible ( struct ast_channel * dest , struct ast_channel * src )
{
struct ast_rtp * destp , * srcp ; /* Audio RTP Channels */
struct ast_rtp * vdestp , * vsrcp ; /* Video RTP channels */
struct ast_rtp_protocol * destpr , * srcpr ;
/* Lock channels */
ast_mutex_lock ( & dest - > lock ) ;
while ( ast_mutex_trylock ( & src - > lock ) ) {
ast_mutex_unlock ( & dest - > lock ) ;
usleep ( 1 ) ;
ast_mutex_lock ( & dest - > lock ) ;
}
/* Find channel driver interfaces */
destpr = get_proto ( dest ) ;
srcpr = get_proto ( src ) ;
if ( ! destpr ) {
2006-01-03 09:30:19 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Channel '%s' has no RTP, not doing anything \n " , dest - > name ) ;
2005-12-20 17:52:31 +00:00
ast_mutex_unlock ( & dest - > lock ) ;
ast_mutex_unlock ( & src - > lock ) ;
return 0 ;
}
if ( ! srcpr ) {
2006-01-03 09:30:19 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Channel '%s' has no RTP, not doing anything \n " , src - > name ) ;
2005-12-20 17:52:31 +00:00
ast_mutex_unlock ( & dest - > lock ) ;
ast_mutex_unlock ( & src - > lock ) ;
return 0 ;
}
/* Get audio and video interface (if native bridge is possible) */
destp = destpr - > get_rtp_info ( dest ) ;
if ( destpr - > get_vrtp_info )
vdestp = destpr - > get_vrtp_info ( dest ) ;
else
vdestp = NULL ;
srcp = srcpr - > get_rtp_info ( src ) ;
if ( srcpr - > get_vrtp_info )
vsrcp = srcpr - > get_vrtp_info ( src ) ;
else
vsrcp = NULL ;
/* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
if ( ! destp | | ! srcp ) {
/* Somebody doesn't want to play... */
ast_mutex_unlock ( & dest - > lock ) ;
ast_mutex_unlock ( & src - > lock ) ;
return 0 ;
}
ast_rtp_pt_copy ( destp , srcp ) ;
if ( vdestp & & vsrcp )
ast_rtp_pt_copy ( vdestp , vsrcp ) ;
ast_mutex_unlock ( & dest - > lock ) ;
ast_mutex_unlock ( & src - > lock ) ;
2006-01-03 09:30:19 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Seeded SDP of '%s' with that of '%s' \n " , dest - > name , src - > name ) ;
2005-12-20 17:52:31 +00:00
return 1 ;
}
2006-01-03 09:30:19 +00:00
/*! \brief Make a note of a RTP paymoad type that was seen in a SDP "m=" line.
* By default , use the well - known value for this type ( although it may
* still be set to a different value by a subsequent " a=rtpmap: " line )
*/
2005-12-20 17:52:31 +00:00
void ast_rtp_set_m_type ( struct ast_rtp * rtp , int pt )
{
2004-12-28 16:43:20 +00:00
if ( pt < 0 | | pt > MAX_RTP_PT )
return ; /* bogus payload type */
2003-03-12 06:00:18 +00:00
2004-12-28 16:43:20 +00:00
if ( static_RTP_PT [ pt ] . code ! = 0 ) {
rtp - > current_RTP_PT [ pt ] = static_RTP_PT [ pt ] ;
}
2003-03-12 06:00:18 +00:00
}
2006-01-03 09:30:19 +00:00
/*! \brief Make a note of a RTP payload type (with MIME type) that was seen in
a SDP " a=rtpmap: " line . */
2003-03-13 06:00:20 +00:00
void ast_rtp_set_rtpmap_type ( struct ast_rtp * rtp , int pt ,
2005-12-20 17:52:31 +00:00
char * mimeType , char * mimeSubtype )
{
2004-12-28 16:43:20 +00:00
int i ;
2003-03-12 06:00:18 +00:00
2004-12-28 16:43:20 +00:00
if ( pt < 0 | | pt > MAX_RTP_PT )
return ; /* bogus payload type */
2003-03-12 06:00:18 +00:00
2004-12-28 16:43:20 +00:00
for ( i = 0 ; i < sizeof mimeTypes / sizeof mimeTypes [ 0 ] ; + + i ) {
if ( strcasecmp ( mimeSubtype , mimeTypes [ i ] . subtype ) = = 0 & &
strcasecmp ( mimeType , mimeTypes [ i ] . type ) = = 0 ) {
rtp - > current_RTP_PT [ pt ] = mimeTypes [ i ] . payloadType ;
return ;
}
}
2003-03-12 06:00:18 +00:00
}
2006-01-03 09:30:19 +00:00
/*! \brief Return the union of all of the codecs that were set by rtp_set...() calls
* They ' re returned as two distinct sets : AST_FORMATs , and AST_RTPs */
2003-03-13 06:00:20 +00:00
void ast_rtp_get_current_formats ( struct ast_rtp * rtp ,
2003-03-12 06:00:18 +00:00
int * astFormats , int * nonAstFormats ) {
2004-12-28 16:43:20 +00:00
int pt ;
* astFormats = * nonAstFormats = 0 ;
for ( pt = 0 ; pt < MAX_RTP_PT ; + + pt ) {
if ( rtp - > current_RTP_PT [ pt ] . isAstFormat ) {
* astFormats | = rtp - > current_RTP_PT [ pt ] . code ;
} else {
* nonAstFormats | = rtp - > current_RTP_PT [ pt ] . code ;
}
}
2002-06-16 16:06:38 +00:00
}
2004-03-22 21:52:22 +00:00
struct rtpPayloadType ast_rtp_lookup_pt ( struct ast_rtp * rtp , int pt )
{
2004-12-28 16:43:20 +00:00
struct rtpPayloadType result ;
result . isAstFormat = result . code = 0 ;
if ( pt < 0 | | pt > MAX_RTP_PT )
return result ; /* bogus payload type */
/* Start with the negotiated codecs */
2005-12-20 17:52:31 +00:00
result = rtp - > current_RTP_PT [ pt ] ;
2004-12-28 16:43:20 +00:00
/* If it doesn't exist, check our static RTP type list, just in case */
if ( ! result . code )
result = static_RTP_PT [ pt ] ;
return result ;
2003-03-12 06:00:18 +00:00
}
2006-01-03 09:30:19 +00:00
/*! \brief Looks up an RTP code out of our *static* outbound list */
2005-04-05 23:34:56 +00:00
int ast_rtp_lookup_code ( struct ast_rtp * rtp , const int isAstFormat , const int code ) {
2003-03-12 06:00:18 +00:00
2004-12-28 16:43:20 +00:00
int pt ;
2003-04-10 15:36:52 +00:00
2004-12-28 16:43:20 +00:00
if ( isAstFormat = = rtp - > rtp_lookup_code_cache_isAstFormat & &
code = = rtp - > rtp_lookup_code_cache_code ) {
/* Use our cached mapping, to avoid the overhead of the loop below */
return rtp - > rtp_lookup_code_cache_result ;
}
2003-03-12 06:00:18 +00:00
2004-03-22 21:52:22 +00:00
/* Check the dynamic list first */
2004-12-28 16:43:20 +00:00
for ( pt = 0 ; pt < MAX_RTP_PT ; + + pt ) {
if ( rtp - > current_RTP_PT [ pt ] . code = = code & & rtp - > current_RTP_PT [ pt ] . isAstFormat = = isAstFormat ) {
rtp - > rtp_lookup_code_cache_isAstFormat = isAstFormat ;
rtp - > rtp_lookup_code_cache_code = code ;
rtp - > rtp_lookup_code_cache_result = pt ;
return pt ;
}
}
2004-03-22 21:52:22 +00:00
/* Then the static list */
2004-12-28 16:43:20 +00:00
for ( pt = 0 ; pt < MAX_RTP_PT ; + + pt ) {
if ( static_RTP_PT [ pt ] . code = = code & & static_RTP_PT [ pt ] . isAstFormat = = isAstFormat ) {
rtp - > rtp_lookup_code_cache_isAstFormat = isAstFormat ;
rtp - > rtp_lookup_code_cache_code = code ;
rtp - > rtp_lookup_code_cache_result = pt ;
return pt ;
}
}
return - 1 ;
2002-08-09 17:17:54 +00:00
}
2003-03-12 06:00:18 +00:00
2005-12-20 17:52:31 +00:00
char * ast_rtp_lookup_mime_subtype ( const int isAstFormat , const int code )
{
2004-12-28 16:43:20 +00:00
int i ;
for ( i = 0 ; i < sizeof mimeTypes / sizeof mimeTypes [ 0 ] ; + + i ) {
if ( mimeTypes [ i ] . payloadType . code = = code & & mimeTypes [ i ] . payloadType . isAstFormat = = isAstFormat ) {
return mimeTypes [ i ] . subtype ;
}
}
return " " ;
2003-03-12 06:00:18 +00:00
}
2005-04-05 23:34:56 +00:00
char * ast_rtp_lookup_mime_multiple ( char * buf , int size , const int capability , const int isAstFormat )
{
int format ;
2005-04-06 03:43:59 +00:00
unsigned len ;
char * end = buf ;
char * start = buf ;
2005-04-05 23:34:56 +00:00
if ( ! buf | | ! size )
return NULL ;
2005-04-06 03:43:59 +00:00
snprintf ( end , size , " 0x%x ( " , capability ) ;
len = strlen ( end ) ;
end + = len ;
size - = len ;
start = end ;
2005-04-05 23:34:56 +00:00
for ( format = 1 ; format < AST_RTP_MAX ; format < < = 1 ) {
if ( capability & format ) {
const char * name = ast_rtp_lookup_mime_subtype ( isAstFormat , format ) ;
2005-04-06 03:43:59 +00:00
snprintf ( end , size , " %s| " , name ) ;
len = strlen ( end ) ;
end + = len ;
size - = len ;
2005-04-05 23:34:56 +00:00
}
}
2005-04-06 03:43:59 +00:00
if ( start = = end )
snprintf ( start , size , " nothing) " ) ;
else if ( size > 1 )
* ( end - 1 ) = ' ) ' ;
2005-04-05 23:34:56 +00:00
return buf ;
}
2004-06-09 01:33:16 +00:00
static int rtp_socket ( void )
{
int s ;
long flags ;
s = socket ( AF_INET , SOCK_DGRAM , 0 ) ;
if ( s > - 1 ) {
flags = fcntl ( s , F_GETFL ) ;
fcntl ( s , F_SETFL , flags | O_NONBLOCK ) ;
2004-07-19 18:09:33 +00:00
# ifdef SO_NO_CHECK
2005-03-31 19:09:48 +00:00
if ( nochecksums )
setsockopt ( s , SOL_SOCKET , SO_NO_CHECK , & nochecksums , sizeof ( nochecksums ) ) ;
2004-07-19 18:09:33 +00:00
# endif
2004-06-09 01:33:16 +00:00
}
return s ;
}
2005-10-12 20:45:18 +00:00
/*!
* \ brief Initialize a new RTCP session .
*
* \ returns The newly initialized RTCP session .
*/
2003-06-28 16:40:02 +00:00
static struct ast_rtcp * ast_rtcp_new ( void )
{
struct ast_rtcp * rtcp ;
2006-03-18 18:55:35 +00:00
if ( ! ( rtcp = ast_calloc ( 1 , sizeof ( * rtcp ) ) ) )
2003-06-28 16:40:02 +00:00
return NULL ;
2004-06-09 01:33:16 +00:00
rtcp - > s = rtp_socket ( ) ;
2003-06-28 16:40:02 +00:00
rtcp - > us . sin_family = AF_INET ;
if ( rtcp - > s < 0 ) {
free ( rtcp ) ;
ast_log ( LOG_WARNING , " Unable to allocate socket: %s \n " , strerror ( errno ) ) ;
return NULL ;
}
2006-03-18 18:55:35 +00:00
2003-06-28 16:40:02 +00:00
return rtcp ;
}
2004-07-08 11:46:15 +00:00
struct ast_rtp * ast_rtp_new_with_bindaddr ( struct sched_context * sched , struct io_context * io , int rtcpenable , int callbackmode , struct in_addr addr )
2002-06-16 16:06:38 +00:00
{
struct ast_rtp * rtp ;
int x ;
2004-06-09 01:33:16 +00:00
int first ;
2003-05-16 02:50:46 +00:00
int startplace ;
2006-03-18 18:55:35 +00:00
if ( ! ( rtp = ast_calloc ( 1 , sizeof ( * rtp ) ) ) )
2002-06-16 16:06:38 +00:00
return NULL ;
rtp - > them . sin_family = AF_INET ;
rtp - > us . sin_family = AF_INET ;
2004-06-09 01:33:16 +00:00
rtp - > s = rtp_socket ( ) ;
2006-04-05 17:44:44 +00:00
rtp - > ssrc = ast_random ( ) ;
rtp - > seqno = ast_random ( ) & 0xffff ;
2002-06-16 16:06:38 +00:00
if ( rtp - > s < 0 ) {
free ( rtp ) ;
2004-12-28 16:43:20 +00:00
ast_log ( LOG_ERROR , " Unable to allocate socket: %s \n " , strerror ( errno ) ) ;
2002-06-16 16:06:38 +00:00
return NULL ;
}
2003-06-28 16:40:02 +00:00
if ( sched & & rtcpenable ) {
rtp - > sched = sched ;
rtp - > rtcp = ast_rtcp_new ( ) ;
}
2005-10-12 20:45:18 +00:00
/* Select a random port number in the range of possible RTP */
2006-04-05 17:44:44 +00:00
x = ( ast_random ( ) % ( rtpend - rtpstart ) ) + rtpstart ;
2003-05-16 02:50:46 +00:00
x = x & ~ 1 ;
2005-10-12 20:45:18 +00:00
/* Save it for future references. */
2003-05-16 02:50:46 +00:00
startplace = x ;
2005-10-12 20:45:18 +00:00
/* Iterate tring to bind that port and incrementing it otherwise untill a port was found or no ports are available. */
2002-06-16 16:06:38 +00:00
for ( ; ; ) {
/* Must be an even port number by RTP spec */
rtp - > us . sin_port = htons ( x ) ;
2004-07-08 11:46:15 +00:00
rtp - > us . sin_addr = addr ;
2005-10-12 20:45:18 +00:00
/* If there's rtcp, initialize it as well. */
2003-06-28 16:40:02 +00:00
if ( rtp - > rtcp )
rtp - > rtcp - > us . sin_port = htons ( x + 1 ) ;
2005-10-12 20:45:18 +00:00
/* Try to bind it/them. */
2004-06-09 01:33:16 +00:00
if ( ! ( first = bind ( rtp - > s , ( struct sockaddr * ) & rtp - > us , sizeof ( rtp - > us ) ) ) & &
2003-09-08 16:48:07 +00:00
( ! rtp - > rtcp | | ! bind ( rtp - > rtcp - > s , ( struct sockaddr * ) & rtp - > rtcp - > us , sizeof ( rtp - > rtcp - > us ) ) ) )
2002-06-16 16:06:38 +00:00
break ;
2004-06-09 01:33:16 +00:00
if ( ! first ) {
/* Primary bind succeeded! Gotta recreate it */
close ( rtp - > s ) ;
rtp - > s = rtp_socket ( ) ;
}
2002-06-16 16:06:38 +00:00
if ( errno ! = EADDRINUSE ) {
2005-10-12 20:45:18 +00:00
/* We got an error that wasn't expected, abort! */
2004-12-28 16:43:20 +00:00
ast_log ( LOG_ERROR , " Unexpected bind error: %s \n " , strerror ( errno ) ) ;
2002-06-16 16:06:38 +00:00
close ( rtp - > s ) ;
2003-06-28 16:40:02 +00:00
if ( rtp - > rtcp ) {
close ( rtp - > rtcp - > s ) ;
free ( rtp - > rtcp ) ;
}
2002-06-16 16:06:38 +00:00
free ( rtp ) ;
return NULL ;
}
2005-10-12 20:45:18 +00:00
/* The port was used, increment it (by two). */
2003-05-16 02:50:46 +00:00
x + = 2 ;
2005-10-12 20:45:18 +00:00
/* Did we go over the limit ? */
2003-05-16 02:50:46 +00:00
if ( x > rtpend )
2005-10-12 20:45:18 +00:00
/* then, start from the begingig. */
2003-05-16 02:50:46 +00:00
x = ( rtpstart + 1 ) & ~ 1 ;
2005-10-12 20:45:18 +00:00
/* Check if we reached the place were we started. */
2003-05-16 02:50:46 +00:00
if ( x = = startplace ) {
2005-10-12 20:45:18 +00:00
/* If so, there's no ports available. */
2005-05-16 13:22:34 +00:00
ast_log ( LOG_ERROR , " No RTP ports remaining. Can't setup media stream for this call. \n " ) ;
2003-05-16 02:50:46 +00:00
close ( rtp - > s ) ;
2003-06-28 16:40:02 +00:00
if ( rtp - > rtcp ) {
close ( rtp - > rtcp - > s ) ;
free ( rtp - > rtcp ) ;
}
2003-05-16 02:50:46 +00:00
free ( rtp ) ;
return NULL ;
}
2002-06-16 16:06:38 +00:00
}
2003-06-28 16:40:02 +00:00
if ( io & & sched & & callbackmode ) {
2003-02-12 13:59:15 +00:00
/* Operate this one in a callback mode */
rtp - > sched = sched ;
rtp - > io = io ;
rtp - > ioid = ast_io_add ( rtp - > io , rtp - > s , rtpread , AST_IO_IN , rtp ) ;
}
2003-03-13 06:00:20 +00:00
ast_rtp_pt_default ( rtp ) ;
2002-06-16 16:06:38 +00:00
return rtp ;
}
2004-07-08 11:46:15 +00:00
struct ast_rtp * ast_rtp_new ( struct sched_context * sched , struct io_context * io , int rtcpenable , int callbackmode )
{
struct in_addr ia ;
2004-12-28 16:43:20 +00:00
2004-07-08 11:46:15 +00:00
memset ( & ia , 0 , sizeof ( ia ) ) ;
return ast_rtp_new_with_bindaddr ( sched , io , rtcpenable , callbackmode , ia ) ;
}
2003-02-05 19:26:49 +00:00
int ast_rtp_settos ( struct ast_rtp * rtp , int tos )
{
int res ;
2004-12-28 16:43:20 +00:00
2003-04-23 20:22:14 +00:00
if ( ( res = setsockopt ( rtp - > s , IPPROTO_IP , IP_TOS , & tos , sizeof ( tos ) ) ) )
2003-02-05 19:26:49 +00:00
ast_log ( LOG_WARNING , " Unable to set TOS to %d \n " , tos ) ;
return res ;
}
2002-06-16 16:06:38 +00:00
void ast_rtp_set_peer ( struct ast_rtp * rtp , struct sockaddr_in * them )
{
rtp - > them . sin_port = them - > sin_port ;
rtp - > them . sin_addr = them - > sin_addr ;
2003-06-28 16:40:02 +00:00
if ( rtp - > rtcp ) {
rtp - > rtcp - > them . sin_port = htons ( ntohs ( them - > sin_port ) + 1 ) ;
rtp - > rtcp - > them . sin_addr = them - > sin_addr ;
}
2004-10-19 21:07:10 +00:00
rtp - > rxseqno = 0 ;
2002-06-16 16:06:38 +00:00
}
2003-02-05 19:26:49 +00:00
void ast_rtp_get_peer ( struct ast_rtp * rtp , struct sockaddr_in * them )
{
them - > sin_family = AF_INET ;
them - > sin_port = rtp - > them . sin_port ;
them - > sin_addr = rtp - > them . sin_addr ;
}
2002-06-16 16:06:38 +00:00
void ast_rtp_get_us ( struct ast_rtp * rtp , struct sockaddr_in * us )
{
memcpy ( us , & rtp - > us , sizeof ( rtp - > us ) ) ;
}
2003-03-20 22:01:53 +00:00
void ast_rtp_stop ( struct ast_rtp * rtp )
{
memset ( & rtp - > them . sin_addr , 0 , sizeof ( rtp - > them . sin_addr ) ) ;
memset ( & rtp - > them . sin_port , 0 , sizeof ( rtp - > them . sin_port ) ) ;
2003-06-28 16:40:02 +00:00
if ( rtp - > rtcp ) {
memset ( & rtp - > rtcp - > them . sin_addr , 0 , sizeof ( rtp - > them . sin_addr ) ) ;
memset ( & rtp - > rtcp - > them . sin_port , 0 , sizeof ( rtp - > them . sin_port ) ) ;
}
2003-03-20 22:01:53 +00:00
}
2004-12-28 16:35:31 +00:00
void ast_rtp_reset ( struct ast_rtp * rtp )
{
memset ( & rtp - > rxcore , 0 , sizeof ( rtp - > rxcore ) ) ;
memset ( & rtp - > txcore , 0 , sizeof ( rtp - > txcore ) ) ;
memset ( & rtp - > dtmfmute , 0 , sizeof ( rtp - > dtmfmute ) ) ;
rtp - > lastts = 0 ;
2005-04-04 02:13:40 +00:00
rtp - > lastdigitts = 0 ;
2004-12-28 16:35:31 +00:00
rtp - > lastrxts = 0 ;
rtp - > lastividtimestamp = 0 ;
rtp - > lastovidtimestamp = 0 ;
rtp - > lasteventseqn = 0 ;
2005-07-12 23:36:00 +00:00
rtp - > lasteventendseqn = 0 ;
2004-12-28 16:35:31 +00:00
rtp - > lasttxformat = 0 ;
rtp - > lastrxformat = 0 ;
rtp - > dtmfcount = 0 ;
rtp - > dtmfduration = 0 ;
rtp - > seqno = 0 ;
rtp - > rxseqno = 0 ;
}
2002-06-16 16:06:38 +00:00
void ast_rtp_destroy ( struct ast_rtp * rtp )
{
2002-08-09 17:17:54 +00:00
if ( rtp - > smoother )
ast_smoother_free ( rtp - > smoother ) ;
2002-06-16 16:06:38 +00:00
if ( rtp - > ioid )
ast_io_remove ( rtp - > io , rtp - > ioid ) ;
if ( rtp - > s > - 1 )
close ( rtp - > s ) ;
2003-06-28 16:40:02 +00:00
if ( rtp - > rtcp ) {
close ( rtp - > rtcp - > s ) ;
free ( rtp - > rtcp ) ;
}
2002-06-16 16:06:38 +00:00
free ( rtp ) ;
}
2004-03-13 03:52:14 +00:00
static unsigned int calc_txstamp ( struct ast_rtp * rtp , struct timeval * delivery )
2002-06-16 16:06:38 +00:00
{
2005-07-15 23:00:47 +00:00
struct timeval t ;
long ms ;
if ( ast_tvzero ( rtp - > txcore ) ) {
rtp - > txcore = ast_tvnow ( ) ;
2004-06-30 06:03:57 +00:00
/* Round to 20ms for nice, pretty timestamps */
2004-03-20 05:22:52 +00:00
rtp - > txcore . tv_usec - = rtp - > txcore . tv_usec % 20000 ;
2002-06-16 16:06:38 +00:00
}
2005-07-15 23:00:47 +00:00
/* Use previous txcore if available */
t = ( delivery & & ! ast_tvzero ( * delivery ) ) ? * delivery : ast_tvnow ( ) ;
ms = ast_tvdiff_ms ( t , rtp - > txcore ) ;
2005-11-11 04:07:03 +00:00
if ( ms < 0 )
ms = 0 ;
2005-07-15 23:00:47 +00:00
/* Use what we just got for next time */
rtp - > txcore = t ;
return ( unsigned int ) ms ;
2002-06-16 16:06:38 +00:00
}
2003-02-05 19:26:49 +00:00
int ast_rtp_senddigit ( struct ast_rtp * rtp , char digit )
{
unsigned int * rtpheader ;
int hdrlen = 12 ;
int res ;
int x ;
2004-07-31 20:31:11 +00:00
int payload ;
2003-02-05 19:26:49 +00:00
char data [ 256 ] ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-02-05 19:26:49 +00:00
if ( ( digit < = ' 9 ' ) & & ( digit > = ' 0 ' ) )
digit - = ' 0 ' ;
else if ( digit = = ' * ' )
digit = 10 ;
else if ( digit = = ' # ' )
digit = 11 ;
else if ( ( digit > = ' A ' ) & & ( digit < = ' D ' ) )
digit = digit - ' A ' + 12 ;
else if ( ( digit > = ' a ' ) & & ( digit < = ' d ' ) )
digit = digit - ' a ' + 12 ;
else {
ast_log ( LOG_WARNING , " Don't know how to represent '%c' \n " , digit ) ;
return - 1 ;
}
2004-07-31 20:31:11 +00:00
payload = ast_rtp_lookup_code ( rtp , 0 , AST_RTP_DTMF ) ;
2003-02-05 19:26:49 +00:00
/* If we have no peer, return immediately */
if ( ! rtp - > them . sin_addr . s_addr )
return 0 ;
2005-07-15 23:00:47 +00:00
rtp - > dtmfmute = ast_tvadd ( ast_tvnow ( ) , ast_tv ( 0 , 500000 ) ) ;
2003-02-05 19:26:49 +00:00
/* Get a pointer to the header */
rtpheader = ( unsigned int * ) data ;
2005-07-12 23:36:00 +00:00
rtpheader [ 0 ] = htonl ( ( 2 < < 30 ) | ( 1 < < 23 ) | ( payload < < 16 ) | ( rtp - > seqno ) ) ;
2005-04-04 02:13:40 +00:00
rtpheader [ 1 ] = htonl ( rtp - > lastdigitts ) ;
2003-02-05 19:26:49 +00:00
rtpheader [ 2 ] = htonl ( rtp - > ssrc ) ;
rtpheader [ 3 ] = htonl ( ( digit < < 24 ) | ( 0xa < < 16 ) | ( 0 ) ) ;
2006-03-15 18:15:33 +00:00
for ( x = 0 ; x < 6 ; x + + ) {
2003-02-05 19:26:49 +00:00
if ( rtp - > them . sin_port & & rtp - > them . sin_addr . s_addr ) {
2005-05-15 04:06:16 +00:00
res = sendto ( rtp - > s , ( void * ) rtpheader , hdrlen + 4 , 0 , ( struct sockaddr * ) & rtp - > them , sizeof ( rtp - > them ) ) ;
2005-04-04 02:13:40 +00:00
if ( res < 0 )
2005-05-15 04:06:16 +00:00
ast_log ( LOG_ERROR , " RTP Transmission error to %s:%d: %s \n " ,
ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , rtp - > them . sin_addr ) ,
ntohs ( rtp - > them . sin_port ) , strerror ( errno ) ) ;
if ( rtp_debug_test_addr ( & rtp - > them ) )
2005-11-08 01:44:47 +00:00
ast_verbose ( " Sent RTP packet to %s:%d (type %d, seq %u, ts %u, len %u) \n " ,
2005-05-15 04:06:16 +00:00
ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , rtp - > them . sin_addr ) ,
ntohs ( rtp - > them . sin_port ) , payload , rtp - > seqno , rtp - > lastdigitts , res - hdrlen ) ;
2003-02-05 19:26:49 +00:00
}
2006-03-15 18:15:33 +00:00
/* Sequence number of last two end packets does not get incremented */
if ( x < 3 )
rtp - > seqno + + ;
2005-07-12 23:36:00 +00:00
/* Clear marker bit and set seqno */
rtpheader [ 0 ] = htonl ( ( 2 < < 30 ) | ( payload < < 16 ) | ( rtp - > seqno ) ) ;
2006-03-15 18:15:33 +00:00
/* For the last three packets, set the duration and the end bit */
if ( x = = 2 ) {
#if 0
/* No, this is wrong... Do not increment lastdigitts, that's not according
to the RFC , as best we can determine */
rtp - > lastdigitts + + ; /* or else the SPA3000 will click instead of beeping... */
rtpheader [ 1 ] = htonl ( rtp - > lastdigitts ) ;
# endif
/* Make duration 800 (100ms) */
rtpheader [ 3 ] | = htonl ( ( 800 ) ) ;
/* Set the End bit */
rtpheader [ 3 ] | = htonl ( ( 1 < < 23 ) ) ;
2003-02-05 19:26:49 +00:00
}
}
2005-04-20 16:46:25 +00:00
/* Increment the digit timestamp by 120ms, to ensure that digits
2005-04-04 02:13:40 +00:00
sent sequentially with no intervening non - digit packets do not
2005-04-20 16:46:25 +00:00
get sent with the same timestamp , and that sequential digits
have some ' dead air ' in between them
2005-04-04 02:13:40 +00:00
*/
2006-03-15 18:15:33 +00:00
rtp - > lastdigitts + = 960 ;
/* Increment the sequence number to reflect the last packet
that was sent
*/
rtp - > seqno + + ;
2003-02-05 19:26:49 +00:00
return 0 ;
}
2005-01-07 07:11:40 +00:00
int ast_rtp_sendcng ( struct ast_rtp * rtp , int level )
{
unsigned int * rtpheader ;
int hdrlen = 12 ;
int res ;
int payload ;
char data [ 256 ] ;
char iabuf [ INET_ADDRSTRLEN ] ;
level = 127 - ( level & 0x7f ) ;
payload = ast_rtp_lookup_code ( rtp , 0 , AST_RTP_CN ) ;
/* If we have no peer, return immediately */
if ( ! rtp - > them . sin_addr . s_addr )
return 0 ;
2005-07-15 23:00:47 +00:00
rtp - > dtmfmute = ast_tvadd ( ast_tvnow ( ) , ast_tv ( 0 , 500000 ) ) ;
2005-01-07 07:11:40 +00:00
/* Get a pointer to the header */
rtpheader = ( unsigned int * ) data ;
rtpheader [ 0 ] = htonl ( ( 2 < < 30 ) | ( 1 < < 23 ) | ( payload < < 16 ) | ( rtp - > seqno + + ) ) ;
rtpheader [ 1 ] = htonl ( rtp - > lastts ) ;
rtpheader [ 2 ] = htonl ( rtp - > ssrc ) ;
data [ 12 ] = level ;
if ( rtp - > them . sin_port & & rtp - > them . sin_addr . s_addr ) {
res = sendto ( rtp - > s , ( void * ) rtpheader , hdrlen + 1 , 0 , ( struct sockaddr * ) & rtp - > them , sizeof ( rtp - > them ) ) ;
if ( res < 0 )
ast_log ( LOG_ERROR , " RTP Comfort Noise Transmission error to %s:%d: %s \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , rtp - > them . sin_addr ) , ntohs ( rtp - > them . sin_port ) , strerror ( errno ) ) ;
if ( rtp_debug_test_addr ( & rtp - > them ) )
ast_verbose ( " Sent Comfort Noise RTP packet to %s:%d (type %d, seq %d, ts %d, len %d) \n "
, ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , rtp - > them . sin_addr ) , ntohs ( rtp - > them . sin_port ) , payload , rtp - > seqno , rtp - > lastts , res - hdrlen ) ;
}
return 0 ;
}
2002-08-09 17:17:54 +00:00
static int ast_rtp_raw_write ( struct ast_rtp * rtp , struct ast_frame * f , int codec )
2002-06-16 16:06:38 +00:00
{
2004-12-14 23:36:30 +00:00
unsigned char * rtpheader ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2002-06-16 16:06:38 +00:00
int hdrlen = 12 ;
int res ;
2005-11-11 04:07:03 +00:00
unsigned int ms ;
2002-08-09 17:17:54 +00:00
int pred ;
2003-06-28 16:40:02 +00:00
int mark = 0 ;
2002-06-16 16:06:38 +00:00
2004-03-13 03:52:14 +00:00
ms = calc_txstamp ( rtp , & f - > delivery ) ;
2002-08-09 17:17:54 +00:00
/* Default prediction */
2003-06-28 16:40:02 +00:00
if ( f - > subclass < AST_FORMAT_MAX_AUDIO ) {
2005-11-11 04:07:03 +00:00
pred = rtp - > lastts + f - > samples ;
2005-05-14 23:57:44 +00:00
2003-06-28 16:40:02 +00:00
/* Re-calculate last TS */
rtp - > lastts = rtp - > lastts + ms * 8 ;
2005-07-15 23:00:47 +00:00
if ( ast_tvzero ( f - > delivery ) ) {
2004-03-14 05:31:47 +00:00
/* If this isn't an absolute delivery time, Check if it is close to our prediction,
and if so , go with our prediction */
2004-06-30 06:03:57 +00:00
if ( abs ( rtp - > lastts - pred ) < MAX_TIMESTAMP_SKEW )
2004-03-14 05:31:47 +00:00
rtp - > lastts = pred ;
2004-05-01 15:18:28 +00:00
else {
2004-12-28 16:43:20 +00:00
if ( option_debug > 2 )
ast_log ( LOG_DEBUG , " Difference is %d, ms is %d \n " , abs ( rtp - > lastts - pred ) , ms ) ;
2004-05-01 15:18:28 +00:00
mark = 1 ;
}
2004-03-14 05:31:47 +00:00
}
2003-06-28 16:40:02 +00:00
} else {
2003-06-28 18:35:58 +00:00
mark = f - > subclass & 0x1 ;
2003-06-28 16:40:02 +00:00
pred = rtp - > lastovidtimestamp + f - > samples ;
/* Re-calculate last TS */
rtp - > lastts = rtp - > lastts + ms * 90 ;
/* If it's close to our prediction, go for it */
2005-07-15 23:00:47 +00:00
if ( ast_tvzero ( f - > delivery ) ) {
2004-05-30 20:24:48 +00:00
if ( abs ( rtp - > lastts - pred ) < 7200 ) {
rtp - > lastts = pred ;
rtp - > lastovidtimestamp + = f - > samples ;
} else {
2004-12-28 16:43:20 +00:00
if ( option_debug > 2 )
ast_log ( LOG_DEBUG , " Difference is %d, ms is %d (%d), pred/ts/samples %d/%d/%d \n " , abs ( rtp - > lastts - pred ) , ms , ms * 90 , rtp - > lastts , pred , f - > samples ) ;
2004-05-30 20:24:48 +00:00
rtp - > lastovidtimestamp = rtp - > lastts ;
}
2003-06-28 16:40:02 +00:00
}
2003-06-28 18:35:58 +00:00
}
2005-04-04 02:13:40 +00:00
/* If the timestamp for non-digit packets has moved beyond the timestamp
for digits , update the digit timestamp .
*/
if ( rtp - > lastts > rtp - > lastdigitts )
rtp - > lastdigitts = rtp - > lastts ;
2003-06-28 18:35:58 +00:00
/* Get a pointer to the header */
2004-12-14 23:36:30 +00:00
rtpheader = ( unsigned char * ) ( f - > data - hdrlen ) ;
2005-03-29 04:49:24 +00:00
put_unaligned_uint32 ( rtpheader , htonl ( ( 2 < < 30 ) | ( codec < < 16 ) | ( rtp - > seqno ) | ( mark < < 23 ) ) ) ;
put_unaligned_uint32 ( rtpheader + 4 , htonl ( rtp - > lastts ) ) ;
put_unaligned_uint32 ( rtpheader + 8 , htonl ( rtp - > ssrc ) ) ;
2004-12-14 23:36:30 +00:00
2003-06-28 18:35:58 +00:00
if ( rtp - > them . sin_port & & rtp - > them . sin_addr . s_addr ) {
2003-09-08 16:48:07 +00:00
res = sendto ( rtp - > s , ( void * ) rtpheader , f - > datalen + hdrlen , 0 , ( struct sockaddr * ) & rtp - > them , sizeof ( rtp - > them ) ) ;
2005-09-07 20:33:30 +00:00
if ( res < 0 ) {
if ( ! rtp - > nat | | ( rtp - > nat & & ( ast_test_flag ( rtp , FLAG_NAT_ACTIVE ) = = FLAG_NAT_ACTIVE ) ) ) {
ast_log ( LOG_DEBUG , " RTP Transmission error of packet %d to %s:%d: %s \n " , rtp - > seqno , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , rtp - > them . sin_addr ) , ntohs ( rtp - > them . sin_port ) , strerror ( errno ) ) ;
} else if ( ( ast_test_flag ( rtp , FLAG_NAT_ACTIVE ) = = FLAG_NAT_INACTIVE ) | | rtpdebug ) {
/* Only give this error message once if we are not RTP debugging */
if ( option_debug | | rtpdebug )
ast_log ( LOG_DEBUG , " RTP NAT: Can't write RTP to private address %s:%d, waiting for other end to send audio... \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , rtp - > them . sin_addr ) , ntohs ( rtp - > them . sin_port ) ) ;
ast_set_flag ( rtp , FLAG_NAT_INACTIVE_NOWARN ) ;
}
}
2004-10-30 01:52:12 +00:00
if ( rtp_debug_test_addr ( & rtp - > them ) )
2005-11-08 01:44:47 +00:00
ast_verbose ( " Sent RTP packet to %s:%d (type %d, seq %u, ts %u, len %u) \n "
2004-10-30 01:52:12 +00:00
, ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , rtp - > them . sin_addr ) , ntohs ( rtp - > them . sin_port ) , codec , rtp - > seqno , rtp - > lastts , res - hdrlen ) ;
2002-06-16 16:06:38 +00:00
}
2005-03-24 22:00:23 +00:00
rtp - > seqno + + ;
2002-06-16 16:06:38 +00:00
return 0 ;
}
2002-08-09 17:17:54 +00:00
int ast_rtp_write ( struct ast_rtp * rtp , struct ast_frame * _f )
{
struct ast_frame * f ;
int codec ;
int hdrlen = 12 ;
2003-06-28 18:35:58 +00:00
int subclass ;
2002-08-09 17:17:54 +00:00
2003-02-05 19:26:49 +00:00
/* If we have no peer, return immediately */
if ( ! rtp - > them . sin_addr . s_addr )
return 0 ;
2003-04-08 21:53:46 +00:00
/* If there is no data length, return immediately */
if ( ! _f - > datalen )
return 0 ;
2002-08-09 17:17:54 +00:00
2003-02-05 19:26:49 +00:00
/* Make sure we have enough space for RTP header */
2003-06-28 16:40:02 +00:00
if ( ( _f - > frametype ! = AST_FRAME_VOICE ) & & ( _f - > frametype ! = AST_FRAME_VIDEO ) ) {
2002-08-09 17:17:54 +00:00
ast_log ( LOG_WARNING , " RTP can only send voice \n " ) ;
return - 1 ;
}
2003-06-28 18:35:58 +00:00
subclass = _f - > subclass ;
if ( _f - > frametype = = AST_FRAME_VIDEO )
subclass & = ~ 0x1 ;
2003-04-08 21:53:46 +00:00
2003-06-28 18:35:58 +00:00
codec = ast_rtp_lookup_code ( rtp , 1 , subclass ) ;
2002-08-09 17:17:54 +00:00
if ( codec < 0 ) {
2003-08-16 05:10:35 +00:00
ast_log ( LOG_WARNING , " Don't know how to send format %s packets with RTP \n " , ast_getformatname ( _f - > subclass ) ) ;
2002-08-09 17:17:54 +00:00
return - 1 ;
}
2003-06-28 18:35:58 +00:00
if ( rtp - > lasttxformat ! = subclass ) {
2003-02-05 19:26:49 +00:00
/* New format, reset the smoother */
2004-12-28 16:43:20 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Ooh, format changed from %s to %s \n " , ast_getformatname ( rtp - > lasttxformat ) , ast_getformatname ( subclass ) ) ;
2003-06-28 18:35:58 +00:00
rtp - > lasttxformat = subclass ;
2003-02-05 19:26:49 +00:00
if ( rtp - > smoother )
ast_smoother_free ( rtp - > smoother ) ;
rtp - > smoother = NULL ;
}
2002-08-09 17:17:54 +00:00
2003-06-28 18:35:58 +00:00
switch ( subclass ) {
2005-04-03 22:57:18 +00:00
case AST_FORMAT_SLINEAR :
if ( ! rtp - > smoother ) {
rtp - > smoother = ast_smoother_new ( 320 ) ;
}
if ( ! rtp - > smoother ) {
ast_log ( LOG_WARNING , " Unable to create smoother :( \n " ) ;
return - 1 ;
}
ast_smoother_feed_be ( rtp - > smoother , _f ) ;
while ( ( f = ast_smoother_read ( rtp - > smoother ) ) )
ast_rtp_raw_write ( rtp , f , codec ) ;
break ;
2002-08-09 17:17:54 +00:00
case AST_FORMAT_ULAW :
case AST_FORMAT_ALAW :
if ( ! rtp - > smoother ) {
rtp - > smoother = ast_smoother_new ( 160 ) ;
}
if ( ! rtp - > smoother ) {
ast_log ( LOG_WARNING , " Unable to create smoother :( \n " ) ;
return - 1 ;
}
ast_smoother_feed ( rtp - > smoother , _f ) ;
2004-02-25 04:10:32 +00:00
while ( ( f = ast_smoother_read ( rtp - > smoother ) ) )
ast_rtp_raw_write ( rtp , f , codec ) ;
break ;
2004-03-05 17:32:00 +00:00
case AST_FORMAT_ADPCM :
2004-02-25 04:10:32 +00:00
case AST_FORMAT_G726 :
if ( ! rtp - > smoother ) {
rtp - > smoother = ast_smoother_new ( 80 ) ;
}
if ( ! rtp - > smoother ) {
ast_log ( LOG_WARNING , " Unable to create smoother :( \n " ) ;
return - 1 ;
}
ast_smoother_feed ( rtp - > smoother , _f ) ;
2002-08-09 17:17:54 +00:00
while ( ( f = ast_smoother_read ( rtp - > smoother ) ) )
ast_rtp_raw_write ( rtp , f , codec ) ;
break ;
case AST_FORMAT_G729A :
if ( ! rtp - > smoother ) {
rtp - > smoother = ast_smoother_new ( 20 ) ;
2004-03-14 18:01:29 +00:00
if ( rtp - > smoother )
ast_smoother_set_flags ( rtp - > smoother , AST_SMOOTHER_FLAG_G729 ) ;
2002-08-09 17:17:54 +00:00
}
if ( ! rtp - > smoother ) {
ast_log ( LOG_WARNING , " Unable to create g729 smoother :( \n " ) ;
return - 1 ;
}
ast_smoother_feed ( rtp - > smoother , _f ) ;
while ( ( f = ast_smoother_read ( rtp - > smoother ) ) )
ast_rtp_raw_write ( rtp , f , codec ) ;
break ;
2003-02-05 19:26:49 +00:00
case AST_FORMAT_GSM :
if ( ! rtp - > smoother ) {
rtp - > smoother = ast_smoother_new ( 33 ) ;
}
if ( ! rtp - > smoother ) {
ast_log ( LOG_WARNING , " Unable to create GSM smoother :( \n " ) ;
return - 1 ;
}
ast_smoother_feed ( rtp - > smoother , _f ) ;
while ( ( f = ast_smoother_read ( rtp - > smoother ) ) )
ast_rtp_raw_write ( rtp , f , codec ) ;
break ;
2003-04-15 04:36:52 +00:00
case AST_FORMAT_ILBC :
if ( ! rtp - > smoother ) {
2003-04-17 19:19:12 +00:00
rtp - > smoother = ast_smoother_new ( 50 ) ;
2003-04-15 04:36:52 +00:00
}
if ( ! rtp - > smoother ) {
ast_log ( LOG_WARNING , " Unable to create ILBC smoother :( \n " ) ;
return - 1 ;
}
ast_smoother_feed ( rtp - > smoother , _f ) ;
while ( ( f = ast_smoother_read ( rtp - > smoother ) ) )
ast_rtp_raw_write ( rtp , f , codec ) ;
break ;
2002-08-09 17:17:54 +00:00
default :
2003-08-16 05:10:35 +00:00
ast_log ( LOG_WARNING , " Not sure about sending format %s packets \n " , ast_getformatname ( subclass ) ) ;
2004-06-29 20:10:57 +00:00
/* fall through to... */
2003-06-28 16:40:02 +00:00
case AST_FORMAT_H261 :
case AST_FORMAT_H263 :
2005-03-05 20:57:49 +00:00
case AST_FORMAT_H263_PLUS :
2006-01-07 17:54:22 +00:00
case AST_FORMAT_H264 :
2003-08-18 05:31:25 +00:00
case AST_FORMAT_G723_1 :
2004-09-15 18:40:07 +00:00
case AST_FORMAT_LPC10 :
2003-03-12 06:00:18 +00:00
case AST_FORMAT_SPEEX :
2004-06-29 20:10:57 +00:00
/* Don't buffer outgoing frames; send them one-per-packet: */
2002-08-09 17:17:54 +00:00
if ( _f - > offset < hdrlen ) {
f = ast_frdup ( _f ) ;
} else {
f = _f ;
}
ast_rtp_raw_write ( rtp , f , codec ) ;
}
return 0 ;
}
2003-02-16 06:00:12 +00:00
2006-01-03 09:30:19 +00:00
/*! \brief Unregister interface to channel driver */
2003-02-16 06:00:12 +00:00
void ast_rtp_proto_unregister ( struct ast_rtp_protocol * proto )
{
2006-01-03 09:30:19 +00:00
AST_LIST_LOCK ( & protos ) ;
2006-01-03 17:08:35 +00:00
AST_LIST_REMOVE ( & protos , proto , list ) ;
2006-01-03 09:30:19 +00:00
AST_LIST_UNLOCK ( & protos ) ;
2003-02-16 06:00:12 +00:00
}
2006-01-03 09:30:19 +00:00
/*! \brief Register interface to channel driver */
2003-02-16 06:00:12 +00:00
int ast_rtp_proto_register ( struct ast_rtp_protocol * proto )
{
struct ast_rtp_protocol * cur ;
2006-01-03 09:30:19 +00:00
AST_LIST_LOCK ( & protos ) ;
AST_LIST_TRAVERSE ( & protos , cur , list ) {
2006-01-03 17:08:35 +00:00
if ( ! strcmp ( cur - > type , proto - > type ) ) {
2003-02-16 06:00:12 +00:00
ast_log ( LOG_WARNING , " Tried to register same protocol '%s' twice \n " , cur - > type ) ;
2006-01-03 09:30:19 +00:00
AST_LIST_UNLOCK ( & protos ) ;
2003-02-16 06:00:12 +00:00
return - 1 ;
}
}
2006-01-03 09:30:19 +00:00
AST_LIST_INSERT_HEAD ( & protos , proto , list ) ;
AST_LIST_UNLOCK ( & protos ) ;
2003-02-16 06:00:12 +00:00
return 0 ;
}
2006-01-03 09:30:19 +00:00
/*! \brief Bridge calls. If possible and allowed, initiate
2005-05-16 13:22:34 +00:00
re - invite so the peers exchange media directly outside
of Asterisk . */
2005-10-13 18:27:54 +00:00
enum ast_bridge_result ast_rtp_bridge ( struct ast_channel * c0 , struct ast_channel * c1 , int flags , struct ast_frame * * fo , struct ast_channel * * rc , int timeoutms )
2003-02-16 06:00:12 +00:00
{
struct ast_frame * f ;
struct ast_channel * who , * cs [ 3 ] ;
2005-08-03 05:00:42 +00:00
struct ast_rtp * p0 , * p1 ; /* Audio RTP Channels */
struct ast_rtp * vp0 , * vp1 ; /* Video RTP channels */
2003-02-16 06:00:12 +00:00
struct ast_rtp_protocol * pr0 , * pr1 ;
2003-04-14 20:48:30 +00:00
struct sockaddr_in ac0 , ac1 ;
2003-06-28 16:40:02 +00:00
struct sockaddr_in vac0 , vac1 ;
2003-04-14 20:48:30 +00:00
struct sockaddr_in t0 , t1 ;
2003-06-28 16:40:02 +00:00
struct sockaddr_in vt0 , vt1 ;
2004-06-30 16:56:51 +00:00
char iabuf [ INET_ADDRSTRLEN ] ;
2003-04-14 20:48:30 +00:00
2003-02-16 06:00:12 +00:00
void * pvt0 , * pvt1 ;
2004-05-27 04:18:46 +00:00
int codec0 , codec1 , oldcodec0 , oldcodec1 ;
2003-06-28 16:40:02 +00:00
memset ( & vt0 , 0 , sizeof ( vt0 ) ) ;
memset ( & vt1 , 0 , sizeof ( vt1 ) ) ;
memset ( & vac0 , 0 , sizeof ( vac0 ) ) ;
memset ( & vac1 , 0 , sizeof ( vac1 ) ) ;
2003-02-16 06:00:12 +00:00
/* if need DTMF, cant native bridge */
if ( flags & ( AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1 ) )
2005-08-09 01:59:59 +00:00
return AST_BRIDGE_FAILED_NOWARN ;
2005-08-03 05:00:42 +00:00
/* Lock channels */
2003-08-13 15:25:16 +00:00
ast_mutex_lock ( & c0 - > lock ) ;
2004-08-31 21:55:19 +00:00
while ( ast_mutex_trylock ( & c1 - > lock ) ) {
ast_mutex_unlock ( & c0 - > lock ) ;
usleep ( 1 ) ;
ast_mutex_lock ( & c0 - > lock ) ;
}
2005-08-03 05:00:42 +00:00
/* Find channel driver interfaces */
2003-02-16 06:00:12 +00:00
pr0 = get_proto ( c0 ) ;
pr1 = get_proto ( c1 ) ;
if ( ! pr0 ) {
ast_log ( LOG_WARNING , " Can't find native functions for channel '%s' \n " , c0 - > name ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & c0 - > lock ) ;
ast_mutex_unlock ( & c1 - > lock ) ;
2005-08-09 01:59:59 +00:00
return AST_BRIDGE_FAILED ;
2003-02-16 06:00:12 +00:00
}
if ( ! pr1 ) {
ast_log ( LOG_WARNING , " Can't find native functions for channel '%s' \n " , c1 - > name ) ;
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & c0 - > lock ) ;
ast_mutex_unlock ( & c1 - > lock ) ;
2005-08-09 01:59:59 +00:00
return AST_BRIDGE_FAILED ;
2003-02-16 06:00:12 +00:00
}
2005-08-03 05:00:42 +00:00
/* Get channel specific interface structures */
2005-03-04 06:47:24 +00:00
pvt0 = c0 - > tech_pvt ;
pvt1 = c1 - > tech_pvt ;
2005-08-03 05:00:42 +00:00
/* Get audio and video interface (if native bridge is possible) */
2003-02-16 06:00:12 +00:00
p0 = pr0 - > get_rtp_info ( c0 ) ;
2003-06-28 16:40:02 +00:00
if ( pr0 - > get_vrtp_info )
vp0 = pr0 - > get_vrtp_info ( c0 ) ;
else
vp0 = NULL ;
2003-02-16 06:00:12 +00:00
p1 = pr1 - > get_rtp_info ( c1 ) ;
2003-06-28 16:40:02 +00:00
if ( pr1 - > get_vrtp_info )
vp1 = pr1 - > get_vrtp_info ( c1 ) ;
else
vp1 = NULL ;
2005-08-03 05:00:42 +00:00
/* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
2003-02-16 06:00:12 +00:00
if ( ! p0 | | ! p1 ) {
/* Somebody doesn't want to play... */
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & c0 - > lock ) ;
ast_mutex_unlock ( & c1 - > lock ) ;
2005-08-09 01:59:59 +00:00
return AST_BRIDGE_FAILED_NOWARN ;
2003-02-16 06:00:12 +00:00
}
2005-08-03 05:00:42 +00:00
/* Get codecs from both sides */
2004-05-27 04:18:46 +00:00
if ( pr0 - > get_codec )
2003-11-15 00:53:33 +00:00
codec0 = pr0 - > get_codec ( c0 ) ;
2004-05-27 04:18:46 +00:00
else
codec0 = 0 ;
if ( pr1 - > get_codec )
2003-11-15 00:53:33 +00:00
codec1 = pr1 - > get_codec ( c1 ) ;
2004-05-27 04:18:46 +00:00
else
codec1 = 0 ;
if ( pr0 - > get_codec & & pr1 - > get_codec ) {
2005-05-16 13:22:34 +00:00
/* Hey, we can't do reinvite if both parties speak different codecs */
2004-02-18 21:38:46 +00:00
if ( ! ( codec0 & codec1 ) ) {
2005-05-16 13:22:34 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Channel codec0 = %d is not codec1 = %d, cannot native bridge in RTP. \n " , codec0 , codec1 ) ;
2003-11-25 16:26:15 +00:00
ast_mutex_unlock ( & c0 - > lock ) ;
ast_mutex_unlock ( & c1 - > lock ) ;
2005-08-09 01:59:59 +00:00
return AST_BRIDGE_FAILED_NOWARN ;
2003-11-25 16:26:15 +00:00
}
2003-11-15 00:53:33 +00:00
}
2005-08-03 05:00:42 +00:00
2006-01-17 05:15:33 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Native bridging %s and %s \n " , c0 - > name , c1 - > name ) ;
2005-05-16 13:22:34 +00:00
/* Ok, we should be able to redirect the media. Start with one channel */
2005-09-09 19:54:34 +00:00
if ( pr0 - > set_rtp_peer ( c0 , p1 , vp1 , codec1 , ast_test_flag ( p1 , FLAG_NAT_ACTIVE ) ) )
2003-02-16 06:00:12 +00:00
ast_log ( LOG_WARNING , " Channel '%s' failed to talk to '%s' \n " , c0 - > name , c1 - > name ) ;
2003-04-14 20:48:30 +00:00
else {
/* Store RTP peer */
ast_rtp_get_peer ( p1 , & ac1 ) ;
2003-06-28 16:40:02 +00:00
if ( vp1 )
2004-05-28 00:52:45 +00:00
ast_rtp_get_peer ( vp1 , & vac1 ) ;
2003-04-14 20:48:30 +00:00
}
2005-05-16 13:22:34 +00:00
/* Then test the other channel */
2005-09-09 19:54:34 +00:00
if ( pr1 - > set_rtp_peer ( c1 , p0 , vp0 , codec0 , ast_test_flag ( p0 , FLAG_NAT_ACTIVE ) ) )
2003-02-16 06:00:12 +00:00
ast_log ( LOG_WARNING , " Channel '%s' failed to talk back to '%s' \n " , c1 - > name , c0 - > name ) ;
2003-04-14 20:48:30 +00:00
else {
/* Store RTP peer */
ast_rtp_get_peer ( p0 , & ac0 ) ;
2003-06-28 16:40:02 +00:00
if ( vp0 )
2004-05-28 00:52:45 +00:00
ast_rtp_get_peer ( vp0 , & vac0 ) ;
2003-04-14 20:48:30 +00:00
}
2003-08-13 15:25:16 +00:00
ast_mutex_unlock ( & c0 - > lock ) ;
ast_mutex_unlock ( & c1 - > lock ) ;
2005-08-03 05:00:42 +00:00
/* External RTP Bridge up, now loop and see if something happes that force us to take the
media back to Asterisk */
2003-02-16 06:00:12 +00:00
cs [ 0 ] = c0 ;
cs [ 1 ] = c1 ;
cs [ 2 ] = NULL ;
2004-05-27 04:18:46 +00:00
oldcodec0 = codec0 ;
oldcodec1 = codec1 ;
2003-02-16 06:00:12 +00:00
for ( ; ; ) {
2005-08-03 05:00:42 +00:00
/* Check if something changed... */
2005-03-04 06:47:24 +00:00
if ( ( c0 - > tech_pvt ! = pvt0 ) | |
( c1 - > tech_pvt ! = pvt1 ) | |
2003-02-16 06:00:12 +00:00
( c0 - > masq | | c0 - > masqr | | c1 - > masq | | c1 - > masqr ) ) {
2005-02-15 15:57:52 +00:00
ast_log ( LOG_DEBUG , " Oooh, something is weird, backing out \n " ) ;
2005-03-04 06:47:24 +00:00
if ( c0 - > tech_pvt = = pvt0 ) {
2005-09-09 19:54:34 +00:00
if ( pr0 - > set_rtp_peer ( c0 , NULL , NULL , 0 , 0 ) )
2005-08-03 05:00:42 +00:00
ast_log ( LOG_WARNING , " Channel '%s' failed to break RTP bridge \n " , c0 - > name ) ;
2003-02-16 06:00:12 +00:00
}
2005-03-04 06:47:24 +00:00
if ( c1 - > tech_pvt = = pvt1 ) {
2005-09-09 19:54:34 +00:00
if ( pr1 - > set_rtp_peer ( c1 , NULL , NULL , 0 , 0 ) )
2005-08-03 05:00:42 +00:00
ast_log ( LOG_WARNING , " Channel '%s' failed to break RTP bridge \n " , c1 - > name ) ;
2003-02-16 06:00:12 +00:00
}
2005-08-09 01:59:59 +00:00
return AST_BRIDGE_RETRY ;
2003-02-16 06:00:12 +00:00
}
2005-08-03 05:00:42 +00:00
/* Now check if they have changed address */
2003-04-14 20:48:30 +00:00
ast_rtp_get_peer ( p1 , & t1 ) ;
2003-07-11 21:51:06 +00:00
ast_rtp_get_peer ( p0 , & t0 ) ;
2004-05-27 04:18:46 +00:00
if ( pr0 - > get_codec )
codec0 = pr0 - > get_codec ( c0 ) ;
if ( pr1 - > get_codec )
codec1 = pr1 - > get_codec ( c1 ) ;
2003-06-28 16:40:02 +00:00
if ( vp1 )
ast_rtp_get_peer ( vp1 , & vt1 ) ;
if ( vp0 )
ast_rtp_get_peer ( vp0 , & vt0 ) ;
2004-05-27 04:18:46 +00:00
if ( inaddrcmp ( & t1 , & ac1 ) | | ( vp1 & & inaddrcmp ( & vt1 , & vac1 ) ) | | ( codec1 ! = oldcodec1 ) ) {
2005-08-03 05:00:42 +00:00
if ( option_debug > 1 ) {
2004-12-28 16:43:20 +00:00
ast_log ( LOG_DEBUG , " Oooh, '%s' changed end address to %s:%d (format %d) \n " ,
c1 - > name , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , t1 . sin_addr ) , ntohs ( t1 . sin_port ) , codec1 ) ;
ast_log ( LOG_DEBUG , " Oooh, '%s' changed end vaddress to %s:%d (format %d) \n " ,
c1 - > name , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , vt1 . sin_addr ) , ntohs ( vt1 . sin_port ) , codec1 ) ;
ast_log ( LOG_DEBUG , " Oooh, '%s' was %s:%d/(format %d) \n " ,
c1 - > name , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , ac1 . sin_addr ) , ntohs ( ac1 . sin_port ) , oldcodec1 ) ;
2005-09-09 19:54:34 +00:00
ast_log ( LOG_DEBUG , " Oooh, '%s' was %s:%d/(format %d) \n " ,
2004-12-28 16:43:20 +00:00
c1 - > name , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , vac1 . sin_addr ) , ntohs ( vac1 . sin_port ) , oldcodec1 ) ;
}
2005-09-09 19:54:34 +00:00
if ( pr0 - > set_rtp_peer ( c0 , t1 . sin_addr . s_addr ? p1 : NULL , vt1 . sin_addr . s_addr ? vp1 : NULL , codec1 , ast_test_flag ( p1 , FLAG_NAT_ACTIVE ) ) )
2003-04-14 20:48:30 +00:00
ast_log ( LOG_WARNING , " Channel '%s' failed to update to '%s' \n " , c0 - > name , c1 - > name ) ;
memcpy ( & ac1 , & t1 , sizeof ( ac1 ) ) ;
2003-06-28 16:40:02 +00:00
memcpy ( & vac1 , & vt1 , sizeof ( vac1 ) ) ;
2004-05-27 04:18:46 +00:00
oldcodec1 = codec1 ;
2003-04-14 20:48:30 +00:00
}
2003-06-28 16:40:02 +00:00
if ( inaddrcmp ( & t0 , & ac0 ) | | ( vp0 & & inaddrcmp ( & vt0 , & vac0 ) ) ) {
2004-12-28 16:43:20 +00:00
if ( option_debug ) {
ast_log ( LOG_DEBUG , " Oooh, '%s' changed end address to %s:%d (format %d) \n " ,
c0 - > name , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , t0 . sin_addr ) , ntohs ( t0 . sin_port ) , codec0 ) ;
ast_log ( LOG_DEBUG , " Oooh, '%s' was %s:%d/(format %d) \n " ,
c0 - > name , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , ac0 . sin_addr ) , ntohs ( ac0 . sin_port ) , oldcodec0 ) ;
}
2005-09-09 19:54:34 +00:00
if ( pr1 - > set_rtp_peer ( c1 , t0 . sin_addr . s_addr ? p0 : NULL , vt0 . sin_addr . s_addr ? vp0 : NULL , codec0 , ast_test_flag ( p0 , FLAG_NAT_ACTIVE ) ) )
2003-04-14 20:48:30 +00:00
ast_log ( LOG_WARNING , " Channel '%s' failed to update to '%s' \n " , c1 - > name , c0 - > name ) ;
memcpy ( & ac0 , & t0 , sizeof ( ac0 ) ) ;
2003-06-28 16:40:02 +00:00
memcpy ( & vac0 , & vt0 , sizeof ( vac0 ) ) ;
2004-05-27 04:18:46 +00:00
oldcodec0 = codec0 ;
2003-04-14 20:48:30 +00:00
}
2005-10-13 18:27:54 +00:00
who = ast_waitfor_n ( cs , 2 , & timeoutms ) ;
2003-02-16 06:00:12 +00:00
if ( ! who ) {
2005-10-14 17:02:20 +00:00
if ( ! timeoutms )
return AST_BRIDGE_RETRY ;
2004-12-28 16:43:20 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Ooh, empty read... \n " ) ;
2005-05-16 13:22:34 +00:00
/* check for hangup / whentohangup */
2003-11-18 00:45:04 +00:00
if ( ast_check_hangup ( c0 ) | | ast_check_hangup ( c1 ) )
break ;
2003-02-16 06:00:12 +00:00
continue ;
}
f = ast_read ( who ) ;
if ( ! f | | ( ( f - > frametype = = AST_FRAME_DTMF ) & &
( ( ( who = = c0 ) & & ( flags & AST_BRIDGE_DTMF_CHANNEL_0 ) ) | |
( ( who = = c1 ) & & ( flags & AST_BRIDGE_DTMF_CHANNEL_1 ) ) ) ) ) {
* fo = f ;
* rc = who ;
2004-12-28 16:43:20 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Oooh, got a %s \n " , f ? " digit " : " hangup " ) ;
2005-12-20 17:52:31 +00:00
if ( ( c0 - > tech_pvt = = pvt0 ) ) {
2005-09-09 19:54:34 +00:00
if ( pr0 - > set_rtp_peer ( c0 , NULL , NULL , 0 , 0 ) )
2005-08-03 05:00:42 +00:00
ast_log ( LOG_WARNING , " Channel '%s' failed to break RTP bridge \n " , c0 - > name ) ;
2003-02-16 06:00:12 +00:00
}
2005-12-20 17:52:31 +00:00
if ( ( c1 - > tech_pvt = = pvt1 ) ) {
2005-09-09 19:54:34 +00:00
if ( pr1 - > set_rtp_peer ( c1 , NULL , NULL , 0 , 0 ) )
2005-08-03 05:00:42 +00:00
ast_log ( LOG_WARNING , " Channel '%s' failed to break RTP bridge \n " , c1 - > name ) ;
2003-02-16 06:00:12 +00:00
}
2005-08-09 01:59:59 +00:00
return AST_BRIDGE_COMPLETE ;
2005-08-30 02:12:09 +00:00
} else if ( ( f - > frametype = = AST_FRAME_CONTROL ) & & ! ( flags & AST_BRIDGE_IGNORE_SIGS ) ) {
if ( ( f - > subclass = = AST_CONTROL_HOLD ) | | ( f - > subclass = = AST_CONTROL_UNHOLD ) | |
( f - > subclass = = AST_CONTROL_VIDUPDATE ) ) {
ast_indicate ( who = = c0 ? c1 : c0 , f - > subclass ) ;
ast_frfree ( f ) ;
} else {
* fo = f ;
* rc = who ;
ast_log ( LOG_DEBUG , " Got a FRAME_CONTROL (%d) frame on channel %s \n " , f - > subclass , who - > name ) ;
return AST_BRIDGE_COMPLETE ;
}
2003-03-15 06:00:16 +00:00
} else {
2003-06-28 22:50:47 +00:00
if ( ( f - > frametype = = AST_FRAME_DTMF ) | |
( f - > frametype = = AST_FRAME_VOICE ) | |
( f - > frametype = = AST_FRAME_VIDEO ) ) {
2003-03-15 06:00:16 +00:00
/* Forward voice or DTMF frames if they happen upon us */
if ( who = = c0 ) {
ast_write ( c1 , f ) ;
} else if ( who = = c1 ) {
ast_write ( c0 , f ) ;
}
}
2003-02-16 06:00:12 +00:00
ast_frfree ( f ) ;
2003-03-15 06:00:16 +00:00
}
2003-02-16 06:00:12 +00:00
/* Swap priority not that it's a big deal at this point */
cs [ 2 ] = cs [ 0 ] ;
cs [ 0 ] = cs [ 1 ] ;
cs [ 1 ] = cs [ 2 ] ;
}
2005-08-09 01:59:59 +00:00
return AST_BRIDGE_FAILED ;
2003-02-16 06:00:12 +00:00
}
2003-05-16 02:50:46 +00:00
2004-10-30 01:52:12 +00:00
static int rtp_do_debug_ip ( int fd , int argc , char * argv [ ] )
{
struct hostent * hp ;
struct ast_hostent ahp ;
char iabuf [ INET_ADDRSTRLEN ] ;
int port = 0 ;
char * p , * arg ;
2004-12-28 16:43:20 +00:00
2004-10-30 01:52:12 +00:00
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
arg = argv [ 3 ] ;
p = strstr ( arg , " : " ) ;
2004-12-28 16:43:20 +00:00
if ( p ) {
2004-10-30 01:52:12 +00:00
* p = ' \0 ' ;
p + + ;
port = atoi ( p ) ;
}
hp = ast_gethostbyname ( arg , & ahp ) ;
if ( hp = = NULL )
return RESULT_SHOWUSAGE ;
rtpdebugaddr . sin_family = AF_INET ;
memcpy ( & rtpdebugaddr . sin_addr , hp - > h_addr , sizeof ( rtpdebugaddr . sin_addr ) ) ;
rtpdebugaddr . sin_port = htons ( port ) ;
if ( port = = 0 )
ast_cli ( fd , " RTP Debugging Enabled for IP: %s \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , rtpdebugaddr . sin_addr ) ) ;
else
ast_cli ( fd , " RTP Debugging Enabled for IP: %s:%d \n " , ast_inet_ntoa ( iabuf , sizeof ( iabuf ) , rtpdebugaddr . sin_addr ) , port ) ;
rtpdebug = 1 ;
return RESULT_SUCCESS ;
}
static int rtp_do_debug ( int fd , int argc , char * argv [ ] )
{
2005-08-03 05:00:42 +00:00
if ( argc ! = 2 ) {
2004-10-30 01:52:12 +00:00
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
return rtp_do_debug_ip ( fd , argc , argv ) ;
}
rtpdebug = 1 ;
memset ( & rtpdebugaddr , 0 , sizeof ( rtpdebugaddr ) ) ;
ast_cli ( fd , " RTP Debugging Enabled \n " ) ;
return RESULT_SUCCESS ;
}
static int rtp_no_debug ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 3 )
return RESULT_SHOWUSAGE ;
rtpdebug = 0 ;
ast_cli ( fd , " RTP Debugging Disabled \n " ) ;
return RESULT_SUCCESS ;
}
static char debug_usage [ ] =
" Usage: rtp debug [ip host[:port]] \n "
" Enable dumping of all RTP packets to and from host. \n " ;
2004-12-28 16:43:20 +00:00
2004-10-30 01:52:12 +00:00
static char no_debug_usage [ ] =
" Usage: rtp no debug \n "
" Disable all RTP debugging \n " ;
static struct ast_cli_entry cli_debug_ip =
{ { " rtp " , " debug " , " ip " , NULL } , rtp_do_debug , " Enable RTP debugging on IP " , debug_usage } ;
static struct ast_cli_entry cli_debug =
{ { " rtp " , " debug " , NULL } , rtp_do_debug , " Enable RTP debugging " , debug_usage } ;
static struct ast_cli_entry cli_no_debug =
{ { " rtp " , " no " , " debug " , NULL } , rtp_no_debug , " Disable RTP debugging " , no_debug_usage } ;
2006-02-14 23:08:06 +00:00
int ast_rtp_reload ( void )
2003-05-16 02:50:46 +00:00
{
struct ast_config * cfg ;
char * s ;
2004-12-28 16:43:20 +00:00
2003-05-16 02:50:46 +00:00
rtpstart = 5000 ;
rtpend = 31000 ;
2005-11-01 00:06:43 +00:00
dtmftimeout = DEFAULT_DTMF_TIMEOUT ;
2005-01-25 06:10:20 +00:00
cfg = ast_config_load ( " rtp.conf " ) ;
2003-05-16 02:50:46 +00:00
if ( cfg ) {
if ( ( s = ast_variable_retrieve ( cfg , " general " , " rtpstart " ) ) ) {
rtpstart = atoi ( s ) ;
if ( rtpstart < 1024 )
rtpstart = 1024 ;
if ( rtpstart > 65535 )
rtpstart = 65535 ;
}
if ( ( s = ast_variable_retrieve ( cfg , " general " , " rtpend " ) ) ) {
rtpend = atoi ( s ) ;
if ( rtpend < 1024 )
rtpend = 1024 ;
if ( rtpend > 65535 )
rtpend = 65535 ;
}
2004-07-17 21:08:12 +00:00
if ( ( s = ast_variable_retrieve ( cfg , " general " , " rtpchecksums " ) ) ) {
2004-07-19 18:09:33 +00:00
# ifdef SO_NO_CHECK
2005-03-31 19:09:48 +00:00
if ( ast_false ( s ) )
nochecksums = 1 ;
2004-07-17 21:08:12 +00:00
else
2005-03-31 19:09:48 +00:00
nochecksums = 0 ;
2004-07-19 18:09:33 +00:00
# else
2005-03-31 19:09:48 +00:00
if ( ast_false ( s ) )
2004-07-19 18:09:33 +00:00
ast_log ( LOG_WARNING , " Disabling RTP checksums is not supported on this operating system! \n " ) ;
# endif
2004-07-17 21:08:12 +00:00
}
2005-11-01 00:06:43 +00:00
if ( ( s = ast_variable_retrieve ( cfg , " general " , " dtmftimeout " ) ) ) {
dtmftimeout = atoi ( s ) ;
if ( ( dtmftimeout < 0 ) | | ( dtmftimeout > 20000 ) ) {
ast_log ( LOG_WARNING , " DTMF timeout of '%d' outside range, using default of '%d' instead \n " ,
dtmftimeout , DEFAULT_DTMF_TIMEOUT ) ;
dtmftimeout = DEFAULT_DTMF_TIMEOUT ;
} ;
}
2005-01-25 06:10:20 +00:00
ast_config_destroy ( cfg ) ;
2003-05-16 02:50:46 +00:00
}
if ( rtpstart > = rtpend ) {
2005-05-16 13:22:34 +00:00
ast_log ( LOG_WARNING , " Unreasonable values for RTP start/end port in rtp.conf \n " ) ;
2003-05-16 02:50:46 +00:00
rtpstart = 5000 ;
rtpend = 31000 ;
}
if ( option_verbose > 1 )
ast_verbose ( VERBOSE_PREFIX_2 " RTP Allocating from port range %d -> %d \n " , rtpstart , rtpend ) ;
2006-02-14 23:08:06 +00:00
return 0 ;
2003-05-16 02:50:46 +00:00
}
2006-01-03 09:30:19 +00:00
/*! \brief Initialize the RTP system in Asterisk */
2003-05-16 02:50:46 +00:00
void ast_rtp_init ( void )
{
2004-10-30 01:52:12 +00:00
ast_cli_register ( & cli_debug ) ;
ast_cli_register ( & cli_debug_ip ) ;
ast_cli_register ( & cli_no_debug ) ;
2003-05-16 02:50:46 +00:00
ast_rtp_reload ( ) ;
}