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
*
2006-05-02 20:31:39 +00:00
* \ note RTP is defined in RFC 3550.
2002-06-16 16:06:38 +00:00
*/
2006-06-07 18:54:56 +00:00
# include "asterisk.h"
ASTERISK_FILE_VERSION ( __FILE__ , " $Revision$ " )
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-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
2006-06-05 08:39:42 +00:00
# define RTP_SEQ_MOD (1<<16) /*!< A sequence number can't be more than 16 bits */
# define RTCP_DEFAULT_INTERVALMS 5000 /*!< Default milli-seconds between RTCP reports we send */
# define RTCP_MIN_INTERVALMS 500 /*!< Min milli-seconds between RTCP reports we send */
# define RTCP_MAX_INTERVALMS 60000 /*!< Max milli-seconds between RTCP reports we send */
# define RTCP_PT_FUR 192
# define RTCP_PT_SR 200
# define RTCP_PT_RR 201
# define RTCP_PT_SDES 202
# define RTCP_PT_BYE 203
# define RTCP_PT_APP 204
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? */
2006-06-05 08:39:42 +00:00
static int rtcpdebug = 0 ; /*!< Are we debugging RTCP? */
static int rtcpstats = 0 ; /*!< Are we debugging RTCP? */
static int rtcpinterval = RTCP_DEFAULT_INTERVALMS ; /*!< Time between rtcp reports in millisecs */
2006-05-11 14:56:52 +00:00
static int stundebug = 0 ; /*!< Are we debugging stun? */
2006-01-03 09:30:19 +00:00
static struct sockaddr_in rtpdebugaddr ; /*!< Debug packets to/from this host */
2006-06-05 08:39:42 +00:00
static struct sockaddr_in rtcpdebugaddr ; /*!< Debug RTCP 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-06-09 20:13:47 +00:00
/*!
* \ brief Structure representing a RTP session .
*
* RTP session is defined on page 9 of RFC 3550 : " An association among a set of participants communicating with RTP. A participant may be involved in multiple RTP sessions at the same time [...] "
*
*/
/*! \brief The value of each payload format mapping: */
struct rtpPayloadType {
int isAstFormat ; /*!< whether the following code is an AST_FORMAT */
int code ;
} ;
2006-06-08 23:10:45 +00:00
/*! \brief RTP session description */
struct ast_rtp {
int s ;
char resp ;
struct ast_frame f ;
unsigned char rawdata [ 8192 + AST_FRIENDLY_OFFSET ] ;
unsigned int ssrc ; /*!< Synchronization source, RFC 3550, page 10. */
unsigned int themssrc ; /*!< Their SSRC */
unsigned int rxssrc ;
unsigned int lastts ;
unsigned int lastdigitts ;
unsigned int lastrxts ;
unsigned int lastividtimestamp ;
unsigned int lastovidtimestamp ;
unsigned int lasteventseqn ;
int lastrxseqno ; /*!< Last received sequence number */
unsigned short seedrxseqno ; /*!< What sequence number did they start with?*/
unsigned int seedrxts ; /*!< What RTP timestamp did they start with? */
unsigned int rxcount ; /*!< How many packets have we received? */
unsigned int rxoctetcount ; /*!< How many octets have we received? should be rxcount *160*/
unsigned int txcount ; /*!< How many packets have we sent? */
unsigned int txoctetcount ; /*!< How many octets have we sent? (txcount*160)*/
unsigned int cycles ; /*!< Shifted count of sequence number cycles */
double rxjitter ; /*!< Interarrival jitter at the moment */
double rxtransit ; /*!< Relative transit time for previous packet */
unsigned int lasteventendseqn ;
int lasttxformat ;
int lastrxformat ;
int dtmfcount ;
unsigned int dtmfduration ;
int nat ;
unsigned int flags ;
struct sockaddr_in us ; /*!< Socket representation of the local endpoint. */
struct sockaddr_in them ; /*!< Socket representation of the remote endpoint. */
struct timeval rxcore ;
struct timeval txcore ;
double drxcore ; /*!< The double representation of the first received packet */
struct timeval lastrx ; /*!< timeval when we last received a packet */
struct timeval dtmfmute ;
struct ast_smoother * smoother ;
int * ioid ;
unsigned short seqno ; /*!< Sequence number, RFC 3550, page 13. */
unsigned short rxseqno ;
struct sched_context * sched ;
struct io_context * io ;
void * data ;
ast_rtp_callback callback ;
struct rtpPayloadType current_RTP_PT [ MAX_RTP_PT ] ;
int rtp_lookup_code_cache_isAstFormat ; /*!< a cache for the result of rtp_lookup_code(): */
int rtp_lookup_code_cache_code ;
int rtp_lookup_code_cache_result ;
struct ast_rtcp * rtcp ;
} ;
2006-06-05 08:39:42 +00:00
/* Forward declarations */
static int ast_rtcp_write ( void * data ) ;
static void timeval2ntp ( struct timeval tv , unsigned int * msw , unsigned int * lsw ) ;
static int ast_rtcp_write_sr ( void * data ) ;
static int ast_rtcp_write_rr ( void * data ) ;
static unsigned int ast_rtcp_calc_interval ( struct ast_rtp * rtp ) ;
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)
2006-05-16 22:11:02 +00:00
# define FLAG_HAS_DTMF (1 << 3)
2004-04-20 19:23:08 +00:00
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. */
2006-06-05 08:39:42 +00:00
unsigned int soc ; /*!< What they told us */
unsigned int spc ; /*!< What they told us */
unsigned int themrxlsr ; /*!< The middle 32 bits of the NTP timestamp in the last received SR*/
struct timeval rxlsr ; /*!< Time when we got their last SR */
struct timeval txlsr ; /*!< Time when we sent or last SR*/
unsigned int expected_prior ; /*!< no. packets in previous interval */
unsigned int received_prior ; /*!< no. packets received in previous interval */
int schedid ; /*!< Schedid returned from ast_sched_add() to schedule RTCP-transmissions*/
unsigned int rr_count ; /*!< number of RRs we've sent, not including report blocks in SR's */
unsigned int sr_count ; /*!< number of SRs we've sent */
unsigned int lastsrtxcount ; /*!< Transmit packet count when last SR sent */
double accumulated_transit ; /*!< accumulated a-dlsr-lsr */
double rtt ; /*!< Last reported rtt */
unsigned int reported_jitter ; /*!< The contents of their last jitter entry in the RR */
unsigned int reported_lost ; /*!< Reported lost packets in their RR */
char quality [ AST_MAX_USER_FIELD ] ;
double maxrxjitter ;
double minrxjitter ;
double maxrtt ;
double minrtt ;
int sendfur ;
2002-06-16 16:06:38 +00:00
} ;
2006-05-11 14:56:52 +00:00
typedef struct { unsigned int id [ 4 ] ; } __attribute__ ( ( packed ) ) stun_trans_id ;
/* XXX Maybe stun belongs in another file if it ever has use outside of RTP */
struct stun_header {
unsigned short msgtype ;
unsigned short msglen ;
stun_trans_id id ;
unsigned char ies [ 0 ] ;
} __attribute__ ( ( packed ) ) ;
struct stun_attr {
unsigned short attr ;
unsigned short len ;
unsigned char value [ 0 ] ;
} __attribute__ ( ( packed ) ) ;
struct stun_addr {
unsigned char unused ;
unsigned char family ;
unsigned short port ;
unsigned int addr ;
} __attribute__ ( ( packed ) ) ;
# define STUN_IGNORE (0)
# define STUN_ACCEPT (1)
# define STUN_BINDREQ 0x0001
# define STUN_BINDRESP 0x0101
# define STUN_BINDERR 0x0111
2006-05-16 12:42:59 +00:00
# define STUN_SECREQ 0x0002
2006-05-11 14:56:52 +00:00
# define STUN_SECRESP 0x0102
2006-05-16 12:42:59 +00:00
# define STUN_SECERR 0x0112
2006-05-11 14:56:52 +00:00
2006-05-16 12:42:59 +00:00
# define STUN_MAPPED_ADDRESS 0x0001
2006-05-11 14:56:52 +00:00
# define STUN_RESPONSE_ADDRESS 0x0002
2006-05-16 12:42:59 +00:00
# define STUN_CHANGE_REQUEST 0x0003
# define STUN_SOURCE_ADDRESS 0x0004
2006-05-11 14:56:52 +00:00
# define STUN_CHANGED_ADDRESS 0x0005
2006-05-16 12:42:59 +00:00
# define STUN_USERNAME 0x0006
# define STUN_PASSWORD 0x0007
2006-05-11 14:56:52 +00:00
# define STUN_MESSAGE_INTEGRITY 0x0008
2006-05-16 12:42:59 +00:00
# define STUN_ERROR_CODE 0x0009
2006-05-11 14:56:52 +00:00
# define STUN_UNKNOWN_ATTRIBUTES 0x000a
2006-05-16 12:42:59 +00:00
# define STUN_REFLECTED_FROM 0x000b
2006-05-11 14:56:52 +00:00
static const char * stun_msg2str ( int msg )
{
switch ( msg ) {
case STUN_BINDREQ :
return " Binding Request " ;
case STUN_BINDRESP :
return " Binding Response " ;
case STUN_BINDERR :
return " Binding Error Response " ;
case STUN_SECREQ :
return " Shared Secret Request " ;
case STUN_SECRESP :
return " Shared Secret Response " ;
case STUN_SECERR :
return " Shared Secret Error Response " ;
}
return " Non-RFC3489 Message " ;
}
static const char * stun_attr2str ( int msg )
{
switch ( msg ) {
case STUN_MAPPED_ADDRESS :
return " Mapped Address " ;
case STUN_RESPONSE_ADDRESS :
return " Response Address " ;
case STUN_CHANGE_REQUEST :
return " Change Request " ;
case STUN_SOURCE_ADDRESS :
return " Source Address " ;
case STUN_CHANGED_ADDRESS :
return " Changed Address " ;
case STUN_USERNAME :
return " Username " ;
case STUN_PASSWORD :
return " Password " ;
case STUN_MESSAGE_INTEGRITY :
return " Message Integrity " ;
case STUN_ERROR_CODE :
return " Error Code " ;
case STUN_UNKNOWN_ATTRIBUTES :
return " Unknown Attributes " ;
case STUN_REFLECTED_FROM :
return " Reflected From " ;
}
return " Non-RFC3489 Attribute " ;
}
struct stun_state {
2006-07-07 06:44:40 +00:00
const char * username ;
const char * password ;
2006-05-11 14:56:52 +00:00
} ;
static int stun_process_attr ( struct stun_state * state , struct stun_attr * attr )
{
if ( stundebug )
ast_verbose ( " Found STUN Attribute %s (%04x), length %d \n " ,
stun_attr2str ( ntohs ( attr - > attr ) ) , ntohs ( attr - > attr ) , ntohs ( attr - > len ) ) ;
switch ( ntohs ( attr - > attr ) ) {
case STUN_USERNAME :
2006-07-07 06:44:40 +00:00
state - > username = ( const char * ) ( attr - > value ) ;
2006-05-11 14:56:52 +00:00
break ;
case STUN_PASSWORD :
2006-07-07 06:44:40 +00:00
state - > password = ( const char * ) ( attr - > value ) ;
2006-05-11 14:56:52 +00:00
break ;
default :
if ( stundebug )
ast_verbose ( " Ignoring STUN attribute %s (%04x), length %d \n " ,
stun_attr2str ( ntohs ( attr - > attr ) ) , ntohs ( attr - > attr ) , ntohs ( attr - > len ) ) ;
}
return 0 ;
}
static void append_attr_string ( struct stun_attr * * attr , int attrval , const char * s , int * len , int * left )
{
int size = sizeof ( * * attr ) + strlen ( s ) ;
if ( * left > size ) {
( * attr ) - > attr = htons ( attrval ) ;
( * attr ) - > len = htons ( strlen ( s ) ) ;
memcpy ( ( * attr ) - > value , s , strlen ( s ) ) ;
( * attr ) = ( struct stun_attr * ) ( ( * attr ) - > value + strlen ( s ) ) ;
* len + = size ;
* left - = size ;
}
}
static void append_attr_address ( struct stun_attr * * attr , int attrval , struct sockaddr_in * sin , int * len , int * left )
{
int size = sizeof ( * * attr ) + 8 ;
struct stun_addr * addr ;
if ( * left > size ) {
( * attr ) - > attr = htons ( attrval ) ;
( * attr ) - > len = htons ( 8 ) ;
addr = ( struct stun_addr * ) ( ( * attr ) - > value ) ;
addr - > unused = 0 ;
addr - > family = 0x01 ;
addr - > port = sin - > sin_port ;
addr - > addr = sin - > sin_addr . s_addr ;
( * attr ) = ( struct stun_attr * ) ( ( * attr ) - > value + 8 ) ;
* len + = size ;
* left - = size ;
}
}
static int stun_send ( int s , struct sockaddr_in * dst , struct stun_header * resp )
{
2006-05-11 15:25:21 +00:00
return sendto ( s , resp , ntohs ( resp - > msglen ) + sizeof ( * resp ) , 0 ,
( struct sockaddr * ) dst , sizeof ( * dst ) ) ;
2006-05-11 14:56:52 +00:00
}
static void stun_req_id ( struct stun_header * req )
{
int x ;
for ( x = 0 ; x < 4 ; x + + )
req - > id . id [ x ] = ast_random ( ) ;
}
2006-06-08 23:10:45 +00:00
size_t ast_rtp_alloc_size ( void )
{
return sizeof ( struct ast_rtp ) ;
}
2006-05-11 14:56:52 +00:00
void ast_rtp_stun_request ( struct ast_rtp * rtp , struct sockaddr_in * suggestion , const char * username )
{
struct stun_header * req ;
unsigned char reqdata [ 1024 ] ;
int reqlen , reqleft ;
struct stun_attr * attr ;
req = ( struct stun_header * ) reqdata ;
stun_req_id ( req ) ;
reqlen = 0 ;
reqleft = sizeof ( reqdata ) - sizeof ( struct stun_header ) ;
req - > msgtype = 0 ;
req - > msglen = 0 ;
attr = ( struct stun_attr * ) req - > ies ;
if ( username )
append_attr_string ( & attr , STUN_USERNAME , username , & reqlen , & reqleft ) ;
req - > msglen = htons ( reqlen ) ;
req - > msgtype = htons ( STUN_BINDREQ ) ;
stun_send ( rtp - > s , suggestion , req ) ;
}
2006-05-16 21:45:15 +00:00
static int stun_handle_packet ( int s , struct sockaddr_in * src , unsigned char * data , size_t len )
2006-05-11 14:56:52 +00:00
{
struct stun_header * resp , * hdr = ( struct stun_header * ) data ;
struct stun_attr * attr ;
struct stun_state st ;
int ret = STUN_IGNORE ;
unsigned char respdata [ 1024 ] ;
int resplen , respleft ;
if ( len < sizeof ( struct stun_header ) ) {
2006-05-16 12:42:59 +00:00
if ( option_debug )
2006-05-16 21:45:15 +00:00
ast_log ( LOG_DEBUG , " Runt STUN packet (only %zd, wanting at least %zd) \n " , len , sizeof ( struct stun_header ) ) ;
2006-05-11 14:56:52 +00:00
return - 1 ;
}
if ( stundebug )
ast_verbose ( " STUN Packet, msg %s (%04x), length: %d \n " , stun_msg2str ( ntohs ( hdr - > msgtype ) ) , ntohs ( hdr - > msgtype ) , ntohs ( hdr - > msglen ) ) ;
if ( ntohs ( hdr - > msglen ) > len - sizeof ( struct stun_header ) ) {
2006-05-16 12:42:59 +00:00
if ( option_debug )
2006-05-16 21:45:15 +00:00
ast_log ( LOG_DEBUG , " Scrambled STUN packet length (got %d, expecting %zd) \n " , ntohs ( hdr - > msglen ) , len - sizeof ( struct stun_header ) ) ;
2006-05-11 14:56:52 +00:00
} else
len = ntohs ( hdr - > msglen ) ;
data + = sizeof ( struct stun_header ) ;
memset ( & st , 0 , sizeof ( st ) ) ;
while ( len ) {
if ( len < sizeof ( struct stun_attr ) ) {
2006-05-16 12:42:59 +00:00
if ( option_debug )
2006-05-16 21:45:15 +00:00
ast_log ( LOG_DEBUG , " Runt Attribute (got %zd, expecting %zd) \n " , len , sizeof ( struct stun_attr ) ) ;
2006-05-11 14:56:52 +00:00
break ;
}
attr = ( struct stun_attr * ) data ;
if ( ntohs ( attr - > len ) > len ) {
2006-05-16 12:42:59 +00:00
if ( option_debug )
2006-06-09 21:09:42 +00:00
ast_log ( LOG_DEBUG , " Inconsistent Attribute (length %d exceeds remaining msg len %zd) \n " , ntohs ( attr - > len ) , len ) ;
2006-05-11 14:56:52 +00:00
break ;
}
if ( stun_process_attr ( & st , attr ) ) {
2006-05-16 12:42:59 +00:00
if ( option_debug )
ast_log ( LOG_DEBUG , " Failed to handle attribute %s (%04x) \n " , stun_attr2str ( ntohs ( attr - > attr ) ) , ntohs ( attr - > attr ) ) ;
2006-05-11 14:56:52 +00:00
break ;
}
/* Clear attribute in case previous entry was a string */
attr - > attr = 0 ;
data + = ntohs ( attr - > len ) + sizeof ( struct stun_attr ) ;
len - = ntohs ( attr - > len ) + sizeof ( struct stun_attr ) ;
}
/* Null terminate any string */
* data = ' \0 ' ;
resp = ( struct stun_header * ) respdata ;
resplen = 0 ;
respleft = sizeof ( respdata ) - sizeof ( struct stun_header ) ;
resp - > id = hdr - > id ;
resp - > msgtype = 0 ;
resp - > msglen = 0 ;
attr = ( struct stun_attr * ) resp - > ies ;
if ( ! len ) {
switch ( ntohs ( hdr - > msgtype ) ) {
case STUN_BINDREQ :
if ( stundebug )
ast_verbose ( " STUN Bind Request, username: %s \n " ,
2006-07-07 06:44:40 +00:00
st . username ? st . username : " <none> " ) ;
2006-05-11 14:56:52 +00:00
if ( st . username )
append_attr_string ( & attr , STUN_USERNAME , st . username , & resplen , & respleft ) ;
append_attr_address ( & attr , STUN_MAPPED_ADDRESS , src , & resplen , & respleft ) ;
resp - > msglen = htons ( resplen ) ;
resp - > msgtype = htons ( STUN_BINDRESP ) ;
stun_send ( s , src , resp ) ;
ret = STUN_ACCEPT ;
break ;
default :
if ( stundebug )
ast_verbose ( " Dunno what to do with STUN message %04x (%s) \n " , ntohs ( hdr - > msgtype ) , stun_msg2str ( ntohs ( hdr - > msgtype ) ) ) ;
}
}
return ret ;
}
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
2006-06-05 08:39:42 +00:00
static void timeval2ntp ( struct timeval tv , unsigned int * msw , unsigned int * lsw )
{
unsigned int sec , usec , frac ;
sec = tv . tv_sec + 2208988800u ; /* Sec between 1900 and 1970 */
usec = tv . tv_usec ;
frac = ( usec < < 12 ) + ( usec < < 8 ) - ( ( usec * 3650 ) > > 6 ) ;
* msw = sec ;
* lsw = frac ;
}
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 ;
}
2006-06-05 08:39:42 +00:00
unsigned int ast_rtcp_calc_interval ( struct ast_rtp * rtp )
{
unsigned int interval ;
/*! \todo XXX Do a more reasonable calculation on this one
* Look in RFC 3550 Section A .7 for an example */
interval = rtcpinterval ;
return interval ;
}
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 ;
}
2006-05-16 22:11:02 +00:00
void ast_rtp_setdtmf ( struct ast_rtp * rtp , int dtmf )
{
ast_set2_flag ( rtp , dtmf ? 1 : 0 , FLAG_HAS_DTMF ) ;
}
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
{
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 )
2006-07-21 17:31:28 +00:00
ast_log ( LOG_DEBUG , " Ignore potential DTMF echo from '%s' \n " , ast_inet_ntoa ( 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 )
2006-07-21 17:31:28 +00:00
ast_log ( LOG_DEBUG , " Sending dtmf: %d (%c), at %s \n " , rtp - > resp , rtp - > resp , ast_inet_ntoa ( 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 ;
}
2006-06-05 08:39:42 +00:00
static inline int rtcp_debug_test_addr ( struct sockaddr_in * addr )
{
if ( rtcpdebug = = 0 )
return 0 ;
if ( rtcpdebugaddr . sin_addr . s_addr ) {
if ( ( ( ntohs ( rtcpdebugaddr . sin_port ) ! = 0 )
& & ( rtcpdebugaddr . sin_port ! = addr - > sin_port ) )
| | ( rtcpdebugaddr . 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 ) ;
2006-06-05 15:47:36 +00:00
} else if ( event_end & 0x80 ) {
2003-08-16 16:51:58 +00:00
if ( rtp - > resp ) {
2006-06-05 15:47:36 +00:00
if ( rtp - > lasteventendseqn ! = seqno ) {
2005-07-12 23:36:00 +00:00
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 ) ) ) {
ast_log ( LOG_NOTICE , " Comfort noise support incomplete in Asterisk (RFC 3389). Please turn off on client if possible. Client IP: %s \n " ,
2006-07-21 17:31:28 +00:00
ast_inet_ntoa ( rtp - > them . sin_addr ) ) ;
2005-09-07 20:33:30 +00:00
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 ;
2006-06-05 08:39:42 +00:00
int position , i , packetwords ;
2003-06-28 16:40:02 +00:00
int res ;
struct sockaddr_in sin ;
2006-06-05 08:39:42 +00:00
unsigned int rtcpdata [ 8192 + AST_FRIENDLY_OFFSET ] ;
unsigned int * rtcpheader ;
int pt ;
struct timeval now ;
unsigned int length ;
int rc ;
double rtt = 0 ;
double a ;
double dlsr ;
double lsr ;
unsigned int msw ;
unsigned int lsw ;
unsigned int comp ;
struct ast_frame * f = & ast_null_frame ;
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 ) ;
2006-06-05 08:39:42 +00:00
res = recvfrom ( rtp - > rtcp - > s , rtcpdata + AST_FRIENDLY_OFFSET , sizeof ( rtcpdata ) - sizeof ( unsigned int ) * AST_FRIENDLY_OFFSET ,
2003-06-28 16:40:02 +00:00
0 , ( struct sockaddr * ) & sin , & len ) ;
2006-06-05 08:39:42 +00:00
rtcpheader = ( unsigned int * ) ( rtcpdata + AST_FRIENDLY_OFFSET ) ;
2003-06-28 16:40:02 +00:00
if ( res < 0 ) {
2005-05-04 04:43:30 +00:00
if ( errno ! = EAGAIN )
2006-06-05 08:39:42 +00:00
ast_log ( LOG_WARNING , " RTCP 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
}
2006-06-05 08:39:42 +00:00
packetwords = res / 4 ;
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 )
2006-07-21 17:31:28 +00:00
ast_log ( LOG_DEBUG , " RTCP NAT: Got RTCP from other end. Now sending to address %s:%d \n " , ast_inet_ntoa ( 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-06-05 08:39:42 +00:00
/* Process a compound packet */
position = 0 ;
while ( position < packetwords ) {
i = position ;
length = ntohl ( rtcpheader [ i ] ) ;
pt = ( length & 0xff0000 ) > > 16 ;
rc = ( length & 0x1f000000 ) > > 24 ;
length & = 0xffff ;
if ( ( i + length ) > packetwords ) {
ast_log ( LOG_WARNING , " RTCP Read too short \n " ) ;
return & ast_null_frame ;
}
2006-06-05 15:47:36 +00:00
if ( rtcp_debug_test_addr ( & sin ) ) {
2006-07-21 17:31:28 +00:00
ast_verbose ( " \n \n Got RTCP from %s:%d \n " , ast_inet_ntoa ( sin . sin_addr ) , ntohs ( sin . sin_port ) ) ;
2006-06-05 15:47:36 +00:00
ast_verbose ( " PT: %d(%s) \n " , pt , ( pt = = 200 ) ? " Sender Report " : ( pt = = 201 ) ? " Receiver Report " : ( pt = = 192 ) ? " H.261 FUR " : " Unknown " ) ;
ast_verbose ( " Reception reports: %d \n " , rc ) ;
ast_verbose ( " SSRC of sender: %u \n " , rtcpheader [ i + 1 ] ) ;
}
2006-06-05 08:39:42 +00:00
2006-06-05 15:47:36 +00:00
i + = 2 ; /* Advance past header and ssrc */
2006-06-05 08:39:42 +00:00
2006-06-05 15:47:36 +00:00
switch ( pt ) {
case RTCP_PT_SR :
gettimeofday ( & rtp - > rtcp - > rxlsr , NULL ) ; /* To be able to populate the dlsr */
rtp - > rtcp - > spc = ntohl ( rtcpheader [ i + 3 ] ) ;
rtp - > rtcp - > soc = ntohl ( rtcpheader [ i + 4 ] ) ;
rtp - > rtcp - > themrxlsr = ( ( ntohl ( rtcpheader [ i ] ) & 0x0000ffff ) < < 16 ) | ( ( ntohl ( rtcpheader [ i + 1 ] ) & 0xffff ) > > 16 ) ; /* Going to LSR in RR*/
2006-06-05 08:39:42 +00:00
2006-06-05 15:47:36 +00:00
if ( rtcp_debug_test_addr ( & sin ) ) {
ast_verbose ( " NTP timestamp: %lu.%010lu \n " , ( unsigned long ) ntohl ( rtcpheader [ i ] ) , ( unsigned long ) ntohl ( rtcpheader [ i + 1 ] ) * 4096 ) ;
ast_verbose ( " RTP timestamp: %lu \n " , ( unsigned long ) ntohl ( rtcpheader [ i + 2 ] ) ) ;
ast_verbose ( " SPC: %lu \t SOC: %lu \n " , ( unsigned long ) ntohl ( rtcpheader [ i + 3 ] ) , ( unsigned long ) ntohl ( rtcpheader [ i + 4 ] ) ) ;
}
2006-06-05 08:39:42 +00:00
i + = 5 ;
if ( rc < 1 )
break ;
/* Intentional fall through */
2006-06-05 15:47:36 +00:00
case RTCP_PT_RR :
/* This is the place to calculate RTT */
/* Don't handle multiple reception reports (rc > 1) yet */
gettimeofday ( & now , NULL ) ;
timeval2ntp ( now , & msw , & lsw ) ;
/* Use the one we sent them in our SR instead, rtcp->txlsr could have been rewritten if the dlsr is large */
if ( ntohl ( rtcpheader [ i + 4 ] ) ) { /* We must have the LSR */
comp = ( ( msw & 0xffff ) < < 16 ) | ( ( lsw & 0xffff0000 ) > > 16 ) ;
a = ( double ) ( ( comp & 0xffff0000 ) > > 16 ) + ( double ) ( ( double ) ( comp & 0xffff ) / 1000000. ) ;
lsr = ( double ) ( ( ntohl ( rtcpheader [ i + 4 ] ) & 0xffff0000 ) > > 16 ) + ( double ) ( ( double ) ( ntohl ( rtcpheader [ i + 4 ] ) & 0xffff ) / 1000000. ) ;
dlsr = ( double ) ( ntohl ( rtcpheader [ i + 5 ] ) / 65536. ) ;
rtt = a - dlsr - lsr ;
rtp - > rtcp - > accumulated_transit + = rtt ;
rtp - > rtcp - > rtt = rtt ;
if ( rtp - > rtcp - > maxrtt < rtt )
rtp - > rtcp - > maxrtt = rtt ;
if ( rtp - > rtcp - > minrtt > rtt )
rtp - > rtcp - > minrtt = rtt ;
}
rtp - > rtcp - > reported_jitter = ntohl ( rtcpheader [ i + 3 ] ) ;
rtp - > rtcp - > reported_lost = ntohl ( rtcpheader [ i + 1 ] ) & 0xffffff ;
if ( rtcp_debug_test_addr ( & sin ) ) {
ast_verbose ( " Fraction lost: %ld \n " , ( ( ( long ) ntohl ( rtcpheader [ i + 1 ] ) & 0xff000000 ) > > 24 ) ) ;
ast_verbose ( " Packets lost so far: %d \n " , rtp - > rtcp - > reported_lost ) ;
ast_verbose ( " Highest sequence number: %ld \n " , ( long ) ( ntohl ( rtcpheader [ i + 2 ] ) & 0xffff ) ) ;
ast_verbose ( " Sequence number cycles: %ld \n " , ( long ) ( ntohl ( rtcpheader [ i + 2 ] ) & 0xffff ) > > 16 ) ;
ast_verbose ( " Interarrival jitter: %u \n " , rtp - > rtcp - > reported_jitter ) ;
ast_verbose ( " Last SR(our NTP): %lu.%010lu \n " , ( unsigned long ) ntohl ( rtcpheader [ i + 4 ] ) > > 16 , ( ( unsigned long ) ntohl ( rtcpheader [ i + 4 ] ) < < 16 ) * 4096 ) ;
ast_verbose ( " DLSR: %4.4f (sec) \n " , ntohl ( rtcpheader [ i + 5 ] ) / 65536.0 ) ;
if ( rtt )
ast_verbose ( " RTT: %f(sec) \n " , rtt ) ;
}
break ;
case RTCP_PT_FUR :
if ( rtcp_debug_test_addr ( & sin ) )
ast_verbose ( " Received an RTCP Fast Update Request \n " ) ;
rtp - > f . frametype = AST_FRAME_CONTROL ;
rtp - > f . subclass = AST_CONTROL_VIDUPDATE ;
rtp - > f . datalen = 0 ;
rtp - > f . samples = 0 ;
rtp - > f . mallocd = 0 ;
rtp - > f . src = " RTP " ;
f = & rtp - > f ;
break ;
case RTCP_PT_SDES :
if ( rtcp_debug_test_addr ( & sin ) )
2006-07-21 17:31:28 +00:00
ast_verbose ( " Received an SDES from %s:%d \n " , ast_inet_ntoa ( rtp - > rtcp - > them . sin_addr ) , ntohs ( rtp - > rtcp - > them . sin_port ) ) ;
2006-06-05 15:47:36 +00:00
break ;
case RTCP_PT_BYE :
if ( rtcp_debug_test_addr ( & sin ) )
2006-07-21 17:31:28 +00:00
ast_verbose ( " Received a BYE from %s:%d \n " , ast_inet_ntoa ( rtp - > rtcp - > them . sin_addr ) , ntohs ( rtp - > rtcp - > them . sin_port ) ) ;
2006-06-05 15:47:36 +00:00
break ;
default :
2006-07-21 17:31:28 +00:00
ast_log ( LOG_NOTICE , " Unknown RTCP packet (pt=%d) received from %s:%d \n " , pt , ast_inet_ntoa ( rtp - > rtcp - > them . sin_addr ) , ntohs ( rtp - > rtcp - > them . sin_port ) ) ;
2006-06-05 15:47:36 +00:00
break ;
2006-06-05 08:39:42 +00:00
}
position + = ( length + 1 ) ;
}
return f ;
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
{
2006-06-05 08:39:42 +00:00
struct timeval now ;
double transit ;
double current_time ;
double d ;
double dtv ;
double prog ;
if ( ( ! rtp - > rxcore . tv_sec & & ! rtp - > rxcore . tv_usec ) | | mark ) {
gettimeofday ( & rtp - > rxcore , NULL ) ;
2006-06-05 15:47:36 +00:00
rtp - > drxcore = ( double ) rtp - > rxcore . tv_sec + ( double ) rtp - > rxcore . tv_usec / 1000000 ;
2006-06-05 08:39:42 +00:00
/* map timestamp to a real time */
rtp - > seedrxts = timestamp ; /* Their RTP timestamp started with this */
rtp - > rxcore . tv_sec - = timestamp / 8000 ;
rtp - > rxcore . tv_usec - = ( timestamp % 8000 ) * 125 ;
/* Round to 0.1ms for nice, pretty timestamps */
rtp - > rxcore . tv_usec - = rtp - > rxcore . tv_usec % 100 ;
if ( rtp - > rxcore . tv_usec < 0 ) {
/* Adjust appropriately if necessary */
rtp - > rxcore . tv_usec + = 1000000 ;
rtp - > rxcore . tv_sec - = 1 ;
}
2004-03-13 03:52:14 +00:00
}
2006-06-05 08:39:42 +00:00
gettimeofday ( & now , NULL ) ;
/* rxcore is the mapping between the RTP timestamp and _our_ real time from gettimeofday() */
tv - > tv_sec = rtp - > rxcore . tv_sec + timestamp / 8000 ;
tv - > tv_usec = rtp - > rxcore . tv_usec + ( timestamp % 8000 ) * 125 ;
if ( tv - > tv_usec > = 1000000 ) {
tv - > tv_usec - = 1000000 ;
tv - > tv_sec + = 1 ;
}
prog = ( double ) ( ( timestamp - rtp - > seedrxts ) / 8000. ) ;
dtv = ( double ) rtp - > drxcore + ( double ) ( prog ) ;
current_time = ( double ) now . tv_sec + ( double ) now . tv_usec / 1000000 ;
transit = current_time - dtv ;
d = transit - rtp - > rxtransit ;
rtp - > rxtransit = transit ;
2006-06-05 15:47:36 +00:00
if ( d < 0 )
2006-06-05 08:39:42 +00:00
d = - d ;
rtp - > rxjitter + = ( 1. / 16. ) * ( d - rtp - > rxjitter ) ;
2006-06-05 15:47:36 +00:00
if ( rtp - > rxjitter > rtp - > rtcp - > maxrxjitter )
2006-06-05 08:39:42 +00:00
rtp - > rtcp - > maxrxjitter = rtp - > rxjitter ;
2006-06-05 15:47:36 +00:00
if ( rtp - > rxjitter < rtp - > rtcp - > minrxjitter )
2006-06-05 08:39:42 +00:00
rtp - > rtcp - > minrxjitter = rtp - > rxjitter ;
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 ;
2006-06-05 08:39:42 +00:00
int tseqno ;
2002-06-16 16:06:38 +00:00
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 ;
2006-05-11 08:47:37 +00:00
unsigned int ssrc ;
2002-06-16 16:06:38 +00:00
unsigned int timestamp ;
unsigned int * rtpheader ;
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-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
}
2006-06-05 08:39:42 +00:00
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
2006-05-11 14:56:52 +00:00
/* Get fields */
seqno = ntohl ( rtpheader [ 0 ] ) ;
/* Check RTP version */
version = ( seqno & 0xC0000000 ) > > 30 ;
if ( ! version ) {
if ( ( stun_handle_packet ( rtp - > s , & sin , rtp - > rawdata + AST_FRIENDLY_OFFSET , res ) = = STUN_ACCEPT ) & &
( ! rtp - > them . sin_port & & ! rtp - > them . sin_addr . s_addr ) ) {
memcpy ( & rtp - > them , & sin , sizeof ( rtp - > them ) ) ;
}
return & ast_null_frame ;
}
if ( version ! = 2 )
return & ast_null_frame ;
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 ) ) {
2006-04-15 00:36:05 +00:00
rtp - > them = sin ;
2006-06-05 15:47:36 +00:00
if ( rtp - > rtcp ) {
2006-06-05 08:39:42 +00:00
memcpy ( & rtp - > rtcp - > them , & sin , sizeof ( rtp - > rtcp - > them ) ) ;
rtp - > rtcp - > them . sin_port = htons ( ntohs ( rtp - > them . sin_port ) + 1 ) ;
}
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 )
2006-07-21 17:31:28 +00:00
ast_log ( LOG_DEBUG , " RTP NAT: Got audio from other end. Now sending to address %s:%d \n " , ast_inet_ntoa ( 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
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 ] ) ;
2006-05-11 08:47:37 +00:00
ssrc = ntohl ( rtpheader [ 2 ] ) ;
if ( ! mark & & rtp - > rxssrc & & rtp - > rxssrc ! = ssrc ) {
2006-07-07 23:59:54 +00:00
if ( option_debug | | rtpdebug )
ast_log ( LOG_DEBUG , " Forcing Marker bit, because SSRC has changed \n " ) ;
2006-05-11 08:47:37 +00:00
mark = 1 ;
}
rtp - > rxssrc = ssrc ;
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
}
2006-06-05 08:39:42 +00:00
rtp - > rxcount + + ; /* Only count reasonably valid packets, this'll make the rtcp stats more accurate */
tseqno = rtp - > lastrxseqno + 1 ;
2006-06-05 15:47:36 +00:00
if ( rtp - > rxcount = = 1 ) {
2006-06-05 08:39:42 +00:00
/* This is the first RTP packet successfully received from source */
rtp - > seedrxseqno = seqno ;
}
2006-07-31 15:24:05 +00:00
if ( rtp - > rtcp & & rtp - > rtcp - > schedid < 1 ) {
2006-06-05 08:39:42 +00:00
/* Schedule transmission of Receiver Report */
rtp - > rtcp - > schedid = ast_sched_add ( rtp - > sched , ast_rtcp_calc_interval ( rtp ) , ast_rtcp_write , rtp ) ;
}
2006-06-05 15:47:36 +00:00
if ( tseqno > RTP_SEQ_MOD ) { /* if tseqno is greater than RTP_SEQ_MOD it would indicate that the sender cycled */
2006-06-05 08:39:42 +00:00
rtp - > cycles + = RTP_SEQ_MOD ;
ast_verbose ( " SEQNO cycled: %u \t %d \n " , rtp - > cycles , seqno ) ;
}
rtp - > lastrxseqno = seqno ;
2006-06-05 15:47:36 +00:00
if ( rtp - > themssrc = = 0 )
2006-06-05 08:39:42 +00:00
rtp - > themssrc = ntohl ( rtpheader [ 2 ] ) ; /* Record their SSRC to put in future RR */
2006-06-05 15:47:36 +00:00
if ( rtp_debug_test_addr ( & sin ) )
2006-06-09 21:09:42 +00:00
ast_verbose ( " Got RTP packet from %s:%d (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u) \n " ,
2006-07-21 17:31:28 +00:00
ast_inet_ntoa ( sin . sin_addr ) , ntohs ( sin . sin_port ) , payloadtype , seqno , timestamp , res - hdrlen ) ;
2004-10-30 01:52:12 +00:00
2006-06-05 08:39:42 +00:00
rtpPT = ast_rtp_lookup_pt ( rtp , payloadtype ) ;
2003-03-12 06:00:18 +00:00
if ( ! rtpPT . isAstFormat ) {
2006-04-15 00:36:05 +00:00
struct ast_frame * f = NULL ;
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 */
2006-06-05 15:47:36 +00:00
if ( rtp_debug_test_addr ( & sin ) ) {
2005-07-12 23:36:00 +00:00
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 ;
2006-07-21 17:31:28 +00:00
ast_verbose ( " Got RTP RFC2833 from %s:%d (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u, mark %d, event %08x, end %d, duration %-5.5d) \n " , ast_inet_ntoa ( sin . sin_addr ) , ntohs ( sin . sin_port ) , payloadtype , seqno , timestamp , res - hdrlen , ( mark ? 1 : 0 ) , event , ( ( event_end & 0x80 ) ? 1 : 0 ) , duration ) ;
2005-07-12 23:36:00 +00:00
}
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 ;
2006-04-15 00:36:05 +00:00
}
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 ;
2006-04-15 00:36:05 +00:00
}
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 ) ;
} else {
2006-07-21 17:31:28 +00:00
ast_log ( LOG_NOTICE , " Unknown RTP codec %d received from '%s' \n " , payloadtype , ast_inet_ntoa ( rtp - > them . sin_addr ) ) ;
2005-10-12 20:45:18 +00:00
}
2006-04-15 00:36:05 +00:00
return f ? f : & ast_null_frame ;
2003-03-12 06:00:18 +00:00
}
2006-04-15 00:36:05 +00:00
rtp - > lastrxformat = rtp - > f . subclass = rtpPT . code ;
rtp - > f . frametype = ( rtp - > f . subclass < AST_FORMAT_MAX_AUDIO ) ? AST_FRAME_VOICE : AST_FRAME_VIDEO ;
2002-06-16 16:06:38 +00:00
if ( ! rtp - > lastrxts )
rtp - > lastrxts = timestamp ;
2004-10-19 21:07:10 +00:00
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 ) ;
2006-05-31 16:56:50 +00:00
/* Add timing data to let ast_generic_bridge() put the frame into a jitterbuf */
rtp - > f . has_timing_info = 1 ;
rtp - > f . ts = timestamp / 8 ;
rtp - > f . len = rtp - > f . samples / 8 ;
rtp - > f . seqno = seqno ;
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 " } ,
2006-07-12 22:42:13 +00:00
{ { 1 , AST_FORMAT_G726_AAL2 } , " audio " , " AAL2-G726-32 " } ,
2006-01-03 09:30:19 +00:00
{ { 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 } ,
2006-07-12 22:42:13 +00:00
[ 112 ] = { 1 , AST_FORMAT_G726_AAL2 } ,
2006-01-03 09:30:19 +00:00
[ 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
}
2006-06-08 23:10:45 +00:00
void ast_rtp_pt_copy ( struct ast_rtp * dest , const struct ast_rtp * src )
2005-12-20 17:52:31 +00:00
{
2006-06-08 23:10:45 +00:00
unsigned int i ;
2005-12-20 17:52:31 +00:00
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
}
2006-06-09 09:47:44 +00:00
int ast_rtp_early_bridge ( struct ast_channel * dest , struct ast_channel * src )
2006-05-09 11:44:50 +00:00
{
struct ast_rtp * destp , * srcp = NULL ; /* Audio RTP Channels */
struct ast_rtp * vdestp , * vsrcp = NULL ; /* Video RTP channels */
struct ast_rtp_protocol * destpr , * srcpr = NULL ;
int srccodec ;
2006-06-08 20:05:36 +00:00
2006-05-09 11:44:50 +00:00
/* Lock channels */
ast_channel_lock ( dest ) ;
if ( src ) {
while ( ast_channel_trylock ( src ) ) {
ast_channel_unlock ( dest ) ;
usleep ( 1 ) ;
ast_channel_lock ( dest ) ;
}
}
/* Find channel driver interfaces */
destpr = get_proto ( dest ) ;
if ( src )
srcpr = get_proto ( src ) ;
if ( ! destpr ) {
if ( option_debug )
ast_log ( LOG_DEBUG , " Channel '%s' has no RTP, not doing anything \n " , dest - > name ) ;
ast_channel_unlock ( dest ) ;
if ( src )
ast_channel_unlock ( src ) ;
return 0 ;
}
if ( ! srcpr ) {
if ( option_debug )
2006-05-10 15:13:26 +00:00
ast_log ( LOG_DEBUG , " Channel '%s' has no RTP, not doing anything \n " , src ? src - > name : " <unspecified> " ) ;
2006-05-09 11:44:50 +00:00
ast_channel_unlock ( dest ) ;
if ( src )
ast_channel_unlock ( src ) ;
return 0 ;
}
/* Get audio and video interface (if native bridge is possible) */
destp = destpr - > get_rtp_info ( dest ) ;
vdestp = ( destpr - > get_vrtp_info ) ? destpr - > get_vrtp_info ( dest ) : NULL ;
if ( srcpr ) {
srcp = srcpr - > get_rtp_info ( src ) ;
vsrcp = ( srcpr - > get_vrtp_info ) ? srcpr - > get_vrtp_info ( src ) : NULL ;
}
/* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
if ( ! destp ) {
/* Somebody doesn't want to play... */
ast_channel_unlock ( dest ) ;
if ( src )
ast_channel_unlock ( src ) ;
return 0 ;
}
if ( srcpr & & srcpr - > get_codec )
srccodec = srcpr - > get_codec ( src ) ;
else
srccodec = 0 ;
/* Consider empty media as non-existant */
if ( srcp & & ! srcp - > them . sin_addr . s_addr )
srcp = NULL ;
2006-06-08 20:05:36 +00:00
/* Bridge media early */
2006-05-09 11:44:50 +00:00
if ( destpr - > set_rtp_peer ( dest , srcp , vsrcp , srccodec , srcp ? ast_test_flag ( srcp , FLAG_NAT_ACTIVE ) : 0 ) )
2006-06-08 20:05:36 +00:00
ast_log ( LOG_WARNING , " Channel '%s' failed to setup early bridge to '%s' \n " , dest - > name , src ? src - > name : " <unspecified> " ) ;
2006-05-09 11:44:50 +00:00
ast_channel_unlock ( dest ) ;
if ( src )
ast_channel_unlock ( src ) ;
if ( option_debug )
2006-06-08 20:05:36 +00:00
ast_log ( LOG_DEBUG , " Setting early bridge SDP of '%s' with that of '%s' \n " , dest - > name , src ? src - > name : " <unspecified> " ) ;
2006-05-09 11:44:50 +00:00
return 1 ;
}
int ast_rtp_make_compatible ( struct ast_channel * dest , struct ast_channel * src , int media )
2005-12-20 17:52:31 +00:00
{
struct ast_rtp * destp , * srcp ; /* Audio RTP Channels */
struct ast_rtp * vdestp , * vsrcp ; /* Video RTP channels */
struct ast_rtp_protocol * destpr , * srcpr ;
2006-05-09 11:44:50 +00:00
int srccodec ;
2005-12-20 17:52:31 +00:00
/* Lock channels */
2006-04-27 17:53:52 +00:00
ast_channel_lock ( dest ) ;
while ( ast_channel_trylock ( src ) ) {
ast_channel_unlock ( dest ) ;
2005-12-20 17:52:31 +00:00
usleep ( 1 ) ;
2006-04-27 17:53:52 +00:00
ast_channel_lock ( dest ) ;
2005-12-20 17:52:31 +00:00
}
/* 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 ) ;
2006-04-27 17:53:52 +00:00
ast_channel_unlock ( dest ) ;
ast_channel_unlock ( src ) ;
2005-12-20 17:52:31 +00:00
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 ) ;
2006-04-27 17:53:52 +00:00
ast_channel_unlock ( dest ) ;
ast_channel_unlock ( src ) ;
2005-12-20 17:52:31 +00:00
return 0 ;
}
/* Get audio and video interface (if native bridge is possible) */
destp = destpr - > get_rtp_info ( dest ) ;
2006-04-14 23:30:18 +00:00
vdestp = ( destpr - > get_vrtp_info ) ? destpr - > get_vrtp_info ( dest ) : NULL ;
2005-12-20 17:52:31 +00:00
srcp = srcpr - > get_rtp_info ( src ) ;
2006-04-14 23:30:18 +00:00
vsrcp = ( srcpr - > get_vrtp_info ) ? srcpr - > get_vrtp_info ( src ) : NULL ;
2005-12-20 17:52:31 +00:00
/* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
if ( ! destp | | ! srcp ) {
/* Somebody doesn't want to play... */
2006-04-27 17:53:52 +00:00
ast_channel_unlock ( dest ) ;
ast_channel_unlock ( src ) ;
2005-12-20 17:52:31 +00:00
return 0 ;
}
ast_rtp_pt_copy ( destp , srcp ) ;
if ( vdestp & & vsrcp )
ast_rtp_pt_copy ( vdestp , vsrcp ) ;
2006-05-09 11:44:50 +00:00
if ( srcpr - > get_codec )
srccodec = srcpr - > get_codec ( src ) ;
else
srccodec = 0 ;
if ( media ) {
2006-06-08 20:05:36 +00:00
/* Bridge early */
2006-05-09 11:44:50 +00:00
if ( destpr - > set_rtp_peer ( dest , srcp , vsrcp , srccodec , ast_test_flag ( srcp , FLAG_NAT_ACTIVE ) ) )
2006-06-08 20:05:36 +00:00
ast_log ( LOG_WARNING , " Channel '%s' failed to setup early bridge to '%s' \n " , dest - > name , src - > name ) ;
2006-05-09 11:44:50 +00:00
}
2006-04-27 17:53:52 +00:00
ast_channel_unlock ( dest ) ;
ast_channel_unlock ( src ) ;
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-06-06 16:09:33 +00:00
/*! \brief Make a note of a RTP payload type that was seen in a SDP "m=" line.
2006-01-03 09:30:19 +00:00
* 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
2006-06-06 16:09:33 +00:00
if ( static_RTP_PT [ pt ] . code ! = 0 )
2004-12-28 16:43:20 +00:00
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
2006-07-13 01:38:47 +00:00
* an SDP " a=rtpmap: " line .
*/
void ast_rtp_set_rtpmap_type ( struct ast_rtp * rtp , int pt ,
char * mimeType , char * mimeSubtype ,
enum ast_rtp_options options )
2005-12-20 17:52:31 +00:00
{
2006-07-13 01:38:47 +00:00
unsigned 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 )
2006-04-14 23:30:18 +00:00
return ; /* bogus payload type */
2003-03-12 06:00:18 +00:00
2006-07-13 01:38:47 +00:00
for ( i = 0 ; i < sizeof ( mimeTypes ) / sizeof ( mimeTypes [ 0 ] ) ; + + i ) {
2004-12-28 16:43:20 +00:00
if ( strcasecmp ( mimeSubtype , mimeTypes [ i ] . subtype ) = = 0 & &
2006-07-13 01:38:47 +00:00
strcasecmp ( mimeType , mimeTypes [ i ] . type ) = = 0 ) {
2004-12-28 16:43:20 +00:00
rtp - > current_RTP_PT [ pt ] = mimeTypes [ i ] . payloadType ;
2006-07-13 01:38:47 +00:00
if ( ( mimeTypes [ i ] . payloadType . code = = AST_FORMAT_G726 ) & &
mimeTypes [ i ] . payloadType . isAstFormat & &
( options & AST_RTP_OPT_G726_NONSTANDARD ) )
rtp - > current_RTP_PT [ pt ] . code = AST_FORMAT_G726_AAL2 ;
2006-04-14 23:30:18 +00:00
return ;
2004-12-28 16:43:20 +00:00
}
}
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 */
2006-06-05 08:39:42 +00:00
/* Start with 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 ) {
2006-06-05 08:39:42 +00:00
if ( rtp - > current_RTP_PT [ pt ] . code = = code & & rtp - > current_RTP_PT [ pt ] . isAstFormat = = isAstFormat ) {
2004-12-28 16:43:20 +00:00
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
2006-07-13 01:38:47 +00:00
const char * ast_rtp_lookup_mime_subtype ( const int isAstFormat , const int code ,
enum ast_rtp_options options )
2005-12-20 17:52:31 +00:00
{
2006-07-13 01:38:47 +00:00
unsigned int i ;
2004-12-28 16:43:20 +00:00
2006-07-13 01:38:47 +00:00
for ( i = 0 ; i < sizeof ( mimeTypes ) / sizeof ( mimeTypes [ 0 ] ) ; + + i ) {
if ( ( mimeTypes [ i ] . payloadType . code = = code ) & & ( mimeTypes [ i ] . payloadType . isAstFormat = = isAstFormat ) ) {
if ( isAstFormat & &
( code = = AST_FORMAT_G726_AAL2 ) & &
( options & AST_RTP_OPT_G726_NONSTANDARD ) )
return " AAL2-G726-32 " ;
else
return mimeTypes [ i ] . subtype ;
}
2004-12-28 16:43:20 +00:00
}
2006-07-13 01:38:47 +00:00
2004-12-28 16:43:20 +00:00
return " " ;
2003-03-12 06:00:18 +00:00
}
2006-07-13 01:38:47 +00:00
char * ast_rtp_lookup_mime_multiple ( char * buf , size_t size , const int capability ,
const int isAstFormat , enum ast_rtp_options options )
2005-04-05 23:34:56 +00:00
{
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 ) {
2006-07-13 01:38:47 +00:00
const char * name = ast_rtp_lookup_mime_subtype ( isAstFormat , format , options ) ;
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 ;
2006-06-05 08:39:42 +00:00
rtcp - > them . sin_family = AF_INET ;
2003-06-28 16:40:02 +00:00
if ( rtcp - > s < 0 ) {
free ( rtcp ) ;
2006-06-05 08:39:42 +00:00
ast_log ( LOG_WARNING , " Unable to allocate RTCP socket: %s \n " , strerror ( errno ) ) ;
2003-06-28 16:40:02 +00:00
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 ;
2006-05-16 22:11:02 +00:00
ast_set_flag ( rtp , FLAG_HAS_DTMF ) ;
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
}
2006-05-09 11:44:50 +00:00
int ast_rtp_get_peer ( struct ast_rtp * rtp , struct sockaddr_in * them )
2003-02-05 19:26:49 +00:00
{
2006-05-09 11:44:50 +00:00
if ( ( them - > sin_family ! = AF_INET ) | |
( them - > sin_port ! = rtp - > them . sin_port ) | |
( them - > sin_addr . s_addr ! = rtp - > them . sin_addr . s_addr ) ) {
them - > sin_family = AF_INET ;
them - > sin_port = rtp - > them . sin_port ;
them - > sin_addr = rtp - > them . sin_addr ;
return 1 ;
}
return 0 ;
2003-02-05 19:26:49 +00:00
}
2002-06-16 16:06:38 +00:00
void ast_rtp_get_us ( struct ast_rtp * rtp , struct sockaddr_in * us )
{
2006-04-14 23:30:18 +00:00
* us = rtp - > us ;
2002-06-16 16:06:38 +00:00
}
2003-03-20 22:01:53 +00:00
void ast_rtp_stop ( struct ast_rtp * rtp )
{
2006-07-31 15:24:05 +00:00
if ( rtp - > rtcp & & rtp - > rtcp - > schedid > 0 ) {
2006-06-05 08:39:42 +00:00
ast_sched_del ( rtp - > sched , rtp - > rtcp - > schedid ) ;
rtp - > rtcp - > schedid = - 1 ;
}
2003-03-20 22:01:53 +00:00
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 ) {
2006-06-05 08:39:42 +00:00
memset ( & rtp - > rtcp - > them . sin_addr , 0 , sizeof ( rtp - > rtcp - > them . sin_addr ) ) ;
memset ( & rtp - > rtcp - > them . sin_port , 0 , sizeof ( rtp - > rtcp - > them . sin_port ) ) ;
2003-06-28 16:40:02 +00:00
}
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 ;
}
2006-06-05 08:39:42 +00:00
char * ast_rtp_get_quality ( struct ast_rtp * rtp )
{
/*
* ssrc our ssrc
* themssrc their ssrc
* lp lost packets
* rxjitter our calculated jitter ( rx )
* rxcount no . received packets
* txjitter reported jitter of the other end
* txcount transmitted packets
* rlp remote lost packets
*/
snprintf ( rtp - > rtcp - > quality , sizeof ( rtp - > rtcp - > quality ) , " ssrc=%u;themssrc=%u;lp=%u;rxjitter=%f;rxcount=%u;txjitter=%f;txcount=%u;rlp=%u;rtt=%f " , rtp - > ssrc , rtp - > themssrc , rtp - > rtcp - > expected_prior - rtp - > rtcp - > received_prior , rtp - > rxjitter , rtp - > rxcount , ( double ) rtp - > rtcp - > reported_jitter / 65536. , rtp - > txcount , rtp - > rtcp - > reported_lost , rtp - > rtcp - > rtt ) ;
return rtp - > rtcp - > quality ;
}
2002-06-16 16:06:38 +00:00
void ast_rtp_destroy ( struct ast_rtp * rtp )
{
2006-06-05 15:47:36 +00:00
if ( rtcp_debug_test_addr ( & rtp - > them ) | | rtcpstats ) {
2006-06-05 08:39:42 +00:00
/*Print some info on the call here */
ast_verbose ( " RTP-stats \n " ) ;
ast_verbose ( " * Our Receiver: \n " ) ;
ast_verbose ( " SSRC: %u \n " , rtp - > themssrc ) ;
ast_verbose ( " Received packets: %u \n " , rtp - > rxcount ) ;
ast_verbose ( " Lost packets: %u \n " , rtp - > rtcp - > expected_prior - rtp - > rtcp - > received_prior ) ;
ast_verbose ( " Jitter: %.4f \n " , rtp - > rxjitter ) ;
ast_verbose ( " Transit: %.4f \n " , rtp - > rxtransit ) ;
ast_verbose ( " RR-count: %u \n " , rtp - > rtcp - > rr_count ) ;
ast_verbose ( " * Our Sender: \n " ) ;
ast_verbose ( " SSRC: %u \n " , rtp - > ssrc ) ;
ast_verbose ( " Sent packets: %u \n " , rtp - > txcount ) ;
ast_verbose ( " Lost packets: %u \n " , rtp - > rtcp - > reported_lost ) ;
ast_verbose ( " Jitter: %u \n " , rtp - > rtcp - > reported_jitter ) ;
ast_verbose ( " SR-count: %u \n " , rtp - > rtcp - > sr_count ) ;
ast_verbose ( " RTT: %f \n " , rtp - > rtcp - > rtt ) ;
}
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 ) {
2006-07-31 15:24:05 +00:00
if ( rtp - > rtcp - > schedid > 0 )
ast_sched_del ( rtp - > sched , rtp - > rtcp - > schedid ) ;
2003-06-28 16:40:02 +00:00
close ( rtp - > rtcp - > s ) ;
free ( rtp - > rtcp ) ;
2006-06-05 08:39:42 +00:00
rtp - > rtcp = NULL ;
2003-06-28 16:40:02 +00:00
}
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 ] ;
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 " ,
2006-07-21 17:31:28 +00:00
ast_inet_ntoa ( rtp - > them . sin_addr ) ,
2005-05-15 04:06:16 +00:00
ntohs ( rtp - > them . sin_port ) , strerror ( errno ) ) ;
if ( rtp_debug_test_addr ( & rtp - > them ) )
2006-06-04 18:55:16 +00:00
ast_verbose ( " Sent RTP DTMF packet to %s:%d (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u) \n " ,
2006-07-21 17:31:28 +00:00
ast_inet_ntoa ( rtp - > them . sin_addr ) ,
2005-05-15 04:06:16 +00:00
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
}
}
2006-06-05 08:39:42 +00:00
/*! \note 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 ;
}
2006-06-05 08:39:42 +00:00
/* \brief Public function: Send an H.261 fast update request, some devices need this rather than SIP XML */
int ast_rtcp_send_h261fur ( void * data )
{
struct ast_rtp * rtp = data ;
int res ;
rtp - > rtcp - > sendfur = 1 ;
res = ast_rtcp_write ( data ) ;
return res ;
}
/*! \brief Send RTCP sender's report */
static int ast_rtcp_write_sr ( void * data )
{
struct ast_rtp * rtp = data ;
int res ;
int len = 0 ;
struct timeval now ;
unsigned int now_lsw ;
unsigned int now_msw ;
unsigned int * rtcpheader ;
unsigned int lost ;
unsigned int extended ;
unsigned int expected ;
unsigned int expected_interval ;
unsigned int received_interval ;
int lost_interval ;
int fraction ;
struct timeval dlsr ;
char bdata [ 512 ] ;
2006-06-05 15:47:36 +00:00
if ( ! rtp | | ! rtp - > rtcp | | ( & rtp - > rtcp - > them . sin_addr = = 0 ) )
2006-06-05 08:39:42 +00:00
return 0 ;
2006-06-05 15:47:36 +00:00
if ( ! rtp - > rtcp - > them . sin_addr . s_addr ) { /* This'll stop rtcp for this rtp session */
2006-06-05 08:39:42 +00:00
ast_verbose ( " RTCP SR transmission error, rtcp halted %s \n " , strerror ( errno ) ) ;
2006-06-21 19:07:02 +00:00
if ( rtp - > rtcp - > schedid > 0 )
ast_sched_del ( rtp - > sched , rtp - > rtcp - > schedid ) ;
2006-06-05 08:39:42 +00:00
rtp - > rtcp - > schedid = - 1 ;
return 0 ;
}
gettimeofday ( & now , NULL ) ;
timeval2ntp ( now , & now_msw , & now_lsw ) ; /* fill thses ones in from utils.c*/
rtcpheader = ( unsigned int * ) bdata ;
rtcpheader [ 1 ] = htonl ( rtp - > ssrc ) ; /* Our SSRC */
rtcpheader [ 2 ] = htonl ( now_msw ) ; /* now, MSW. gettimeofday() + SEC_BETWEEN_1900_AND_1970*/
rtcpheader [ 3 ] = htonl ( now_lsw ) ; /* now, LSW */
rtcpheader [ 4 ] = htonl ( rtp - > lastts ) ; /* FIXME shouldn't be that, it should be now */
rtcpheader [ 5 ] = htonl ( rtp - > txcount ) ; /* No. packets sent */
rtcpheader [ 6 ] = htonl ( rtp - > txoctetcount ) ; /* No. bytes sent */
len + = 28 ;
extended = rtp - > cycles + rtp - > lastrxseqno ;
expected = extended - rtp - > seedrxseqno + 1 ;
if ( rtp - > rxcount > expected )
expected + = rtp - > rxcount - expected ;
lost = expected - rtp - > rxcount ;
expected_interval = expected - rtp - > rtcp - > expected_prior ;
rtp - > rtcp - > expected_prior = expected ;
received_interval = rtp - > rxcount - rtp - > rtcp - > received_prior ;
rtp - > rtcp - > received_prior = rtp - > rxcount ;
lost_interval = expected_interval - received_interval ;
if ( expected_interval = = 0 | | lost_interval < = 0 )
fraction = 0 ;
else
fraction = ( lost_interval < < 8 ) / expected_interval ;
timersub ( & now , & rtp - > rtcp - > rxlsr , & dlsr ) ;
rtcpheader [ 7 ] = htonl ( rtp - > themssrc ) ;
rtcpheader [ 8 ] = htonl ( ( ( fraction & 0xff ) < < 24 ) | ( lost & 0xffffff ) ) ;
rtcpheader [ 9 ] = htonl ( ( rtp - > cycles ) | ( ( rtp - > lastrxseqno & 0xffff ) ) ) ;
rtcpheader [ 10 ] = htonl ( ( unsigned int ) rtp - > rxjitter ) ;
rtcpheader [ 11 ] = htonl ( rtp - > rtcp - > themrxlsr ) ;
rtcpheader [ 12 ] = htonl ( ( ( ( dlsr . tv_sec * 1000 ) + ( dlsr . tv_usec / 1000 ) ) * 65536 ) / 1000 ) ;
len + = 24 ;
rtcpheader [ 0 ] = htonl ( ( 2 < < 30 ) | ( 1 < < 24 ) | ( RTCP_PT_SR < < 16 ) | ( ( len / 4 ) - 1 ) ) ;
if ( rtp - > rtcp - > sendfur ) {
rtcpheader [ 13 ] = htonl ( ( 2 < < 30 ) | ( 0 < < 24 ) | ( RTCP_PT_FUR < < 16 ) | 1 ) ;
rtcpheader [ 14 ] = htonl ( rtp - > ssrc ) ; /* Our SSRC */
len + = 8 ;
rtp - > rtcp - > sendfur = 0 ;
}
/* Insert SDES here. Probably should make SDES text equal to mimetypes[code].type (not subtype 'cos */
/* it can change mid call, and SDES can't) */
rtcpheader [ len / 4 ] = htonl ( ( 2 < < 30 ) | ( 1 < < 24 ) | ( RTCP_PT_SDES < < 16 ) | 2 ) ;
rtcpheader [ ( len / 4 ) + 1 ] = htonl ( rtp - > ssrc ) ; /* Our SSRC */
rtcpheader [ ( len / 4 ) + 2 ] = htonl ( 0x01 < < 24 ) ; /* Empty for the moment */
len + = 12 ;
res = sendto ( rtp - > rtcp - > s , ( unsigned int * ) rtcpheader , len , 0 , ( struct sockaddr * ) & rtp - > rtcp - > them , sizeof ( rtp - > rtcp - > them ) ) ;
if ( res < 0 ) {
2006-07-21 17:31:28 +00:00
ast_log ( LOG_ERROR , " RTCP SR transmission error to %s:%d, rtcp halted %s \n " , ast_inet_ntoa ( rtp - > rtcp - > them . sin_addr ) , ntohs ( rtp - > rtcp - > them . sin_port ) , strerror ( errno ) ) ;
2006-06-21 19:07:02 +00:00
if ( rtp - > rtcp - > schedid > 0 )
ast_sched_del ( rtp - > sched , rtp - > rtcp - > schedid ) ;
2006-06-05 08:39:42 +00:00
rtp - > rtcp - > schedid = - 1 ;
return 0 ;
}
/* FIXME Don't need to get a new one */
gettimeofday ( & rtp - > rtcp - > txlsr , NULL ) ;
rtp - > rtcp - > sr_count + + ;
rtp - > rtcp - > lastsrtxcount = rtp - > txcount ;
if ( rtcp_debug_test_addr ( & rtp - > rtcp - > them ) ) {
2006-07-21 17:31:28 +00:00
ast_verbose ( " * Sent RTCP SR to %s:%d \n " , ast_inet_ntoa ( rtp - > rtcp - > them . sin_addr ) , ntohs ( rtp - > rtcp - > them . sin_port ) ) ;
2006-06-05 08:39:42 +00:00
ast_verbose ( " Our SSRC: %u \n " , rtp - > ssrc ) ;
ast_verbose ( " Sent(NTP): %u.%010u \n " , ( unsigned int ) now . tv_sec , ( unsigned int ) now . tv_usec * 4096 ) ;
ast_verbose ( " Sent(RTP): %u \n " , rtp - > lastts ) ;
ast_verbose ( " Sent packets: %u \n " , rtp - > txcount ) ;
ast_verbose ( " Sent octets: %u \n " , rtp - > txoctetcount ) ;
ast_verbose ( " Report block: \n " ) ;
ast_verbose ( " Fraction lost: %u \n " , fraction ) ;
ast_verbose ( " Cumulative loss: %u \n " , lost ) ;
ast_verbose ( " IA jitter: %.4f \n " , rtp - > rxjitter ) ;
ast_verbose ( " Their last SR: %u \n " , rtp - > rtcp - > themrxlsr ) ;
ast_verbose ( " DLSR: %4.4f (sec) \n \n " , ( double ) ( ntohl ( rtcpheader [ 12 ] ) / 65536.0 ) ) ;
}
return res ;
}
/*! \brief Send RTCP recepient's report */
static int ast_rtcp_write_rr ( void * data )
{
struct ast_rtp * rtp = data ;
int res ;
int len = 32 ;
unsigned int lost ;
unsigned int extended ;
unsigned int expected ;
unsigned int expected_interval ;
unsigned int received_interval ;
int lost_interval ;
struct timeval now ;
unsigned int * rtcpheader ;
char bdata [ 1024 ] ;
struct timeval dlsr ;
int fraction ;
if ( ! rtp | | ! rtp - > rtcp | | ( & rtp - > rtcp - > them . sin_addr = = 0 ) )
return 0 ;
2006-06-05 15:47:36 +00:00
if ( ! rtp - > rtcp - > them . sin_addr . s_addr ) {
2006-06-05 08:39:42 +00:00
ast_log ( LOG_ERROR , " RTCP RR transmission error to, rtcp halted %s \n " , strerror ( errno ) ) ;
2006-06-21 19:07:02 +00:00
if ( rtp - > rtcp - > schedid > 0 )
ast_sched_del ( rtp - > sched , rtp - > rtcp - > schedid ) ;
2006-06-05 08:39:42 +00:00
rtp - > rtcp - > schedid = - 1 ;
return 0 ;
}
extended = rtp - > cycles + rtp - > lastrxseqno ;
expected = extended - rtp - > seedrxseqno + 1 ;
lost = expected - rtp - > rxcount ;
expected_interval = expected - rtp - > rtcp - > expected_prior ;
rtp - > rtcp - > expected_prior = expected ;
received_interval = rtp - > rxcount - rtp - > rtcp - > received_prior ;
rtp - > rtcp - > received_prior = rtp - > rxcount ;
lost_interval = expected_interval - received_interval ;
if ( expected_interval = = 0 | | lost_interval < = 0 )
fraction = 0 ;
else
fraction = ( lost_interval < < 8 ) / expected_interval ;
gettimeofday ( & now , NULL ) ;
timersub ( & now , & rtp - > rtcp - > rxlsr , & dlsr ) ;
rtcpheader = ( unsigned int * ) bdata ;
rtcpheader [ 0 ] = htonl ( ( 2 < < 30 ) | ( 1 < < 24 ) | ( RTCP_PT_RR < < 16 ) | ( ( len / 4 ) - 1 ) ) ;
rtcpheader [ 1 ] = htonl ( rtp - > ssrc ) ;
rtcpheader [ 2 ] = htonl ( rtp - > themssrc ) ;
rtcpheader [ 3 ] = htonl ( ( ( fraction & 0xff ) < < 24 ) | ( lost & 0xffffff ) ) ;
rtcpheader [ 4 ] = htonl ( ( rtp - > cycles ) | ( ( rtp - > lastrxseqno & 0xffff ) ) ) ;
rtcpheader [ 5 ] = htonl ( ( unsigned int ) rtp - > rxjitter ) ;
rtcpheader [ 6 ] = htonl ( rtp - > rtcp - > themrxlsr ) ;
rtcpheader [ 7 ] = htonl ( ( ( ( dlsr . tv_sec * 1000 ) + ( dlsr . tv_usec / 1000 ) ) * 65536 ) / 1000 ) ;
if ( rtp - > rtcp - > sendfur ) {
rtcpheader [ 8 ] = htonl ( ( 2 < < 30 ) | ( 0 < < 24 ) | ( RTCP_PT_FUR < < 16 ) | 1 ) ; /* Header from page 36 in RFC 3550 */
rtcpheader [ 9 ] = htonl ( rtp - > ssrc ) ; /* Our SSRC */
len + = 8 ;
rtp - > rtcp - > sendfur = 0 ;
}
/*! \note Insert SDES here. Probably should make SDES text equal to mimetypes[code].type (not subtype 'cos
it can change mid call , and SDES can ' t ) */
rtcpheader [ len / 4 ] = htonl ( ( 2 < < 30 ) | ( 1 < < 24 ) | ( RTCP_PT_SDES < < 16 ) | 2 ) ;
rtcpheader [ ( len / 4 ) + 1 ] = htonl ( rtp - > ssrc ) ; /* Our SSRC */
rtcpheader [ ( len / 4 ) + 2 ] = htonl ( 0x01 < < 24 ) ; /* Empty for the moment */
len + = 12 ;
res = sendto ( rtp - > rtcp - > s , ( unsigned int * ) rtcpheader , len , 0 , ( struct sockaddr * ) & rtp - > rtcp - > them , sizeof ( rtp - > rtcp - > them ) ) ;
if ( res < 0 ) {
ast_log ( LOG_ERROR , " RTCP RR transmission error, rtcp halted: %s \n " , strerror ( errno ) ) ;
/* Remove the scheduler */
2006-06-21 19:07:02 +00:00
if ( rtp - > rtcp - > schedid > 0 )
ast_sched_del ( rtp - > sched , rtp - > rtcp - > schedid ) ;
2006-06-05 08:39:42 +00:00
rtp - > rtcp - > schedid = - 1 ;
return 0 ;
}
rtp - > rtcp - > rr_count + + ;
if ( rtcp_debug_test_addr ( & rtp - > rtcp - > them ) ) {
ast_verbose ( " \n * Sending RTCP RR to %s:%d \n "
" Our SSRC: %u \n Their SSRC: %u \n iFraction lost: %d \n Cumulative loss: %u \n "
" IA jitter: %.4f \n "
" Their last SR: %u \n "
" DLSR: %4.4f (sec) \n \n " ,
2006-07-21 17:31:28 +00:00
ast_inet_ntoa ( rtp - > rtcp - > them . sin_addr ) ,
2006-06-05 08:39:42 +00:00
ntohs ( rtp - > rtcp - > them . sin_port ) ,
rtp - > ssrc , rtp - > themssrc , fraction , lost ,
rtp - > rxjitter ,
rtp - > rtcp - > themrxlsr ,
( double ) ( ntohl ( rtcpheader [ 7 ] ) / 65536.0 ) ) ;
}
return res ;
}
/*! \brief Write and RTCP packet to the far end
* \ note Decide if we are going to send an SR ( with Reception Block ) or RR
* RR is sent if we have not sent any rtp packets in the previous interval */
static int ast_rtcp_write ( void * data )
{
struct ast_rtp * rtp = data ;
int res ;
if ( rtp - > txcount > rtp - > rtcp - > lastsrtxcount )
res = ast_rtcp_write_sr ( data ) ;
else
res = ast_rtcp_write_rr ( data ) ;
return res ;
}
/*! \brief generate comfort noice (CNG) */
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 ] ;
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 )
2006-07-21 17:31:28 +00:00
ast_log ( LOG_ERROR , " RTP Comfort Noise Transmission error to %s:%d: %s \n " , ast_inet_ntoa ( rtp - > them . sin_addr ) , ntohs ( rtp - > them . sin_port ) , strerror ( errno ) ) ;
2006-06-05 15:47:36 +00:00
if ( rtp_debug_test_addr ( & rtp - > them ) )
2006-06-05 08:39:42 +00:00
ast_verbose ( " Sent Comfort Noise RTP packet to %s:%d (type %d, seq %d, ts %u, len %d) \n "
2006-07-21 17:31:28 +00:00
, ast_inet_ntoa ( rtp - > them . sin_addr ) , ntohs ( rtp - > them . sin_port ) , payload , rtp - > seqno , rtp - > lastts , res - hdrlen ) ;
2005-01-07 07:11:40 +00:00
}
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 ;
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 ;
2006-05-31 16:56:50 +00:00
if ( f - > has_timing_info )
rtp - > lastts = f - > ts * 8 ;
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 ) ) ) {
2006-07-21 17:31:28 +00:00
ast_log ( LOG_DEBUG , " RTP Transmission error of packet %d to %s:%d: %s \n " , rtp - > seqno , ast_inet_ntoa ( rtp - > them . sin_addr ) , ntohs ( rtp - > them . sin_port ) , strerror ( errno ) ) ;
2005-09-07 20:33:30 +00:00
} 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 )
2006-07-21 17:31:28 +00:00
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 ( rtp - > them . sin_addr ) , ntohs ( rtp - > them . sin_port ) ) ;
2005-09-07 20:33:30 +00:00
ast_set_flag ( rtp , FLAG_NAT_INACTIVE_NOWARN ) ;
}
2006-06-05 08:39:42 +00:00
} else {
rtp - > txcount + + ;
rtp - > txoctetcount + = ( res - hdrlen ) ;
2006-07-31 15:24:05 +00:00
if ( rtp - > rtcp & & rtp - > rtcp - > schedid < 1 )
2006-06-05 08:39:42 +00:00
rtp - > rtcp - > schedid = ast_sched_add ( rtp - > sched , ast_rtcp_calc_interval ( rtp ) , ast_rtcp_write , rtp ) ;
2005-09-07 20:33:30 +00:00
}
2006-06-05 15:47:36 +00:00
if ( rtp_debug_test_addr ( & rtp - > them ) )
2006-06-09 21:09:42 +00:00
ast_verbose ( " Sent RTP packet to %s:%d (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u) \n " ,
2006-07-21 17:31:28 +00:00
ast_inet_ntoa ( 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 ) ) {
2006-06-06 16:09:33 +00:00
ast_log ( LOG_WARNING , " RTP can only send voice and video \n " ) ;
2002-08-09 17:17:54 +00:00
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 :
2006-07-12 22:42:13 +00:00
case AST_FORMAT_G726_AAL2 :
2004-02-25 04:10:32 +00:00
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 ;
2006-04-14 23:30:18 +00:00
struct ast_channel * who , * other , * 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 ;
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 ) ) ;
2005-08-03 05:00:42 +00:00
/* Lock channels */
2006-04-27 17:53:52 +00:00
ast_channel_lock ( c0 ) ;
while ( ast_channel_trylock ( c1 ) ) {
ast_channel_unlock ( c0 ) ;
2004-08-31 21:55:19 +00:00
usleep ( 1 ) ;
2006-04-27 17:53:52 +00:00
ast_channel_lock ( c0 ) ;
2004-08-31 21:55:19 +00:00
}
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 ) ;
2006-04-27 17:53:52 +00:00
ast_channel_unlock ( c0 ) ;
ast_channel_unlock ( c1 ) ;
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 ) ;
2006-04-27 17:53:52 +00:00
ast_channel_unlock ( c0 ) ;
ast_channel_unlock ( c1 ) ;
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 ) ;
2006-04-14 23:30:18 +00:00
vp0 = pr0 - > get_vrtp_info ? pr0 - > get_vrtp_info ( c0 ) : NULL ;
2003-02-16 06:00:12 +00:00
p1 = pr1 - > get_rtp_info ( c1 ) ;
2006-04-14 23:30:18 +00:00
vp1 = pr1 - > get_vrtp_info ? pr1 - > get_vrtp_info ( c1 ) : 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... */
2006-04-27 17:53:52 +00:00
ast_channel_unlock ( c0 ) ;
ast_channel_unlock ( c1 ) ;
2005-08-09 01:59:59 +00:00
return AST_BRIDGE_FAILED_NOWARN ;
2003-02-16 06:00:12 +00:00
}
2006-05-16 22:11:02 +00:00
if ( ast_test_flag ( p0 , FLAG_HAS_DTMF ) & & ( flags & AST_BRIDGE_DTMF_CHANNEL_0 ) ) {
/* can't bridge, we are carrying DTMF for this channel and the bridge
needs it
*/
ast_channel_unlock ( c0 ) ;
ast_channel_unlock ( c1 ) ;
return AST_BRIDGE_FAILED_NOWARN ;
}
if ( ast_test_flag ( p1 , FLAG_HAS_DTMF ) & & ( flags & AST_BRIDGE_DTMF_CHANNEL_1 ) ) {
/* can't bridge, we are carrying DTMF for this channel and the bridge
needs it
*/
ast_channel_unlock ( c0 ) ;
ast_channel_unlock ( c1 ) ;
return AST_BRIDGE_FAILED_NOWARN ;
}
2005-08-03 05:00:42 +00:00
/* Get codecs from both sides */
2006-04-14 23:30:18 +00:00
codec0 = pr0 - > get_codec ? pr0 - > get_codec ( c0 ) : 0 ;
codec1 = pr1 - > get_codec ? pr1 - > get_codec ( c1 ) : 0 ;
2004-05-27 04:18:46 +00:00
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 ) ;
2006-04-27 17:53:52 +00:00
ast_channel_unlock ( c0 ) ;
ast_channel_unlock ( c1 ) ;
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
}
2006-04-27 17:53:52 +00:00
ast_channel_unlock ( c0 ) ;
ast_channel_unlock ( c1 ) ;
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 " ,
2006-07-21 17:31:28 +00:00
c1 - > name , ast_inet_ntoa ( t1 . sin_addr ) , ntohs ( t1 . sin_port ) , codec1 ) ;
2004-12-28 16:43:20 +00:00
ast_log ( LOG_DEBUG , " Oooh, '%s' changed end vaddress to %s:%d (format %d) \n " ,
2006-07-21 17:31:28 +00:00
c1 - > name , ast_inet_ntoa ( vt1 . sin_addr ) , ntohs ( vt1 . sin_port ) , codec1 ) ;
2004-12-28 16:43:20 +00:00
ast_log ( LOG_DEBUG , " Oooh, '%s' was %s:%d/(format %d) \n " ,
2006-07-21 17:31:28 +00:00
c1 - > name , ast_inet_ntoa ( 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 " ,
2006-07-21 17:31:28 +00:00
c1 - > name , ast_inet_ntoa ( vac1 . sin_addr ) , ntohs ( vac1 . sin_port ) , oldcodec1 ) ;
2004-12-28 16:43:20 +00:00
}
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 " ,
2006-07-21 17:31:28 +00:00
c0 - > name , ast_inet_ntoa ( t0 . sin_addr ) , ntohs ( t0 . sin_port ) , codec0 ) ;
2004-12-28 16:43:20 +00:00
ast_log ( LOG_DEBUG , " Oooh, '%s' was %s:%d/(format %d) \n " ,
2006-07-21 17:31:28 +00:00
c0 - > name , ast_inet_ntoa ( ac0 . sin_addr ) , ntohs ( ac0 . sin_port ) , oldcodec0 ) ;
2004-12-28 16:43:20 +00:00
}
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 ) ;
2006-04-14 23:30:18 +00:00
other = ( who = = c0 ) ? c1 : c0 ; /* the other channel */
2003-02-16 06:00:12 +00:00
if ( ! f | | ( ( f - > frametype = = AST_FRAME_DTMF ) & &
( ( ( who = = c0 ) & & ( flags & AST_BRIDGE_DTMF_CHANNEL_0 ) ) | |
( ( who = = c1 ) & & ( flags & AST_BRIDGE_DTMF_CHANNEL_1 ) ) ) ) ) {
2006-04-14 23:30:18 +00:00
/* breaking out of the bridge. */
2003-02-16 06:00:12 +00:00
* 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 ) ) {
2006-04-14 23:30:18 +00:00
ast_indicate ( other , f - > subclass ) ;
2005-08-30 02:12:09 +00:00
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 */
2006-04-14 23:30:18 +00:00
ast_write ( other , f ) ;
2003-03-15 06:00:16 +00:00
}
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 ;
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 )
2006-07-21 17:31:28 +00:00
ast_cli ( fd , " RTP Debugging Enabled for IP: %s \n " , ast_inet_ntoa ( rtpdebugaddr . sin_addr ) ) ;
2004-10-30 01:52:12 +00:00
else
2006-07-21 17:31:28 +00:00
ast_cli ( fd , " RTP Debugging Enabled for IP: %s:%d \n " , ast_inet_ntoa ( rtpdebugaddr . sin_addr ) , port ) ;
2004-10-30 01:52:12 +00:00
rtpdebug = 1 ;
return RESULT_SUCCESS ;
}
2006-06-05 08:39:42 +00:00
static int rtcp_do_debug_ip ( int fd , int argc , char * argv [ ] )
{
struct hostent * hp ;
struct ast_hostent ahp ;
int port = 0 ;
char * p , * arg ;
if ( argc ! = 5 )
return RESULT_SHOWUSAGE ;
arg = argv [ 4 ] ;
p = strstr ( arg , " : " ) ;
if ( p ) {
* p = ' \0 ' ;
p + + ;
port = atoi ( p ) ;
}
hp = ast_gethostbyname ( arg , & ahp ) ;
if ( hp = = NULL )
return RESULT_SHOWUSAGE ;
rtcpdebugaddr . sin_family = AF_INET ;
memcpy ( & rtcpdebugaddr . sin_addr , hp - > h_addr , sizeof ( rtcpdebugaddr . sin_addr ) ) ;
rtcpdebugaddr . sin_port = htons ( port ) ;
if ( port = = 0 )
2006-07-21 17:31:28 +00:00
ast_cli ( fd , " RTCP Debugging Enabled for IP: %s \n " , ast_inet_ntoa ( rtcpdebugaddr . sin_addr ) ) ;
2006-06-05 08:39:42 +00:00
else
2006-07-21 17:31:28 +00:00
ast_cli ( fd , " RTCP Debugging Enabled for IP: %s:%d \n " , ast_inet_ntoa ( rtcpdebugaddr . sin_addr ) , port ) ;
2006-06-05 08:39:42 +00:00
rtcpdebug = 1 ;
return RESULT_SUCCESS ;
}
2004-10-30 01:52:12 +00:00
static int rtp_do_debug ( int fd , int argc , char * argv [ ] )
{
2006-06-05 15:47:36 +00:00
if ( argc ! = 2 ) {
if ( argc ! = 4 )
2004-10-30 01:52:12 +00:00
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 ;
}
2006-06-05 15:47:36 +00:00
static int rtcp_do_debug ( int fd , int argc , char * argv [ ] ) {
if ( argc ! = 3 ) {
if ( argc ! = 5 )
2006-06-05 08:39:42 +00:00
return RESULT_SHOWUSAGE ;
return rtcp_do_debug_ip ( fd , argc , argv ) ;
}
rtcpdebug = 1 ;
memset ( & rtcpdebugaddr , 0 , sizeof ( rtcpdebugaddr ) ) ;
ast_cli ( fd , " RTCP Debugging Enabled \n " ) ;
return RESULT_SUCCESS ;
}
2006-06-05 15:47:36 +00:00
static int rtcp_do_stats ( int fd , int argc , char * argv [ ] ) {
if ( argc ! = 3 ) {
2006-06-05 08:39:42 +00:00
return RESULT_SHOWUSAGE ;
}
rtcpstats = 1 ;
ast_cli ( fd , " RTCP Stats Enabled \n " ) ;
return RESULT_SUCCESS ;
}
2004-10-30 01:52:12 +00:00
static int rtp_no_debug ( int fd , int argc , char * argv [ ] )
{
2006-06-05 15:47:36 +00:00
if ( argc ! = 3 )
2004-10-30 01:52:12 +00:00
return RESULT_SHOWUSAGE ;
rtpdebug = 0 ;
ast_cli ( fd , " RTP Debugging Disabled \n " ) ;
return RESULT_SUCCESS ;
}
2006-06-05 08:39:42 +00:00
static int rtcp_no_debug ( int fd , int argc , char * argv [ ] )
{
2006-06-05 15:47:36 +00:00
if ( argc ! = 4 )
2006-06-05 08:39:42 +00:00
return RESULT_SHOWUSAGE ;
rtcpdebug = 0 ;
ast_cli ( fd , " RTCP Debugging Disabled \n " ) ;
return RESULT_SUCCESS ;
}
static int rtcp_no_stats ( int fd , int argc , char * argv [ ] )
{
2006-06-05 15:47:36 +00:00
if ( argc ! = 4 )
2006-06-05 08:39:42 +00:00
return RESULT_SHOWUSAGE ;
rtcpstats = 0 ;
ast_cli ( fd , " RTCP Stats Disabled \n " ) ;
return RESULT_SUCCESS ;
}
2006-05-11 14:56:52 +00:00
static int stun_do_debug ( int fd , int argc , char * argv [ ] )
{
2006-06-05 15:47:36 +00:00
if ( argc ! = 2 ) {
2006-05-11 14:56:52 +00:00
return RESULT_SHOWUSAGE ;
}
stundebug = 1 ;
ast_cli ( fd , " STUN Debugging Enabled \n " ) ;
return RESULT_SUCCESS ;
}
static int stun_no_debug ( int fd , int argc , char * argv [ ] )
{
2006-06-05 15:47:36 +00:00
if ( argc ! = 3 )
2006-05-11 14:56:52 +00:00
return RESULT_SHOWUSAGE ;
stundebug = 0 ;
ast_cli ( fd , " STUN Debugging Disabled \n " ) ;
return RESULT_SUCCESS ;
}
2004-10-30 01:52:12 +00:00
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 " ;
2006-05-11 14:56:52 +00:00
static char stun_debug_usage [ ] =
" Usage: stun debug \n "
" Enable STUN (Simple Traversal of UDP through NATs) debugging \n " ;
static char stun_no_debug_usage [ ] =
" Usage: stun no debug \n "
" Disable STUN debugging \n " ;
2004-10-30 01:52:12 +00:00
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-06-05 08:39:42 +00:00
static char rtcp_debug_usage [ ] =
" Usage: rtp rtcp debug [ip host[:port]] \n "
" Enable dumping of all RTCP packets to and from host. \n " ;
static char rtcp_no_debug_usage [ ] =
" Usage: rtp rtcp no debug \n "
" Disable all RTCP debugging \n " ;
static char rtcp_stats_usage [ ] =
" Usage: rtp rtcp stats \n "
" Enable dumping of RTCP stats. \n " ;
static char rtcp_no_stats_usage [ ] =
" Usage: rtp rtcp no stats \n "
" Disable all RTCP stats \n " ;
static struct ast_cli_entry cli_debug_ip_rtcp =
{ { " rtp " , " rtcp " , " debug " , " ip " , NULL } , rtcp_do_debug , " Enable RTCP debugging on IP " , rtcp_debug_usage } ;
static struct ast_cli_entry cli_debug_rtcp =
{ { " rtp " , " rtcp " , " debug " , NULL } , rtcp_do_debug , " Enable RTCP debugging " , rtcp_debug_usage } ;
static struct ast_cli_entry cli_no_debug_rtcp =
{ { " rtp " , " rtcp " , " no " , " debug " , NULL } , rtcp_no_debug , " Disable RTCP debugging " , rtcp_no_debug_usage } ;
static struct ast_cli_entry cli_stats_rtcp =
{ { " rtp " , " rtcp " , " stats " , NULL } , rtcp_do_stats , " Enable RTCP stats " , rtcp_stats_usage } ;
static struct ast_cli_entry cli_no_stats_rtcp =
{ { " rtp " , " rtcp " , " no " , " stats " , NULL } , rtcp_no_stats , " Disable RTCP stats " , rtcp_no_stats_usage } ;
2006-05-11 14:56:52 +00:00
static struct ast_cli_entry cli_stun_debug =
{ { " stun " , " debug " , NULL } , stun_do_debug , " Enable STUN debugging " , stun_debug_usage } ;
static struct ast_cli_entry cli_stun_no_debug =
{ { " stun " , " no " , " debug " , NULL } , stun_no_debug , " Disable STUN debugging " , stun_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 ;
}
2006-06-05 08:39:42 +00:00
if ( ( s = ast_variable_retrieve ( cfg , " general " , " rtcpinterval " ) ) ) {
rtcpinterval = atoi ( s ) ;
if ( rtcpinterval = = 0 )
rtcpinterval = 0 ; /* Just so we're clear... it's zero */
if ( rtcpinterval < RTCP_MIN_INTERVALMS )
rtcpinterval = RTCP_MIN_INTERVALMS ; /* This catches negative numbers too */
if ( rtcpinterval > RTCP_MAX_INTERVALMS )
rtcpinterval = RTCP_MAX_INTERVALMS ;
}
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 ) ;
2006-06-05 08:39:42 +00:00
ast_cli_register ( & cli_debug_rtcp ) ;
ast_cli_register ( & cli_debug_ip_rtcp ) ;
ast_cli_register ( & cli_no_debug_rtcp ) ;
ast_cli_register ( & cli_stats_rtcp ) ;
ast_cli_register ( & cli_no_stats_rtcp ) ;
2006-05-11 14:56:52 +00:00
ast_cli_register ( & cli_stun_debug ) ;
ast_cli_register ( & cli_stun_no_debug ) ;
2003-05-16 02:50:46 +00:00
ast_rtp_reload ( ) ;
}
2006-06-05 08:39:42 +00:00