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"
2007-04-30 16:16:26 +00:00
# include "asterisk/netsock.h"
2005-04-21 06:02:45 +00:00
# include "asterisk/cli.h"
2007-06-21 23:07:20 +00:00
# include "asterisk/manager.h"
2005-04-21 06:02:45 +00:00
# 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-12-27 22:14:33 +00:00
static int rtpstart ; /*!< First port for RTP sessions (set in rtp.conf) */
static int rtpend ; /*!< Last port for RTP sessions (set in rtp.conf) */
static int rtpdebug ; /*!< Are we debugging? */
static int rtcpdebug ; /*!< Are we debugging RTCP? */
static int rtcpstats ; /*!< Are we debugging RTCP? */
2006-06-05 08:39:42 +00:00
static int rtcpinterval = RTCP_DEFAULT_INTERVALMS ; /*!< Time between rtcp reports in millisecs */
2006-12-27 22:14:33 +00:00
static int stundebug ; /*!< 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
2006-12-27 22:14:33 +00:00
static int nochecksums ;
2004-07-19 18:09:33 +00:00
# endif
2003-05-16 02:50:46 +00:00
2007-01-08 18:23:39 +00:00
/* Uncomment this to enable more intense native bridging, but note: this is currently buggy */
/* #define P2P_INTENSE */
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 ;
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 lastrxts ;
unsigned int lastividtimestamp ;
unsigned int lastovidtimestamp ;
2007-02-16 13:35:44 +00:00
unsigned int lastitexttimestamp ;
unsigned int lastotexttimestamp ;
2006-06-08 23:10:45 +00:00
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 */
int lasttxformat ;
int lastrxformat ;
2006-12-02 12:05:40 +00:00
int rtptimeout ; /*!< RTP timeout time (negative or zero means disabled, negative value means temporarily disabled) */
int rtpholdtimeout ; /*!< RTP timeout when on hold (negative or zero means disabled, negative value means temporarily disabled). */
int rtpkeepalive ; /*!< Send RTP comfort noice packets for keepalive */
2006-08-31 01:59:02 +00:00
/* DTMF Reception Variables */
char resp ;
2007-03-12 01:22:29 +00:00
unsigned int lastevent ;
2006-06-08 23:10:45 +00:00
int dtmfcount ;
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
unsigned int dtmfsamples ;
2006-08-31 01:59:02 +00:00
/* DTMF Transmission Variables */
unsigned int lastdigitts ;
2007-04-18 20:48:13 +00:00
char sending_digit ; /*!< boolean - are we sending digits */
char send_digit ; /*!< digit we are sending */
2006-08-31 01:59:02 +00:00
int send_payload ;
2006-09-09 18:07:59 +00:00
int send_duration ;
2006-06-08 23:10:45 +00:00
int nat ;
After some study, thought, comparing, etc. I've backed out the previous universal mod to make ast_flags a 64 bit thing. Instead, I added a 64-bit version of ast_flags (ast_flags64), and 64-bit versions of the test-flag, set-flag, etc. macros, and an app_parse_options64 routine, and I use these in app_dial alone, to eliminate the 30-option limit it had grown to meet. There is room now for 32 more options and flags. I was heavily tempted to implement some of the other ideas that were presented, but this solution does not intro any new versions of dial, doesn't have a different API, has a minimal/zero impact on code outside of dial, and doesn't seriously (I hope) affect the code structure of dial. It's the best I can think of right now. My goal was NOT to rewrite dial. I leave that to a future, coordinated effort.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@75983 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-07-19 23:24:27 +00:00
unsigned int flags ;
2006-06-08 23:10:45 +00:00
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 ;
2007-01-29 21:03:07 +00:00
# ifdef P2P_INTENSE
2006-12-15 19:57:04 +00:00
ast_mutex_t bridge_lock ;
2007-01-29 21:03:07 +00:00
# endif
2006-06-08 23:10:45 +00:00
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-09-18 23:32:57 +00:00
struct ast_codec_pref pref ;
2006-09-01 18:57:10 +00:00
struct ast_rtp * bridged ; /*!< Who we are Packet bridged to */
2006-06-08 23:10:45 +00:00
} ;
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 ) ;
2006-08-31 01:59:02 +00:00
static int ast_rtp_senddigit_continuation ( struct ast_rtp * rtp ) ;
int ast_rtp_senddigit_end ( struct ast_rtp * rtp , char digit ) ;
2006-06-05 08:39:42 +00:00
2005-09-07 20:33:30 +00:00
# define FLAG_3389_WARNING (1 << 0)
# define FLAG_NAT_ACTIVE (3 << 1)
# define FLAG_NAT_INACTIVE (0 << 1)
# define FLAG_NAT_INACTIVE_NOWARN (1 << 1)
2006-05-16 22:11:02 +00:00
# define FLAG_HAS_DTMF (1 << 3)
2006-08-28 17:37:56 +00:00
# define FLAG_P2P_SENT_MARK (1 << 4)
# define FLAG_P2P_NEED_DTMF (1 << 5)
2006-08-30 01:29:59 +00:00
# define FLAG_CALLBACK_MODE (1 << 6)
2006-08-31 01:59:02 +00:00
# define FLAG_DTMF_COMPENSATE (1 << 7)
2006-11-30 21:22:01 +00:00
# define FLAG_HAS_STUN (1 << 8)
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
} ;
2007-07-11 16:24:35 +00:00
/*!
* \ brief STUN support code
*
* This code provides some support for doing STUN transactions .
* Eventually it should be moved elsewhere as other protocols
* than RTP can benefit from it - e . g . SIP .
* STUN is described in RFC3489 and it is based on the exchange
* of UDP packets between a client and one or more servers to
* determine the externally visible address ( and port ) of the client
* once it has gone through the NAT boxes that connect it to the
* outside .
* The simplest request packet is just the header defined in
* struct stun_header , and from the response we may just look at
* one attribute , STUN_MAPPED_ADDRESS , that we find in the response .
* By doing more transactions with different server addresses we
* may determine more about the behaviour of the NAT boxes , of
* course - the details are in the RFC .
*
* All STUN packets start with a simple header made of a type ,
* length ( excluding the header ) and a 16 - byte random transaction id .
* Following the header we may have zero or more attributes , each
* structured as a type , length and a value ( whose format depends
* on the type , but often contains addresses ) .
* Of course all fields are in network format .
*/
2006-05-11 14:56:52 +00:00
typedef struct { unsigned int id [ 4 ] ; } __attribute__ ( ( packed ) ) stun_trans_id ;
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 ) ) ;
2007-07-11 16:24:35 +00:00
/*
* The format normally used for addresses carried by STUN messages .
*/
2006-05-11 14:56:52 +00:00
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)
2007-07-11 16:24:35 +00:00
/*! \brief STUN message types
* ' BIND ' refers to transactions used to determine the externally
* visible addresses . ' SEC ' refers to transactions used to establish
* a session key for subsequent requests .
* ' SEC ' functionality is not supported here .
*/
2006-05-11 14:56:52 +00:00
# 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
2007-07-11 16:24:35 +00:00
/*! \brief Basic attribute types in stun messages.
* Messages can also contain custom attributes ( codes above 0x7fff )
*/
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
2007-07-11 16:24:35 +00:00
/*! \brief helper function to print message names */
2006-05-11 14:56:52 +00:00
static const char * stun_msg2str ( int msg )
{
2007-01-22 23:51:42 +00:00
switch ( msg ) {
2006-05-11 14:56:52 +00:00
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 " ;
}
2007-07-11 16:24:35 +00:00
/*! \brief helper function to print attribute names */
2006-05-11 14:56:52 +00:00
static const char * stun_attr2str ( int msg )
{
2007-01-22 23:51:42 +00:00
switch ( msg ) {
2006-05-11 14:56:52 +00:00
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 " ;
}
2007-07-11 16:24:35 +00:00
/*! \brief here we store credentials extracted from a message */
2006-05-11 14:56:52 +00:00
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 " ,
2007-01-22 23:51:42 +00:00
stun_attr2str ( ntohs ( attr - > attr ) ) , ntohs ( attr - > attr ) , ntohs ( attr - > len ) ) ;
switch ( ntohs ( attr - > attr ) ) {
2006-05-11 14:56:52 +00:00
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 " ,
2007-01-22 23:51:42 +00:00
stun_attr2str ( ntohs ( attr - > attr ) ) , ntohs ( attr - > attr ) , ntohs ( attr - > len ) ) ;
2006-05-11 14:56:52 +00:00
}
return 0 ;
}
2007-07-11 16:24:35 +00:00
/*! \brief append a string to an STUN message */
2006-05-11 14:56:52 +00:00
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 ;
}
}
2007-07-11 16:24:35 +00:00
/*! \brief append an address to an STUN message */
2006-05-11 14:56:52 +00:00
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 ;
}
}
2007-07-11 16:24:35 +00:00
/*! \brief wrapper to send an STUN message */
2006-05-11 14:56:52 +00:00
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 ,
2007-01-22 23:51:42 +00:00
( struct sockaddr * ) dst , sizeof ( * dst ) ) ;
2006-05-11 14:56:52 +00:00
}
2007-07-11 16:24:35 +00:00
/*! \brief helper function to generate a random request id */
2006-05-11 14:56:52 +00:00
static void stun_req_id ( struct stun_header * req )
{
int x ;
2007-01-22 23:51:42 +00:00
for ( x = 0 ; x < 4 ; x + + )
2006-05-11 14:56:52 +00:00
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 ) ;
}
Small improvement to the STUN support so it can be used by
sockets other than RTP ones.
The main change is a new API function in main/rtp.c (see there
for a description)
int ast_stun_request(int s, struct sockaddr_in *dst,
const char *username, struct sockaddr_in *answer)
which can be used to send an STUN request on a socket, and
optionally wait for a reply and store the STUN_MAPPED_ADDRESS
into the 'answer' argument (obviously, the version that
waits for a reply is blocking, but this is no different
from DNS resolutions).
Internally there are minor modifications to let stun_handle_packet()
be somewhat configurable on how to parse the body of responses.
At the moment i am not committing any change to the clients,
but adding STUN client support is extremely simple, e.g. chan_sip.c
could do something like this:
+ add a variable to store the stun server address;
static struct sockaddr_in stunaddr = { 0, }; /*!< stun server address */
+ add code to parse a config file of the form "stunaddr=my.stun.server.org:3478"
(not shown for brevity);
+ right after binding the main sip socket, talk to the stun server to
determine the externally visible address
if (stunaddr.sin_addr.s_addr != 0)
ast_stun_request(sipsock, &stunaddr, NULL, &externip);
so now 'externip' is set with the externally visible address.
so it is really trivial.
Similarly ast_stun_request could be called when creating the RTP
socket (possibly adding a struct sockaddr_in field in the struct
ast_rtp to store the externalip).
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@75034 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-07-13 16:22:09 +00:00
/*! \brief callback type to be invoked on stun responses. */
typedef int ( stun_cb_f ) ( struct stun_attr * attr , void * arg ) ;
2006-05-11 14:56:52 +00:00
2007-07-11 16:24:35 +00:00
/*! \brief handle an incoming STUN message.
*
* Do some basic sanity checks on packet size and content ,
* try to extract a bit of information , and possibly reply .
* At the moment this only processes BIND requests , and returns
* the externally visible address of the request .
Small improvement to the STUN support so it can be used by
sockets other than RTP ones.
The main change is a new API function in main/rtp.c (see there
for a description)
int ast_stun_request(int s, struct sockaddr_in *dst,
const char *username, struct sockaddr_in *answer)
which can be used to send an STUN request on a socket, and
optionally wait for a reply and store the STUN_MAPPED_ADDRESS
into the 'answer' argument (obviously, the version that
waits for a reply is blocking, but this is no different
from DNS resolutions).
Internally there are minor modifications to let stun_handle_packet()
be somewhat configurable on how to parse the body of responses.
At the moment i am not committing any change to the clients,
but adding STUN client support is extremely simple, e.g. chan_sip.c
could do something like this:
+ add a variable to store the stun server address;
static struct sockaddr_in stunaddr = { 0, }; /*!< stun server address */
+ add code to parse a config file of the form "stunaddr=my.stun.server.org:3478"
(not shown for brevity);
+ right after binding the main sip socket, talk to the stun server to
determine the externally visible address
if (stunaddr.sin_addr.s_addr != 0)
ast_stun_request(sipsock, &stunaddr, NULL, &externip);
so now 'externip' is set with the externally visible address.
so it is really trivial.
Similarly ast_stun_request could be called when creating the RTP
socket (possibly adding a struct sockaddr_in field in the struct
ast_rtp to store the externalip).
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@75034 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-07-13 16:22:09 +00:00
* If a callback is specified , invoke it with the attribute .
2007-07-11 16:24:35 +00:00
*/
Small improvement to the STUN support so it can be used by
sockets other than RTP ones.
The main change is a new API function in main/rtp.c (see there
for a description)
int ast_stun_request(int s, struct sockaddr_in *dst,
const char *username, struct sockaddr_in *answer)
which can be used to send an STUN request on a socket, and
optionally wait for a reply and store the STUN_MAPPED_ADDRESS
into the 'answer' argument (obviously, the version that
waits for a reply is blocking, but this is no different
from DNS resolutions).
Internally there are minor modifications to let stun_handle_packet()
be somewhat configurable on how to parse the body of responses.
At the moment i am not committing any change to the clients,
but adding STUN client support is extremely simple, e.g. chan_sip.c
could do something like this:
+ add a variable to store the stun server address;
static struct sockaddr_in stunaddr = { 0, }; /*!< stun server address */
+ add code to parse a config file of the form "stunaddr=my.stun.server.org:3478"
(not shown for brevity);
+ right after binding the main sip socket, talk to the stun server to
determine the externally visible address
if (stunaddr.sin_addr.s_addr != 0)
ast_stun_request(sipsock, &stunaddr, NULL, &externip);
so now 'externip' is set with the externally visible address.
so it is really trivial.
Similarly ast_stun_request could be called when creating the RTP
socket (possibly adding a struct sockaddr_in field in the struct
ast_rtp to store the externalip).
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@75034 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-07-13 16:22:09 +00:00
static int stun_handle_packet ( int s , struct sockaddr_in * src ,
unsigned char * data , size_t len , stun_cb_f * stun_cb , void * arg )
2006-05-11 14:56:52 +00:00
{
2007-07-12 16:21:12 +00:00
struct stun_header * hdr = ( struct stun_header * ) data ;
2006-05-11 14:56:52 +00:00
struct stun_attr * attr ;
struct stun_state st ;
int ret = STUN_IGNORE ;
2007-07-12 16:21:12 +00:00
int x ;
/* On entry, 'len' is the length of the udp payload. After the
* initial checks it becomes the size of unprocessed options ,
* while ' data ' is advanced accordingly .
*/
2006-05-11 14:56:52 +00:00
if ( len < sizeof ( struct stun_header ) ) {
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " Runt STUN packet (only %d, wanting at least %d) \n " , ( int ) len , ( int ) sizeof ( struct stun_header ) ) ;
2006-05-11 14:56:52 +00:00
return - 1 ;
}
2007-07-12 16:21:12 +00:00
len - = sizeof ( struct stun_header ) ;
data + = sizeof ( struct stun_header ) ;
x = ntohs ( hdr - > msglen ) ; /* len as advertised in the message */
2006-05-11 14:56:52 +00:00
if ( stundebug )
2007-07-12 16:21:12 +00:00
ast_verbose ( " STUN Packet, msg %s (%04x), length: %d \n " , stun_msg2str ( ntohs ( hdr - > msgtype ) ) , ntohs ( hdr - > msgtype ) , x ) ;
if ( x > len ) {
ast_debug ( 1 , " Scrambled STUN packet length (got %d, expecting %d) \n " , x , ( int ) len ) ;
2006-05-11 14:56:52 +00:00
} else
2007-07-12 16:21:12 +00:00
len = x ;
2006-05-11 14:56:52 +00:00
memset ( & st , 0 , sizeof ( st ) ) ;
2007-01-22 23:51:42 +00:00
while ( len ) {
2006-05-11 14:56:52 +00:00
if ( len < sizeof ( struct stun_attr ) ) {
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " Runt Attribute (got %d, expecting %d) \n " , ( int ) len , ( int ) sizeof ( struct stun_attr ) ) ;
2006-05-11 14:56:52 +00:00
break ;
}
attr = ( struct stun_attr * ) data ;
2007-07-12 16:21:12 +00:00
/* compute total attribute length */
x = ntohs ( attr - > len ) + sizeof ( struct stun_attr ) ;
if ( x > len ) {
ast_debug ( 1 , " Inconsistent Attribute (length %d exceeds remaining msg len %d) \n " , x , ( int ) len ) ;
2006-05-11 14:56:52 +00:00
break ;
}
Small improvement to the STUN support so it can be used by
sockets other than RTP ones.
The main change is a new API function in main/rtp.c (see there
for a description)
int ast_stun_request(int s, struct sockaddr_in *dst,
const char *username, struct sockaddr_in *answer)
which can be used to send an STUN request on a socket, and
optionally wait for a reply and store the STUN_MAPPED_ADDRESS
into the 'answer' argument (obviously, the version that
waits for a reply is blocking, but this is no different
from DNS resolutions).
Internally there are minor modifications to let stun_handle_packet()
be somewhat configurable on how to parse the body of responses.
At the moment i am not committing any change to the clients,
but adding STUN client support is extremely simple, e.g. chan_sip.c
could do something like this:
+ add a variable to store the stun server address;
static struct sockaddr_in stunaddr = { 0, }; /*!< stun server address */
+ add code to parse a config file of the form "stunaddr=my.stun.server.org:3478"
(not shown for brevity);
+ right after binding the main sip socket, talk to the stun server to
determine the externally visible address
if (stunaddr.sin_addr.s_addr != 0)
ast_stun_request(sipsock, &stunaddr, NULL, &externip);
so now 'externip' is set with the externally visible address.
so it is really trivial.
Similarly ast_stun_request could be called when creating the RTP
socket (possibly adding a struct sockaddr_in field in the struct
ast_rtp to store the externalip).
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@75034 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-07-13 16:22:09 +00:00
if ( stun_cb )
stun_cb ( attr , arg ) ;
2006-05-11 14:56:52 +00:00
if ( stun_process_attr ( & st , attr ) ) {
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " Failed to handle attribute %s (%04x) \n " , stun_attr2str ( ntohs ( attr - > attr ) ) , ntohs ( attr - > attr ) ) ;
2006-05-11 14:56:52 +00:00
break ;
}
2007-07-12 16:21:12 +00:00
/* Clear attribute id: in case previous entry was a string,
* this will act as the terminator for the string .
*/
2006-05-11 14:56:52 +00:00
attr - > attr = 0 ;
2007-07-12 16:21:12 +00:00
data + = x ;
len - = x ;
2006-05-11 14:56:52 +00:00
}
2007-07-12 16:21:12 +00:00
/* Null terminate any string.
* XXX NOTE , we write past the size of the buffer passed by the
* caller , so this is potentially dangerous . The only thing that
* saves us is that usually we read the incoming message in a
* much larger buffer in the struct ast_rtp
*/
2006-05-11 14:56:52 +00:00
* data = ' \0 ' ;
2007-07-12 16:21:12 +00:00
/* Now prepare to generate a reply, which at the moment is done
* only for properly formed ( len = = 0 ) STUN_BINDREQ messages .
*/
if ( len = = 0 ) {
unsigned char respdata [ 1024 ] ;
struct stun_header * resp = ( struct stun_header * ) respdata ;
int resplen = 0 ; /* len excluding header */
int respleft = sizeof ( respdata ) - sizeof ( struct stun_header ) ;
resp - > id = hdr - > id ;
resp - > msgtype = 0 ;
resp - > msglen = 0 ;
attr = ( struct stun_attr * ) resp - > ies ;
2007-01-22 23:51:42 +00:00
switch ( ntohs ( hdr - > msgtype ) ) {
2006-05-11 14:56:52 +00:00
case STUN_BINDREQ :
if ( stundebug )
ast_verbose ( " STUN Bind Request, username: %s \n " ,
2007-01-22 23:51:42 +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 ;
}
Small improvement to the STUN support so it can be used by
sockets other than RTP ones.
The main change is a new API function in main/rtp.c (see there
for a description)
int ast_stun_request(int s, struct sockaddr_in *dst,
const char *username, struct sockaddr_in *answer)
which can be used to send an STUN request on a socket, and
optionally wait for a reply and store the STUN_MAPPED_ADDRESS
into the 'answer' argument (obviously, the version that
waits for a reply is blocking, but this is no different
from DNS resolutions).
Internally there are minor modifications to let stun_handle_packet()
be somewhat configurable on how to parse the body of responses.
At the moment i am not committing any change to the clients,
but adding STUN client support is extremely simple, e.g. chan_sip.c
could do something like this:
+ add a variable to store the stun server address;
static struct sockaddr_in stunaddr = { 0, }; /*!< stun server address */
+ add code to parse a config file of the form "stunaddr=my.stun.server.org:3478"
(not shown for brevity);
+ right after binding the main sip socket, talk to the stun server to
determine the externally visible address
if (stunaddr.sin_addr.s_addr != 0)
ast_stun_request(sipsock, &stunaddr, NULL, &externip);
so now 'externip' is set with the externally visible address.
so it is really trivial.
Similarly ast_stun_request could be called when creating the RTP
socket (possibly adding a struct sockaddr_in field in the struct
ast_rtp to store the externalip).
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@75034 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-07-13 16:22:09 +00:00
/*! \brief Extract the STUN_MAPPED_ADDRESS from the stun response.
* This is used as a callback for stun_handle_response
* when called from ast_stun_request .
*/
static int stun_get_mapped ( struct stun_attr * attr , void * arg )
{
struct stun_addr * addr = ( struct stun_addr * ) ( attr + 1 ) ;
struct sockaddr_in * sa = ( struct sockaddr_in * ) arg ;
if ( ntohs ( attr - > attr ) ! = STUN_MAPPED_ADDRESS | | ntohs ( attr - > len ) ! = 8 )
return 1 ; /* not us. */
sa - > sin_port = addr - > port ;
sa - > sin_addr . s_addr = addr - > addr ;
return 0 ;
}
/*! \brief Generic STUN request
* Send a generic stun request to the server specified ,
* possibly waiting for a reply and filling the ' reply ' field with
* the externally visible address . Note that in this case the request
* will be blocking .
* ( Note , the interface may change slightly in the future ) .
*
* \ param s the socket used to send the request
* \ param dst the address of the STUN server
* \ param username if non null , add the username in the request
* \ param answer if non null , the function waits for a response and
* puts here the externally visible address .
* \ return 0 on success , other values on error .
*/
int ast_stun_request ( int s , struct sockaddr_in * dst ,
const char * username , struct sockaddr_in * answer )
{
struct stun_header * req ;
unsigned char reqdata [ 1024 ] ;
int reqlen , reqleft ;
struct stun_attr * attr ;
int res = 0 ;
int retry ;
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 ) ;
for ( retry = 0 ; retry < 3 ; retry + + ) { /* XXX make retries configurable */
/* send request, possibly wait for reply */
unsigned char reply_buf [ 1024 ] ;
fd_set rfds ;
struct timeval to = { 3 , 0 } ; /* timeout, make it configurable */
struct sockaddr_in src ;
2007-07-13 20:15:16 +00:00
socklen_t srclen ;
Small improvement to the STUN support so it can be used by
sockets other than RTP ones.
The main change is a new API function in main/rtp.c (see there
for a description)
int ast_stun_request(int s, struct sockaddr_in *dst,
const char *username, struct sockaddr_in *answer)
which can be used to send an STUN request on a socket, and
optionally wait for a reply and store the STUN_MAPPED_ADDRESS
into the 'answer' argument (obviously, the version that
waits for a reply is blocking, but this is no different
from DNS resolutions).
Internally there are minor modifications to let stun_handle_packet()
be somewhat configurable on how to parse the body of responses.
At the moment i am not committing any change to the clients,
but adding STUN client support is extremely simple, e.g. chan_sip.c
could do something like this:
+ add a variable to store the stun server address;
static struct sockaddr_in stunaddr = { 0, }; /*!< stun server address */
+ add code to parse a config file of the form "stunaddr=my.stun.server.org:3478"
(not shown for brevity);
+ right after binding the main sip socket, talk to the stun server to
determine the externally visible address
if (stunaddr.sin_addr.s_addr != 0)
ast_stun_request(sipsock, &stunaddr, NULL, &externip);
so now 'externip' is set with the externally visible address.
so it is really trivial.
Similarly ast_stun_request could be called when creating the RTP
socket (possibly adding a struct sockaddr_in field in the struct
ast_rtp to store the externalip).
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@75034 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-07-13 16:22:09 +00:00
res = stun_send ( s , dst , req ) ;
if ( res < 0 ) {
ast_log ( LOG_WARNING , " ast_stun_request send #%d failed error %d, retry \n " ,
retry , res ) ;
continue ;
}
if ( answer = = NULL )
break ;
FD_ZERO ( & rfds ) ;
FD_SET ( s , & rfds ) ;
res = ast_select ( s + 1 , & rfds , NULL , NULL , & to ) ;
if ( res < = 0 ) /* timeout or error */
continue ;
bzero ( & src , sizeof ( src ) ) ;
srclen = sizeof ( src ) ;
/* XXX pass -1 in the size, because stun_handle_packet might
* write past the end of the buffer .
*/
res = recvfrom ( s , reply_buf , sizeof ( reply_buf ) - 1 ,
0 , ( struct sockaddr * ) & src , & srclen ) ;
if ( res < 0 ) {
ast_log ( LOG_WARNING , " ast_stun_request recvfrom #%d failed error %d, retry \n " ,
retry , res ) ;
continue ;
}
bzero ( answer , sizeof ( struct sockaddr_in ) ) ;
stun_handle_packet ( s , & src , reply_buf , res ,
stun_get_mapped , answer ) ;
res = 0 ; /* signal regular exit */
break ;
}
return res ;
}
/*! \brief send a STUN BIND request to the given destination.
* Optionally , add a username if specified .
*/
void ast_rtp_stun_request ( struct ast_rtp * rtp , struct sockaddr_in * suggestion , const char * username )
{
ast_stun_request ( rtp - > s , suggestion , username , NULL ) ;
}
2006-01-03 09:30:19 +00:00
/*! \brief List of current sessions */
2007-01-22 23:53:16 +00:00
static AST_RWLIST_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
2007-01-22 23:51:42 +00:00
* Look in RFC 3550 Section A .7 for an example */
2006-06-05 08:39:42 +00:00
interval = rtcpinterval ;
return interval ;
}
2006-12-02 12:05:40 +00:00
/* \brief Put RTP timeout timers on hold during another transaction, like T.38 */
void ast_rtp_set_rtptimers_onhold ( struct ast_rtp * rtp )
{
rtp - > rtptimeout = ( - 1 ) * rtp - > rtptimeout ;
rtp - > rtpholdtimeout = ( - 1 ) * rtp - > rtpholdtimeout ;
}
/*! \brief Set rtp timeout */
void ast_rtp_set_rtptimeout ( struct ast_rtp * rtp , int timeout )
{
rtp - > rtptimeout = timeout ;
}
/*! \brief Set rtp hold timeout */
void ast_rtp_set_rtpholdtimeout ( struct ast_rtp * rtp , int timeout )
{
rtp - > rtpholdtimeout = timeout ;
}
/*! \brief set RTP keepalive interval */
void ast_rtp_set_rtpkeepalive ( struct ast_rtp * rtp , int period )
{
rtp - > rtpkeepalive = period ;
}
/*! \brief Get rtp timeout */
int ast_rtp_get_rtptimeout ( struct ast_rtp * rtp )
{
if ( rtp - > rtptimeout < 0 ) /* We're not checking, but remembering the setting (during T.38 transmission) */
return 0 ;
return rtp - > rtptimeout ;
}
/*! \brief Get rtp hold timeout */
int ast_rtp_get_rtpholdtimeout ( struct ast_rtp * rtp )
{
if ( rtp - > rtptimeout < 0 ) /* We're not checking, but remembering the setting (during T.38 transmission) */
return 0 ;
return rtp - > rtpholdtimeout ;
}
/*! \brief Get RTP keepalive interval */
int ast_rtp_get_rtpkeepalive ( struct ast_rtp * rtp )
{
return rtp - > rtpkeepalive ;
}
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 ;
}
2007-01-11 05:21:03 +00:00
int ast_rtp_getnat ( struct ast_rtp * rtp )
{
return ast_test_flag ( rtp , FLAG_NAT_ACTIVE ) ;
}
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 ) ;
}
2006-08-31 01:59:02 +00:00
void ast_rtp_setdtmfcompensate ( struct ast_rtp * rtp , int compensate )
{
ast_set2_flag ( rtp , compensate ? 1 : 0 , FLAG_DTMF_COMPENSATE ) ;
}
2006-11-30 21:22:01 +00:00
void ast_rtp_setstun ( struct ast_rtp * rtp , int stun_enable )
{
ast_set2_flag ( rtp , stun_enable ? 1 : 0 , FLAG_HAS_STUN ) ;
}
2007-01-29 21:03:07 +00:00
static void rtp_bridge_lock ( struct ast_rtp * rtp )
{
# ifdef P2P_INTENSE
ast_mutex_lock ( & rtp - > bridge_lock ) ;
# endif
return ;
}
static void rtp_bridge_unlock ( struct ast_rtp * rtp )
{
# ifdef P2P_INTENSE
ast_mutex_unlock ( & rtp - > bridge_lock ) ;
# endif
return ;
}
2006-08-31 01:59:02 +00:00
static struct ast_frame * send_dtmf ( struct ast_rtp * rtp , enum ast_frame_type type )
2002-06-16 16:06:38 +00:00
{
2006-08-31 21:00:16 +00:00
if ( ( ( ast_test_flag ( rtp , FLAG_DTMF_COMPENSATE ) & & type = = AST_FRAME_DTMF_END ) | |
( type = = AST_FRAME_DTMF_BEGIN ) ) & & ast_tvcmp ( ast_tvnow ( ) , rtp - > dtmfmute ) < 0 ) {
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " 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 ;
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
rtp - > dtmfsamples = 0 ;
2006-01-31 17:18:58 +00:00
return & ast_null_frame ;
2004-03-15 16:20:01 +00:00
}
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " 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 {
2006-08-31 01:59:02 +00:00
rtp - > f . frametype = type ;
2004-12-09 14:54:13 +00:00
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 " ;
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 )
2007-01-22 23:51:42 +00:00
& & ( rtpdebugaddr . sin_port ! = addr - > sin_port ) )
| | ( rtpdebugaddr . sin_addr . s_addr ! = addr - > sin_addr . s_addr ) )
return 0 ;
2004-10-30 01:52:12 +00:00
}
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 )
2007-01-22 23:51:42 +00:00
& & ( rtcpdebugaddr . sin_port ! = addr - > sin_port ) )
| | ( rtcpdebugaddr . sin_addr . s_addr ! = addr - > sin_addr . s_addr ) )
return 0 ;
2006-06-05 08:39:42 +00:00
}
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 ;
2006-09-23 18:25:13 +00:00
unsigned char seq ;
After some study, thought, comparing, etc. I've backed out the previous universal mod to make ast_flags a 64 bit thing. Instead, I added a 64-bit version of ast_flags (ast_flags64), and 64-bit versions of the test-flag, set-flag, etc. macros, and an app_parse_options64 routine, and I use these in app_dial alone, to eliminate the 30-option limit it had grown to meet. There is room now for 32 more options and flags. I was heavily tempted to implement some of the other ideas that were presented, but this solution does not intro any new versions of dial, doesn't have a different API, has a minimal/zero impact on code outside of dial, and doesn't seriously (I hope) affect the code structure of dial. It's the best I can think of right now. My goal was NOT to rewrite dial. I leave that to a future, coordinated effort.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@75983 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-07-19 23:24:27 +00:00
unsigned int flags ;
2006-09-23 18:25:13 +00:00
unsigned int power ;
/* We should have at least 4 bytes in RTP data */
if ( len < 4 )
return f ;
/* The format of Cisco RTP DTMF packet looks like next:
+ 0 - sequence number of DTMF RTP packet ( begins from 1 ,
wrapped to 0 )
2006-09-24 12:15:49 +00:00
+ 1 - set of flags
2006-09-23 18:25:13 +00:00
+ 1 ( bit 0 ) - flaps by different DTMF digits delimited by audio
2006-09-24 12:15:49 +00:00
or repeated digit without audio ? ? ?
2006-09-23 18:25:13 +00:00
+ 2 ( + 4 , + 6 , . . . ) - power level ? ( rises from 0 to 32 at begin of tone
then falls to 0 at its end )
+ 3 ( + 5 , + 7 , . . . ) - detected DTMF digit ( 0. .9 , * , # , A - D , . . . )
Repeated DTMF information ( bytes 4 / 5 , 6 / 7 ) is history shifted right
by each new packet and thus provides some redudancy .
Sample of Cisco RTP DTMF packet is ( all data in hex ) :
19 07 00 02 12 02 20 02
showing end of DTMF digit ' 2 ' .
The packets
27 07 00 02 0 A 02 20 02
28 06 20 02 00 02 0 A 02
shows begin of new digit ' 2 ' with very short pause ( 20 ms ) after
previous digit ' 2 ' . Bit + 1.0 flips at begin of new digit .
Cisco RTP DTMF packets comes as replacement of audio RTP packets
so its uses the same sequencing and timestamping rules as replaced
audio packets . Repeat interval of DTMF packets is 20 ms and not rely
on audio framing parameters . Marker bit isn ' t used within stream of
DTMFs nor audio stream coming immediately after DTMF stream . Timestamps
are not sequential at borders between DTMF and audio streams ,
*/
seq = data [ 0 ] ;
2006-09-24 12:15:49 +00:00
flags = data [ 1 ] ;
2006-09-23 18:25:13 +00:00
power = data [ 2 ] ;
event = data [ 3 ] & 0x1f ;
2006-01-03 09:30:19 +00:00
if ( option_debug > 2 | | rtpdebug )
After some study, thought, comparing, etc. I've backed out the previous universal mod to make ast_flags a 64 bit thing. Instead, I added a 64-bit version of ast_flags (ast_flags64), and 64-bit versions of the test-flag, set-flag, etc. macros, and an app_parse_options64 routine, and I use these in app_dial alone, to eliminate the 30-option limit it had grown to meet. There is room now for 32 more options and flags. I was heavily tempted to implement some of the other ideas that were presented, but this solution does not intro any new versions of dial, doesn't have a different API, has a minimal/zero impact on code outside of dial, and doesn't seriously (I hope) affect the code structure of dial. It's the best I can think of right now. My goal was NOT to rewrite dial. I leave that to a future, coordinated effort.
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@75983 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-07-19 23:24:27 +00:00
ast_debug ( 0 , " Cisco DTMF Digit: %02x (len=%d, seq=%d, flags=%02x, power=%d, history count=%d) \n " , event , len , seq , flags , power , ( len - 4 ) / 2 ) ;
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
}
2006-09-23 18:25:13 +00:00
if ( ( ! rtp - > resp & & power ) | | ( rtp - > resp & & ( rtp - > resp ! = resp ) ) ) {
rtp - > resp = resp ;
2006-10-26 17:52:15 +00:00
/* Why we should care on DTMF compensation at reception? */
2006-09-23 18:25:13 +00:00
if ( ! ast_test_flag ( rtp , FLAG_DTMF_COMPENSATE ) ) {
f = send_dtmf ( rtp , AST_FRAME_DTMF_BEGIN ) ;
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
rtp - > dtmfsamples = 0 ;
2006-09-23 18:25:13 +00:00
}
} else if ( ( rtp - > resp = = resp ) & & ! power ) {
2006-08-31 01:59:02 +00:00
f = send_dtmf ( rtp , AST_FRAME_DTMF_END ) ;
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
f - > samples = rtp - > dtmfsamples * 8 ;
2006-09-23 18:25:13 +00:00
rtp - > resp = 0 ;
} else if ( rtp - > resp = = resp )
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
rtp - > dtmfsamples + = 20 * 8 ;
2003-05-02 15:37:34 +00:00
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
2007-06-07 23:07:25 +00:00
* \ param timestamp
2005-10-12 20:45:18 +00:00
* \ returns
*/
2007-03-12 01:22:29 +00:00
static struct ast_frame * process_rfc2833 ( struct ast_rtp * rtp , unsigned char * data , int len , unsigned int seqno , unsigned int timestamp )
2002-06-16 16:06:38 +00:00
{
unsigned int event ;
2003-08-14 21:55:31 +00:00
unsigned int event_end ;
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
unsigned int samples ;
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
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
/* Figure out event, event end, and samples */
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 ;
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
samples = ntohl ( * ( ( unsigned int * ) ( data ) ) ) ;
samples & = 0xFFFF ;
2006-08-31 01:59:02 +00:00
/* Print out debug if turned on */
2006-01-03 09:30:19 +00:00
if ( rtpdebug | | option_debug > 2 )
2007-06-25 13:42:51 +00:00
ast_debug ( 0 , " - RTP 2833 Event: %08x (len = %d) \n " , event , len ) ;
2006-08-31 01:59:02 +00:00
/* Figure out what digit was pressed */
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
}
2007-01-22 23:51:42 +00:00
2007-03-12 01:22:29 +00:00
if ( ast_test_flag ( rtp , FLAG_DTMF_COMPENSATE ) ) {
if ( ( rtp - > lastevent ! = timestamp ) | | ( rtp - > resp & & rtp - > resp ! = resp ) ) {
rtp - > resp = resp ;
f = send_dtmf ( rtp , AST_FRAME_DTMF_END ) ;
f - > len = 0 ;
rtp - > lastevent = timestamp ;
}
} else {
if ( ( ! ( rtp - > resp ) & & ( ! ( event_end & 0x80 ) ) ) | | ( rtp - > resp & & rtp - > resp ! = resp ) ) {
rtp - > resp = resp ;
2006-08-31 01:59:02 +00:00
f = send_dtmf ( rtp , AST_FRAME_DTMF_BEGIN ) ;
2007-03-12 01:22:29 +00:00
} else if ( ( event_end & 0x80 ) & & ( rtp - > lastevent ! = seqno ) & & rtp - > resp ) {
f = send_dtmf ( rtp , AST_FRAME_DTMF_END ) ;
f - > len = ast_tvdiff_ms ( ast_samp2tv ( samples , 8000 ) , ast_tv ( 0 , 0 ) ) ; /* XXX hard coded 8kHz */
rtp - > resp = 0 ;
rtp - > lastevent = seqno ;
}
2006-08-31 01:59:02 +00:00
}
2002-06-16 16:06:38 +00:00
rtp - > dtmfcount = dtmftimeout ;
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
rtp - > dtmfsamples = samples ;
2006-08-31 01:59:02 +00:00
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 )
2007-06-25 13:42:51 +00:00
ast_debug ( 0 , " - 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
}
2007-01-22 23:51:42 +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 ;
2007-05-24 14:50:25 +00:00
double rttsec ;
2007-05-24 15:10:13 +00:00
uint64_t rtt = 0 ;
2007-05-24 14:50:25 +00:00
unsigned int dlsr ;
unsigned int lsr ;
2006-06-05 08:39:42 +00:00
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 ) {
if ( errno = = EBADF )
CRASH ;
2007-03-29 17:20:43 +00:00
if ( errno ! = EAGAIN ) {
ast_log ( LOG_WARNING , " RTCP Read error: %s. Hanging up. \n " , strerror ( errno ) ) ;
return NULL ;
}
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 )
2007-06-25 13:42:51 +00:00
ast_debug ( 0 , " 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
}
}
2006-08-30 01:22:46 +00:00
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " 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 ] ) ;
2007-02-07 17:46:42 +00:00
rtp - > rtcp - > themrxlsr = ( ( ntohl ( rtcpheader [ i ] ) & 0x0000ffff ) < < 16 ) | ( ( ntohl ( rtcpheader [ i + 1 ] ) & 0xffff0000 ) > > 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 :
/* Don't handle multiple reception reports (rc > 1) yet */
2007-05-24 14:50:25 +00:00
/* Calculate RTT per RFC */
2006-06-05 15:47:36 +00:00
gettimeofday ( & now , NULL ) ;
timeval2ntp ( now , & msw , & lsw ) ;
2007-05-24 14:50:25 +00:00
if ( ntohl ( rtcpheader [ i + 4 ] ) & & ntohl ( rtcpheader [ i + 5 ] ) ) { /* We must have the LSR && DLSR */
2006-06-05 15:47:36 +00:00
comp = ( ( msw & 0xffff ) < < 16 ) | ( ( lsw & 0xffff0000 ) > > 16 ) ;
2007-05-24 14:50:25 +00:00
lsr = ntohl ( rtcpheader [ i + 4 ] ) ;
dlsr = ntohl ( rtcpheader [ i + 5 ] ) ;
rtt = comp - lsr - dlsr ;
/* Convert end to end delay to usec (keeping the calculation in 64bit space)
sess - > ee_delay = ( eedelay * 1000 ) / 65536 ; */
if ( rtt < 4294 ) {
rtt = ( rtt * 1000000 ) > > 16 ;
} else {
rtt = ( rtt * 1000 ) > > 16 ;
rtt * = 1000 ;
}
rtt = rtt / 1000. ;
rttsec = rtt / 1000. ;
if ( comp - dlsr > = lsr ) {
rtp - > rtcp - > accumulated_transit + = rttsec ;
rtp - > rtcp - > rtt = rttsec ;
if ( rtp - > rtcp - > maxrtt < rttsec )
rtp - > rtcp - > maxrtt = rttsec ;
if ( rtp - > rtcp - > minrtt > rttsec )
rtp - > rtcp - > minrtt = rttsec ;
2007-06-27 16:38:12 +00:00
} else if ( rtcp_debug_test_addr ( & sin ) ) {
2007-05-24 14:50:25 +00:00
ast_verbose ( " Internal RTCP NTP clock skew detected: "
" lsr=%u, now=%u, dlsr=%u (%d:%03dms), "
2007-06-04 21:48:15 +00:00
" diff=%d \n " ,
2007-05-24 14:50:25 +00:00
lsr , comp , dlsr , dlsr / 65536 ,
( dlsr % 65536 ) * 1000 / 65536 ,
dlsr - ( comp - lsr ) ) ;
2007-04-18 20:48:13 +00:00
}
2007-04-18 20:39:31 +00:00
}
2007-05-24 14:50:25 +00:00
2006-06-05 15:47:36 +00:00
rtp - > rtcp - > reported_jitter = ntohl ( rtcpheader [ i + 3 ] ) ;
rtp - > rtcp - > reported_lost = ntohl ( rtcpheader [ i + 1 ] ) & 0xffffff ;
if ( rtcp_debug_test_addr ( & sin ) ) {
2007-04-18 20:48:13 +00:00
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 ) ;
2006-06-05 15:47:36 +00:00
if ( rtt )
2007-05-24 18:07:56 +00:00
ast_verbose ( " RTT: %lu(sec) \n " , ( unsigned long ) rtt ) ;
2006-06-05 15:47:36 +00:00
}
2007-06-21 23:07:20 +00:00
if ( rtt ) {
manager_event ( EVENT_FLAG_REPORTING , " RTCPReceived " , " From %s:%d \r \n "
" PT: %d(%s) \r \n "
" ReceptionReports: %d \r \n "
" SenderSSRC: %u \r \n "
" FractionLost: %ld \r \n "
" PacketsLost: %d \r \n "
" HighestSequence: %ld \r \n "
" SequenceNumberCycles: %ld \r \n "
" IAJitter: %u \r \n "
" LastSR: %lu.%010lu \r \n "
" DLSR: %4.4f(sec) \r \n "
2007-06-22 15:15:35 +00:00
" RTT: %llu(sec) \r \n " ,
2007-06-21 23:07:20 +00:00
ast_inet_ntoa ( sin . sin_addr ) , ntohs ( sin . sin_port ) ,
pt , ( pt = = 200 ) ? " Sender Report " : ( pt = = 201 ) ? " Receiver Report " : ( pt = = 192 ) ? " H.261 FUR " : " Unknown " ,
rc ,
rtcpheader [ i + 1 ] ,
( ( ( long ) ntohl ( rtcpheader [ i + 1 ] ) & 0xff000000 ) > > 24 ) ,
rtp - > rtcp - > reported_lost ,
( long ) ( ntohl ( rtcpheader [ i + 2 ] ) & 0xffff ) ,
( long ) ( ntohl ( rtcpheader [ i + 2 ] ) & 0xffff ) > > 16 ,
rtp - > rtcp - > reported_jitter ,
( unsigned long ) ntohl ( rtcpheader [ i + 4 ] ) > > 16 , ( ( unsigned long ) ntohl ( rtcpheader [ i + 4 ] ) < < 16 ) * 4096 ,
ntohl ( rtcpheader [ i + 5 ] ) / 65536.0 ,
2007-06-22 16:14:00 +00:00
( unsigned long long ) rtt ) ;
2007-06-21 23:07:20 +00:00
} else {
manager_event ( EVENT_FLAG_REPORTING , " RTCPReceived " , " From %s:%d \r \n "
" PT: %d(%s) \r \n "
" ReceptionReports: %d \r \n "
" SenderSSRC: %u \r \n "
" FractionLost: %ld \r \n "
" PacketsLost: %d \r \n "
" HighestSequence: %ld \r \n "
" SequenceNumberCycles: %ld \r \n "
" IAJitter: %u \r \n "
" LastSR: %lu.%010lu \r \n "
" DLSR: %4.4f(sec) \r \n " ,
ast_inet_ntoa ( sin . sin_addr ) , ntohs ( sin . sin_port ) ,
pt , ( pt = = 200 ) ? " Sender Report " : ( pt = = 201 ) ? " Receiver Report " : ( pt = = 192 ) ? " H.261 FUR " : " Unknown " ,
rc ,
rtcpheader [ i + 1 ] ,
( ( ( long ) ntohl ( rtcpheader [ i + 1 ] ) & 0xff000000 ) > > 24 ) ,
rtp - > rtcp - > reported_lost ,
( long ) ( ntohl ( rtcpheader [ i + 2 ] ) & 0xffff ) ,
( long ) ( ntohl ( rtcpheader [ i + 2 ] ) & 0xffff ) > > 16 ,
rtp - > rtcp - > reported_jitter ,
( unsigned long ) ntohl ( rtcpheader [ i + 4 ] ) > > 16 ,
( ( unsigned long ) ntohl ( rtcpheader [ i + 4 ] ) < < 16 ) * 4096 ,
ntohl ( rtcpheader [ i + 5 ] ) / 65536.0 ) ;
}
2006-06-05 15:47:36 +00:00
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 :
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " 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-10-18 03:03:37 +00:00
if ( rtp - > rtcp & & rtp - > rxjitter > rtp - > rtcp - > maxrxjitter )
2006-06-05 08:39:42 +00:00
rtp - > rtcp - > maxrxjitter = rtp - > rxjitter ;
2006-10-18 03:03:37 +00:00
if ( rtp - > rtcp & & 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
}
2006-08-30 01:22:46 +00:00
/*! \brief Perform a Packet2Packet RTP write */
2006-12-15 19:57:04 +00:00
static int bridge_p2p_rtp_write ( struct ast_rtp * rtp , struct ast_rtp * bridged , unsigned int * rtpheader , int len , int hdrlen )
2006-08-28 17:37:56 +00:00
{
2007-06-19 17:09:20 +00:00
int res = 0 , payload = 0 , bridged_payload = 0 , mark ;
2006-08-28 17:37:56 +00:00
struct rtpPayloadType rtpPT ;
2007-06-19 17:09:20 +00:00
int reconstruct = ntohl ( rtpheader [ 0 ] ) ;
2006-08-28 17:37:56 +00:00
/* Get fields from packet */
2007-06-19 17:09:20 +00:00
payload = ( reconstruct & 0x7f0000 ) > > 16 ;
mark = ( ( ( reconstruct & 0x800000 ) > > 23 ) ! = 0 ) ;
2006-08-28 17:37:56 +00:00
/* Check what the payload value should be */
rtpPT = ast_rtp_lookup_pt ( rtp , payload ) ;
/* If the payload is DTMF, and we are listening for DTMF - then feed it into the core */
2006-08-30 14:57:06 +00:00
if ( ast_test_flag ( rtp , FLAG_P2P_NEED_DTMF ) & & ! rtpPT . isAstFormat & & rtpPT . code = = AST_RTP_DTMF )
2006-08-28 17:37:56 +00:00
return - 1 ;
/* Otherwise adjust bridged payload to match */
bridged_payload = ast_rtp_lookup_code ( bridged , rtpPT . isAstFormat , rtpPT . code ) ;
/* If the mark bit has not been sent yet... do it now */
if ( ! ast_test_flag ( rtp , FLAG_P2P_SENT_MARK ) ) {
mark = 1 ;
ast_set_flag ( rtp , FLAG_P2P_SENT_MARK ) ;
}
/* Reconstruct part of the packet */
2007-06-19 17:09:20 +00:00
reconstruct & = 0xFF80FFFF ;
reconstruct | = ( bridged_payload < < 16 ) ;
reconstruct | = ( mark < < 23 ) ;
rtpheader [ 0 ] = htonl ( reconstruct ) ;
2006-08-28 17:37:56 +00:00
2006-08-30 01:22:46 +00:00
/* Send the packet back out */
res = sendto ( bridged - > s , ( void * ) rtpheader , len , 0 , ( struct sockaddr * ) & bridged - > them , sizeof ( bridged - > them ) ) ;
if ( res < 0 ) {
if ( ! bridged - > nat | | ( bridged - > nat & & ( ast_test_flag ( bridged , FLAG_NAT_ACTIVE ) = = FLAG_NAT_ACTIVE ) ) ) {
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " RTP Transmission error of packet to %s:%d: %s \n " , ast_inet_ntoa ( bridged - > them . sin_addr ) , ntohs ( bridged - > them . sin_port ) , strerror ( errno ) ) ;
2006-08-30 01:22:46 +00:00
} else if ( ( ( ast_test_flag ( bridged , FLAG_NAT_ACTIVE ) = = FLAG_NAT_INACTIVE ) | | rtpdebug ) & & ! ast_test_flag ( bridged , FLAG_NAT_INACTIVE_NOWARN ) ) {
if ( option_debug | | rtpdebug )
2007-06-25 13:42:51 +00:00
ast_debug ( 0 , " RTP NAT: Can't write RTP to private address %s:%d, waiting for other end to send audio... \n " , ast_inet_ntoa ( bridged - > them . sin_addr ) , ntohs ( bridged - > them . sin_port ) ) ;
2006-08-30 01:22:46 +00:00
ast_set_flag ( bridged , FLAG_NAT_INACTIVE_NOWARN ) ;
2006-08-28 17:37:56 +00:00
}
2007-01-17 06:37:47 +00:00
return 0 ;
2006-08-30 01:22:46 +00:00
} else if ( rtp_debug_test_addr ( & bridged - > them ) )
2007-01-31 17:45:43 +00:00
ast_verbose ( " Sent RTP P2P packet to %s:%u (type %-2.2d, len %-6.6u) \n " , ast_inet_ntoa ( bridged - > them . sin_addr ) , ntohs ( bridged - > them . sin_port ) , bridged_payload , len - hdrlen ) ;
2006-08-28 17:37:56 +00:00
2007-01-17 06:37:47 +00:00
return 0 ;
2006-08-28 17:37:56 +00:00
}
2003-02-12 13:59:15 +00:00
struct ast_frame * ast_rtp_read ( struct ast_rtp * rtp )
{
2002-06-16 16:06:38 +00:00
int res ;
struct sockaddr_in sin ;
2005-05-15 03:21:51 +00:00
socklen_t len ;
2002-06-16 16:06:38 +00:00
unsigned int seqno ;
2004-12-28 16:45:03 +00:00
int version ;
2002-06-16 16:06:38 +00:00
int payloadtype ;
int hdrlen = 12 ;
2005-05-14 23:41:12 +00:00
int padding ;
2003-06-28 16:40:02 +00:00
int mark ;
2004-08-31 00:16:28 +00:00
int ext ;
2007-06-19 17:09:20 +00:00
int cc ;
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 ;
2006-12-15 19:57:04 +00:00
struct ast_rtp * bridged = NULL ;
2002-06-16 16:06:38 +00:00
2006-08-31 01:59:02 +00:00
/* If time is up, kill it */
2007-01-17 00:22:20 +00:00
if ( rtp - > sending_digit )
2006-08-31 01:59:02 +00:00
ast_rtp_senddigit_continuation ( rtp ) ;
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 ) {
if ( errno = = EBADF )
CRASH ;
2007-03-29 17:20:43 +00:00
if ( errno ! = EAGAIN ) {
ast_log ( LOG_WARNING , " RTP Read error: %s. Hanging up. \n " , strerror ( errno ) ) ;
return NULL ;
}
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 ) {
2007-07-11 16:24:35 +00:00
/* If the two high bits are 0, this might be a
* STUN message , so process it . stun_handle_packet ( )
* answers to requests , and it returns STUN_ACCEPT
* if the request is valid .
*/
Small improvement to the STUN support so it can be used by
sockets other than RTP ones.
The main change is a new API function in main/rtp.c (see there
for a description)
int ast_stun_request(int s, struct sockaddr_in *dst,
const char *username, struct sockaddr_in *answer)
which can be used to send an STUN request on a socket, and
optionally wait for a reply and store the STUN_MAPPED_ADDRESS
into the 'answer' argument (obviously, the version that
waits for a reply is blocking, but this is no different
from DNS resolutions).
Internally there are minor modifications to let stun_handle_packet()
be somewhat configurable on how to parse the body of responses.
At the moment i am not committing any change to the clients,
but adding STUN client support is extremely simple, e.g. chan_sip.c
could do something like this:
+ add a variable to store the stun server address;
static struct sockaddr_in stunaddr = { 0, }; /*!< stun server address */
+ add code to parse a config file of the form "stunaddr=my.stun.server.org:3478"
(not shown for brevity);
+ right after binding the main sip socket, talk to the stun server to
determine the externally visible address
if (stunaddr.sin_addr.s_addr != 0)
ast_stun_request(sipsock, &stunaddr, NULL, &externip);
so now 'externip' is set with the externally visible address.
so it is really trivial.
Similarly ast_stun_request could be called when creating the RTP
socket (possibly adding a struct sockaddr_in field in the struct
ast_rtp to store the externalip).
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@75034 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-07-13 16:22:09 +00:00
if ( ( stun_handle_packet ( rtp - > s , & sin , rtp - > rawdata + AST_FRIENDLY_OFFSET , res , NULL , NULL ) = = STUN_ACCEPT ) & &
2006-05-11 14:56:52 +00:00
( ! rtp - > them . sin_port & & ! rtp - > them . sin_addr . s_addr ) ) {
memcpy ( & rtp - > them , & sin , sizeof ( rtp - > them ) ) ;
}
return & ast_null_frame ;
}
2006-09-30 19:23:59 +00:00
#if 0 /* Allow to receive RTP stream with closed transmission path */
2006-08-29 23:41:16 +00:00
/* If we don't have the other side's address, then ignore this */
2004-04-15 20:12:46 +00:00
if ( ! rtp - > them . sin_addr . s_addr | | ! rtp - > them . sin_port )
2006-01-31 17:18:58 +00:00
return & ast_null_frame ;
2006-09-30 19:23:59 +00:00
# endif
2004-04-15 20:12:46 +00:00
2006-08-29 23:41:16 +00:00
/* Send to whoever send to us if NAT is turned on */
2003-03-07 06:00:13 +00:00
if ( rtp - > nat ) {
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 )
2007-06-25 13:42:51 +00:00
ast_debug ( 0 , " 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
2006-08-29 23:41:16 +00:00
/* If we are bridged to another RTP stream, send direct */
2006-12-15 19:57:04 +00:00
if ( ( bridged = ast_rtp_get_bridged ( rtp ) ) & & ! bridge_p2p_rtp_write ( rtp , bridged , rtpheader , res , hdrlen ) )
2006-08-29 23:41:16 +00:00
return & ast_null_frame ;
if ( version ! = 2 )
return & ast_null_frame ;
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 ) ;
2007-06-19 17:09:20 +00:00
cc = ( seqno & 0xF000000 ) > > 24 ;
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 )
2007-06-25 13:42:51 +00:00
ast_debug ( 0 , " 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 ] ;
}
2007-06-19 17:09:20 +00:00
if ( cc ) {
/* CSRC fields present */
hdrlen + = cc * 4 ;
}
2004-08-31 00:16:28 +00:00
if ( ext ) {
/* RTP Extension present */
2007-06-19 17:09:20 +00:00
hdrlen + = ( ntohl ( rtpheader [ hdrlen / 4 ] ) & 0xffff ) < < 2 ;
2004-08-31 00:16:28 +00:00
hdrlen + = 4 ;
2006-10-30 16:59:02 +00:00
if ( option_debug ) {
int profile ;
profile = ( ntohl ( rtpheader [ 3 ] ) & 0xffff0000 ) > > 16 ;
if ( profile = = 0x505a )
2007-06-25 13:42:51 +00:00
ast_debug ( 1 , " Found Zfone extension in RTP stream - zrtp - not supported. \n " ) ;
2006-10-30 16:59:02 +00:00
else
2007-06-25 13:42:51 +00:00
ast_debug ( 1 , " Found unknown RTP Extensions %x \n " , profile ) ;
2006-10-30 16:59:02 +00:00
}
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 */
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-09-30 19:23:59 +00:00
/* Do not schedule RR if RTCP isn't run */
if ( rtp - > rtcp & & rtp - > rtcp - > them . sin_addr . s_addr & & 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 ) ;
}
2007-04-20 21:37:04 +00:00
if ( ( int ) rtp - > lastrxseqno - ( int ) seqno > 100 ) /* if so it would indicate that the sender cycled; allow for misordering */
2006-06-05 08:39:42 +00:00
rtp - > cycles + = RTP_SEQ_MOD ;
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 ) )
2007-01-31 17:45:43 +00:00
ast_verbose ( " Got RTP packet from %s:%u (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 ;
2007-01-31 17:45:43 +00:00
ast_verbose ( " Got RTP RFC2833 from %s:%u (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
}
2007-03-12 01:22:29 +00:00
f = process_rfc2833 ( rtp , rtp - > rawdata + AST_FRIENDLY_OFFSET + hdrlen , res - hdrlen , seqno , timestamp ) ;
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 */
2007-03-12 01:22:29 +00:00
if ( rtp - > lastevent < = seqno | | ( rtp - > lastevent > = 65530 & & seqno < = 6 ) ) {
2005-10-12 20:45:18 +00:00
f = process_cisco_dtmf ( rtp , rtp - > rawdata + AST_FRIENDLY_OFFSET + hdrlen , res - hdrlen ) ;
2007-03-12 01:22:29 +00:00
rtp - > lastevent = 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 ;
2007-02-16 13:35:44 +00:00
rtp - > f . frametype = ( rtp - > f . subclass < AST_FORMAT_MAX_AUDIO ) ? AST_FRAME_VOICE : ( rtp - > f . subclass < AST_FORMAT_MAX_VIDEO ) ? AST_FRAME_VIDEO : AST_FRAME_TEXT ;
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 ;
2006-08-31 01:59:02 +00:00
/* Record received timestamp as last received now */
2002-06-16 16:06:38 +00:00
rtp - > lastrxts = timestamp ;
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 ;
2007-02-16 13:35:44 +00:00
} else if ( rtp - > f . subclass < AST_FORMAT_MAX_VIDEO ) {
2003-06-28 16:40:02 +00:00
/* 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 ;
2007-02-16 13:35:44 +00:00
} else {
/* TEXT -- samples is # of samples vs. 1000 */
if ( ! rtp - > lastitexttimestamp )
rtp - > lastitexttimestamp = timestamp ;
rtp - > f . samples = timestamp - rtp - > lastitexttimestamp ;
rtp - > lastitexttimestamp = timestamp ;
rtp - > f . delivery . tv_sec = 0 ;
rtp - > f . delivery . tv_usec = 0 ;
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-10-25 00:32:23 +00:00
{ { 1 , AST_FORMAT_G722 } , " audio " , " G722 " } ,
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 " } ,
2007-01-08 11:49:23 +00:00
{ { 1 , AST_FORMAT_MP4_VIDEO } , " video " , " MP4V-ES " } ,
2006-12-05 10:52:53 +00:00
{ { 1 , AST_FORMAT_T140 } , " text " , " T140 " } ,
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 } ,
2006-10-25 00:32:23 +00:00
[ 9 ] = { 1 , AST_FORMAT_G722 } ,
2006-01-03 09:30:19 +00:00
[ 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 } ,
[ 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 } ,
2006-12-05 11:09:23 +00:00
[ 102 ] = { 1 , AST_FORMAT_T140 } , /* Real time text chat */
2007-01-08 11:49:23 +00:00
[ 103 ] = { 1 , AST_FORMAT_H263_PLUS } ,
[ 104 ] = { 1 , AST_FORMAT_MP4_VIDEO } ,
2006-01-03 09:30:19 +00:00
[ 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 ;
2006-12-14 17:39:16 +00:00
2005-09-07 20:33:30 +00:00
if ( ! rtp )
return ;
2003-03-12 06:00:18 +00:00
2007-01-29 21:03:07 +00:00
rtp_bridge_lock ( rtp ) ;
2006-12-14 17:39:16 +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 ;
2006-12-14 17:39:16 +00:00
2007-01-29 21:03:07 +00:00
rtp_bridge_unlock ( rtp ) ;
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 ;
2007-01-29 21:03:07 +00:00
rtp_bridge_lock ( rtp ) ;
2006-12-14 17:39:16 +00:00
2004-12-28 16:43:20 +00:00
/* 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 ;
2006-12-14 17:39:16 +00:00
2007-01-29 21:03:07 +00:00
rtp_bridge_unlock ( rtp ) ;
2003-03-13 06:00:20 +00:00
}
2006-12-14 17:39:16 +00:00
void ast_rtp_pt_copy ( struct ast_rtp * dest , struct ast_rtp * src )
2005-12-20 17:52:31 +00:00
{
2006-06-08 23:10:45 +00:00
unsigned int i ;
2007-01-29 21:03:07 +00:00
rtp_bridge_lock ( dest ) ;
rtp_bridge_lock ( src ) ;
2006-12-14 17:39:16 +00:00
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-12-14 17:39:16 +00:00
2007-01-29 21:03:07 +00:00
rtp_bridge_unlock ( src ) ;
rtp_bridge_unlock ( dest ) ;
2005-12-20 17:52:31 +00:00
}
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
2007-01-22 23:53:16 +00:00
AST_RWLIST_RDLOCK ( & protos ) ;
AST_RWLIST_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
}
2007-01-22 23:53:16 +00:00
AST_RWLIST_UNLOCK ( & protos ) ;
2006-01-03 09:30:19 +00:00
2006-01-03 17:08:35 +00:00
return cur ;
2005-12-20 17:52:31 +00:00
}
2006-09-21 19:27:26 +00:00
int ast_rtp_early_bridge ( struct ast_channel * c0 , struct ast_channel * c1 )
2006-05-09 11:44:50 +00:00
{
2006-09-21 19:27:26 +00:00
// dest = c0, src = c1
2006-08-28 17:37:56 +00:00
struct ast_rtp * destp = NULL , * srcp = NULL ; /* Audio RTP Channels */
struct ast_rtp * vdestp = NULL , * vsrcp = NULL ; /* Video RTP channels */
2007-02-16 13:35:44 +00:00
struct ast_rtp * tdestp = NULL , * tsrcp = NULL ; /* Text RTP channels */
2006-08-28 17:37:56 +00:00
struct ast_rtp_protocol * destpr = NULL , * srcpr = NULL ;
2007-02-16 13:35:44 +00:00
enum ast_rtp_get_result audio_dest_res = AST_RTP_GET_FAILED , video_dest_res = AST_RTP_GET_FAILED , text_dest_res = AST_RTP_GET_FAILED ;
enum ast_rtp_get_result audio_src_res = AST_RTP_GET_FAILED , video_src_res = AST_RTP_GET_FAILED , text_src_res = AST_RTP_GET_FAILED ;
2007-03-07 17:55:11 +00:00
int srccodec , destcodec , nat_active = 0 ;
2006-06-08 20:05:36 +00:00
2006-05-09 11:44:50 +00:00
/* Lock channels */
2006-09-21 19:27:26 +00:00
ast_channel_lock ( c0 ) ;
if ( c1 ) {
2007-01-22 23:51:42 +00:00
while ( ast_channel_trylock ( c1 ) ) {
2006-09-21 19:27:26 +00:00
ast_channel_unlock ( c0 ) ;
2006-05-09 11:44:50 +00:00
usleep ( 1 ) ;
2006-09-21 19:27:26 +00:00
ast_channel_lock ( c0 ) ;
2006-05-09 11:44:50 +00:00
}
}
/* Find channel driver interfaces */
2006-09-21 19:27:26 +00:00
destpr = get_proto ( c0 ) ;
if ( c1 )
srcpr = get_proto ( c1 ) ;
2006-05-09 11:44:50 +00:00
if ( ! destpr ) {
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " Channel '%s' has no RTP, not doing anything \n " , c0 - > name ) ;
2006-09-21 19:27:26 +00:00
ast_channel_unlock ( c0 ) ;
if ( c1 )
ast_channel_unlock ( c1 ) ;
return - 1 ;
2006-05-09 11:44:50 +00:00
}
if ( ! srcpr ) {
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " Channel '%s' has no RTP, not doing anything \n " , c1 ? c1 - > name : " <unspecified> " ) ;
2006-09-21 19:27:26 +00:00
ast_channel_unlock ( c0 ) ;
if ( c1 )
ast_channel_unlock ( c1 ) ;
return - 1 ;
2006-05-09 11:44:50 +00:00
}
2007-02-16 13:35:44 +00:00
/* Get audio, video and text interface (if native bridge is possible) */
2006-09-21 19:27:26 +00:00
audio_dest_res = destpr - > get_rtp_info ( c0 , & destp ) ;
video_dest_res = destpr - > get_vrtp_info ? destpr - > get_vrtp_info ( c0 , & vdestp ) : AST_RTP_GET_FAILED ;
2007-02-16 13:35:44 +00:00
text_dest_res = destpr - > get_trtp_info ? destpr - > get_trtp_info ( c0 , & tdestp ) : AST_RTP_GET_FAILED ;
2006-05-09 11:44:50 +00:00
if ( srcpr ) {
2006-09-21 19:27:26 +00:00
audio_src_res = srcpr - > get_rtp_info ( c1 , & srcp ) ;
video_src_res = srcpr - > get_vrtp_info ? srcpr - > get_vrtp_info ( c1 , & vsrcp ) : AST_RTP_GET_FAILED ;
2007-02-16 13:35:44 +00:00
text_src_res = srcpr - > get_trtp_info ? srcpr - > get_trtp_info ( c1 , & tsrcp ) : AST_RTP_GET_FAILED ;
2006-05-09 11:44:50 +00:00
}
/* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
2006-08-28 17:37:56 +00:00
if ( audio_dest_res ! = AST_RTP_TRY_NATIVE ) {
2006-05-09 11:44:50 +00:00
/* Somebody doesn't want to play... */
2006-09-21 19:27:26 +00:00
ast_channel_unlock ( c0 ) ;
if ( c1 )
ast_channel_unlock ( c1 ) ;
return - 1 ;
2006-05-09 11:44:50 +00:00
}
2006-08-28 17:37:56 +00:00
if ( audio_src_res = = AST_RTP_TRY_NATIVE & & srcpr - > get_codec )
2006-09-21 19:27:26 +00:00
srccodec = srcpr - > get_codec ( c1 ) ;
2006-05-09 11:44:50 +00:00
else
srccodec = 0 ;
2007-03-07 17:55:11 +00:00
if ( audio_dest_res = = AST_RTP_TRY_NATIVE & & destpr - > get_codec )
destcodec = destpr - > get_codec ( c0 ) ;
else
destcodec = 0 ;
/* Ensure we have at least one matching codec */
if ( ! ( srccodec & destcodec ) ) {
ast_channel_unlock ( c0 ) ;
if ( c1 )
ast_channel_unlock ( c1 ) ;
return 0 ;
}
2006-05-09 11:44:50 +00:00
/* Consider empty media as non-existant */
2006-08-28 17:37:56 +00:00
if ( audio_src_res = = AST_RTP_TRY_NATIVE & & ! srcp - > them . sin_addr . s_addr )
2006-05-09 11:44:50 +00:00
srcp = NULL ;
2006-11-15 04:47:52 +00:00
if ( srcp & & ( srcp - > nat | | ast_test_flag ( srcp , FLAG_NAT_ACTIVE ) ) )
nat_active = 1 ;
2006-06-08 20:05:36 +00:00
/* Bridge media early */
2007-02-16 13:35:44 +00:00
if ( destpr - > set_rtp_peer ( c0 , srcp , vsrcp , tsrcp , srccodec , nat_active ) )
2006-09-21 19:27:26 +00:00
ast_log ( LOG_WARNING , " Channel '%s' failed to setup early bridge to '%s' \n " , c0 - > name , c1 ? c1 - > name : " <unspecified> " ) ;
ast_channel_unlock ( c0 ) ;
if ( c1 )
ast_channel_unlock ( c1 ) ;
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " Setting early bridge SDP of '%s' with that of '%s' \n " , c0 - > name , c1 ? c1 - > name : " <unspecified> " ) ;
2006-09-21 19:27:26 +00:00
return 0 ;
2006-05-09 11:44:50 +00:00
}
int ast_rtp_make_compatible ( struct ast_channel * dest , struct ast_channel * src , int media )
2005-12-20 17:52:31 +00:00
{
2006-08-28 17:37:56 +00:00
struct ast_rtp * destp = NULL , * srcp = NULL ; /* Audio RTP Channels */
struct ast_rtp * vdestp = NULL , * vsrcp = NULL ; /* Video RTP channels */
2007-02-16 13:35:44 +00:00
struct ast_rtp * tdestp = NULL , * tsrcp = NULL ; /* Text RTP channels */
2006-08-28 17:37:56 +00:00
struct ast_rtp_protocol * destpr = NULL , * srcpr = NULL ;
2007-02-16 13:35:44 +00:00
enum ast_rtp_get_result audio_dest_res = AST_RTP_GET_FAILED , video_dest_res = AST_RTP_GET_FAILED , text_dest_res = AST_RTP_GET_FAILED ;
enum ast_rtp_get_result audio_src_res = AST_RTP_GET_FAILED , video_src_res = AST_RTP_GET_FAILED , text_src_res = AST_RTP_GET_FAILED ;
2007-03-08 18:05:54 +00:00
int srccodec , destcodec ;
2006-08-28 17:37:56 +00:00
2005-12-20 17:52:31 +00:00
/* Lock channels */
2006-04-27 17:53:52 +00:00
ast_channel_lock ( dest ) ;
2007-01-22 23:51:42 +00:00
while ( ast_channel_trylock ( src ) ) {
2006-04-27 17:53:52 +00:00
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 */
2006-08-28 17:37:56 +00:00
if ( ! ( destpr = get_proto ( dest ) ) ) {
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " 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 ;
}
2006-08-28 17:37:56 +00:00
if ( ! ( srcpr = get_proto ( src ) ) ) {
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " 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) */
2006-08-28 17:37:56 +00:00
audio_dest_res = destpr - > get_rtp_info ( dest , & destp ) ;
video_dest_res = destpr - > get_vrtp_info ? destpr - > get_vrtp_info ( dest , & vdestp ) : AST_RTP_GET_FAILED ;
2007-02-16 13:35:44 +00:00
text_dest_res = destpr - > get_trtp_info ? destpr - > get_trtp_info ( dest , & tdestp ) : AST_RTP_GET_FAILED ;
2006-08-28 17:37:56 +00:00
audio_src_res = srcpr - > get_rtp_info ( src , & srcp ) ;
video_src_res = srcpr - > get_vrtp_info ? srcpr - > get_vrtp_info ( src , & vsrcp ) : AST_RTP_GET_FAILED ;
2007-02-16 13:35:44 +00:00
text_src_res = srcpr - > get_trtp_info ? srcpr - > get_trtp_info ( src , & tsrcp ) : AST_RTP_GET_FAILED ;
2005-12-20 17:52:31 +00:00
2007-03-08 18:05:54 +00:00
/* Ensure we have at least one matching codec */
if ( srcpr - > get_codec )
srccodec = srcpr - > get_codec ( src ) ;
else
srccodec = 0 ;
if ( destpr - > get_codec )
destcodec = destpr - > get_codec ( dest ) ;
else
destcodec = 0 ;
2005-12-20 17:52:31 +00:00
/* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
2007-03-08 18:05:54 +00:00
if ( audio_dest_res ! = AST_RTP_TRY_NATIVE | | audio_src_res ! = AST_RTP_TRY_NATIVE | | ! ( srccodec & destcodec ) ) {
2005-12-20 17:52:31 +00:00
/* 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 ) ;
2007-02-16 13:35:44 +00:00
if ( tdestp & & tsrcp )
ast_rtp_pt_copy ( tdestp , tsrcp ) ;
2006-05-09 11:44:50 +00:00
if ( media ) {
2006-06-08 20:05:36 +00:00
/* Bridge early */
2007-02-16 13:35:44 +00:00
if ( destpr - > set_rtp_peer ( dest , srcp , vsrcp , tsrcp , 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 ) ;
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " 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 )
{
2006-12-14 17:39:16 +00:00
if ( pt < 0 | | pt > MAX_RTP_PT | | static_RTP_PT [ pt ] . code = = 0 )
2004-12-28 16:43:20 +00:00
return ; /* bogus payload type */
2003-03-12 06:00:18 +00:00
2007-01-29 21:03:07 +00:00
rtp_bridge_lock ( rtp ) ;
2006-12-14 17:39:16 +00:00
rtp - > current_RTP_PT [ pt ] = static_RTP_PT [ pt ] ;
2007-01-29 21:03:07 +00:00
rtp_bridge_unlock ( rtp ) ;
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 */
2006-12-14 17:39:16 +00:00
2007-01-29 21:03:07 +00:00
rtp_bridge_lock ( rtp ) ;
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-12-14 17:39:16 +00:00
break ;
2004-12-28 16:43:20 +00:00
}
}
2006-12-14 17:39:16 +00:00
2007-01-29 21:03:07 +00:00
rtp_bridge_unlock ( rtp ) ;
2006-12-14 17:39:16 +00:00
return ;
2003-03-12 06:00:18 +00:00
}
2006-01-03 09:30:19 +00:00
/*! \brief Return the union of all of the codecs that were set by rtp_set...() calls
* They ' re returned as two distinct sets : AST_FORMATs , and AST_RTPs */
2003-03-13 06:00:20 +00:00
void ast_rtp_get_current_formats ( struct ast_rtp * rtp ,
2006-12-14 17:39:16 +00:00
int * astFormats , int * nonAstFormats )
{
2004-12-28 16:43:20 +00:00
int pt ;
2006-12-14 17:39:16 +00:00
2007-01-29 21:03:07 +00:00
rtp_bridge_lock ( rtp ) ;
2006-12-14 17:39:16 +00:00
2004-12-28 16:43:20 +00:00
* 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 ;
}
}
2007-01-29 21:03:07 +00:00
rtp_bridge_unlock ( rtp ) ;
2006-12-14 17:39:16 +00:00
return ;
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 ;
2006-12-14 17:39:16 +00:00
2004-12-28 16:43:20 +00:00
if ( pt < 0 | | pt > MAX_RTP_PT )
return result ; /* bogus payload type */
2006-06-05 08:39:42 +00:00
/* Start with negotiated codecs */
2007-01-29 21:03:07 +00:00
rtp_bridge_lock ( rtp ) ;
2005-12-20 17:52:31 +00:00
result = rtp - > current_RTP_PT [ pt ] ;
2007-01-29 21:03:07 +00:00
rtp_bridge_unlock ( rtp ) ;
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 ] ;
2006-12-14 17:39:16 +00:00
2004-12-28 16:43:20 +00:00
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 */
2006-12-14 17:39:16 +00:00
int ast_rtp_lookup_code ( struct ast_rtp * rtp , const int isAstFormat , const int code )
{
int pt = 0 ;
2003-03-12 06:00:18 +00:00
2007-01-29 21:03:07 +00:00
rtp_bridge_lock ( rtp ) ;
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 */
2006-12-14 17:39:16 +00:00
pt = rtp - > rtp_lookup_code_cache_result ;
2007-01-29 21:03:07 +00:00
rtp_bridge_unlock ( rtp ) ;
2006-12-14 17:39:16 +00:00
return pt ;
2004-12-28 16:43:20 +00:00
}
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 ;
2007-01-29 21:03:07 +00:00
rtp_bridge_unlock ( rtp ) ;
2004-12-28 16:43:20 +00:00
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 ;
2007-01-29 21:03:07 +00:00
rtp_bridge_unlock ( rtp ) ;
2004-12-28 16:43:20 +00:00
return pt ;
}
}
2006-12-14 17:39:16 +00:00
2007-01-29 21:03:07 +00:00
rtp_bridge_unlock ( rtp ) ;
2006-12-14 17:39:16 +00:00
2004-12-28 16:43:20 +00:00
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 ) )
2006-11-21 17:34:22 +00:00
return " G726-32 " ;
2006-07-13 01:38:47 +00:00
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 ;
}
2007-07-12 15:42:56 +00:00
/*! \brief Open RTP or RTCP socket for a session.
* Print a message on failure .
*/
static int rtp_socket ( const char * type )
2004-06-09 01:33:16 +00:00
{
2007-07-12 15:42:56 +00:00
int s = socket ( AF_INET , SOCK_DGRAM , 0 ) ;
if ( s < 0 ) {
if ( type = = NULL )
type = " RTP/RTCP " ;
ast_log ( LOG_WARNING , " Unable to allocate %s socket: %s \n " , type , strerror ( errno ) ) ;
} else {
long flags = fcntl ( s , F_GETFL ) ;
2004-06-09 01:33:16 +00:00
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 ;
2007-07-12 15:42:56 +00:00
rtcp - > s = rtp_socket ( " RTCP " ) ;
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 ) {
2007-06-06 21:20:11 +00:00
ast_free ( rtcp ) ;
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 ;
}
2006-12-26 04:34:07 +00:00
/*!
* \ brief Initialize a new RTP structure .
*
*/
void ast_rtp_new_init ( struct ast_rtp * rtp )
{
2007-01-29 21:03:07 +00:00
# ifdef P2P_INTENSE
2006-12-26 04:34:07 +00:00
ast_mutex_init ( & rtp - > bridge_lock ) ;
2007-01-29 21:03:07 +00:00
# endif
2006-12-26 04:34:07 +00:00
rtp - > them . sin_family = AF_INET ;
rtp - > us . sin_family = AF_INET ;
rtp - > ssrc = ast_random ( ) ;
rtp - > seqno = ast_random ( ) & 0xffff ;
ast_set_flag ( rtp , FLAG_HAS_DTMF ) ;
return ;
}
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 ;
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 ;
2006-12-14 17:39:16 +00:00
2006-12-26 04:34:07 +00:00
ast_rtp_new_init ( rtp ) ;
2006-12-14 17:39:16 +00:00
2007-07-12 15:42:56 +00:00
rtp - > s = rtp_socket ( " RTP " ) ;
if ( rtp - > s < 0 )
goto fail ;
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
2007-07-12 15:42:56 +00:00
/*
* Try to bind the RTP port , x , and possibly the RTCP port , x + 1 as well .
* Start from a random ( even , by RTP spec ) port number , and
* iterate until success or no ports are available .
* Note that the requirement of RTP port being even , or RTCP being the
* next one , cannot be enforced in presence of a NAT box because the
* mapping is not under our control .
*/
2006-04-05 17:44:44 +00:00
x = ( ast_random ( ) % ( rtpend - rtpstart ) ) + rtpstart ;
2007-07-12 15:42:56 +00:00
x = x & ~ 1 ; /* make it an even number */
startplace = x ; /* remember the starting point */
/* this is constant across the loop */
rtp - > us . sin_addr = addr ;
if ( rtp - > rtcp )
rtp - > rtcp - > us . sin_addr = addr ;
2002-06-16 16:06:38 +00:00
for ( ; ; ) {
rtp - > us . sin_port = htons ( x ) ;
2007-07-12 15:42:56 +00:00
if ( ! bind ( rtp - > s , ( struct sockaddr * ) & rtp - > us , sizeof ( rtp - > us ) ) ) {
/* bind succeeded, if no rtcp then we are done */
if ( ! rtp - > rtcp )
break ;
/* have rtcp, try to bind it */
2003-06-28 16:40:02 +00:00
rtp - > rtcp - > us . sin_port = htons ( x + 1 ) ;
2007-07-12 15:42:56 +00:00
if ( ! bind ( rtp - > rtcp - > s , ( struct sockaddr * ) & rtp - > rtcp - > us , sizeof ( rtp - > rtcp - > us ) ) )
break ; /* success again, we are really done */
/*
* RTCP bind failed , so close and recreate the
* already bound RTP socket for the next round .
*/
2004-06-09 01:33:16 +00:00
close ( rtp - > s ) ;
2007-07-12 15:42:56 +00:00
rtp - > s = rtp_socket ( " RTP " ) ;
if ( rtp - > s < 0 )
goto fail ;
2004-06-09 01:33:16 +00:00
}
2007-07-12 15:42:56 +00:00
/*
* If we get here , there was an error in one of the bind ( )
* calls , so make sure it is nothing unexpected .
*/
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 ) ) ;
2007-07-12 15:42:56 +00:00
goto fail ;
2002-06-16 16:06:38 +00:00
}
2007-07-12 15:42:56 +00:00
/*
* One of the ports is in use . For the next iteration ,
* increment by two and handle wraparound .
* If we reach the starting point , then declare failure .
*/
2003-05-16 02:50:46 +00:00
x + = 2 ;
if ( x > rtpend )
x = ( rtpstart + 1 ) & ~ 1 ;
if ( x = = startplace ) {
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 " ) ;
2007-07-12 15:42:56 +00:00
goto fail ;
2003-05-16 02:50:46 +00:00
}
2002-06-16 16:06:38 +00:00
}
2006-08-30 01:22:46 +00:00
rtp - > sched = sched ;
rtp - > io = io ;
2006-08-30 01:29:59 +00:00
if ( callbackmode ) {
2003-02-12 13:59:15 +00:00
rtp - > ioid = ast_io_add ( rtp - > io , rtp - > s , rtpread , AST_IO_IN , rtp ) ;
2006-08-30 01:29:59 +00:00
ast_set_flag ( rtp , FLAG_CALLBACK_MODE ) ;
}
2003-03-13 06:00:20 +00:00
ast_rtp_pt_default ( rtp ) ;
2002-06-16 16:06:38 +00:00
return rtp ;
2007-07-12 15:42:56 +00:00
fail :
if ( rtp - > s > = 0 )
close ( rtp - > s ) ;
if ( rtp - > rtcp ) {
close ( rtp - > rtcp - > s ) ;
ast_free ( rtp - > rtcp ) ;
}
ast_free ( rtp ) ;
return NULL ;
2002-06-16 16:06:38 +00:00
}
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 ) ;
}
2007-04-30 16:16:26 +00:00
int ast_rtp_setqos ( struct ast_rtp * rtp , int tos , int cos )
2003-02-05 19:26:49 +00:00
{
2007-04-30 16:16:26 +00:00
return ast_netsock_set_qos ( rtp - > s , tos , cos ) ;
2003-02-05 19:26:49 +00:00
}
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
}
2006-08-30 03:16:03 +00:00
struct ast_rtp * ast_rtp_get_bridged ( struct ast_rtp * rtp )
{
2006-12-15 19:57:04 +00:00
struct ast_rtp * bridged = NULL ;
2007-01-29 21:03:07 +00:00
rtp_bridge_lock ( rtp ) ;
2006-12-15 19:57:04 +00:00
bridged = rtp - > bridged ;
2007-01-29 21:03:07 +00:00
rtp_bridge_unlock ( rtp ) ;
2006-12-15 19:57:04 +00:00
return bridged ;
2006-08-30 03:16:03 +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
}
2006-08-28 17:37:56 +00:00
ast_clear_flag ( rtp , FLAG_P2P_SENT_MARK ) ;
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 ;
2007-02-16 13:35:44 +00:00
rtp - > lastitexttimestamp = 0 ;
rtp - > lastotexttimestamp = 0 ;
2004-12-28 16:35:31 +00:00
rtp - > lasteventseqn = 0 ;
2007-03-12 01:22:29 +00:00
rtp - > lastevent = 0 ;
2004-12-28 16:35:31 +00:00
rtp - > lasttxformat = 0 ;
rtp - > lastrxformat = 0 ;
rtp - > dtmfcount = 0 ;
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
rtp - > dtmfsamples = 0 ;
2004-12-28 16:35:31 +00:00
rtp - > seqno = 0 ;
rtp - > rxseqno = 0 ;
}
2007-03-26 17:51:27 +00:00
char * ast_rtp_get_quality ( struct ast_rtp * rtp , struct ast_rtp_quality * qual )
2006-06-05 08:39:42 +00:00
{
/*
* 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
2007-03-26 17:51:27 +00:00
* rtt round trip time
2006-06-05 08:39:42 +00:00
*/
2007-03-26 17:51:27 +00:00
if ( qual ) {
qual - > local_ssrc = rtp - > ssrc ;
qual - > local_lostpackets = rtp - > rtcp - > expected_prior - rtp - > rtcp - > received_prior ;
qual - > local_jitter = rtp - > rxjitter ;
qual - > local_count = rtp - > rxcount ;
qual - > remote_ssrc = rtp - > themssrc ;
qual - > remote_lostpackets = rtp - > rtcp - > reported_lost ;
qual - > remote_jitter = rtp - > rtcp - > reported_jitter / 65536.0 ;
qual - > remote_count = rtp - > txcount ;
qual - > rtt = rtp - > rtcp - > rtt ;
}
2006-06-05 08:39:42 +00:00
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 ) ;
}
2007-06-21 23:07:20 +00:00
manager_event ( EVENT_FLAG_REPORTING , " RTPReceiverStat " , " SSRC: %u \r \n "
" ReceivedPackets: %u \r \n "
" LostPackets: %u \r \n "
" Jitter: %.4f \r \n "
" Transit: %.4f \r \n "
" RRCount: %u \r \n " ,
rtp - > themssrc ,
rtp - > rxcount ,
rtp - > rtcp - > expected_prior - rtp - > rtcp - > received_prior ,
rtp - > rxjitter ,
rtp - > rxtransit ,
rtp - > rtcp - > rr_count ) ;
manager_event ( EVENT_FLAG_REPORTING , " RTPSenderStat " , " SSRC: %u \r \n "
" SentPackets: %u \r \n "
" LostPackets: %u \r \n "
" Jitter: %u \r \n "
" SRCount: %u \r \n "
" RTT: %f \r \n " ,
rtp - > ssrc ,
rtp - > txcount ,
rtp - > rtcp - > reported_lost ,
rtp - > rtcp - > reported_jitter ,
rtp - > rtcp - > sr_count ,
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 ) ;
2007-06-06 21:20:11 +00:00
ast_free ( rtp - > rtcp ) ;
2006-06-05 08:39:42 +00:00
rtp - > rtcp = NULL ;
2003-06-28 16:40:02 +00:00
}
2007-01-29 21:03:07 +00:00
# ifdef P2P_INTENSE
2006-12-15 19:57:04 +00:00
ast_mutex_destroy ( & rtp - > bridge_lock ) ;
2007-01-29 21:03:07 +00:00
# endif
2007-06-06 21:20:11 +00:00
ast_free ( rtp ) ;
2002-06-16 16:06:38 +00:00
}
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
}
2006-08-31 01:59:02 +00:00
/*! \brief Send begin frames for DTMF */
int ast_rtp_senddigit_begin ( struct ast_rtp * rtp , char digit )
2003-02-05 19:26:49 +00:00
{
unsigned int * rtpheader ;
2006-08-31 01:59:02 +00:00
int hdrlen = 12 , res = 0 , i = 0 , payload = 0 ;
2003-02-05 19:26:49 +00:00
char data [ 256 ] ;
2006-09-09 18:07:59 +00:00
if ( ( digit < = ' 9 ' ) & & ( digit > = ' 0 ' ) )
digit - = ' 0 ' ;
else if ( digit = = ' * ' )
digit = 10 ;
else if ( digit = = ' # ' )
digit = 11 ;
else if ( ( digit > = ' A ' ) & & ( digit < = ' D ' ) )
digit = digit - ' A ' + 12 ;
else if ( ( digit > = ' a ' ) & & ( digit < = ' d ' ) )
digit = digit - ' a ' + 12 ;
else {
ast_log ( LOG_WARNING , " Don't know how to represent '%c' \n " , digit ) ;
return 0 ;
}
2003-02-05 19:26:49 +00:00
/* If we have no peer, return immediately */
2006-08-31 01:59:02 +00:00
if ( ! rtp - > them . sin_addr . s_addr | | ! rtp - > them . sin_port )
2003-02-05 19:26:49 +00:00
return 0 ;
2006-08-31 01:59:02 +00:00
payload = ast_rtp_lookup_code ( rtp , 0 , AST_RTP_DTMF ) ;
2005-07-15 23:00:47 +00:00
rtp - > dtmfmute = ast_tvadd ( ast_tvnow ( ) , ast_tv ( 0 , 500000 ) ) ;
2006-09-09 18:07:59 +00:00
rtp - > send_duration = 160 ;
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 ) ;
2006-08-31 01:59:02 +00:00
for ( i = 0 ; i < 2 ; i + + ) {
2006-09-09 19:12:52 +00:00
rtpheader [ 3 ] = htonl ( ( digit < < 24 ) | ( 0xa < < 16 ) | ( rtp - > send_duration ) ) ;
2006-08-31 01:59:02 +00:00
res = sendto ( rtp - > s , ( void * ) rtpheader , hdrlen + 4 , 0 , ( struct sockaddr * ) & rtp - > them , sizeof ( rtp - > them ) ) ;
if ( res < 0 )
2007-01-31 17:45:43 +00:00
ast_log ( LOG_ERROR , " RTP Transmission error to %s:%u: %s \n " ,
2006-08-31 01:59:02 +00:00
ast_inet_ntoa ( rtp - > them . sin_addr ) ,
ntohs ( rtp - > them . sin_port ) , strerror ( errno ) ) ;
if ( rtp_debug_test_addr ( & rtp - > them ) )
2007-01-31 17:45:43 +00:00
ast_verbose ( " Sent RTP DTMF packet to %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u) \n " ,
2006-08-31 01:59:02 +00:00
ast_inet_ntoa ( rtp - > them . sin_addr ) ,
ntohs ( rtp - > them . sin_port ) , payload , rtp - > seqno , rtp - > lastdigitts , res - hdrlen ) ;
/* Increment sequence number */
rtp - > seqno + + ;
2006-09-09 18:07:59 +00:00
/* Increment duration */
rtp - > send_duration + = 160 ;
2005-07-12 23:36:00 +00:00
/* Clear marker bit and set seqno */
rtpheader [ 0 ] = htonl ( ( 2 < < 30 ) | ( payload < < 16 ) | ( rtp - > seqno ) ) ;
2003-02-05 19:26:49 +00:00
}
2006-08-31 01:59:02 +00:00
/* Since we received a begin, we can safely store the digit and disable any compensation */
2007-01-17 00:22:20 +00:00
rtp - > sending_digit = 1 ;
2006-08-31 01:59:02 +00:00
rtp - > send_digit = digit ;
rtp - > send_payload = payload ;
return 0 ;
}
/*! \brief Send continuation frame for DTMF */
static int ast_rtp_senddigit_continuation ( struct ast_rtp * rtp )
{
unsigned int * rtpheader ;
int hdrlen = 12 , res = 0 ;
char data [ 256 ] ;
if ( ! rtp - > them . sin_addr . s_addr | | ! rtp - > them . sin_port )
return 0 ;
/* Setup packet to send */
rtpheader = ( unsigned int * ) data ;
rtpheader [ 0 ] = htonl ( ( 2 < < 30 ) | ( 1 < < 23 ) | ( rtp - > send_payload < < 16 ) | ( rtp - > seqno ) ) ;
rtpheader [ 1 ] = htonl ( rtp - > lastdigitts ) ;
rtpheader [ 2 ] = htonl ( rtp - > ssrc ) ;
2006-09-09 19:12:52 +00:00
rtpheader [ 3 ] = htonl ( ( rtp - > send_digit < < 24 ) | ( 0xa < < 16 ) | ( rtp - > send_duration ) ) ;
2006-08-31 01:59:02 +00:00
rtpheader [ 0 ] = htonl ( ( 2 < < 30 ) | ( rtp - > send_payload < < 16 ) | ( rtp - > seqno ) ) ;
/* Transmit */
res = sendto ( rtp - > s , ( void * ) rtpheader , hdrlen + 4 , 0 , ( struct sockaddr * ) & rtp - > them , sizeof ( rtp - > them ) ) ;
if ( res < 0 )
ast_log ( LOG_ERROR , " RTP Transmission error to %s:%d: %s \n " ,
ast_inet_ntoa ( rtp - > them . sin_addr ) ,
ntohs ( rtp - > them . sin_port ) , strerror ( errno ) ) ;
if ( rtp_debug_test_addr ( & rtp - > them ) )
2007-01-31 17:45:43 +00:00
ast_verbose ( " Sent RTP DTMF packet to %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u) \n " ,
2006-08-31 01:59:02 +00:00
ast_inet_ntoa ( rtp - > them . sin_addr ) ,
ntohs ( rtp - > them . sin_port ) , rtp - > send_payload , rtp - > seqno , rtp - > lastdigitts , res - hdrlen ) ;
/* Increment sequence number */
2006-03-15 18:15:33 +00:00
rtp - > seqno + + ;
2006-09-09 18:07:59 +00:00
/* Increment duration */
rtp - > send_duration + = 160 ;
2006-08-31 01:59:02 +00:00
2003-02-05 19:26:49 +00:00
return 0 ;
}
2006-08-31 01:59:02 +00:00
/*! \brief Send end packets for DTMF */
int ast_rtp_senddigit_end ( struct ast_rtp * rtp , char digit )
{
unsigned int * rtpheader ;
int hdrlen = 12 , res = 0 , i = 0 ;
char data [ 256 ] ;
/* If no address, then bail out */
if ( ! rtp - > them . sin_addr . s_addr | | ! rtp - > them . sin_port )
return 0 ;
2006-09-09 18:07:59 +00:00
if ( ( digit < = ' 9 ' ) & & ( digit > = ' 0 ' ) )
digit - = ' 0 ' ;
else if ( digit = = ' * ' )
digit = 10 ;
else if ( digit = = ' # ' )
digit = 11 ;
else if ( ( digit > = ' A ' ) & & ( digit < = ' D ' ) )
digit = digit - ' A ' + 12 ;
else if ( ( digit > = ' a ' ) & & ( digit < = ' d ' ) )
digit = digit - ' a ' + 12 ;
else {
ast_log ( LOG_WARNING , " Don't know how to represent '%c' \n " , digit ) ;
return 0 ;
}
2006-08-31 01:59:02 +00:00
2006-08-31 21:00:16 +00:00
rtp - > dtmfmute = ast_tvadd ( ast_tvnow ( ) , ast_tv ( 0 , 500000 ) ) ;
2006-08-31 01:59:02 +00:00
rtpheader = ( unsigned int * ) data ;
rtpheader [ 0 ] = htonl ( ( 2 < < 30 ) | ( 1 < < 23 ) | ( rtp - > send_payload < < 16 ) | ( rtp - > seqno ) ) ;
rtpheader [ 1 ] = htonl ( rtp - > lastdigitts ) ;
rtpheader [ 2 ] = htonl ( rtp - > ssrc ) ;
2006-09-09 19:12:52 +00:00
rtpheader [ 3 ] = htonl ( ( digit < < 24 ) | ( 0xa < < 16 ) | ( rtp - > send_duration ) ) ;
2006-08-31 01:59:02 +00:00
/* Set end bit */
rtpheader [ 3 ] | = htonl ( ( 1 < < 23 ) ) ;
rtpheader [ 0 ] = htonl ( ( 2 < < 30 ) | ( rtp - > send_payload < < 16 ) | ( rtp - > seqno ) ) ;
/* Send 3 termination packets */
for ( i = 0 ; i < 3 ; i + + ) {
res = sendto ( rtp - > s , ( void * ) rtpheader , hdrlen + 4 , 0 , ( struct sockaddr * ) & rtp - > them , sizeof ( rtp - > them ) ) ;
if ( res < 0 )
ast_log ( LOG_ERROR , " RTP Transmission error to %s:%d: %s \n " ,
ast_inet_ntoa ( rtp - > them . sin_addr ) ,
ntohs ( rtp - > them . sin_port ) , strerror ( errno ) ) ;
if ( rtp_debug_test_addr ( & rtp - > them ) )
2007-01-31 17:45:43 +00:00
ast_verbose ( " Sent RTP DTMF packet to %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u) \n " ,
2006-08-31 01:59:02 +00:00
ast_inet_ntoa ( rtp - > them . sin_addr ) ,
ntohs ( rtp - > them . sin_port ) , rtp - > send_payload , rtp - > seqno , rtp - > lastdigitts , res - hdrlen ) ;
}
2007-01-17 00:22:20 +00:00
rtp - > sending_digit = 0 ;
2006-08-31 01:59:02 +00:00
rtp - > send_digit = 0 ;
/* Increment lastdigitts */
rtp - > lastdigitts + = 960 ;
rtp - > seqno + + ;
return res ;
}
/*! \brief Public function: Send an H.261 fast update request, some devices need this rather than SIP XML */
2006-06-05 08:39:42 +00:00
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-09-30 19:23:59 +00:00
/* Commented condition is always not NULL if rtp->rtcp is not NULL */
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-09-30 19:23:59 +00:00
ast_verbose ( " RTCP SR transmission error, rtcp halted \n " ) ;
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 ) ) ) ;
2007-04-18 20:39:31 +00:00
rtcpheader [ 10 ] = htonl ( ( unsigned int ) ( rtp - > rxjitter * 65536. ) ) ;
2006-06-05 08:39:42 +00:00
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 ) ) ;
}
2007-06-21 23:07:20 +00:00
manager_event ( EVENT_FLAG_REPORTING , " RTCPSent " , " To %s:%d \r \n "
" OurSSRC: %u \r \n "
" SentNTP: %u.%010u \r \n "
" SentRTP: %u \r \n "
" SentPackets: %u \r \n "
" SentOctets: %u \r \n "
" ReportBlock: \r \n "
" FractionLost: %u \r \n "
" CumulativeLoss: %u \r \n "
" IAJitter: %.4f \r \n "
" TheirLastSR: %u \r \n "
" DLSR: %4.4f (sec) \r \n " ,
ast_inet_ntoa ( rtp - > rtcp - > them . sin_addr ) , ntohs ( rtp - > rtcp - > them . sin_port ) ,
rtp - > ssrc ,
( unsigned int ) now . tv_sec , ( unsigned int ) now . tv_usec * 4096 ,
rtp - > lastts ,
rtp - > txcount ,
rtp - > txoctetcount ,
fraction ,
lost ,
rtp - > rxjitter ,
rtp - > rtcp - > themrxlsr ,
( double ) ( ntohl ( rtcpheader [ 12 ] ) / 65536.0 ) ) ;
2006-06-05 08:39:42 +00:00
return res ;
}
2006-10-26 17:52:15 +00:00
/*! \brief Send RTCP recipient's report */
2006-06-05 08:39:42 +00:00
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 ) {
2007-02-02 17:16:05 +00:00
ast_log ( LOG_ERROR , " RTCP RR transmission error, rtcp halted \n " ) ;
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 ) ) ) ;
2007-04-18 20:39:31 +00:00
rtcpheader [ 5 ] = htonl ( ( unsigned int ) ( rtp - > rxjitter * 65536. ) ) ;
2006-06-05 08:39:42 +00:00
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 ;
2007-06-26 20:36:50 +00:00
if ( ! rtp | | ! rtp - > rtcp )
return 0 ;
2006-06-05 08:39:42 +00:00
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 ) )
2007-01-31 17:45:43 +00:00
ast_verbose ( " Sent Comfort Noise RTP packet to %s:%u (type %d, seq %u, 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 ;
}
2006-11-25 09:45:57 +00:00
/*! \brief Write RTP packet with audio or video media frames into UDP packet */
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 {
2007-06-24 18:51:41 +00:00
ast_debug ( 3 , " 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
}
2007-02-16 13:35:44 +00:00
} else if ( f - > subclass < AST_FORMAT_MAX_VIDEO ) {
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 {
2007-06-24 18:51:41 +00:00
ast_debug ( 3 , " 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
}
2007-02-16 13:35:44 +00:00
} else {
pred = rtp - > lastotexttimestamp + f - > samples ;
/* Re-calculate last TS */
rtp - > lastts = rtp - > lastts + ms * 90 ;
/* If it's close to our prediction, go for it */
if ( ast_tvzero ( f - > delivery ) ) {
if ( abs ( rtp - > lastts - pred ) < 7200 ) {
rtp - > lastts = pred ;
rtp - > lastotexttimestamp + = f - > samples ;
} else {
2007-06-24 18:51:41 +00:00
ast_debug ( 3 , " 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 ) ;
2007-02-16 13:35:44 +00:00
rtp - > lastotexttimestamp = rtp - > lastts ;
}
}
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 ) ) ) {
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " 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 ) ) ;
2006-08-30 01:22:46 +00:00
} else if ( ( ( ast_test_flag ( rtp , FLAG_NAT_ACTIVE ) = = FLAG_NAT_INACTIVE ) | | rtpdebug ) & & ! ast_test_flag ( rtp , FLAG_NAT_INACTIVE_NOWARN ) ) {
2005-09-07 20:33:30 +00:00
/* Only give this error message once if we are not RTP debugging */
if ( option_debug | | rtpdebug )
2007-06-25 13:42:51 +00:00
ast_debug ( 0 , " 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 ) )
2007-01-31 17:45:43 +00:00
ast_verbose ( " Sent RTP packet to %s:%u (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
2006-09-18 23:32:57 +00:00
int ast_rtp_codec_setpref ( struct ast_rtp * rtp , struct ast_codec_pref * prefs )
{
int x ;
for ( x = 0 ; x < 32 ; x + + ) { /* Ugly way */
rtp - > pref . order [ x ] = prefs - > order [ x ] ;
rtp - > pref . framing [ x ] = prefs - > framing [ x ] ;
}
if ( rtp - > smoother )
ast_smoother_free ( rtp - > smoother ) ;
rtp - > smoother = NULL ;
return 0 ;
}
struct ast_codec_pref * ast_rtp_codec_getpref ( struct ast_rtp * rtp )
{
return & rtp - > pref ;
}
int ast_rtp_codec_getformat ( int pt )
{
if ( pt < 0 | | pt > MAX_RTP_PT )
return 0 ; /* bogus payload type */
if ( static_RTP_PT [ pt ] . isAstFormat )
return static_RTP_PT [ pt ] . code ;
else
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 */
2007-02-16 13:35:44 +00:00
if ( ( _f - > frametype ! = AST_FRAME_VOICE ) & & ( _f - > frametype ! = AST_FRAME_VIDEO ) & & ( _f - > frametype ! = AST_FRAME_TEXT ) ) {
ast_log ( LOG_WARNING , " RTP can only send voice, video and text \n " ) ;
2002-08-09 17:17:54 +00:00
return - 1 ;
}
2007-02-16 13:35:44 +00:00
/* The bottom bit of a video subclass contains the marker bit */
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 */
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " 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 ;
}
2007-06-20 17:55:09 +00:00
if ( ! rtp - > smoother & & subclass ! = AST_FORMAT_SPEEX ) {
2006-09-18 23:32:57 +00:00
struct ast_format_list fmt = ast_codec_pref_getsize ( & rtp - > pref , subclass ) ;
if ( fmt . inc_ms ) { /* if codec parameters is set / avoid division by zero */
if ( ! ( rtp - > smoother = ast_smoother_new ( ( fmt . cur_ms * fmt . fr_len ) / fmt . inc_ms ) ) ) {
ast_log ( LOG_WARNING , " Unable to create smoother: format: %d ms: %d len: %d \n " , subclass , fmt . cur_ms , ( ( fmt . cur_ms * fmt . fr_len ) / fmt . inc_ms ) ) ;
return - 1 ;
}
if ( fmt . flags )
ast_smoother_set_flags ( rtp - > smoother , fmt . flags ) ;
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " Created smoother: format: %d ms: %d len: %d \n " , subclass , fmt . cur_ms , ( ( fmt . cur_ms * fmt . fr_len ) / fmt . inc_ms ) ) ;
2003-04-15 04:36:52 +00:00
}
2006-09-18 23:32:57 +00:00
}
if ( rtp - > smoother ) {
if ( ast_smoother_test_flag ( rtp - > smoother , AST_SMOOTHER_FLAG_BE ) ) {
ast_smoother_feed_be ( rtp - > smoother , _f ) ;
} else {
ast_smoother_feed ( rtp - > smoother , _f ) ;
2003-04-15 04:36:52 +00:00
}
2006-09-18 23:32:57 +00:00
2007-05-29 16:46:49 +00:00
while ( ( f = ast_smoother_read ( rtp - > smoother ) ) & & ( f - > data ) )
2003-04-15 04:36:52 +00:00
ast_rtp_raw_write ( rtp , f , codec ) ;
2006-09-18 23:32:57 +00:00
} else {
2004-06-29 20:10:57 +00:00
/* Don't buffer outgoing frames; send them one-per-packet: */
2006-11-25 09:45:57 +00:00
if ( _f - > offset < hdrlen )
f = ast_frdup ( _f ) ; /*! \bug XXX this might never be free'd. Why do we do this? */
else
2002-08-09 17:17:54 +00:00
f = _f ;
2007-05-29 16:46:49 +00:00
if ( f - > data )
ast_rtp_raw_write ( rtp , f , codec ) ;
2006-11-29 16:53:27 +00:00
if ( f ! = _f )
ast_frfree ( f ) ;
2002-08-09 17:17:54 +00:00
}
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 )
{
2007-01-22 23:53:16 +00:00
AST_RWLIST_WRLOCK ( & protos ) ;
AST_RWLIST_REMOVE ( & protos , proto , list ) ;
AST_RWLIST_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
2007-01-22 23:53:16 +00:00
AST_RWLIST_WRLOCK ( & protos ) ;
AST_RWLIST_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 ) ;
2007-01-22 23:53:16 +00:00
AST_RWLIST_UNLOCK ( & protos ) ;
2003-02-16 06:00:12 +00:00
return - 1 ;
}
}
2007-01-22 23:53:16 +00:00
AST_RWLIST_INSERT_HEAD ( & protos , proto , list ) ;
AST_RWLIST_UNLOCK ( & protos ) ;
2006-01-03 09:30:19 +00:00
2003-02-16 06:00:12 +00:00
return 0 ;
}
2006-08-28 17:37:56 +00:00
/*! \brief Bridge loop for true native bridge (reinvite) */
2007-02-16 13:35:44 +00:00
static enum ast_bridge_result bridge_native_loop ( struct ast_channel * c0 , struct ast_channel * c1 , struct ast_rtp * p0 , struct ast_rtp * p1 , struct ast_rtp * vp0 , struct ast_rtp * vp1 , struct ast_rtp * tp0 , struct ast_rtp * tp1 , struct ast_rtp_protocol * pr0 , struct ast_rtp_protocol * pr1 , int codec0 , int codec1 , int timeoutms , int flags , struct ast_frame * * fo , struct ast_channel * * rc , void * pvt0 , void * pvt1 )
2003-02-16 06:00:12 +00:00
{
2006-08-28 17:37:56 +00:00
struct ast_frame * fr = NULL ;
struct ast_channel * who = NULL , * other = NULL , * cs [ 3 ] = { NULL , } ;
int oldcodec0 = codec0 , oldcodec1 = codec1 ;
2007-02-16 13:35:44 +00:00
struct sockaddr_in ac1 = { 0 , } , vac1 = { 0 , } , tac1 = { 0 , } , ac0 = { 0 , } , vac0 = { 0 , } , tac0 = { 0 , } ;
struct sockaddr_in t1 = { 0 , } , vt1 = { 0 , } , tt1 = { 0 , } , t0 = { 0 , } , vt0 = { 0 , } , tt0 = { 0 , } ;
2007-02-01 00:24:50 +00:00
2006-08-28 17:37:56 +00:00
/* Set it up so audio goes directly between the two endpoints */
2006-01-17 05:15:33 +00:00
2006-08-28 17:37:56 +00:00
/* Test the first channel */
2007-02-16 13:35:44 +00:00
if ( ! ( pr0 - > set_rtp_peer ( c0 , p1 , vp1 , tp1 , codec1 , ast_test_flag ( p1 , FLAG_NAT_ACTIVE ) ) ) ) {
2003-04-14 20:48:30 +00:00
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 ) ;
2007-02-16 13:35:44 +00:00
if ( tp1 )
ast_rtp_get_peer ( tp1 , & tac1 ) ;
2006-08-28 17:37:56 +00:00
} else
ast_log ( LOG_WARNING , " Channel '%s' failed to talk to '%s' \n " , c0 - > name , c1 - > name ) ;
/* Test the second channel */
2007-02-16 13:35:44 +00:00
if ( ! ( pr1 - > set_rtp_peer ( c1 , p0 , vp0 , tp0 , codec0 , ast_test_flag ( p0 , FLAG_NAT_ACTIVE ) ) ) ) {
2003-04-14 20:48:30 +00:00
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 ) ;
2007-02-16 13:35:44 +00:00
if ( tp0 )
ast_rtp_get_peer ( tp0 , & tac0 ) ;
2006-08-28 17:37:56 +00:00
} else
ast_log ( LOG_WARNING , " Channel '%s' failed to talk to '%s' \n " , c1 - > name , c0 - > name ) ;
/* Now we can unlock and move into our loop */
2006-04-27 17:53:52 +00:00
ast_channel_unlock ( c0 ) ;
ast_channel_unlock ( c1 ) ;
2006-08-28 17:37:56 +00:00
/* Throw our channels into the structure and enter the loop */
2003-02-16 06:00:12 +00:00
cs [ 0 ] = c0 ;
cs [ 1 ] = c1 ;
cs [ 2 ] = NULL ;
for ( ; ; ) {
2006-08-28 17:37:56 +00:00
/* Check if anything changed */
if ( ( c0 - > tech_pvt ! = pvt0 ) | |
( c1 - > tech_pvt ! = pvt1 ) | |
( c0 - > masq | | c0 - > masqr | | c1 - > masq | | c1 - > masqr ) ) {
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " Oooh, something is weird, backing out \n " ) ;
2006-08-28 17:37:56 +00:00
if ( c0 - > tech_pvt = = pvt0 )
2007-02-16 13:35:44 +00:00
if ( pr0 - > set_rtp_peer ( c0 , NULL , NULL , NULL , 0 , 0 ) )
2006-08-28 17:37:56 +00:00
ast_log ( LOG_WARNING , " Channel '%s' failed to break RTP bridge \n " , c0 - > name ) ;
if ( c1 - > tech_pvt = = pvt1 )
2007-02-16 13:35:44 +00:00
if ( pr1 - > set_rtp_peer ( c1 , NULL , NULL , NULL , 0 , 0 ) )
2006-08-28 17:37:56 +00:00
ast_log ( LOG_WARNING , " Channel '%s' failed to break RTP bridge \n " , c1 - > name ) ;
return AST_BRIDGE_RETRY ;
2003-02-16 06:00:12 +00:00
}
2006-08-28 17:37:56 +00:00
/* Check if they have changed their address */
2003-04-14 20:48:30 +00:00
ast_rtp_get_peer ( p1 , & t1 ) ;
2003-06-28 16:40:02 +00:00
if ( vp1 )
ast_rtp_get_peer ( vp1 , & vt1 ) ;
2007-02-16 13:35:44 +00:00
if ( tp1 )
ast_rtp_get_peer ( tp1 , & tt1 ) ;
2006-08-28 17:37:56 +00:00
if ( pr1 - > get_codec )
codec1 = pr1 - > get_codec ( c1 ) ;
ast_rtp_get_peer ( p0 , & t0 ) ;
2003-06-28 16:40:02 +00:00
if ( vp0 )
ast_rtp_get_peer ( vp0 , & vt0 ) ;
2007-02-16 13:35:44 +00:00
if ( tp0 )
ast_rtp_get_peer ( tp0 , & tt0 ) ;
2006-08-28 17:37:56 +00:00
if ( pr0 - > get_codec )
codec0 = pr0 - > get_codec ( c0 ) ;
if ( ( inaddrcmp ( & t1 , & ac1 ) ) | |
( vp1 & & inaddrcmp ( & vt1 , & vac1 ) ) | |
2007-02-16 13:35:44 +00:00
( tp1 & & inaddrcmp ( & tt1 , & tac1 ) ) | |
2006-08-28 17:37:56 +00:00
( codec1 ! = oldcodec1 ) ) {
2007-06-24 18:51:41 +00:00
ast_debug ( 2 , " Oooh, '%s' changed end address to %s:%d (format %d) \n " ,
c1 - > name , ast_inet_ntoa ( t1 . sin_addr ) , ntohs ( t1 . sin_port ) , codec1 ) ;
ast_debug ( 2 , " Oooh, '%s' changed end vaddress to %s:%d (format %d) \n " ,
c1 - > name , ast_inet_ntoa ( vt1 . sin_addr ) , ntohs ( vt1 . sin_port ) , codec1 ) ;
ast_debug ( 2 , " Oooh, '%s' changed end taddress to %s:%d (format %d) \n " ,
c1 - > name , ast_inet_ntoa ( tt1 . sin_addr ) , ntohs ( tt1 . sin_port ) , codec1 ) ;
ast_debug ( 2 , " Oooh, '%s' was %s:%d/(format %d) \n " ,
c1 - > name , ast_inet_ntoa ( ac1 . sin_addr ) , ntohs ( ac1 . sin_port ) , oldcodec1 ) ;
ast_debug ( 2 , " Oooh, '%s' was %s:%d/(format %d) \n " ,
c1 - > name , ast_inet_ntoa ( vac1 . sin_addr ) , ntohs ( vac1 . sin_port ) , oldcodec1 ) ;
ast_debug ( 2 , " Oooh, '%s' was %s:%d/(format %d) \n " ,
c1 - > name , ast_inet_ntoa ( tac1 . sin_addr ) , ntohs ( tac1 . sin_port ) , oldcodec1 ) ;
2007-02-16 13:35:44 +00:00
if ( pr0 - > set_rtp_peer ( c0 , t1 . sin_addr . s_addr ? p1 : NULL , vt1 . sin_addr . s_addr ? vp1 : NULL , tt1 . sin_addr . s_addr ? tp1 : 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 ) ) ;
2007-02-16 13:35:44 +00:00
memcpy ( & tac1 , & tt1 , sizeof ( tac1 ) ) ;
2004-05-27 04:18:46 +00:00
oldcodec1 = codec1 ;
2003-04-14 20:48:30 +00:00
}
2006-08-28 17:37:56 +00:00
if ( ( inaddrcmp ( & t0 , & ac0 ) ) | |
2007-02-16 13:35:44 +00:00
( vp0 & & inaddrcmp ( & vt0 , & vac0 ) ) | |
( tp0 & & inaddrcmp ( & tt0 , & tac0 ) ) ) {
2007-06-24 18:51:41 +00:00
ast_debug ( 2 , " Oooh, '%s' changed end address to %s:%d (format %d) \n " ,
c0 - > name , ast_inet_ntoa ( t0 . sin_addr ) , ntohs ( t0 . sin_port ) , codec0 ) ;
ast_debug ( 2 , " Oooh, '%s' was %s:%d/(format %d) \n " ,
c0 - > name , ast_inet_ntoa ( ac0 . sin_addr ) , ntohs ( ac0 . sin_port ) , oldcodec0 ) ;
2007-02-16 13:35:44 +00:00
if ( pr1 - > set_rtp_peer ( c1 , t0 . sin_addr . s_addr ? p0 : NULL , vt0 . sin_addr . s_addr ? vp0 : NULL , tt0 . sin_addr . s_addr ? tp0 : 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 ) ) ;
2007-02-16 13:35:44 +00:00
memcpy ( & tac0 , & tt0 , sizeof ( tac0 ) ) ;
2004-05-27 04:18:46 +00:00
oldcodec0 = codec0 ;
2003-04-14 20:48:30 +00:00
}
2006-08-28 17:37:56 +00:00
/* Wait for frame to come in on the channels */
if ( ! ( who = ast_waitfor_n ( cs , 2 , & timeoutms ) ) ) {
2007-06-06 13:32:11 +00:00
if ( ! timeoutms ) {
if ( pr0 - > set_rtp_peer ( c0 , NULL , NULL , NULL , 0 , 0 ) )
ast_log ( LOG_WARNING , " Channel '%s' failed to break RTP bridge \n " , c0 - > name ) ;
if ( pr1 - > set_rtp_peer ( c1 , NULL , NULL , NULL , 0 , 0 ) )
ast_log ( LOG_WARNING , " Channel '%s' failed to break RTP bridge \n " , c1 - > name ) ;
2005-10-14 17:02:20 +00:00
return AST_BRIDGE_RETRY ;
2007-06-06 13:32:11 +00:00
}
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " Ooh, empty read... \n " ) ;
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 ;
}
2006-08-28 17:37:56 +00:00
fr = ast_read ( who ) ;
other = ( who = = c0 ) ? c1 : c0 ;
if ( ! fr | | ( ( fr - > frametype = = AST_FRAME_DTMF ) & &
( ( ( who = = c0 ) & & ( flags & AST_BRIDGE_DTMF_CHANNEL_0 ) ) | |
( ( who = = c1 ) & & ( flags & AST_BRIDGE_DTMF_CHANNEL_1 ) ) ) ) ) {
/* Break out of bridge */
* fo = fr ;
2003-02-16 06:00:12 +00:00
* rc = who ;
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " Oooh, got a %s \n " , fr ? " digit " : " hangup " ) ;
2006-08-28 17:37:56 +00:00
if ( c0 - > tech_pvt = = pvt0 )
2007-02-16 13:35:44 +00:00
if ( pr0 - > set_rtp_peer ( c0 , NULL , 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 ) ;
2006-08-28 17:37:56 +00:00
if ( c1 - > tech_pvt = = pvt1 )
2007-02-16 13:35:44 +00:00
if ( pr1 - > set_rtp_peer ( c1 , NULL , 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 ) ;
2006-08-28 17:37:56 +00:00
return AST_BRIDGE_COMPLETE ;
} else if ( ( fr - > frametype = = AST_FRAME_CONTROL ) & & ! ( flags & AST_BRIDGE_IGNORE_SIGS ) ) {
if ( ( fr - > subclass = = AST_CONTROL_HOLD ) | |
( fr - > subclass = = AST_CONTROL_UNHOLD ) | |
( fr - > subclass = = AST_CONTROL_VIDUPDATE ) ) {
2007-02-01 00:24:50 +00:00
if ( fr - > subclass = = AST_CONTROL_HOLD ) {
/* If we someone went on hold we want the other side to reinvite back to us */
if ( who = = c0 )
2007-02-16 13:35:44 +00:00
pr1 - > set_rtp_peer ( c1 , NULL , NULL , NULL , 0 , 0 ) ;
2007-02-01 00:24:50 +00:00
else
2007-02-16 13:35:44 +00:00
pr0 - > set_rtp_peer ( c0 , NULL , NULL , NULL , 0 , 0 ) ;
2007-02-01 00:24:50 +00:00
} else if ( fr - > subclass = = AST_CONTROL_UNHOLD ) {
/* If they went off hold they should go back to being direct */
if ( who = = c0 )
2007-02-16 13:35:44 +00:00
pr1 - > set_rtp_peer ( c1 , p0 , vp0 , tp0 , codec0 , ast_test_flag ( p0 , FLAG_NAT_ACTIVE ) ) ;
2007-02-01 00:24:50 +00:00
else
2007-02-16 13:35:44 +00:00
pr0 - > set_rtp_peer ( c0 , p1 , vp1 , tp1 , codec1 , ast_test_flag ( p1 , FLAG_NAT_ACTIVE ) ) ;
2007-02-01 00:24:50 +00:00
}
2007-01-18 00:20:50 +00:00
ast_indicate_data ( other , fr - > subclass , fr - > data , fr - > datalen ) ;
2006-08-28 17:37:56 +00:00
ast_frfree ( fr ) ;
} else {
* fo = fr ;
* rc = who ;
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " Got a FRAME_CONTROL (%d) frame on channel %s \n " , fr - > subclass , who - > name ) ;
2006-08-28 17:37:56 +00:00
return AST_BRIDGE_COMPLETE ;
}
} else {
2007-02-01 00:23:19 +00:00
if ( ( fr - > frametype = = AST_FRAME_DTMF_BEGIN ) | |
( fr - > frametype = = AST_FRAME_DTMF ) | |
2006-08-28 17:37:56 +00:00
( fr - > frametype = = AST_FRAME_VOICE ) | |
2007-02-01 00:23:19 +00:00
( fr - > frametype = = AST_FRAME_VIDEO ) | |
( fr - > frametype = = AST_FRAME_IMAGE ) | |
( fr - > frametype = = AST_FRAME_HTML ) | |
( fr - > frametype = = AST_FRAME_MODEM ) | |
( fr - > frametype = = AST_FRAME_TEXT ) ) {
2006-08-28 17:37:56 +00:00
ast_write ( other , fr ) ;
}
ast_frfree ( fr ) ;
}
/* Swap priority */
cs [ 2 ] = cs [ 0 ] ;
cs [ 0 ] = cs [ 1 ] ;
cs [ 1 ] = cs [ 2 ] ;
}
2007-06-12 14:26:12 +00:00
if ( pr0 - > set_rtp_peer ( c0 , NULL , NULL , NULL , 0 , 0 ) )
ast_log ( LOG_WARNING , " Channel '%s' failed to break RTP bridge \n " , c0 - > name ) ;
if ( pr1 - > set_rtp_peer ( c1 , NULL , NULL , NULL , 0 , 0 ) )
ast_log ( LOG_WARNING , " Channel '%s' failed to break RTP bridge \n " , c1 - > name ) ;
2006-08-28 17:37:56 +00:00
return AST_BRIDGE_FAILED ;
}
2006-12-11 05:38:57 +00:00
/*! \brief P2P RTP Callback */
2007-01-08 18:23:39 +00:00
# ifdef P2P_INTENSE
2006-08-30 01:22:46 +00:00
static int p2p_rtp_callback ( int * id , int fd , short events , void * cbdata )
{
int res = 0 , hdrlen = 12 ;
struct sockaddr_in sin ;
socklen_t len ;
unsigned int * header ;
2006-12-15 19:57:04 +00:00
struct ast_rtp * rtp = cbdata , * bridged = NULL ;
2006-08-30 01:22:46 +00:00
if ( ! rtp )
return 1 ;
len = sizeof ( sin ) ;
if ( ( res = recvfrom ( fd , rtp - > rawdata + AST_FRIENDLY_OFFSET , sizeof ( rtp - > rawdata ) - AST_FRIENDLY_OFFSET , 0 , ( struct sockaddr * ) & sin , & len ) ) < 0 )
return 1 ;
header = ( unsigned int * ) ( rtp - > rawdata + AST_FRIENDLY_OFFSET ) ;
2007-01-22 23:51:42 +00:00
2006-08-30 01:22:46 +00:00
/* If NAT support is turned on, then see if we need to change their address */
2006-12-11 05:38:57 +00:00
if ( ( rtp - > nat ) & &
( ( rtp - > them . sin_addr . s_addr ! = sin . sin_addr . s_addr ) | |
( rtp - > them . sin_port ! = sin . sin_port ) ) ) {
rtp - > them = sin ;
rtp - > rxseqno = 0 ;
ast_set_flag ( rtp , FLAG_NAT_ACTIVE ) ;
if ( option_debug | | rtpdebug )
2007-06-25 13:42:51 +00:00
ast_debug ( 0 , " P2P 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 ) ) ;
2006-08-30 01:22:46 +00:00
}
2006-12-11 05:38:57 +00:00
/* Write directly out to other RTP stream if bridged */
2006-12-15 19:57:04 +00:00
if ( ( bridged = ast_rtp_get_bridged ( rtp ) ) )
bridge_p2p_rtp_write ( rtp , bridged , header , res , hdrlen ) ;
2007-01-22 23:51:42 +00:00
2006-12-11 05:38:57 +00:00
return 1 ;
}
2006-08-30 01:22:46 +00:00
/*! \brief Helper function to switch a channel and RTP stream into callback mode */
2006-11-20 16:06:10 +00:00
static int p2p_callback_enable ( struct ast_channel * chan , struct ast_rtp * rtp , int * * iod )
2006-08-30 01:22:46 +00:00
{
2006-11-30 21:22:01 +00:00
/* If we need DTMF, are looking for STUN, or we have no IO structure then we can't do direct callback */
if ( ast_test_flag ( rtp , FLAG_P2P_NEED_DTMF ) | | ast_test_flag ( rtp , FLAG_HAS_STUN ) | | ! rtp - > io )
2006-08-30 01:22:46 +00:00
return 0 ;
2006-08-30 01:29:59 +00:00
/* If the RTP structure is already in callback mode, remove it temporarily */
if ( rtp - > ioid ) {
ast_io_remove ( rtp - > io , rtp - > ioid ) ;
rtp - > ioid = NULL ;
}
2006-11-20 16:06:10 +00:00
/* Steal the file descriptors from the channel */
2006-08-30 01:22:46 +00:00
chan - > fds [ 0 ] = - 1 ;
/* Now, fire up callback mode */
2006-11-20 16:06:10 +00:00
iod [ 0 ] = ast_io_add ( rtp - > io , ast_rtp_fd ( rtp ) , p2p_rtp_callback , AST_IO_IN , rtp ) ;
2006-08-30 01:22:46 +00:00
return 1 ;
}
2007-01-08 18:23:39 +00:00
# else
2007-01-08 20:10:23 +00:00
static int p2p_callback_enable ( struct ast_channel * chan , struct ast_rtp * rtp , int * * iod )
2007-01-08 18:23:39 +00:00
{
return 0 ;
}
# endif
2006-08-30 01:22:46 +00:00
/*! \brief Helper function to switch a channel and RTP stream out of callback mode */
2006-11-20 16:06:10 +00:00
static int p2p_callback_disable ( struct ast_channel * chan , struct ast_rtp * rtp , int * * iod )
2006-08-30 01:22:46 +00:00
{
ast_channel_lock ( chan ) ;
2006-12-11 05:38:57 +00:00
2006-08-30 01:22:46 +00:00
/* Remove the callback from the IO context */
ast_io_remove ( rtp - > io , iod [ 0 ] ) ;
2006-12-11 05:38:57 +00:00
2006-08-30 01:22:46 +00:00
/* Restore file descriptors */
2006-11-20 16:06:10 +00:00
chan - > fds [ 0 ] = ast_rtp_fd ( rtp ) ;
2006-08-30 01:22:46 +00:00
ast_channel_unlock ( chan ) ;
2006-12-11 05:38:57 +00:00
2006-08-30 01:29:59 +00:00
/* Restore callback mode if previously used */
if ( ast_test_flag ( rtp , FLAG_CALLBACK_MODE ) )
2006-12-11 05:38:57 +00:00
rtp - > ioid = ast_io_add ( rtp - > io , ast_rtp_fd ( rtp ) , rtpread , AST_IO_IN , rtp ) ;
2006-12-14 03:39:39 +00:00
2006-08-30 01:22:46 +00:00
return 0 ;
}
2006-12-15 19:57:04 +00:00
/*! \brief Helper function that sets what an RTP structure is bridged to */
static void p2p_set_bridge ( struct ast_rtp * rtp0 , struct ast_rtp * rtp1 )
{
2007-01-29 21:03:07 +00:00
rtp_bridge_lock ( rtp0 ) ;
2006-12-15 19:57:04 +00:00
rtp0 - > bridged = rtp1 ;
2007-01-29 21:03:07 +00:00
rtp_bridge_unlock ( rtp0 ) ;
2006-12-15 19:57:04 +00:00
return ;
}
2006-11-25 09:45:57 +00:00
/*! \brief Bridge loop for partial native bridge (packet2packet)
In p2p mode , Asterisk is a very basic RTP proxy , just forwarding whatever
rtp / rtcp we get in to the channel .
\ note this currently only works for Audio
*/
2006-11-22 21:49:11 +00:00
static enum ast_bridge_result bridge_p2p_loop ( struct ast_channel * c0 , struct ast_channel * c1 , struct ast_rtp * p0 , struct ast_rtp * p1 , int timeoutms , int flags , struct ast_frame * * fo , struct ast_channel * * rc , void * pvt0 , void * pvt1 )
2006-08-28 17:37:56 +00:00
{
struct ast_frame * fr = NULL ;
struct ast_channel * who = NULL , * other = NULL , * cs [ 3 ] = { NULL , } ;
2006-11-20 16:04:14 +00:00
int * p0_iod [ 2 ] = { NULL , NULL } , * p1_iod [ 2 ] = { NULL , NULL } ;
2006-08-30 01:22:46 +00:00
int p0_callback = 0 , p1_callback = 0 ;
enum ast_bridge_result res = AST_BRIDGE_FAILED ;
2006-08-28 17:37:56 +00:00
/* Okay, setup each RTP structure to do P2P forwarding */
ast_clear_flag ( p0 , FLAG_P2P_SENT_MARK ) ;
2006-12-15 19:57:04 +00:00
p2p_set_bridge ( p0 , p1 ) ;
2006-08-28 17:37:56 +00:00
ast_clear_flag ( p1 , FLAG_P2P_SENT_MARK ) ;
2006-12-15 19:57:04 +00:00
p2p_set_bridge ( p1 , p0 ) ;
2006-08-28 17:37:56 +00:00
2006-08-30 01:22:46 +00:00
/* Activate callback modes if possible */
2006-11-20 16:06:10 +00:00
p0_callback = p2p_callback_enable ( c0 , p0 , & p0_iod [ 0 ] ) ;
p1_callback = p2p_callback_enable ( c1 , p1 , & p1_iod [ 0 ] ) ;
2006-08-30 01:22:46 +00:00
2006-08-28 17:37:56 +00:00
/* Now let go of the channel locks and be on our way */
ast_channel_unlock ( c0 ) ;
ast_channel_unlock ( c1 ) ;
/* Go into a loop forwarding frames until we don't need to anymore */
cs [ 0 ] = c0 ;
cs [ 1 ] = c1 ;
cs [ 2 ] = NULL ;
for ( ; ; ) {
/* Check if anything changed */
if ( ( c0 - > tech_pvt ! = pvt0 ) | |
( c1 - > tech_pvt ! = pvt1 ) | |
( c0 - > masq | | c0 - > masqr | | c1 - > masq | | c1 - > masqr ) ) {
2007-06-24 18:51:41 +00:00
ast_debug ( 3 , " p2p-rtp-bridge: Oooh, something is weird, backing out \n " ) ;
2006-12-30 18:27:13 +00:00
/* If a masquerade needs to happen we have to try to read in a frame so that it actually happens. Without this we risk being called again and going into a loop */
2006-12-30 05:49:17 +00:00
if ( ( c0 - > masq | | c0 - > masqr ) & & ( fr = ast_read ( c0 ) ) )
ast_frfree ( fr ) ;
if ( ( c1 - > masq | | c1 - > masqr ) & & ( fr = ast_read ( c1 ) ) )
ast_frfree ( fr ) ;
2006-08-30 01:22:46 +00:00
res = AST_BRIDGE_RETRY ;
break ;
2006-08-28 17:37:56 +00:00
}
/* Wait on a channel to feed us a frame */
if ( ! ( who = ast_waitfor_n ( cs , 2 , & timeoutms ) ) ) {
2006-08-30 01:22:46 +00:00
if ( ! timeoutms ) {
res = AST_BRIDGE_RETRY ;
break ;
}
2006-11-29 19:44:06 +00:00
if ( option_debug > 2 )
ast_log ( LOG_NOTICE , " p2p-rtp-bridge: Ooh, empty read... \n " ) ;
2006-08-28 17:37:56 +00:00
if ( ast_check_hangup ( c0 ) | | ast_check_hangup ( c1 ) )
break ;
continue ;
}
/* Read in frame from channel */
fr = ast_read ( who ) ;
other = ( who = = c0 ) ? c1 : c0 ;
2006-11-29 19:44:06 +00:00
/* Depending on the frame we may need to break out of our bridge */
2006-08-28 17:37:56 +00:00
if ( ! fr | | ( ( fr - > frametype = = AST_FRAME_DTMF ) & &
( ( who = = c0 ) & & ( flags & AST_BRIDGE_DTMF_CHANNEL_0 ) ) |
( ( who = = c1 ) & & ( flags & AST_BRIDGE_DTMF_CHANNEL_1 ) ) ) ) {
/* Record received frame and who */
* fo = fr ;
* rc = who ;
2007-06-24 18:51:41 +00:00
ast_debug ( 3 , " p2p-rtp-bridge: Ooh, got a %s \n " , fr ? " digit " : " hangup " ) ;
2006-08-30 01:22:46 +00:00
res = AST_BRIDGE_COMPLETE ;
break ;
2006-08-28 17:37:56 +00:00
} else if ( ( fr - > frametype = = AST_FRAME_CONTROL ) & & ! ( flags & AST_BRIDGE_IGNORE_SIGS ) ) {
if ( ( fr - > subclass = = AST_CONTROL_HOLD ) | |
( fr - > subclass = = AST_CONTROL_UNHOLD ) | |
( fr - > subclass = = AST_CONTROL_VIDUPDATE ) ) {
2006-09-20 17:08:44 +00:00
/* If we are going on hold, then break callback mode and P2P bridging */
2006-08-30 01:22:46 +00:00
if ( fr - > subclass = = AST_CONTROL_HOLD ) {
if ( p0_callback )
2006-11-20 16:06:10 +00:00
p0_callback = p2p_callback_disable ( c0 , p0 , & p0_iod [ 0 ] ) ;
2006-08-30 01:22:46 +00:00
if ( p1_callback )
2006-11-20 16:06:10 +00:00
p1_callback = p2p_callback_disable ( c1 , p1 , & p1_iod [ 0 ] ) ;
2006-12-15 19:57:04 +00:00
p2p_set_bridge ( p0 , NULL ) ;
p2p_set_bridge ( p1 , NULL ) ;
2006-08-30 01:22:46 +00:00
} else if ( fr - > subclass = = AST_CONTROL_UNHOLD ) {
2006-09-20 17:08:44 +00:00
/* If we are off hold, then go back to callback mode and P2P bridging */
ast_clear_flag ( p0 , FLAG_P2P_SENT_MARK ) ;
2006-12-15 19:57:04 +00:00
p2p_set_bridge ( p0 , p1 ) ;
2006-09-20 17:08:44 +00:00
ast_clear_flag ( p1 , FLAG_P2P_SENT_MARK ) ;
2006-12-15 19:57:04 +00:00
p2p_set_bridge ( p1 , p0 ) ;
2006-11-20 16:06:10 +00:00
p0_callback = p2p_callback_enable ( c0 , p0 , & p0_iod [ 0 ] ) ;
p1_callback = p2p_callback_enable ( c1 , p1 , & p1_iod [ 0 ] ) ;
2006-08-30 01:22:46 +00:00
}
2007-01-18 00:20:50 +00:00
ast_indicate_data ( other , fr - > subclass , fr - > data , fr - > datalen ) ;
2006-08-28 17:37:56 +00:00
ast_frfree ( fr ) ;
2005-08-30 02:12:09 +00:00
} else {
2006-08-28 17:37:56 +00:00
* fo = fr ;
2005-08-30 02:12:09 +00:00
* rc = who ;
2007-06-24 18:51:41 +00:00
ast_debug ( 3 , " p2p-rtp-bridge: Got a FRAME_CONTROL (%d) frame on channel %s \n " , fr - > subclass , who - > name ) ;
2006-08-30 01:22:46 +00:00
res = AST_BRIDGE_COMPLETE ;
break ;
2005-08-30 02:12:09 +00:00
}
2003-03-15 06:00:16 +00:00
} else {
2007-02-01 00:23:19 +00:00
if ( ( fr - > frametype = = AST_FRAME_DTMF_BEGIN ) | |
( fr - > frametype = = AST_FRAME_DTMF ) | |
2006-08-28 17:37:56 +00:00
( fr - > frametype = = AST_FRAME_VOICE ) | |
2007-02-01 00:23:19 +00:00
( fr - > frametype = = AST_FRAME_VIDEO ) | |
( fr - > frametype = = AST_FRAME_IMAGE ) | |
( fr - > frametype = = AST_FRAME_HTML ) | |
( fr - > frametype = = AST_FRAME_MODEM ) | |
( fr - > frametype = = AST_FRAME_TEXT ) ) {
2006-08-28 17:37:56 +00:00
ast_write ( other , fr ) ;
2003-03-15 06:00:16 +00:00
}
2007-02-01 00:23:19 +00:00
2006-08-28 17:37:56 +00:00
ast_frfree ( fr ) ;
2003-03-15 06:00:16 +00:00
}
2006-08-28 17:37:56 +00:00
/* Swap priority */
2003-02-16 06:00:12 +00:00
cs [ 2 ] = cs [ 0 ] ;
cs [ 0 ] = cs [ 1 ] ;
cs [ 1 ] = cs [ 2 ] ;
}
2006-08-28 17:37:56 +00:00
2006-08-30 01:22:46 +00:00
/* If we are totally avoiding the core, then restore our link to it */
if ( p0_callback )
2006-11-20 16:06:10 +00:00
p0_callback = p2p_callback_disable ( c0 , p0 , & p0_iod [ 0 ] ) ;
2006-08-30 01:22:46 +00:00
if ( p1_callback )
2006-11-20 16:06:10 +00:00
p1_callback = p2p_callback_disable ( c1 , p1 , & p1_iod [ 0 ] ) ;
2006-08-30 01:22:46 +00:00
2006-09-01 18:57:10 +00:00
/* Break out of the direct bridge */
2006-12-15 19:57:04 +00:00
p2p_set_bridge ( p0 , NULL ) ;
p2p_set_bridge ( p1 , NULL ) ;
2006-09-01 18:57:10 +00:00
2006-08-30 01:22:46 +00:00
return res ;
2003-02-16 06:00:12 +00:00
}
2003-05-16 02:50:46 +00:00
2006-12-05 20:39:13 +00:00
/*! \page AstRTPbridge The Asterisk RTP bridge
The RTP bridge is called from the channel drivers that are using the RTP
subsystem in Asterisk - like SIP , H .323 and Jingle / Google Talk .
This bridge aims to offload the Asterisk server by setting up
the media stream directly between the endpoints , keeping the
signalling in Asterisk .
It checks with the channel driver , using a callback function , if
there are possibilities for a remote bridge .
If this fails , the bridge hands off to the core bridge . Reasons
can be NAT support needed , DTMF features in audio needed by
the PBX for transfers or spying / monitoring on channels .
If transcoding is needed - we can ' t do a remote bridge .
If only NAT support is needed , we ' re using Asterisk in
RTP proxy mode with the p2p RTP bridge , basically
forwarding incoming audio packets to the outbound
stream on a network level .
References :
- ast_rtp_bridge ( )
- ast_channel_early_bridge ( )
- ast_channel_bridge ( )
2007-02-24 20:29:41 +00:00
- rtp . c
- rtp . h
*/
/*! \brief Bridge calls. If possible and allowed, initiate
re - invite so the peers exchange media directly outside
of Asterisk .
2006-12-05 20:39:13 +00:00
*/
2006-08-28 17:37:56 +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 )
{
struct ast_rtp * p0 = NULL , * p1 = NULL ; /* Audio RTP Channels */
struct ast_rtp * vp0 = NULL , * vp1 = NULL ; /* Video RTP channels */
2007-02-16 13:35:44 +00:00
struct ast_rtp * tp0 = NULL , * tp1 = NULL ; /* Text RTP channels */
2006-08-28 17:37:56 +00:00
struct ast_rtp_protocol * pr0 = NULL , * pr1 = NULL ;
2007-02-16 13:35:44 +00:00
enum ast_rtp_get_result audio_p0_res = AST_RTP_GET_FAILED , video_p0_res = AST_RTP_GET_FAILED , text_p0_res = AST_RTP_GET_FAILED ;
enum ast_rtp_get_result audio_p1_res = AST_RTP_GET_FAILED , video_p1_res = AST_RTP_GET_FAILED , text_p1_res = AST_RTP_GET_FAILED ;
2006-08-28 17:37:56 +00:00
enum ast_bridge_result res = AST_BRIDGE_FAILED ;
int codec0 = 0 , codec1 = 0 ;
void * pvt0 = NULL , * pvt1 = NULL ;
/* Lock channels */
ast_channel_lock ( c0 ) ;
2007-01-22 23:51:42 +00:00
while ( ast_channel_trylock ( c1 ) ) {
2006-08-28 17:37:56 +00:00
ast_channel_unlock ( c0 ) ;
usleep ( 1 ) ;
ast_channel_lock ( c0 ) ;
}
/* Find channel driver interfaces */
if ( ! ( pr0 = get_proto ( c0 ) ) ) {
ast_log ( LOG_WARNING , " Can't find native functions for channel '%s' \n " , c0 - > name ) ;
ast_channel_unlock ( c0 ) ;
ast_channel_unlock ( c1 ) ;
return AST_BRIDGE_FAILED ;
}
if ( ! ( pr1 = get_proto ( c1 ) ) ) {
ast_log ( LOG_WARNING , " Can't find native functions for channel '%s' \n " , c1 - > name ) ;
ast_channel_unlock ( c0 ) ;
ast_channel_unlock ( c1 ) ;
return AST_BRIDGE_FAILED ;
}
/* Get channel specific interface structures */
pvt0 = c0 - > tech_pvt ;
pvt1 = c1 - > tech_pvt ;
/* Get audio and video interface (if native bridge is possible) */
audio_p0_res = pr0 - > get_rtp_info ( c0 , & p0 ) ;
video_p0_res = pr0 - > get_vrtp_info ? pr0 - > get_vrtp_info ( c0 , & vp0 ) : AST_RTP_GET_FAILED ;
2007-02-16 13:35:44 +00:00
text_p0_res = pr0 - > get_trtp_info ? pr0 - > get_trtp_info ( c0 , & vp0 ) : AST_RTP_GET_FAILED ;
2006-08-28 17:37:56 +00:00
audio_p1_res = pr1 - > get_rtp_info ( c1 , & p1 ) ;
video_p1_res = pr1 - > get_vrtp_info ? pr1 - > get_vrtp_info ( c1 , & vp1 ) : AST_RTP_GET_FAILED ;
2007-02-16 13:35:44 +00:00
text_p1_res = pr1 - > get_trtp_info ? pr1 - > get_trtp_info ( c1 , & vp1 ) : AST_RTP_GET_FAILED ;
2006-08-28 17:37:56 +00:00
2006-09-01 17:54:22 +00:00
/* If we are carrying video, and both sides are not reinviting... then fail the native bridge */
if ( video_p0_res ! = AST_RTP_GET_FAILED & & ( audio_p0_res ! = AST_RTP_TRY_NATIVE | | video_p0_res ! = AST_RTP_TRY_NATIVE ) )
audio_p0_res = AST_RTP_GET_FAILED ;
if ( video_p1_res ! = AST_RTP_GET_FAILED & & ( audio_p1_res ! = AST_RTP_TRY_NATIVE | | video_p1_res ! = AST_RTP_TRY_NATIVE ) )
audio_p1_res = AST_RTP_GET_FAILED ;
/* Check if a bridge is possible (partial/native) */
2006-08-28 17:37:56 +00:00
if ( audio_p0_res = = AST_RTP_GET_FAILED | | audio_p1_res = = AST_RTP_GET_FAILED ) {
/* Somebody doesn't want to play... */
ast_channel_unlock ( c0 ) ;
ast_channel_unlock ( c1 ) ;
return AST_BRIDGE_FAILED_NOWARN ;
}
/* If we need to feed DTMF frames into the core then only do a partial native bridge */
if ( ast_test_flag ( p0 , FLAG_HAS_DTMF ) & & ( flags & AST_BRIDGE_DTMF_CHANNEL_0 ) ) {
ast_set_flag ( p0 , FLAG_P2P_NEED_DTMF ) ;
audio_p0_res = AST_RTP_TRY_PARTIAL ;
}
if ( ast_test_flag ( p1 , FLAG_HAS_DTMF ) & & ( flags & AST_BRIDGE_DTMF_CHANNEL_1 ) ) {
ast_set_flag ( p1 , FLAG_P2P_NEED_DTMF ) ;
audio_p1_res = AST_RTP_TRY_PARTIAL ;
}
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
/* If both sides are not using the same method of DTMF transmission
* ( ie : one is RFC2833 , other is INFO . . . then we can not do direct media .
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* | DTMF Mode | HAS_DTMF | Accepts Begin Frames |
* | - - - - - - - - - - - | - - - - - - - - - - - - | - - - - - - - - - - - - - - - - - - - - - - - |
* | Inband | False | True |
* | RFC2833 | True | True |
2007-01-29 21:27:34 +00:00
* | SIP INFO | False | False |
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2007-01-29 21:27:34 +00:00
* However , if DTMF from both channels is being monitored by the core , then
* we can still do packet - to - packet bridging , because passing through the
* core will handle DTMF mode translation .
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
*/
if ( ( ast_test_flag ( p0 , FLAG_HAS_DTMF ) ! = ast_test_flag ( p1 , FLAG_HAS_DTMF ) ) | |
( ! c0 - > tech - > send_digit_begin ! = ! c1 - > tech - > send_digit_begin ) ) {
2007-01-29 21:27:34 +00:00
if ( ! ast_test_flag ( p0 , FLAG_P2P_NEED_DTMF ) | | ! ast_test_flag ( p1 , FLAG_P2P_NEED_DTMF ) ) {
ast_channel_unlock ( c0 ) ;
ast_channel_unlock ( c1 ) ;
return AST_BRIDGE_FAILED_NOWARN ;
}
Merged revisions 51311 via svnmerge from
https://origsvn.digium.com/svn/asterisk/branches/1.4
........
r51311 | russell | 2007-01-19 11:49:38 -0600 (Fri, 19 Jan 2007) | 23 lines
Merge the changes from the /team/group/vldtmf_fixup branch.
The main bug being addressed here is a problem introduced when two SIP
channels using SIP INFO dtmf have their media directly bridged. So, when a
DTMF END frame comes into Asterisk from an incoming INFO message, Asterisk
would try to emulate a digit of some length by first sending a DTMF BEGIN
frame and sending a DTMF END later timed off of incoming audio. However,
since there was no audio coming in, the DTMF_END was never generated. This
caused DTMF based features to no longer work.
To fix this, the core now knows when a channel doesn't care about DTMF BEGIN
frames (such as a SIP channel sending INFO dtmf). If this is the case, then
Asterisk will not emulate a digit of some length, and will instead just pass
through the single DTMF END event.
Channel drivers also now get passed the length of the digit to their digit_end
callback. This improves SIP INFO support even further by enabling us to put
the real digit duration in the INFO message instead of a hard coded 250ms.
Also, for an incoming INFO message, the duration is read from the frame and
passed into the core instead of just getting ignored.
(issue #8597, maybe others...)
........
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@51314 65c4cc65-6c06-0410-ace0-fbb531ad65f3
2007-01-19 18:06:03 +00:00
audio_p0_res = AST_RTP_TRY_PARTIAL ;
audio_p1_res = AST_RTP_TRY_PARTIAL ;
}
2007-02-07 17:57:37 +00:00
/* If the core will need to compensate and the P2P bridge will need to feed up DTMF frames then we can not reliably do so yet, so do not P2P bridge */
if ( ( audio_p0_res = = AST_RTP_TRY_PARTIAL & & ast_test_flag ( p0 , FLAG_P2P_NEED_DTMF ) & & ast_test_flag ( p0 , FLAG_DTMF_COMPENSATE ) ) | |
( audio_p1_res = = AST_RTP_TRY_PARTIAL & & ast_test_flag ( p1 , FLAG_P2P_NEED_DTMF ) & & ast_test_flag ( p1 , FLAG_DTMF_COMPENSATE ) ) ) {
ast_channel_unlock ( c0 ) ;
ast_channel_unlock ( c1 ) ;
return AST_BRIDGE_FAILED_NOWARN ;
}
2006-08-28 17:37:56 +00:00
/* Get codecs from both sides */
codec0 = pr0 - > get_codec ? pr0 - > get_codec ( c0 ) : 0 ;
codec1 = pr1 - > get_codec ? pr1 - > get_codec ( c1 ) : 0 ;
2006-09-20 16:55:09 +00:00
if ( codec0 & & codec1 & & ! ( codec0 & codec1 ) ) {
2006-08-28 17:37:56 +00:00
/* Hey, we can't do native bridging if both parties speak different codecs */
2007-06-24 18:51:41 +00:00
ast_debug ( 3 , " Channel codec0 = %d is not codec1 = %d, cannot native bridge in RTP. \n " , codec0 , codec1 ) ;
2006-09-20 16:55:09 +00:00
ast_channel_unlock ( c0 ) ;
ast_channel_unlock ( c1 ) ;
return AST_BRIDGE_FAILED_NOWARN ;
}
/* If either side can only do a partial bridge, then don't try for a true native bridge */
if ( audio_p0_res = = AST_RTP_TRY_PARTIAL | | audio_p1_res = = AST_RTP_TRY_PARTIAL ) {
2007-06-21 15:25:13 +00:00
struct ast_format_list fmt0 , fmt1 ;
2006-09-20 16:55:09 +00:00
/* In order to do Packet2Packet bridging both sides must be in the same rawread/rawwrite */
if ( c0 - > rawreadformat ! = c1 - > rawwriteformat | | c1 - > rawreadformat ! = c0 - > rawwriteformat ) {
2007-06-24 18:51:41 +00:00
ast_debug ( 1 , " Cannot packet2packet bridge - raw formats are incompatible \n " ) ;
2006-08-28 17:37:56 +00:00
ast_channel_unlock ( c0 ) ;
ast_channel_unlock ( c1 ) ;
return AST_BRIDGE_FAILED_NOWARN ;
}
2007-06-21 15:25:13 +00:00
/* They must also be using the same packetization */
fmt0 = ast_codec_pref_getsize ( & p0 - > pref , c0 - > rawreadformat ) ;
fmt1 = ast_codec_pref_getsize ( & p1 - > pref , c1 - > rawreadformat ) ;
if ( fmt0 . cur_ms ! = fmt1 . cur_ms ) {
2007-06-25 13:42:51 +00:00
ast_debug ( 1 , " Cannot packet2packet bridge - packetization settings prevent it \n " ) ;
2007-06-21 15:25:13 +00:00
ast_channel_unlock ( c0 ) ;
ast_channel_unlock ( c1 ) ;
return AST_BRIDGE_FAILED_NOWARN ;
}
2006-08-28 17:37:56 +00:00
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Packet2Packet bridging %s and %s \n " , c0 - > name , c1 - > name ) ;
2006-11-22 21:49:11 +00:00
res = bridge_p2p_loop ( c0 , c1 , p0 , p1 , timeoutms , flags , fo , rc , pvt0 , pvt1 ) ;
2006-08-28 17:37:56 +00:00
} else {
if ( option_verbose > 2 )
ast_verbose ( VERBOSE_PREFIX_3 " Native bridging %s and %s \n " , c0 - > name , c1 - > name ) ;
2007-02-16 13:35:44 +00:00
res = bridge_native_loop ( c0 , c1 , p0 , p1 , vp0 , vp1 , tp0 , tp1 , pr0 , pr1 , codec0 , codec1 , timeoutms , flags , fo , rc , pvt0 , pvt1 ) ;
2006-08-28 17:37:56 +00:00
}
return res ;
}
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-09-18 19:54:18 +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 ! = 4 )
return RESULT_SHOWUSAGE ;
arg = argv [ 3 ] ;
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 )
ast_cli ( fd , " RTCP Debugging Enabled for IP: %s \n " , ast_inet_ntoa ( rtcpdebugaddr . sin_addr ) ) ;
else
ast_cli ( fd , " RTCP Debugging Enabled for IP: %s:%d \n " , ast_inet_ntoa ( rtcpdebugaddr . sin_addr ) , port ) ;
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 ;
}
2007-01-22 23:51:42 +00:00
static int rtcp_do_debug ( int fd , int argc , char * argv [ ] )
{
2006-09-18 19:54:18 +00:00
if ( argc ! = 2 ) {
if ( argc ! = 4 )
return RESULT_SHOWUSAGE ;
2006-06-05 08:39:42 +00:00
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 ;
}
2007-01-22 23:51:42 +00:00
static int rtcp_do_stats ( int fd , int argc , char * argv [ ] )
{
if ( argc ! = 2 )
2006-09-18 19:54:18 +00:00
return RESULT_SHOWUSAGE ;
rtcpstats = 1 ;
ast_cli ( fd , " RTCP Stats Enabled \n " ) ;
return RESULT_SUCCESS ;
}
static int rtp_no_debug ( int fd , int argc , char * argv [ ] )
{
2006-11-02 23:55:59 +00:00
if ( argc ! = 3 )
2006-09-18 19:54:18 +00:00
return RESULT_SHOWUSAGE ;
rtpdebug = 0 ;
ast_cli ( fd , " RTP Debugging Disabled \n " ) ;
return RESULT_SUCCESS ;
}
static int rtcp_no_debug ( int fd , int argc , char * argv [ ] )
{
2006-11-02 23:55:59 +00:00
if ( argc ! = 3 )
2006-09-18 19:54:18 +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-11-02 23:55:59 +00:00
if ( argc ! = 3 )
2006-09-18 19:54:18 +00:00
return RESULT_SHOWUSAGE ;
rtcpstats = 0 ;
ast_cli ( fd , " RTCP Stats Disabled \n " ) ;
return RESULT_SUCCESS ;
}
2006-06-05 08:39:42 +00:00
2006-05-11 14:56:52 +00:00
static int stun_do_debug ( int fd , int argc , char * argv [ ] )
{
2007-01-22 23:51:42 +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 ;
}
2006-09-18 19:54:18 +00:00
static int stun_no_debug ( int fd , int argc , char * argv [ ] )
{
2006-11-02 23:55:59 +00:00
if ( argc ! = 3 )
2006-09-18 19:54:18 +00:00
return RESULT_SHOWUSAGE ;
stundebug = 0 ;
2006-11-02 23:55:59 +00:00
ast_cli ( fd , " STUN Debugging Disabled \n " ) ;
2006-09-18 19:54:18 +00:00
return RESULT_SUCCESS ;
}
2006-05-11 14:56:52 +00:00
2006-12-06 07:28:56 +00:00
static const char debug_usage [ ] =
2004-10-30 01:52:12 +00:00
" 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
2006-12-06 07:28:56 +00:00
static const char no_debug_usage [ ] =
2006-11-02 23:55:59 +00:00
" Usage: rtp debug off \n "
2004-10-30 01:52:12 +00:00
" Disable all RTP debugging \n " ;
2006-12-06 07:28:56 +00:00
static const char stun_debug_usage [ ] =
2006-05-11 14:56:52 +00:00
" Usage: stun debug \n "
" Enable STUN (Simple Traversal of UDP through NATs) debugging \n " ;
2006-12-06 07:28:56 +00:00
static const char stun_no_debug_usage [ ] =
2006-11-02 23:55:59 +00:00
" Usage: stun debug off \n "
2006-05-11 14:56:52 +00:00
" Disable STUN debugging \n " ;
2006-12-06 07:28:56 +00:00
static const char rtcp_debug_usage [ ] =
2006-09-18 19:54:18 +00:00
" Usage: rtcp debug [ip host[:port]] \n "
2006-06-05 08:39:42 +00:00
" Enable dumping of all RTCP packets to and from host. \n " ;
2006-12-06 07:28:56 +00:00
static const char rtcp_no_debug_usage [ ] =
2006-11-02 23:55:59 +00:00
" Usage: rtcp debug off \n "
2006-06-05 08:39:42 +00:00
" Disable all RTCP debugging \n " ;
2006-12-06 07:28:56 +00:00
static const char rtcp_stats_usage [ ] =
2006-09-18 19:54:18 +00:00
" Usage: rtcp stats \n "
2006-06-05 08:39:42 +00:00
" Enable dumping of RTCP stats. \n " ;
2006-12-06 07:28:56 +00:00
static const char rtcp_no_stats_usage [ ] =
2006-11-02 23:55:59 +00:00
" Usage: rtcp stats off \n "
2006-06-05 08:39:42 +00:00
" Disable all RTCP stats \n " ;
2006-09-18 19:54:18 +00:00
static struct ast_cli_entry cli_rtp [ ] = {
{ { " rtp " , " debug " , " ip " , NULL } ,
rtp_do_debug , " Enable RTP debugging on IP " ,
debug_usage } ,
{ { " rtp " , " debug " , NULL } ,
rtp_do_debug , " Enable RTP debugging " ,
debug_usage } ,
2006-11-02 23:55:59 +00:00
{ { " rtp " , " debug " , " off " , NULL } ,
2006-09-18 19:54:18 +00:00
rtp_no_debug , " Disable RTP debugging " ,
2006-09-21 21:17:39 +00:00
no_debug_usage } ,
2006-09-18 19:54:18 +00:00
{ { " rtcp " , " debug " , " ip " , NULL } ,
rtcp_do_debug , " Enable RTCP debugging on IP " ,
2006-09-21 21:17:39 +00:00
rtcp_debug_usage } ,
2006-09-18 19:54:18 +00:00
{ { " rtcp " , " debug " , NULL } ,
rtcp_do_debug , " Enable RTCP debugging " ,
2006-09-21 21:17:39 +00:00
rtcp_debug_usage } ,
2006-09-18 19:54:18 +00:00
2006-11-02 23:55:59 +00:00
{ { " rtcp " , " debug " , " off " , NULL } ,
2006-09-18 19:54:18 +00:00
rtcp_no_debug , " Disable RTCP debugging " ,
2006-09-21 21:17:39 +00:00
rtcp_no_debug_usage } ,
2006-09-18 19:54:18 +00:00
{ { " rtcp " , " stats " , NULL } ,
rtcp_do_stats , " Enable RTCP stats " ,
2006-09-21 21:17:39 +00:00
rtcp_stats_usage } ,
2006-09-18 19:54:18 +00:00
2006-11-02 23:55:59 +00:00
{ { " rtcp " , " stats " , " off " , NULL } ,
2006-09-18 19:54:18 +00:00
rtcp_no_stats , " Disable RTCP stats " ,
2006-09-21 21:17:39 +00:00
rtcp_no_stats_usage } ,
2006-09-18 19:54:18 +00:00
{ { " stun " , " debug " , NULL } ,
stun_do_debug , " Enable STUN debugging " ,
stun_debug_usage } ,
2006-11-02 23:55:59 +00:00
{ { " stun " , " debug " , " off " , NULL } ,
2006-09-18 19:54:18 +00:00
stun_no_debug , " Disable STUN debugging " ,
2006-09-21 21:17:39 +00:00
stun_no_debug_usage } ,
2006-09-18 19:54:18 +00:00
} ;
2006-05-11 14:56:52 +00:00
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 ;
2006-09-20 20:40:39 +00:00
const 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 )
{
2006-09-18 19:54:18 +00:00
ast_cli_register_multiple ( cli_rtp , sizeof ( cli_rtp ) / sizeof ( struct ast_cli_entry ) ) ;
2003-05-16 02:50:46 +00:00
ast_rtp_reload ( ) ;
}
2006-06-05 08:39:42 +00:00