Thu Apr 28 2011 16:57:17

Asterisk developer's documentation


rtp.c File Reference

Supports RTP and RTCP with Symmetric RTP support for NAT traversal. More...

#include "asterisk.h"
#include <sys/time.h>
#include <signal.h>
#include <fcntl.h>
#include <math.h>
#include "asterisk/rtp.h"
#include "asterisk/pbx.h"
#include "asterisk/frame.h"
#include "asterisk/channel.h"
#include "asterisk/acl.h"
#include "asterisk/config.h"
#include "asterisk/lock.h"
#include "asterisk/utils.h"
#include "asterisk/netsock.h"
#include "asterisk/cli.h"
#include "asterisk/manager.h"
#include "asterisk/unaligned.h"
Include dependency graph for rtp.c:

Go to the source code of this file.

Data Structures

struct  ast_rtcp
 Structure defining an RTCP session. More...
struct  ast_rtp
 Structure representing a RTP session. More...
struct  frame_list
struct  mimeType
struct  protos
 List of current sessions. More...
struct  rtp_red
struct  stun_addr
struct  stun_attr
struct  stun_header
struct  stun_state
 here we store credentials extracted from a message More...
struct  stun_trans_id
 STUN support code. More...

Defines

#define DEFAULT_DTMF_TIMEOUT   (150 * (8000 / 1000))
#define FLAG_3389_WARNING   (1 << 0)
#define FLAG_CALLBACK_MODE   (1 << 6)
#define FLAG_DTMF_COMPENSATE   (1 << 7)
#define FLAG_HAS_DTMF   (1 << 3)
#define FLAG_HAS_STUN   (1 << 8)
#define FLAG_NAT_ACTIVE   (3 << 1)
#define FLAG_NAT_INACTIVE   (0 << 1)
#define FLAG_NAT_INACTIVE_NOWARN   (1 << 1)
#define FLAG_P2P_NEED_DTMF   (1 << 5)
#define FLAG_P2P_SENT_MARK   (1 << 4)
#define MAX_TIMESTAMP_SKEW   640
#define RTCP_DEFAULT_INTERVALMS   5000
#define RTCP_JITTER_FORMAT1
#define RTCP_JITTER_FORMAT2   "rxjitter=%f;"
#define RTCP_LOSS_FORMAT1
#define RTCP_LOSS_FORMAT2
#define RTCP_MAX_INTERVALMS   60000
#define RTCP_MIN_INTERVALMS   500
#define RTCP_PT_APP   204
#define RTCP_PT_BYE   203
#define RTCP_PT_FUR   192
#define RTCP_PT_RR   201
#define RTCP_PT_SDES   202
#define RTCP_PT_SR   200
#define RTP_MTU   1200
#define RTP_SEQ_MOD   (1<<16)
#define SQUARE(x)   ((x) * (x))
#define STUN_ACCEPT   (1)
#define STUN_BINDERR   0x0111
#define STUN_BINDREQ   0x0001
 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.
#define STUN_BINDRESP   0x0101
#define STUN_CHANGE_REQUEST   0x0003
#define STUN_CHANGED_ADDRESS   0x0005
#define STUN_ERROR_CODE   0x0009
#define STUN_IGNORE   (0)
#define STUN_MAPPED_ADDRESS   0x0001
 Basic attribute types in stun messages. Messages can also contain custom attributes (codes above 0x7fff)
#define STUN_MESSAGE_INTEGRITY   0x0008
#define STUN_PASSWORD   0x0007
#define STUN_REFLECTED_FROM   0x000b
#define STUN_RESPONSE_ADDRESS   0x0002
#define STUN_SECERR   0x0112
#define STUN_SECREQ   0x0002
#define STUN_SECRESP   0x0102
#define STUN_SOURCE_ADDRESS   0x0004
#define STUN_UNKNOWN_ATTRIBUTES   0x000a
#define STUN_USERNAME   0x0006

Typedefs

typedef int( stun_cb_f )(struct stun_attr *attr, void *arg)
 callback type to be invoked on stun responses.

Enumerations

enum  strict_rtp_state { STRICT_RTP_OPEN = 0, STRICT_RTP_LEARN, STRICT_RTP_CLOSED }

Functions

static double __ast_rtp_get_qos (struct ast_rtp *rtp, const char *qos, int *found)
static char * __ast_rtp_get_quality (struct ast_rtp *rtp)
static char * __ast_rtp_get_quality_jitter (struct ast_rtp *rtp)
static char * __ast_rtp_get_quality_loss (struct ast_rtp *rtp)
static char * __ast_rtp_get_quality_rtt (struct ast_rtp *rtp)
static int __ast_rtp_reload (int reload)
static void __fini_protos (void)
static void __init_protos (void)
static void append_attr_address (struct stun_attr **attr, int attrval, struct sockaddr_in *sock_in, int *len, int *left)
 append an address to an STUN message
static void append_attr_string (struct stun_attr **attr, int attrval, const char *s, int *len, int *left)
 append a string to an STUN message
static unsigned int ast_rtcp_calc_interval (struct ast_rtp *rtp)
int ast_rtcp_fd (struct ast_rtp *rtp)
static struct ast_rtcpast_rtcp_new (void)
 Initialize a new RTCP session.
struct ast_frameast_rtcp_read (struct ast_rtp *rtp)
int ast_rtcp_send_h261fur (void *data)
 Public function: Send an H.261 fast update request, some devices need this rather than SIP XML.
static int ast_rtcp_write (const void *data)
 Write and RTCP packet to the far end.
static int ast_rtcp_write_rr (const void *data)
 Send RTCP recipient's report.
static int ast_rtcp_write_sr (const void *data)
 Send RTCP sender's report.
size_t ast_rtp_alloc_size (void)
 Get the amount of space required to hold an RTP session.
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)
 Bridge calls. If possible and allowed, initiate re-invite so the peers exchange media directly outside of Asterisk.
void ast_rtp_change_source (struct ast_rtp *rtp)
 Indicate that we need to set the marker bit and change the ssrc.
int ast_rtp_codec_getformat (int pt)
 get format from predefined dynamic payload format
struct ast_codec_prefast_rtp_codec_getpref (struct ast_rtp *rtp)
 Get codec preference.
void ast_rtp_codec_setpref (struct ast_rtp *rtp, struct ast_codec_pref *prefs)
 Set codec preference.
void ast_rtp_destroy (struct ast_rtp *rtp)
int ast_rtp_early_bridge (struct ast_channel *c0, struct ast_channel *c1)
 If possible, create an early bridge directly between the devices without having to send a re-invite later.
int ast_rtp_fd (struct ast_rtp *rtp)
struct ast_rtpast_rtp_get_bridged (struct ast_rtp *rtp)
void ast_rtp_get_current_formats (struct ast_rtp *rtp, int *astFormats, int *nonAstFormats)
 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.
int ast_rtp_get_peer (struct ast_rtp *rtp, struct sockaddr_in *them)
int ast_rtp_get_qos (struct ast_rtp *rtp, const char *qos, char *buf, unsigned int buflen)
 Get QOS stats on a RTP channel.
unsigned int ast_rtp_get_qosvalue (struct ast_rtp *rtp, enum ast_rtp_qos_vars value)
 Return RTP and RTCP QoS values.
char * ast_rtp_get_quality (struct ast_rtp *rtp, struct ast_rtp_quality *qual, enum ast_rtp_quality_type qtype)
 Return RTCP quality string.
int ast_rtp_get_rtpholdtimeout (struct ast_rtp *rtp)
 Get rtp hold timeout.
int ast_rtp_get_rtpkeepalive (struct ast_rtp *rtp)
 Get RTP keepalive interval.
int ast_rtp_get_rtptimeout (struct ast_rtp *rtp)
 Get rtp timeout.
void ast_rtp_get_us (struct ast_rtp *rtp, struct sockaddr_in *us)
int ast_rtp_getnat (struct ast_rtp *rtp)
void ast_rtp_init (void)
 Initialize the RTP system in Asterisk.
int ast_rtp_lookup_code (struct ast_rtp *rtp, const int isAstFormat, const int code)
 Looks up an RTP code out of our *static* outbound list.
char * ast_rtp_lookup_mime_multiple (char *buf, size_t size, const int capability, const int isAstFormat, enum ast_rtp_options options)
 Build a string of MIME subtype names from a capability list.
const char * ast_rtp_lookup_mime_subtype (const int isAstFormat, const int code, enum ast_rtp_options options)
 Mapping an Asterisk code into a MIME subtype (string):
struct rtpPayloadType ast_rtp_lookup_pt (struct ast_rtp *rtp, int pt)
 Mapping between RTP payload format codes and Asterisk codes:
unsigned int ast_rtp_lookup_sample_rate (int isAstFormat, int code)
 Get the sample rate associated with known RTP payload types.
int ast_rtp_make_compatible (struct ast_channel *dest, struct ast_channel *src, int media)
struct ast_rtpast_rtp_new (struct sched_context *sched, struct io_context *io, int rtcpenable, int callbackmode)
 Initializate a RTP session.
void ast_rtp_new_init (struct ast_rtp *rtp)
 Initialize a new RTP structure.
void ast_rtp_new_source (struct ast_rtp *rtp)
 Indicate that we need to set the marker bit.
struct ast_rtpast_rtp_new_with_bindaddr (struct sched_context *sched, struct io_context *io, int rtcpenable, int callbackmode, struct in_addr addr)
 Initializate a RTP session using an in_addr structure.
int ast_rtp_proto_register (struct ast_rtp_protocol *proto)
 Register interface to channel driver.
void ast_rtp_proto_unregister (struct ast_rtp_protocol *proto)
 Unregister interface to channel driver.
void ast_rtp_pt_clear (struct ast_rtp *rtp)
 Setting RTP payload types from lines in a SDP description:
void ast_rtp_pt_copy (struct ast_rtp *dest, struct ast_rtp *src)
 Copy payload types between RTP structures.
void ast_rtp_pt_default (struct ast_rtp *rtp)
 Set payload types to defaults.
static int ast_rtp_raw_write (struct ast_rtp *rtp, struct ast_frame *f, int codec)
 Write RTP packet with audio or video media frames into UDP packet.
struct ast_frameast_rtp_read (struct ast_rtp *rtp)
int ast_rtp_reload (void)
void ast_rtp_reset (struct ast_rtp *rtp)
int ast_rtp_sendcng (struct ast_rtp *rtp, int level)
 generate comfort noice (CNG)
int ast_rtp_senddigit_begin (struct ast_rtp *rtp, char digit)
 Send begin frames for DTMF.
static int ast_rtp_senddigit_continuation (struct ast_rtp *rtp)
 Send continuation frame for DTMF.
int ast_rtp_senddigit_end (struct ast_rtp *rtp, char digit)
int ast_rtp_senddigit_end_with_duration (struct ast_rtp *rtp, char digit, unsigned int duration)
 Send end packets for DTMF.
void ast_rtp_set_alt_peer (struct ast_rtp *rtp, struct sockaddr_in *alt)
 set potential alternate source for RTP media
void ast_rtp_set_callback (struct ast_rtp *rtp, ast_rtp_callback callback)
void ast_rtp_set_data (struct ast_rtp *rtp, void *data)
void ast_rtp_set_m_type (struct ast_rtp *rtp, int pt)
 Make a note of a RTP payload type that was seen in a SDP "m=" line. By default, use the well-known value for this type (although it may still be set to a different value by a subsequent "a=rtpmap:" line)
void ast_rtp_set_peer (struct ast_rtp *rtp, struct sockaddr_in *them)
void ast_rtp_set_rtpholdtimeout (struct ast_rtp *rtp, int timeout)
 Set rtp hold timeout.
void ast_rtp_set_rtpkeepalive (struct ast_rtp *rtp, int period)
 set RTP keepalive interval
int ast_rtp_set_rtpmap_type (struct ast_rtp *rtp, int pt, char *mimeType, char *mimeSubtype, enum ast_rtp_options options)
 Set payload type to a known MIME media type for a codec.
int ast_rtp_set_rtpmap_type_rate (struct ast_rtp *rtp, int pt, char *mimeType, char *mimeSubtype, enum ast_rtp_options options, unsigned int sample_rate)
 Make a note of a RTP payload type (with MIME type) that was seen in an SDP "a=rtpmap:" line.
void ast_rtp_set_rtptimeout (struct ast_rtp *rtp, int timeout)
 Set rtp timeout.
void ast_rtp_set_rtptimers_onhold (struct ast_rtp *rtp)
void ast_rtp_set_vars (struct ast_channel *chan, struct ast_rtp *rtp)
 Set RTPAUDIOQOS(...) variables on a channel when it is being hung up.
void ast_rtp_setdtmf (struct ast_rtp *rtp, int dtmf)
 Indicate whether this RTP session is carrying DTMF or not.
void ast_rtp_setdtmfcompensate (struct ast_rtp *rtp, int compensate)
 Compensate for devices that send RFC2833 packets all at once.
void ast_rtp_setnat (struct ast_rtp *rtp, int nat)
int ast_rtp_setqos (struct ast_rtp *rtp, int type_of_service, int class_of_service, char *desc)
void ast_rtp_setstun (struct ast_rtp *rtp, int stun_enable)
 Enable STUN capability.
void ast_rtp_stop (struct ast_rtp *rtp)
void ast_rtp_stun_request (struct ast_rtp *rtp, struct sockaddr_in *suggestion, const char *username)
 send a STUN BIND request to the given destination. Optionally, add a username if specified.
void ast_rtp_unset_m_type (struct ast_rtp *rtp, int pt)
 remove setting from payload type list if the rtpmap header indicates an unknown media type
int ast_rtp_write (struct ast_rtp *rtp, struct ast_frame *_f)
int ast_stun_request (int s, struct sockaddr_in *dst, const char *username, struct sockaddr_in *answer)
 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).
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)
 Bridge loop for true native bridge (reinvite)
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)
 Bridge loop for partial native bridge (packet2packet)
static int bridge_p2p_rtp_write (struct ast_rtp *rtp, struct ast_rtp *bridged, unsigned int *rtpheader, int len, int hdrlen)
 Perform a Packet2Packet RTP write.
static void calc_rxstamp (struct timeval *when, struct ast_rtp *rtp, unsigned int timestamp, int mark)
static unsigned int calc_txstamp (struct ast_rtp *rtp, struct timeval *delivery)
static struct ast_framecreate_dtmf_frame (struct ast_rtp *rtp, enum ast_frame_type type)
static struct ast_rtp_protocolget_proto (struct ast_channel *chan)
 Get channel driver interface structure.
static char * handle_cli_rtcp_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_rtcp_set_stats (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_rtp_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_stun_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static double normdev_compute (double normdev, double sample, unsigned int sample_count)
 Calculate normal deviation.
static int p2p_callback_disable (struct ast_channel *chan, struct ast_rtp *rtp, int **iod)
 Helper function to switch a channel and RTP stream out of callback mode.
static int p2p_callback_enable (struct ast_channel *chan, struct ast_rtp *rtp, int **iod)
 P2P RTP Callback.
static void p2p_set_bridge (struct ast_rtp *rtp0, struct ast_rtp *rtp1)
 Helper function that sets what an RTP structure is bridged to.
static struct ast_frameprocess_cisco_dtmf (struct ast_rtp *rtp, unsigned char *data, int len)
static void process_rfc2833 (struct ast_rtp *rtp, unsigned char *data, int len, unsigned int seqno, unsigned int timestamp, struct frame_list *frames)
 Process RTP DTMF and events according to RFC 2833.
static struct ast_frameprocess_rfc3389 (struct ast_rtp *rtp, unsigned char *data, int len)
 Process Comfort Noise RTP.
void red_buffer_t140 (struct ast_rtp *rtp, struct ast_frame *f)
 Buffer t140 from chan_sip.
static struct ast_framered_t140_to_red (struct rtp_red *red)
 Construct a redundant frame.
static int red_write (const void *data)
 Write t140 redundacy frame.
static int rtcp_debug_test_addr (struct sockaddr_in *addr)
static char * rtcp_do_debug_ip (struct ast_cli_args *a)
static void rtp_bridge_lock (struct ast_rtp *rtp)
static void rtp_bridge_unlock (struct ast_rtp *rtp)
static int rtp_debug_test_addr (struct sockaddr_in *addr)
static char * rtp_do_debug_ip (struct ast_cli_args *a)
static int rtp_get_rate (int subclass)
int rtp_red_init (struct ast_rtp *rtp, int ti, int *red_data_pt, int num_gen)
 Initialize t140 redundancy.
static int rtp_socket (const char *type)
 Open RTP or RTCP socket for a session. Print a message on failure.
static int rtpread (int *id, int fd, short events, void *cbdata)
static double stddev_compute (double stddev, double sample, double normdev, double normdev_curent, unsigned int sample_count)
static const char * stun_attr2str (int msg)
 helper function to print attribute names
static int stun_get_mapped (struct stun_attr *attr, void *arg)
 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_handle_packet (int s, struct sockaddr_in *src, unsigned char *data, size_t len, stun_cb_f *stun_cb, void *arg)
 handle an incoming STUN message.
static const char * stun_msg2str (int msg)
 helper function to print message names
static int stun_process_attr (struct stun_state *state, struct stun_attr *attr)
static void stun_req_id (struct stun_header *req)
 helper function to generate a random request id
static int stun_send (int s, struct sockaddr_in *dst, struct stun_header *resp)
 wrapper to send an STUN message
static void timeval2ntp (struct timeval tv, unsigned int *msw, unsigned int *lsw)

Variables

static struct ast_cli_entry cli_rtp []
static int dtmftimeout = DEFAULT_DTMF_TIMEOUT
static struct mimeType mimeTypes []
static struct protos protos
static int rtcpdebug
static struct sockaddr_in rtcpdebugaddr
static int rtcpinterval = RTCP_DEFAULT_INTERVALMS
static int rtcpstats
static int rtpdebug
static struct sockaddr_in rtpdebugaddr
static int rtpend = 31000
static int rtpstart = 5000
static struct rtpPayloadType static_RTP_PT [MAX_RTP_PT]
 Mapping between Asterisk codecs and rtp payload types.
static int strictrtp
static int stundebug

Detailed Description

Supports RTP and RTCP with Symmetric RTP support for NAT traversal.

Author:
Mark Spencer <markster@digium.com>
Note:
RTP is defined in RFC 3550.

Definition in file rtp.c.


Define Documentation

#define DEFAULT_DTMF_TIMEOUT   (150 * (8000 / 1000))

samples

Definition at line 67 of file rtp.c.

Referenced by __ast_rtp_reload().

#define FLAG_3389_WARNING   (1 << 0)

Definition at line 211 of file rtp.c.

Referenced by process_rfc3389().

#define FLAG_CALLBACK_MODE   (1 << 6)

Definition at line 218 of file rtp.c.

Referenced by ast_rtp_new_with_bindaddr(), and p2p_callback_disable().

#define FLAG_DTMF_COMPENSATE   (1 << 7)
#define FLAG_HAS_DTMF   (1 << 3)

Definition at line 215 of file rtp.c.

Referenced by ast_rtp_bridge(), ast_rtp_new_init(), and ast_rtp_setdtmf().

#define FLAG_HAS_STUN   (1 << 8)

Definition at line 220 of file rtp.c.

Referenced by ast_rtp_setstun().

#define FLAG_NAT_ACTIVE   (3 << 1)
#define FLAG_NAT_INACTIVE   (0 << 1)

Definition at line 213 of file rtp.c.

Referenced by ast_rtp_raw_write(), and bridge_p2p_rtp_write().

#define FLAG_NAT_INACTIVE_NOWARN   (1 << 1)

Definition at line 214 of file rtp.c.

Referenced by ast_rtp_raw_write(), and bridge_p2p_rtp_write().

#define FLAG_P2P_NEED_DTMF   (1 << 5)

Definition at line 217 of file rtp.c.

Referenced by ast_rtp_bridge(), and bridge_p2p_rtp_write().

#define FLAG_P2P_SENT_MARK   (1 << 4)

Definition at line 216 of file rtp.c.

Referenced by ast_rtp_stop(), bridge_p2p_loop(), and bridge_p2p_rtp_write().

#define MAX_TIMESTAMP_SKEW   640

Definition at line 51 of file rtp.c.

Referenced by ast_rtp_raw_write().

#define RTCP_DEFAULT_INTERVALMS   5000

Default milli-seconds between RTCP reports we send

Definition at line 54 of file rtp.c.

#define RTCP_JITTER_FORMAT1
#define RTCP_JITTER_FORMAT2   "rxjitter=%f;"
#define RTCP_LOSS_FORMAT1
#define RTCP_LOSS_FORMAT2
Value:
"lost=%d;" \
   "expected=%d;"

Referenced by __ast_rtp_get_quality_loss().

#define RTCP_MAX_INTERVALMS   60000

Max milli-seconds between RTCP reports we send

Definition at line 56 of file rtp.c.

Referenced by __ast_rtp_reload().

#define RTCP_MIN_INTERVALMS   500

Min milli-seconds between RTCP reports we send

Definition at line 55 of file rtp.c.

Referenced by __ast_rtp_reload().

#define RTCP_PT_APP   204

Definition at line 63 of file rtp.c.

#define RTCP_PT_BYE   203

Definition at line 62 of file rtp.c.

Referenced by ast_rtcp_read().

#define RTCP_PT_FUR   192

Definition at line 58 of file rtp.c.

Referenced by ast_rtcp_read(), ast_rtcp_write_rr(), and ast_rtcp_write_sr().

#define RTCP_PT_RR   201

Definition at line 60 of file rtp.c.

Referenced by ast_rtcp_read(), and ast_rtcp_write_rr().

#define RTCP_PT_SDES   202

Definition at line 61 of file rtp.c.

Referenced by ast_rtcp_read(), ast_rtcp_write_rr(), and ast_rtcp_write_sr().

#define RTCP_PT_SR   200

Definition at line 59 of file rtp.c.

Referenced by ast_rtcp_read(), and ast_rtcp_write_sr().

#define RTP_MTU   1200

Definition at line 65 of file rtp.c.

#define RTP_SEQ_MOD   (1<<16)

A sequence number can't be more than 16 bits

Definition at line 53 of file rtp.c.

Referenced by ast_rtp_read().

#define SQUARE (   x)    ((x) * (x))

Referenced by stddev_compute().

#define STUN_ACCEPT   (1)

Definition at line 341 of file rtp.c.

Referenced by ast_rtp_read(), and stun_handle_packet().

#define STUN_BINDERR   0x0111

Definition at line 352 of file rtp.c.

Referenced by stun_msg2str().

#define STUN_BINDREQ   0x0001

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.

Definition at line 350 of file rtp.c.

Referenced by ast_stun_request(), stun_handle_packet(), and stun_msg2str().

#define STUN_BINDRESP   0x0101

Definition at line 351 of file rtp.c.

Referenced by stun_handle_packet(), and stun_msg2str().

#define STUN_CHANGE_REQUEST   0x0003

Definition at line 362 of file rtp.c.

Referenced by stun_attr2str().

#define STUN_CHANGED_ADDRESS   0x0005

Definition at line 364 of file rtp.c.

Referenced by stun_attr2str().

#define STUN_ERROR_CODE   0x0009

Definition at line 368 of file rtp.c.

Referenced by stun_attr2str().

#define STUN_IGNORE   (0)

Definition at line 340 of file rtp.c.

Referenced by stun_handle_packet().

#define STUN_MAPPED_ADDRESS   0x0001

Basic attribute types in stun messages. Messages can also contain custom attributes (codes above 0x7fff)

Definition at line 360 of file rtp.c.

Referenced by stun_attr2str(), stun_get_mapped(), and stun_handle_packet().

#define STUN_MESSAGE_INTEGRITY   0x0008

Definition at line 367 of file rtp.c.

Referenced by stun_attr2str().

#define STUN_PASSWORD   0x0007

Definition at line 366 of file rtp.c.

Referenced by stun_attr2str(), and stun_process_attr().

#define STUN_REFLECTED_FROM   0x000b

Definition at line 370 of file rtp.c.

Referenced by stun_attr2str().

#define STUN_RESPONSE_ADDRESS   0x0002

Definition at line 361 of file rtp.c.

Referenced by stun_attr2str().

#define STUN_SECERR   0x0112

Definition at line 355 of file rtp.c.

Referenced by stun_msg2str().

#define STUN_SECREQ   0x0002

Definition at line 353 of file rtp.c.

Referenced by stun_msg2str().

#define STUN_SECRESP   0x0102

Definition at line 354 of file rtp.c.

Referenced by stun_msg2str().

#define STUN_SOURCE_ADDRESS   0x0004

Definition at line 363 of file rtp.c.

Referenced by stun_attr2str().

#define STUN_UNKNOWN_ATTRIBUTES   0x000a

Definition at line 369 of file rtp.c.

Referenced by stun_attr2str().

#define STUN_USERNAME   0x0006

Definition at line 365 of file rtp.c.

Referenced by ast_stun_request(), stun_attr2str(), stun_handle_packet(), and stun_process_attr().


Typedef Documentation

typedef int( stun_cb_f)(struct stun_attr *attr, void *arg)

callback type to be invoked on stun responses.

Definition at line 502 of file rtp.c.


Enumeration Type Documentation

Enumerator:
STRICT_RTP_OPEN 
STRICT_RTP_LEARN 

No RTP packets should be dropped, all sources accepted

STRICT_RTP_CLOSED 

Accept next packet as source

Definition at line 85 of file rtp.c.

                      {
   STRICT_RTP_OPEN = 0, /*! No RTP packets should be dropped, all sources accepted */
   STRICT_RTP_LEARN,    /*! Accept next packet as source */
   STRICT_RTP_CLOSED,   /*! Drop all RTP packets not coming from source that was learned */
};

Function Documentation

static double __ast_rtp_get_qos ( struct ast_rtp rtp,
const char *  qos,
int *  found 
) [static]

Definition at line 2831 of file rtp.c.

References ast_rtcp::maxrtt, ast_rtcp::maxrxjitter, ast_rtcp::minrtt, ast_rtcp::minrxjitter, ast_rtcp::normdev_rxjitter, ast_rtcp::normdevrtt, ast_rtcp::reported_maxjitter, ast_rtcp::reported_minjitter, ast_rtcp::reported_normdev_jitter, ast_rtcp::reported_stdev_jitter, ast_rtp::rtcp, ast_rtcp::stdev_rxjitter, and ast_rtcp::stdevrtt.

Referenced by ast_rtp_get_qos().

{
   *found = 1;

   if (!strcasecmp(qos, "remote_maxjitter"))
      return rtp->rtcp->reported_maxjitter * 1000.0;
   if (!strcasecmp(qos, "remote_minjitter"))
      return rtp->rtcp->reported_minjitter * 1000.0;
   if (!strcasecmp(qos, "remote_normdevjitter"))
      return rtp->rtcp->reported_normdev_jitter * 1000.0;
   if (!strcasecmp(qos, "remote_stdevjitter"))
      return sqrt(rtp->rtcp->reported_stdev_jitter) * 1000.0;

   if (!strcasecmp(qos, "local_maxjitter"))
      return rtp->rtcp->maxrxjitter * 1000.0;
   if (!strcasecmp(qos, "local_minjitter"))
      return rtp->rtcp->minrxjitter * 1000.0;
   if (!strcasecmp(qos, "local_normdevjitter"))
      return rtp->rtcp->normdev_rxjitter * 1000.0;
   if (!strcasecmp(qos, "local_stdevjitter"))
      return sqrt(rtp->rtcp->stdev_rxjitter) * 1000.0;

   if (!strcasecmp(qos, "maxrtt"))
      return rtp->rtcp->maxrtt * 1000.0;
   if (!strcasecmp(qos, "minrtt"))
      return rtp->rtcp->minrtt * 1000.0;
   if (!strcasecmp(qos, "normdevrtt"))
      return rtp->rtcp->normdevrtt * 1000.0;
   if (!strcasecmp(qos, "stdevrtt"))
      return sqrt(rtp->rtcp->stdevrtt) * 1000.0;

   *found = 0;

   return 0.0;
}
static char* __ast_rtp_get_quality ( struct ast_rtp rtp) [static]

Definition at line 3034 of file rtp.c.

References ast_rtcp::expected_prior, ast_rtcp::quality, ast_rtcp::received_prior, ast_rtcp::reported_jitter, ast_rtcp::reported_lost, ast_rtp::rtcp, ast_rtcp::rtcp_info, ast_rtcp::rtt, ast_rtp::rxcount, ast_rtp::rxjitter, ast_rtp::ssrc, ast_rtp::themssrc, and ast_rtp::txcount.

Referenced by ast_rtp_get_quality().

{
   /*
   *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
   *rtt           round trip time
   */ 

   if (rtp->rtcp && rtp->rtcp->rtcp_info) {
      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.0,
         rtp->txcount,
         rtp->rtcp->reported_lost,
         rtp->rtcp->rtt
      );
   } else {
      snprintf(rtp->rtcp->quality, sizeof(rtp->rtcp->quality), "ssrc=%u;themssrc=%u;rxjitter=%f;rxcount=%u;txcount=%u;",
         rtp->ssrc,
         rtp->themssrc,
         rtp->rxjitter,
         rtp->rxcount,
         rtp->txcount
      );
   }

   return rtp->rtcp->quality;
}
static char* __ast_rtp_get_quality_jitter ( struct ast_rtp rtp) [static]

Definition at line 2913 of file rtp.c.

References ast_rtcp::maxrxjitter, ast_rtcp::minrxjitter, ast_rtcp::normdev_rxjitter, ast_rtcp::quality_jitter, ast_rtcp::reported_maxjitter, ast_rtcp::reported_minjitter, ast_rtcp::reported_normdev_jitter, ast_rtcp::reported_stdev_jitter, ast_rtp::rtcp, ast_rtcp::rtcp_info, RTCP_JITTER_FORMAT1, RTCP_JITTER_FORMAT2, ast_rtp::rxjitter, and ast_rtcp::stdev_rxjitter.

Referenced by ast_rtp_get_quality().

{
   /*
   *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
   *rtt           round trip time
   */
#define RTCP_JITTER_FORMAT1 \
   "minrxjitter=%f;" \
   "maxrxjitter=%f;" \
   "avgrxjitter=%f;" \
   "stdevrxjitter=%f;" \
   "reported_minjitter=%f;" \
   "reported_maxjitter=%f;" \
   "reported_avgjitter=%f;" \
   "reported_stdevjitter=%f;"

#define RTCP_JITTER_FORMAT2 \
   "rxjitter=%f;"

   if (rtp->rtcp && rtp->rtcp->rtcp_info) {
      snprintf(rtp->rtcp->quality_jitter, sizeof(rtp->rtcp->quality_jitter), RTCP_JITTER_FORMAT1,
         rtp->rtcp->minrxjitter,
         rtp->rtcp->maxrxjitter,
         rtp->rtcp->normdev_rxjitter,
         sqrt(rtp->rtcp->stdev_rxjitter),
         rtp->rtcp->reported_minjitter,
         rtp->rtcp->reported_maxjitter,
         rtp->rtcp->reported_normdev_jitter,
         sqrt(rtp->rtcp->reported_stdev_jitter)
      );
   } else {
      snprintf(rtp->rtcp->quality_jitter, sizeof(rtp->rtcp->quality_jitter), RTCP_JITTER_FORMAT2,
         rtp->rxjitter
      );
   }

   return rtp->rtcp->quality_jitter;

#undef RTCP_JITTER_FORMAT1
#undef RTCP_JITTER_FORMAT2
}
static char* __ast_rtp_get_quality_loss ( struct ast_rtp rtp) [static]

Definition at line 2962 of file rtp.c.

References ast_rtp::cycles, ast_rtp::lastrxseqno, ast_rtcp::maxrxlost, ast_rtcp::minrxlost, ast_rtcp::normdev_rxlost, ast_rtcp::quality_loss, ast_rtcp::reported_maxlost, ast_rtcp::reported_minlost, ast_rtcp::reported_normdev_lost, ast_rtcp::reported_stdev_lost, ast_rtp::rtcp, ast_rtcp::rtcp_info, RTCP_LOSS_FORMAT1, RTCP_LOSS_FORMAT2, ast_rtp::rxcount, ast_rtp::seedrxseqno, and ast_rtcp::stdev_rxlost.

Referenced by ast_rtp_get_quality().

{
   unsigned int lost;
   unsigned int extended;
   unsigned int expected;
   int fraction;

#define RTCP_LOSS_FORMAT1 \
   "minrxlost=%f;" \
   "maxrxlost=%f;" \
   "avgrxlostr=%f;" \
   "stdevrxlost=%f;" \
   "reported_minlost=%f;" \
   "reported_maxlost=%f;" \
   "reported_avglost=%f;" \
   "reported_stdevlost=%f;"

#define RTCP_LOSS_FORMAT2 \
   "lost=%d;" \
   "expected=%d;"
   
   if (rtp->rtcp && rtp->rtcp->rtcp_info && rtp->rtcp->maxrxlost > 0) {
      snprintf(rtp->rtcp->quality_loss, sizeof(rtp->rtcp->quality_loss), RTCP_LOSS_FORMAT1,
         rtp->rtcp->minrxlost,
         rtp->rtcp->maxrxlost,
         rtp->rtcp->normdev_rxlost,
         sqrt(rtp->rtcp->stdev_rxlost),
         rtp->rtcp->reported_minlost,
         rtp->rtcp->reported_maxlost,
         rtp->rtcp->reported_normdev_lost,
         sqrt(rtp->rtcp->reported_stdev_lost)
      );
   } else {
      extended = rtp->cycles + rtp->lastrxseqno;
      expected = extended - rtp->seedrxseqno + 1;
      if (rtp->rxcount > expected) 
         expected += rtp->rxcount - expected;
      lost = expected - rtp->rxcount;

      if (!expected || lost <= 0)
         fraction = 0;
      else
         fraction = (lost << 8) / expected;

      snprintf(rtp->rtcp->quality_loss, sizeof(rtp->rtcp->quality_loss), RTCP_LOSS_FORMAT2,
         lost,
         expected
      );
   }

   return rtp->rtcp->quality_loss;

#undef RTCP_LOSS_FORMAT1
#undef RTCP_LOSS_FORMAT2
}
static char* __ast_rtp_get_quality_rtt ( struct ast_rtp rtp) [static]

Definition at line 3018 of file rtp.c.

References ast_rtcp::maxrtt, ast_rtcp::minrtt, ast_rtcp::normdevrtt, ast_rtcp::quality_rtt, ast_rtp::rtcp, ast_rtcp::rtcp_info, and ast_rtcp::stdevrtt.

Referenced by ast_rtp_get_quality().

{
   if (rtp->rtcp && rtp->rtcp->rtcp_info) {
      snprintf(rtp->rtcp->quality_rtt, sizeof(rtp->rtcp->quality_rtt), "minrtt=%f;maxrtt=%f;avgrtt=%f;stdevrtt=%f;",
         rtp->rtcp->minrtt,
         rtp->rtcp->maxrtt,
         rtp->rtcp->normdevrtt,
         sqrt(rtp->rtcp->stdevrtt)
      );
   } else {
      snprintf(rtp->rtcp->quality_rtt, sizeof(rtp->rtcp->quality_rtt), "Not available");
   }

   return rtp->rtcp->quality_rtt;
}
static int __ast_rtp_reload ( int  reload) [static]

Definition at line 4799 of file rtp.c.

References ast_config_destroy(), ast_config_load2(), ast_false(), ast_log(), ast_true(), ast_variable_retrieve(), ast_verb, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, DEFAULT_DTMF_TIMEOUT, LOG_WARNING, RTCP_MAX_INTERVALMS, RTCP_MIN_INTERVALMS, s, and STRICT_RTP_OPEN.

Referenced by ast_rtp_init(), and ast_rtp_reload().

{
   struct ast_config *cfg;
   const char *s;
   struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };

   cfg = ast_config_load2("rtp.conf", "rtp", config_flags);
   if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) {
      return 0;
   }

   rtpstart = 5000;
   rtpend = 31000;
   dtmftimeout = DEFAULT_DTMF_TIMEOUT;
   strictrtp = STRICT_RTP_OPEN;
   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;
      }
      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;
      }
      if ((s = ast_variable_retrieve(cfg, "general", "rtpchecksums"))) {
#ifdef SO_NO_CHECK
         if (ast_false(s))
            nochecksums = 1;
         else
            nochecksums = 0;
#else
         if (ast_false(s))
            ast_log(LOG_WARNING, "Disabling RTP checksums is not supported on this operating system!\n");
#endif
      }
      if ((s = ast_variable_retrieve(cfg, "general", "dtmftimeout"))) {
         dtmftimeout = atoi(s);
         if ((dtmftimeout < 0) || (dtmftimeout > 64000)) {
            ast_log(LOG_WARNING, "DTMF timeout of '%d' outside range, using default of '%d' instead\n",
               dtmftimeout, DEFAULT_DTMF_TIMEOUT);
            dtmftimeout = DEFAULT_DTMF_TIMEOUT;
         };
      }
      if ((s = ast_variable_retrieve(cfg, "general", "strictrtp"))) {
         strictrtp = ast_true(s);
      }
      ast_config_destroy(cfg);
   }
   if (rtpstart >= rtpend) {
      ast_log(LOG_WARNING, "Unreasonable values for RTP start/end port in rtp.conf\n");
      rtpstart = 5000;
      rtpend = 31000;
   }
   ast_verb(2, "RTP Allocating from port range %d -> %d\n", rtpstart, rtpend);
   return 0;
}
static void __fini_protos ( void  ) [static]

Definition at line 705 of file rtp.c.

{
static void __init_protos ( void  ) [static]

Definition at line 705 of file rtp.c.

{
static void append_attr_address ( struct stun_attr **  attr,
int  attrval,
struct sockaddr_in *  sock_in,
int *  len,
int *  left 
) [static]

append an address to an STUN message

Definition at line 463 of file rtp.c.

References stun_addr::addr, stun_addr::family, stun_addr::port, and stun_addr::unused.

Referenced by stun_handle_packet().

{
   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 = sock_in->sin_port;
      addr->addr = sock_in->sin_addr.s_addr;
      (*attr) = (struct stun_attr *)((*attr)->value + 8);
      *len += size;
      *left -= size;
   }
}
static void append_attr_string ( struct stun_attr **  attr,
int  attrval,
const char *  s,
int *  len,
int *  left 
) [static]

append a string to an STUN message

Definition at line 449 of file rtp.c.

Referenced by ast_stun_request(), and stun_handle_packet().

{
   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;
   }
}
unsigned int ast_rtcp_calc_interval ( struct ast_rtp rtp) [static]

Todo:
XXX Do a more reasonable calculation on this one Look in RFC 3550 Section A.7 for an example

Definition at line 734 of file rtp.c.

References rtcpinterval.

Referenced by ast_rtp_raw_write(), and ast_rtp_read().

{
   unsigned int interval;
   /*! \todo XXX Do a more reasonable calculation on this one
    * Look in RFC 3550 Section A.7 for an example*/
   interval = rtcpinterval;
   return interval;
}
int ast_rtcp_fd ( struct ast_rtp rtp)

Definition at line 722 of file rtp.c.

References ast_rtp::rtcp, and ast_rtcp::s.

Referenced by __oh323_new(), __oh323_rtp_create(), __oh323_update_info(), gtalk_new(), jingle_new(), sip_new(), start_rtp(), and unistim_new().

{
   if (rtp->rtcp)
      return rtp->rtcp->s;
   return -1;
}
static struct ast_rtcp* ast_rtcp_new ( void  ) [static, read]

Initialize a new RTCP session.

Returns:
The newly initialized RTCP session.

Definition at line 2539 of file rtp.c.

References ast_calloc, ast_free, rtp_socket(), ast_rtcp::s, ast_rtcp::schedid, ast_rtcp::them, and ast_rtcp::us.

Referenced by ast_rtp_new_with_bindaddr().

{
   struct ast_rtcp *rtcp;

   if (!(rtcp = ast_calloc(1, sizeof(*rtcp))))
      return NULL;
   rtcp->s = rtp_socket("RTCP");
   rtcp->us.sin_family = AF_INET;
   rtcp->them.sin_family = AF_INET;
   rtcp->schedid = -1;

   if (rtcp->s < 0) {
      ast_free(rtcp);
      return NULL;
   }

   return rtcp;
}
struct ast_frame* ast_rtcp_read ( struct ast_rtp rtp) [read]

Definition at line 1182 of file rtp.c.

References ast_rtcp::accumulated_transit, ast_rtcp::altthem, ast_assert, AST_CONTROL_VIDUPDATE, ast_debug, AST_FRAME_CONTROL, AST_FRIENDLY_OFFSET, ast_inet_ntoa(), ast_log(), ast_null_frame, ast_verbose(), ast_frame::datalen, errno, EVENT_FLAG_REPORTING, ast_rtp::f, f, ast_frame::frametype, len(), LOG_DEBUG, LOG_WARNING, ast_frame::mallocd, manager_event, ast_rtcp::maxrtt, ast_rtcp::minrtt, ast_rtp::nat, normdev_compute(), ast_rtcp::normdevrtt, option_debug, ast_rtcp::reported_jitter, ast_rtcp::reported_jitter_count, ast_rtcp::reported_lost, ast_rtcp::reported_maxjitter, ast_rtcp::reported_maxlost, ast_rtcp::reported_minjitter, ast_rtcp::reported_minlost, ast_rtcp::reported_normdev_jitter, ast_rtcp::reported_normdev_lost, ast_rtcp::reported_stdev_jitter, ast_rtcp::reported_stdev_lost, ast_rtp::rtcp, rtcp_debug_test_addr(), ast_rtcp::rtcp_info, RTCP_PT_BYE, RTCP_PT_FUR, RTCP_PT_RR, RTCP_PT_SDES, RTCP_PT_SR, ast_rtcp::rtt, ast_rtcp::rtt_count, ast_rtcp::rxlsr, ast_rtcp::s, ast_frame::samples, ast_rtcp::soc, ast_rtcp::spc, ast_frame::src, stddev_compute(), ast_rtcp::stdevrtt, ast_frame::subclass, ast_rtcp::them, ast_rtcp::themrxlsr, and timeval2ntp().

Referenced by oh323_read(), sip_rtp_read(), skinny_rtp_read(), and unistim_rtp_read().

{
   socklen_t len;
   int position, i, packetwords;
   int res;
   struct sockaddr_in sock_in;
   unsigned int rtcpdata[8192 + AST_FRIENDLY_OFFSET];
   unsigned int *rtcpheader;
   int pt;
   struct timeval now;
   unsigned int length;
   int rc;
   double rttsec;
   uint64_t rtt = 0;
   unsigned int dlsr;
   unsigned int lsr;
   unsigned int msw;
   unsigned int lsw;
   unsigned int comp;
   struct ast_frame *f = &ast_null_frame;
   
   double reported_jitter;
   double reported_normdev_jitter_current;
   double normdevrtt_current;
   double reported_lost;
   double reported_normdev_lost_current;

   if (!rtp || !rtp->rtcp)
      return &ast_null_frame;

   len = sizeof(sock_in);
   
   res = recvfrom(rtp->rtcp->s, rtcpdata + AST_FRIENDLY_OFFSET, sizeof(rtcpdata) - sizeof(unsigned int) * AST_FRIENDLY_OFFSET,
               0, (struct sockaddr *)&sock_in, &len);
   rtcpheader = (unsigned int *)(rtcpdata + AST_FRIENDLY_OFFSET);
   
   if (res < 0) {
      ast_assert(errno != EBADF);
      if (errno != EAGAIN) {
         ast_log(LOG_WARNING, "RTCP Read error: %s.  Hanging up.\n", strerror(errno));
         return NULL;
      }
      return &ast_null_frame;
   }

   packetwords = res / 4;
   
   if (rtp->nat) {
      /* Send to whoever sent to us */
      if (((rtp->rtcp->them.sin_addr.s_addr != sock_in.sin_addr.s_addr) ||
          (rtp->rtcp->them.sin_port != sock_in.sin_port)) && 
          ((rtp->rtcp->altthem.sin_addr.s_addr != sock_in.sin_addr.s_addr) || 
          (rtp->rtcp->altthem.sin_port != sock_in.sin_port))) {
         memcpy(&rtp->rtcp->them, &sock_in, sizeof(rtp->rtcp->them));
         if (option_debug || rtpdebug)
            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));
      }
   }

   ast_debug(1, "Got RTCP report of %d bytes\n", res);

   /* 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) {
         if (option_debug || rtpdebug)
            ast_log(LOG_DEBUG, "RTCP Read too short\n");
         return &ast_null_frame;
      }
      
      if (rtcp_debug_test_addr(&sock_in)) {
         ast_verbose("\n\nGot RTCP from %s:%d\n", ast_inet_ntoa(sock_in.sin_addr), ntohs(sock_in.sin_port));
         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]);
      }
 
      i += 2; /* Advance past header and ssrc */
      
      switch (pt) {
      case RTCP_PT_SR:
         gettimeofday(&rtp->rtcp->rxlsr,NULL); /* To be able to populate the dlsr */
         rtp->rtcp->spc = ntohl(rtcpheader[i+3]);
         rtp->rtcp->soc = ntohl(rtcpheader[i + 4]);
         rtp->rtcp->themrxlsr = ((ntohl(rtcpheader[i]) & 0x0000ffff) << 16) | ((ntohl(rtcpheader[i + 1]) & 0xffff0000) >> 16); /* Going to LSR in RR*/
 
         if (rtcp_debug_test_addr(&sock_in)) {
            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\tSOC: %lu\n", (unsigned long) ntohl(rtcpheader[i + 3]), (unsigned long) ntohl(rtcpheader[i + 4]));
         }
         i += 5;
         if (rc < 1)
            break;
         /* Intentional fall through */
      case RTCP_PT_RR:
         /* Don't handle multiple reception reports (rc > 1) yet */
         /* Calculate RTT per RFC */
         gettimeofday(&now, NULL);
         timeval2ntp(now, &msw, &lsw);
         if (ntohl(rtcpheader[i + 4]) && ntohl(rtcpheader[i + 5])) { /* We must have the LSR && DLSR */
            comp = ((msw & 0xffff) << 16) | ((lsw & 0xffff0000) >> 16);
            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.;
            rtp->rtcp->rtt = rttsec;

            if (comp - dlsr >= lsr) {
               rtp->rtcp->accumulated_transit += rttsec;

               if (rtp->rtcp->rtt_count == 0) 
                  rtp->rtcp->minrtt = rttsec;

               if (rtp->rtcp->maxrtt<rttsec)
                  rtp->rtcp->maxrtt = rttsec;

               if (rtp->rtcp->minrtt>rttsec)
                  rtp->rtcp->minrtt = rttsec;

               normdevrtt_current = normdev_compute(rtp->rtcp->normdevrtt, rttsec, rtp->rtcp->rtt_count);

               rtp->rtcp->stdevrtt = stddev_compute(rtp->rtcp->stdevrtt, rttsec, rtp->rtcp->normdevrtt, normdevrtt_current, rtp->rtcp->rtt_count);

               rtp->rtcp->normdevrtt = normdevrtt_current;

               rtp->rtcp->rtt_count++;
            } else if (rtcp_debug_test_addr(&sock_in)) {
               ast_verbose("Internal RTCP NTP clock skew detected: "
                        "lsr=%u, now=%u, dlsr=%u (%d:%03dms), "
                        "diff=%d\n",
                        lsr, comp, dlsr, dlsr / 65536,
                        (dlsr % 65536) * 1000 / 65536,
                        dlsr - (comp - lsr));
            }
         }

         rtp->rtcp->reported_jitter = ntohl(rtcpheader[i + 3]);
         reported_jitter = (double) rtp->rtcp->reported_jitter;

         if (rtp->rtcp->reported_jitter_count == 0) 
            rtp->rtcp->reported_minjitter = reported_jitter;

         if (reported_jitter < rtp->rtcp->reported_minjitter) 
            rtp->rtcp->reported_minjitter = reported_jitter;

         if (reported_jitter > rtp->rtcp->reported_maxjitter) 
            rtp->rtcp->reported_maxjitter = reported_jitter;

         reported_normdev_jitter_current = normdev_compute(rtp->rtcp->reported_normdev_jitter, reported_jitter, rtp->rtcp->reported_jitter_count);

         rtp->rtcp->reported_stdev_jitter = stddev_compute(rtp->rtcp->reported_stdev_jitter, reported_jitter, rtp->rtcp->reported_normdev_jitter, reported_normdev_jitter_current, rtp->rtcp->reported_jitter_count);

         rtp->rtcp->reported_normdev_jitter = reported_normdev_jitter_current;

         rtp->rtcp->reported_lost = ntohl(rtcpheader[i + 1]) & 0xffffff;

         reported_lost = (double) rtp->rtcp->reported_lost;

         /* using same counter as for jitter */
         if (rtp->rtcp->reported_jitter_count == 0)
            rtp->rtcp->reported_minlost = reported_lost;

         if (reported_lost < rtp->rtcp->reported_minlost)
            rtp->rtcp->reported_minlost = reported_lost;

         if (reported_lost > rtp->rtcp->reported_maxlost) 
            rtp->rtcp->reported_maxlost = reported_lost;

         reported_normdev_lost_current = normdev_compute(rtp->rtcp->reported_normdev_lost, reported_lost, rtp->rtcp->reported_jitter_count);

         rtp->rtcp->reported_stdev_lost = stddev_compute(rtp->rtcp->reported_stdev_lost, reported_lost, rtp->rtcp->reported_normdev_lost, reported_normdev_lost_current, rtp->rtcp->reported_jitter_count);

         rtp->rtcp->reported_normdev_lost = reported_normdev_lost_current;

         rtp->rtcp->reported_jitter_count++;

         if (rtcp_debug_test_addr(&sock_in)) {
            ast_verbose("  Fraction lost: %ld\n", (((long) ntohl(rtcpheader[i + 1]) & 0xff000000) >> 24));
            ast_verbose("  Packets lost so far: %d\n", rtp->rtcp->reported_lost);
            ast_verbose("  Highest sequence number: %ld\n", (long) (ntohl(rtcpheader[i + 2]) & 0xffff));
            ast_verbose("  Sequence number cycles: %ld\n", (long) (ntohl(rtcpheader[i + 2]) & 0xffff) >> 16);
            ast_verbose("  Interarrival jitter: %u\n", rtp->rtcp->reported_jitter);
            ast_verbose("  Last SR(our NTP): %lu.%010lu\n",(unsigned long) ntohl(rtcpheader[i + 4]) >> 16,((unsigned long) ntohl(rtcpheader[i + 4]) << 16) * 4096);
            ast_verbose("  DLSR: %4.4f (sec)\n",ntohl(rtcpheader[i + 5])/65536.0);
            if (rtt)
               ast_verbose("  RTT: %lu(sec)\n", (unsigned long) rtt);
         }

         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"
                            "RTT: %llu(sec)\r\n",
                            ast_inet_ntoa(sock_in.sin_addr), ntohs(sock_in.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,
                            (unsigned long long)rtt);
         } 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(sock_in.sin_addr), ntohs(sock_in.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);
         }
         break;
      case RTCP_PT_FUR:
         if (rtcp_debug_test_addr(&sock_in))
            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(&sock_in))
            ast_verbose("Received an SDES from %s:%d\n", ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
         break;
      case RTCP_PT_BYE:
         if (rtcp_debug_test_addr(&sock_in))
            ast_verbose("Received a BYE from %s:%d\n", ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
         break;
      default:
         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));
         break;
      }
      position += (length + 1);
   }
   rtp->rtcp->rtcp_info = 1;  
   return f;
}
int ast_rtcp_send_h261fur ( void *  data)

Public function: Send an H.261 fast update request, some devices need this rather than SIP XML.

Send an H.261 fast update request. Some devices need this rather than the XML message in SIP.

Definition at line 3357 of file rtp.c.

References ast_rtcp_write(), ast_rtp::data, ast_rtp::rtcp, and ast_rtcp::sendfur.

{
   struct ast_rtp *rtp = data;
   int res;

   rtp->rtcp->sendfur = 1;
   res = ast_rtcp_write(data);
   
   return res;
}
static int ast_rtcp_write ( const void *  data) [static]

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

Definition at line 3615 of file rtp.c.

References ast_rtcp_write_rr(), ast_rtcp_write_sr(), ast_rtcp::lastsrtxcount, ast_rtp::rtcp, and ast_rtp::txcount.

Referenced by ast_rtcp_send_h261fur(), ast_rtp_raw_write(), and ast_rtp_read().

{
   struct ast_rtp *rtp = (struct ast_rtp *)data;
   int res;
   
   if (!rtp || !rtp->rtcp)
      return 0;

   if (rtp->txcount > rtp->rtcp->lastsrtxcount)
      res = ast_rtcp_write_sr(data);
   else
      res = ast_rtcp_write_rr(data);
   
   return res;
}
static int ast_rtcp_write_rr ( const void *  data) [static]

Send RTCP recipient's report.

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)

Definition at line 3502 of file rtp.c.

References ast_inet_ntoa(), ast_log(), AST_SCHED_DEL, ast_verbose(), ast_rtp::cycles, errno, ast_rtcp::expected_prior, ast_rtp::lastrxseqno, len(), LOG_ERROR, ast_rtcp::maxrxlost, ast_rtcp::minrxlost, normdev_compute(), ast_rtcp::normdev_rxlost, ast_rtcp::received_prior, ast_rtcp::rr_count, ast_rtp::rtcp, rtcp_debug_test_addr(), RTCP_PT_FUR, RTCP_PT_RR, RTCP_PT_SDES, ast_rtp::rxcount, ast_rtp::rxjitter, ast_rtcp::rxlost, ast_rtcp::rxlost_count, ast_rtcp::rxlsr, ast_rtcp::s, ast_rtp::sched, ast_rtcp::schedid, ast_rtp::seedrxseqno, ast_rtcp::sendfur, ast_rtp::ssrc, stddev_compute(), ast_rtcp::stdev_rxlost, ast_rtcp::them, ast_rtcp::themrxlsr, ast_rtp::themssrc, and timersub().

Referenced by ast_rtcp_write().

{
   struct ast_rtp *rtp = (struct ast_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;

   double rxlost_current;
   
   if (!rtp || !rtp->rtcp || (&rtp->rtcp->them.sin_addr == 0))
      return 0;
     
   if (!rtp->rtcp->them.sin_addr.s_addr) {
      ast_log(LOG_ERROR, "RTCP RR transmission error, rtcp halted\n");
      AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
      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 (lost_interval <= 0)
      rtp->rtcp->rxlost = 0;
   else rtp->rtcp->rxlost = rtp->rtcp->rxlost;
   if (rtp->rtcp->rxlost_count == 0)
      rtp->rtcp->minrxlost = rtp->rtcp->rxlost;
   if (lost_interval < rtp->rtcp->minrxlost) 
      rtp->rtcp->minrxlost = rtp->rtcp->rxlost;
   if (lost_interval > rtp->rtcp->maxrxlost) 
      rtp->rtcp->maxrxlost = rtp->rtcp->rxlost;

   rxlost_current = normdev_compute(rtp->rtcp->normdev_rxlost, rtp->rtcp->rxlost, rtp->rtcp->rxlost_count);
   rtp->rtcp->stdev_rxlost = stddev_compute(rtp->rtcp->stdev_rxlost, rtp->rtcp->rxlost, rtp->rtcp->normdev_rxlost, rxlost_current, rtp->rtcp->rxlost_count);
   rtp->rtcp->normdev_rxlost = rxlost_current;
   rtp->rtcp->rxlost_count++;

   if (expected_interval == 0 || lost_interval <= 0)
      fraction = 0;
   else
      fraction = (lost_interval << 8) / expected_interval;
   gettimeofday(&now, NULL);
   timersub(&now, &rtp->rtcp->rxlsr, &dlsr);
   rtcpheader = (unsigned int *)bdata;
   rtcpheader[0] = htonl((2 << 30) | (1 << 24) | (RTCP_PT_RR << 16) | ((len/4)-1));
   rtcpheader[1] = htonl(rtp->ssrc);
   rtcpheader[2] = htonl(rtp->themssrc);
   rtcpheader[3] = htonl(((fraction & 0xff) << 24) | (lost & 0xffffff));
   rtcpheader[4] = htonl((rtp->cycles) | ((rtp->lastrxseqno & 0xffff)));
   rtcpheader[5] = htonl((unsigned int)(rtp->rxjitter * 65536.));
   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 */
      AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
      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\nTheir SSRC: %u\niFraction lost: %d\nCumulative loss: %u\n" 
         "  IA jitter: %.4f\n" 
         "  Their last SR: %u\n" 
         "  DLSR: %4.4f (sec)\n\n",
         ast_inet_ntoa(rtp->rtcp->them.sin_addr),
         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;
}
static int ast_rtcp_write_sr ( const void *  data) [static]

Send RTCP sender's report.

Definition at line 3369 of file rtp.c.

References ast_inet_ntoa(), ast_log(), AST_SCHED_DEL, ast_verbose(), ast_rtp::cycles, errno, EVENT_FLAG_REPORTING, ast_rtcp::expected_prior, ast_rtp::lastrxseqno, ast_rtcp::lastsrtxcount, ast_rtp::lastts, len(), LOG_ERROR, manager_event, ast_rtcp::received_prior, ast_rtp::rtcp, rtcp_debug_test_addr(), RTCP_PT_FUR, RTCP_PT_SDES, RTCP_PT_SR, ast_rtp::rxcount, ast_rtp::rxjitter, ast_rtcp::rxlsr, ast_rtcp::s, ast_rtp::sched, ast_rtcp::schedid, ast_rtp::seedrxseqno, ast_rtcp::sendfur, ast_rtcp::sr_count, ast_rtp::ssrc, ast_rtcp::them, ast_rtcp::themrxlsr, ast_rtp::themssrc, timersub(), timeval2ntp(), ast_rtp::txcount, ast_rtcp::txlsr, and ast_rtp::txoctetcount.

Referenced by ast_rtcp_write().

{
   struct ast_rtp *rtp = (struct ast_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];

   /* Commented condition is always not NULL if rtp->rtcp is not NULL */
   if (!rtp || !rtp->rtcp/* || (&rtp->rtcp->them.sin_addr == 0)*/)
      return 0;
   
   if (!rtp->rtcp->them.sin_addr.s_addr) {  /* This'll stop rtcp for this rtp session */
      ast_verbose("RTCP SR transmission error, rtcp halted\n");
      AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
      return 0;
   }

   gettimeofday(&now, NULL);
   timeval2ntp(now, &now_msw, &now_lsw); /* fill thses ones in from utils.c*/
   rtcpheader = (unsigned int *)bdata;
   rtcpheader[1] = htonl(rtp->ssrc);               /* Our SSRC */
   rtcpheader[2] = htonl(now_msw);                 /* now, MSW. gettimeofday() + SEC_BETWEEN_1900_AND_1970*/
   rtcpheader[3] = htonl(now_lsw);                 /* now, LSW */
   rtcpheader[4] = htonl(rtp->lastts);             /* FIXME shouldn't be that, it should be now */
   rtcpheader[5] = htonl(rtp->txcount);            /* No. packets sent */
   rtcpheader[6] = htonl(rtp->txoctetcount);       /* No. bytes sent */
   len += 28;
   
   extended = rtp->cycles + rtp->lastrxseqno;
   expected = extended - rtp->seedrxseqno + 1;
   if (rtp->rxcount > expected) 
      expected += rtp->rxcount - expected;
   lost = expected - rtp->rxcount;
   expected_interval = expected - rtp->rtcp->expected_prior;
   rtp->rtcp->expected_prior = expected;
   received_interval = rtp->rxcount - rtp->rtcp->received_prior;
   rtp->rtcp->received_prior = rtp->rxcount;
   lost_interval = expected_interval - received_interval;
   if (expected_interval == 0 || lost_interval <= 0)
      fraction = 0;
   else
      fraction = (lost_interval << 8) / expected_interval;
   timersub(&now, &rtp->rtcp->rxlsr, &dlsr);
   rtcpheader[7] = htonl(rtp->themssrc);
   rtcpheader[8] = htonl(((fraction & 0xff) << 24) | (lost & 0xffffff));
   rtcpheader[9] = htonl((rtp->cycles) | ((rtp->lastrxseqno & 0xffff)));
   rtcpheader[10] = htonl((unsigned int)(rtp->rxjitter * 65536.));
   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) {
      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));
      AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
      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)) {
      ast_verbose("* Sent RTCP SR to %s:%d\n", ast_inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
      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));
   }
   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));
   return res;
}
size_t ast_rtp_alloc_size ( void  )

Get the amount of space required to hold an RTP session.

Returns:
number of bytes required

Definition at line 496 of file rtp.c.

Referenced by process_sdp().

{
   return sizeof(struct ast_rtp);
}
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 
)

Bridge calls. If possible and allowed, initiate re-invite so the peers exchange media directly outside of Asterisk.

The RTP bridge.

Definition at line 4456 of file rtp.c.

References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, AST_BRIDGE_FAILED, AST_BRIDGE_FAILED_NOWARN, ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_check_hangup(), ast_codec_pref_getsize(), ast_debug, ast_log(), AST_RTP_GET_FAILED, AST_RTP_TRY_NATIVE, AST_RTP_TRY_PARTIAL, ast_set_flag, ast_test_flag, ast_verb, bridge_native_loop(), bridge_p2p_loop(), ast_format_list::cur_ms, FLAG_HAS_DTMF, FLAG_P2P_NEED_DTMF, ast_rtp_protocol::get_codec, get_proto(), ast_rtp_protocol::get_rtp_info, ast_rtp_protocol::get_trtp_info, ast_rtp_protocol::get_vrtp_info, LOG_WARNING, ast_channel::name, ast_rtp::pref, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel_tech::send_digit_begin, ast_channel::tech, and ast_channel::tech_pvt.

{
   struct ast_rtp *p0 = NULL, *p1 = NULL;    /* Audio RTP Channels */
   struct ast_rtp *vp0 = NULL, *vp1 = NULL;  /* Video RTP channels */
   struct ast_rtp *tp0 = NULL, *tp1 = NULL;  /* Text RTP channels */
   struct ast_rtp_protocol *pr0 = NULL, *pr1 = NULL;
   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;
   enum ast_bridge_result res = AST_BRIDGE_FAILED;
   int codec0 = 0, codec1 = 0;
   void *pvt0 = NULL, *pvt1 = NULL;

   /* Lock channels */
   ast_channel_lock(c0);
   while (ast_channel_trylock(c1)) {
      ast_channel_unlock(c0);
      usleep(1);
      ast_channel_lock(c0);
   }

   /* Ensure neither channel got hungup during lock avoidance */
   if (ast_check_hangup(c0) || ast_check_hangup(c1)) {
      ast_log(LOG_WARNING, "Got hangup while attempting to bridge '%s' and '%s'\n", c0->name, c1->name);
      ast_channel_unlock(c0);
      ast_channel_unlock(c1);
      return AST_BRIDGE_FAILED;
   }
      
   /* 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;
   text_p0_res = pr0->get_trtp_info ? pr0->get_trtp_info(c0, &vp0) : AST_RTP_GET_FAILED;
   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;
   text_p1_res = pr1->get_trtp_info ? pr1->get_trtp_info(c1, &vp1) : AST_RTP_GET_FAILED;

   /* 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) */
   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;
   }

   /* 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                  |
    * | SIP INFO  | False      | False                 |
    * --------------------------------------------------
    * 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.
    */
   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)) {
      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;
      }
      audio_p0_res = AST_RTP_TRY_PARTIAL;
      audio_p1_res = AST_RTP_TRY_PARTIAL;
   }

   /* If we need to feed frames into the core don't do a P2P bridge */
   if ((audio_p0_res == AST_RTP_TRY_PARTIAL && ast_test_flag(p0, FLAG_P2P_NEED_DTMF)) ||
       (audio_p1_res == AST_RTP_TRY_PARTIAL && ast_test_flag(p1, FLAG_P2P_NEED_DTMF))) {
      ast_channel_unlock(c0);
      ast_channel_unlock(c1);
      return AST_BRIDGE_FAILED_NOWARN;
   }

   /* Get codecs from both sides */
   codec0 = pr0->get_codec ? pr0->get_codec(c0) : 0;
   codec1 = pr1->get_codec ? pr1->get_codec(c1) : 0;
   if (codec0 && codec1 && !(codec0 & codec1)) {
      /* Hey, we can't do native bridging if both parties speak different codecs */
      ast_debug(3, "Channel codec0 = %d is not codec1 = %d, cannot native bridge in RTP.\n", codec0, codec1);
      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) {
      struct ast_format_list fmt0, fmt1;

      /* In order to do Packet2Packet bridging both sides must be in the same rawread/rawwrite */
      if (c0->rawreadformat != c1->rawwriteformat || c1->rawreadformat != c0->rawwriteformat) {
         ast_debug(1, "Cannot packet2packet bridge - raw formats are incompatible\n");
         ast_channel_unlock(c0);
         ast_channel_unlock(c1);
         return AST_BRIDGE_FAILED_NOWARN;
      }
      /* 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) {
         ast_debug(1, "Cannot packet2packet bridge - packetization settings prevent it\n");
         ast_channel_unlock(c0);
         ast_channel_unlock(c1);
         return AST_BRIDGE_FAILED_NOWARN;
      }

      ast_verb(3, "Packet2Packet bridging %s and %s\n", c0->name, c1->name);
      res = bridge_p2p_loop(c0, c1, p0, p1, timeoutms, flags, fo, rc, pvt0, pvt1);
   } else {
      ast_verb(3, "Native bridging %s and %s\n", c0->name, c1->name);
      res = bridge_native_loop(c0, c1, p0, p1, vp0, vp1, tp0, tp1, pr0, pr1, codec0, codec1, timeoutms, flags, fo, rc, pvt0, pvt1);
   }

   return res;
}
void ast_rtp_change_source ( struct ast_rtp rtp)

Indicate that we need to set the marker bit and change the ssrc.

Definition at line 2692 of file rtp.c.

References ast_debug, ast_random(), ast_rtp::set_marker_bit, and ast_rtp::ssrc.

Referenced by mgcp_indicate(), oh323_indicate(), sip_indicate(), and skinny_indicate().

{
   if (rtp) {
      unsigned int ssrc = ast_random();

      rtp->set_marker_bit = 1;
      ast_debug(3, "Changing ssrc from %u to %u due to a source change\n", rtp->ssrc, ssrc);
      rtp->ssrc = ssrc;
   }
}
int ast_rtp_codec_getformat ( int  pt)

get format from predefined dynamic payload format

Definition at line 3837 of file rtp.c.

References rtpPayloadType::code, and MAX_RTP_PT.

Referenced by process_sdp_a_audio().

{
   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;
}
struct ast_codec_pref* ast_rtp_codec_getpref ( struct ast_rtp rtp) [read]

Get codec preference.

Definition at line 3832 of file rtp.c.

References ast_rtp::pref.

Referenced by add_codec_to_sdp(), and process_sdp_a_audio().

{
   return &rtp->pref;
}
void ast_rtp_codec_setpref ( struct ast_rtp rtp,
struct ast_codec_pref prefs 
)

Set codec preference.

Definition at line 3786 of file rtp.c.

References ast_codec_pref_getsize(), ast_log(), ast_smoother_new(), ast_smoother_reconfigure(), ast_smoother_set_flags(), ast_format_list::cur_ms, ast_format_list::flags, ast_format_list::fr_len, ast_format_list::inc_ms, ast_rtp::lasttxformat, LOG_DEBUG, LOG_WARNING, option_debug, ast_rtp::pref, prefs, and ast_rtp::smoother.

Referenced by __oh323_rtp_create(), check_peer_ok(), create_addr_from_peer(), gtalk_new(), jingle_new(), process_sdp_a_audio(), register_verify(), set_peer_capabilities(), sip_alloc(), start_rtp(), and transmit_response_with_sdp().

{
   struct ast_format_list current_format_old, current_format_new;

   /* if no packets have been sent through this session yet, then
    *  changing preferences does not require any extra work
    */
   if (rtp->lasttxformat == 0) {
      rtp->pref = *prefs;
      return;
   }

   current_format_old = ast_codec_pref_getsize(&rtp->pref, rtp->lasttxformat);

   rtp->pref = *prefs;

   current_format_new = ast_codec_pref_getsize(&rtp->pref, rtp->lasttxformat);

   /* if the framing desired for the current format has changed, we may have to create
    * or adjust the smoother for this session
    */
   if ((current_format_new.inc_ms != 0) &&
       (current_format_new.cur_ms != current_format_old.cur_ms)) {
      int new_size = (current_format_new.cur_ms * current_format_new.fr_len) / current_format_new.inc_ms;

      if (rtp->smoother) {
         ast_smoother_reconfigure(rtp->smoother, new_size);
         if (option_debug) {
            ast_log(LOG_DEBUG, "Adjusted smoother to %d ms and %d bytes\n", current_format_new.cur_ms, new_size);
         }
      } else {
         if (!(rtp->smoother = ast_smoother_new(new_size))) {
            ast_log(LOG_WARNING, "Unable to create smoother: format: %d ms: %d len: %d\n", rtp->lasttxformat, current_format_new.cur_ms, new_size);
            return;
         }
         if (current_format_new.flags) {
            ast_smoother_set_flags(rtp->smoother, current_format_new.flags);
         }
         if (option_debug) {
            ast_log(LOG_DEBUG, "Created smoother: format: %d ms: %d len: %d\n", rtp->lasttxformat, current_format_new.cur_ms, new_size);
         }
      }
   }

}
void ast_rtp_destroy ( struct ast_rtp rtp)

Destroy RTP session

Definition at line 3105 of file rtp.c.

References ast_free, ast_io_remove(), ast_mutex_destroy(), AST_SCHED_DEL, ast_smoother_free(), ast_verbose(), EVENT_FLAG_REPORTING, ast_rtcp::expected_prior, ast_rtp::io, ast_rtp::ioid, manager_event, ast_rtcp::received_prior, ast_rtcp::reported_jitter, ast_rtcp::reported_lost, ast_rtcp::rr_count, ast_rtp::rtcp, rtcp_debug_test_addr(), ast_rtcp::rtt, ast_rtp::rxcount, ast_rtp::rxjitter, ast_rtp::rxtransit, ast_rtcp::s, ast_rtp::s, ast_rtp::sched, ast_rtcp::schedid, ast_rtp::smoother, ast_rtcp::sr_count, ast_rtp::ssrc, ast_rtp::them, ast_rtp::themssrc, and ast_rtp::txcount.

Referenced by __oh323_destroy(), __sip_destroy(), check_peer_ok(), cleanup_connection(), create_addr_from_peer(), destroy_endpoint(), gtalk_free_pvt(), jingle_free_pvt(), mgcp_hangup(), oh323_alloc(), skinny_hangup(), start_rtp(), unalloc_sub(), and unistim_hangup().

{
   if (rtcp_debug_test_addr(&rtp->them) || rtcpstats) {
      /*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 ? (rtp->rtcp->expected_prior - rtp->rtcp->received_prior) : 0);
      ast_verbose("  Jitter:      %.4f\n", rtp->rxjitter);
      ast_verbose("  Transit:     %.4f\n", rtp->rxtransit);
      ast_verbose("  RR-count:    %u\n", rtp->rtcp ? rtp->rtcp->rr_count : 0);
      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 ? rtp->rtcp->reported_lost : 0);
      ast_verbose("  Jitter:      %u\n", rtp->rtcp ? (rtp->rtcp->reported_jitter / (unsigned int)65536.0) : 0);
      ast_verbose("  SR-count:    %u\n", rtp->rtcp ? rtp->rtcp->sr_count : 0);
      ast_verbose("  RTT:      %f\n", rtp->rtcp ? rtp->rtcp->rtt : 0);
   }

   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 ? (rtp->rtcp->expected_prior - rtp->rtcp->received_prior) : 0,
                   rtp->rxjitter,
                   rtp->rxtransit,
                   rtp->rtcp ? rtp->rtcp->rr_count : 0);
   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 ? rtp->rtcp->reported_lost : 0,
                   rtp->rtcp ? rtp->rtcp->reported_jitter : 0,
                   rtp->rtcp ? rtp->rtcp->sr_count : 0,
                   rtp->rtcp ? rtp->rtcp->rtt : 0);
   if (rtp->smoother)
      ast_smoother_free(rtp->smoother);
   if (rtp->ioid)
      ast_io_remove(rtp->io, rtp->ioid);
   if (rtp->s > -1)
      close(rtp->s);
   if (rtp->rtcp) {
      AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
      close(rtp->rtcp->s);
      ast_free(rtp->rtcp);
      rtp->rtcp=NULL;
   }
#ifdef P2P_INTENSE
   ast_mutex_destroy(&rtp->bridge_lock);
#endif
   ast_free(rtp);
}
int ast_rtp_early_bridge ( struct ast_channel c0,
struct ast_channel c1 
)

If possible, create an early bridge directly between the devices without having to send a re-invite later.

Definition at line 2114 of file rtp.c.

References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_debug, ast_log(), AST_RTP_GET_FAILED, AST_RTP_TRY_NATIVE, ast_test_flag, FLAG_NAT_ACTIVE, ast_rtp_protocol::get_codec, get_proto(), ast_rtp_protocol::get_rtp_info, ast_rtp_protocol::get_trtp_info, ast_rtp_protocol::get_vrtp_info, LOG_WARNING, ast_channel::name, and ast_rtp_protocol::set_rtp_peer.

{
   struct ast_rtp *destp = NULL, *srcp = NULL;     /* Audio RTP Channels */
   struct ast_rtp *vdestp = NULL, *vsrcp = NULL;      /* Video RTP channels */
   struct ast_rtp *tdestp = NULL, *tsrcp = NULL;      /* Text RTP channels */
   struct ast_rtp_protocol *destpr = NULL, *srcpr = NULL;
   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;
   int srccodec, destcodec, nat_active = 0;

   /* Lock channels */
   ast_channel_lock(c0);
   if (c1) {
      while (ast_channel_trylock(c1)) {
         ast_channel_unlock(c0);
         usleep(1);
         ast_channel_lock(c0);
      }
   }

   /* Find channel driver interfaces */
   destpr = get_proto(c0);
   if (c1)
      srcpr = get_proto(c1);
   if (!destpr) {
      ast_debug(1, "Channel '%s' has no RTP, not doing anything\n", c0->name);
      ast_channel_unlock(c0);
      if (c1)
         ast_channel_unlock(c1);
      return -1;
   }
   if (!srcpr) {
      ast_debug(1, "Channel '%s' has no RTP, not doing anything\n", c1 ? c1->name : "<unspecified>");
      ast_channel_unlock(c0);
      if (c1)
         ast_channel_unlock(c1);
      return -1;
   }

   /* Get audio, video  and text interface (if native bridge is possible) */
   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;
   text_dest_res = destpr->get_trtp_info ? destpr->get_trtp_info(c0, &tdestp) : AST_RTP_GET_FAILED;
   if (srcpr) {
      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;
      text_src_res = srcpr->get_trtp_info ? srcpr->get_trtp_info(c1, &tsrcp) : AST_RTP_GET_FAILED;
   }

   /* Check if bridge is still possible (In SIP directmedia=no stops this, like NAT) */
   if (audio_dest_res != AST_RTP_TRY_NATIVE || (video_dest_res != AST_RTP_GET_FAILED && video_dest_res != AST_RTP_TRY_NATIVE)) {
      /* Somebody doesn't want to play... */
      ast_channel_unlock(c0);
      if (c1)
         ast_channel_unlock(c1);
      return -1;
   }
   if (audio_src_res == AST_RTP_TRY_NATIVE && (video_src_res == AST_RTP_GET_FAILED || video_src_res == AST_RTP_TRY_NATIVE) && srcpr->get_codec)
      srccodec = srcpr->get_codec(c1);
   else
      srccodec = 0;
   if (audio_dest_res == AST_RTP_TRY_NATIVE && (video_dest_res == AST_RTP_GET_FAILED || video_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 (srcp && !(srccodec & destcodec)) {
      ast_channel_unlock(c0);
      ast_channel_unlock(c1);
      return 0;
   }
   /* Consider empty media as non-existent */
   if (audio_src_res == AST_RTP_TRY_NATIVE && !srcp->them.sin_addr.s_addr)
      srcp = NULL;
   if (srcp && (srcp->nat || ast_test_flag(srcp, FLAG_NAT_ACTIVE)))
      nat_active = 1;
   /* Bridge media early */
   if (destpr->set_rtp_peer(c0, srcp, vsrcp, tsrcp, srccodec, nat_active))
      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);
   ast_debug(1, "Setting early bridge SDP of '%s' with that of '%s'\n", c0->name, c1 ? c1->name : "<unspecified>");
   return 0;
}
int ast_rtp_fd ( struct ast_rtp rtp)
struct ast_rtp* ast_rtp_get_bridged ( struct ast_rtp rtp) [read]

Definition at line 2746 of file rtp.c.

References ast_rtp::bridged, rtp_bridge_lock(), and rtp_bridge_unlock().

Referenced by __sip_destroy(), ast_rtp_read(), and dialog_needdestroy().

{
   struct ast_rtp *bridged = NULL;

   rtp_bridge_lock(rtp);
   bridged = rtp->bridged;
   rtp_bridge_unlock(rtp);

   return bridged;
}
void ast_rtp_get_current_formats ( struct ast_rtp rtp,
int *  astFormats,
int *  nonAstFormats 
)

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.

Definition at line 2362 of file rtp.c.

References rtpPayloadType::code, ast_rtp::current_RTP_PT, rtpPayloadType::isAstFormat, MAX_RTP_PT, rtp_bridge_lock(), and rtp_bridge_unlock().

Referenced by gtalk_is_answered(), gtalk_newcall(), and process_sdp().

{
   int pt;
   
   rtp_bridge_lock(rtp);
   
   *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;
      }
   }

   rtp_bridge_unlock(rtp);
}
int ast_rtp_get_peer ( struct ast_rtp rtp,
struct sockaddr_in *  them 
)

Definition at line 2728 of file rtp.c.

References ast_rtp::them.

Referenced by acf_channel_read(), add_sdp(), bridge_native_loop(), check_rtp_timeout(), gtalk_update_stun(), oh323_set_rtp_peer(), process_sdp(), sip_set_rtp_peer(), skinny_set_rtp_peer(), and transmit_modify_with_sdp().

{
   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;
}
int ast_rtp_get_qos ( struct ast_rtp rtp,
const char *  qos,
char *  buf,
unsigned int  buflen 
)

Get QOS stats on a RTP channel.

Since:
1.6.1

Definition at line 2867 of file rtp.c.

References __ast_rtp_get_qos().

Referenced by acf_channel_read().

{
   double value;
   int found;

   value = __ast_rtp_get_qos(rtp, qos, &found);

   if (!found)
      return -1;

   snprintf(buf, buflen, "%.0lf", value);

   return 0;
}
unsigned int ast_rtp_get_qosvalue ( struct ast_rtp rtp,
enum ast_rtp_qos_vars  value 
)

Return RTP and RTCP QoS values.

Get QoS values from RTP and RTCP data (used in "sip show channelstats")

Definition at line 2801 of file rtp.c.

References ast_log(), AST_RTP_RTT, AST_RTP_RXCOUNT, AST_RTP_RXJITTER, AST_RTP_RXPLOSS, AST_RTP_TXCOUNT, AST_RTP_TXJITTER, AST_RTP_TXPLOSS, ast_rtcp::expected_prior, LOG_DEBUG, option_debug, ast_rtcp::received_prior, ast_rtcp::reported_jitter, ast_rtcp::reported_lost, ast_rtp::rtcp, ast_rtcp::rtt, ast_rtp::rxcount, ast_rtp::rxjitter, and ast_rtp::txcount.

Referenced by show_chanstats_cb().

{
   if (rtp == NULL) {
      if (option_debug > 1)
         ast_log(LOG_DEBUG, "NO RTP Structure? Kidding me? \n");
      return 0;
   }
   if (option_debug > 1 && rtp->rtcp == NULL) {
      ast_log(LOG_DEBUG, "NO RTCP structure. Maybe in RTP p2p bridging mode? \n");
   }

   switch (value) {
   case AST_RTP_TXCOUNT:
      return (unsigned int) rtp->txcount;
   case AST_RTP_RXCOUNT:
      return (unsigned int) rtp->rxcount;
   case AST_RTP_TXJITTER:
      return (unsigned int) (rtp->rxjitter * 1000.0);
   case AST_RTP_RXJITTER:
      return (unsigned int) (rtp->rtcp ? (rtp->rtcp->reported_jitter / (unsigned int) 65536.0) : 0);
   case AST_RTP_RXPLOSS:
      return rtp->rtcp ? (rtp->rtcp->expected_prior - rtp->rtcp->received_prior) : 0;
   case AST_RTP_TXPLOSS:
      return rtp->rtcp ? rtp->rtcp->reported_lost : 0;
   case AST_RTP_RTT:
      return (unsigned int) (rtp->rtcp ? (rtp->rtcp->rtt * 100) : 0);
   }
   return 0;   /* To make the compiler happy */
}
char* ast_rtp_get_quality ( struct ast_rtp rtp,
struct ast_rtp_quality qual,
enum ast_rtp_quality_type  qtype 
)

Return RTCP quality string.

Parameters:
rtpAn rtp structure to get qos information about.
qualAn (optional) rtp quality structure that will be filled with the quality information described in the ast_rtp_quality structure. This structure is not dependent on any qtype, so a call for any type of information would yield the same results because ast_rtp_quality is not a data type specific to any qos type.
qtypeThe quality type you'd like, default should be RTPQOS_SUMMARY which returns basic information about the call. The return from RTPQOS_SUMMARY is basically ast_rtp_quality in a string. The other types are RTPQOS_JITTER, RTPQOS_LOSS and RTPQOS_RTT which will return more specific statistics.
Version:
1.6.1 added qtype parameter

Definition at line 3074 of file rtp.c.

References __ast_rtp_get_quality(), __ast_rtp_get_quality_jitter(), __ast_rtp_get_quality_loss(), __ast_rtp_get_quality_rtt(), ast_rtcp::expected_prior, ast_rtp_quality::local_count, ast_rtp_quality::local_jitter, ast_rtp_quality::local_lostpackets, ast_rtp_quality::local_ssrc, ast_rtcp::received_prior, ast_rtp_quality::remote_count, ast_rtp_quality::remote_jitter, ast_rtp_quality::remote_lostpackets, ast_rtp_quality::remote_ssrc, ast_rtcp::reported_jitter, ast_rtcp::reported_lost, ast_rtp::rtcp, RTPQOS_JITTER, RTPQOS_LOSS, RTPQOS_RTT, RTPQOS_SUMMARY, ast_rtcp::rtt, ast_rtp_quality::rtt, ast_rtp::rxcount, ast_rtp::rxjitter, ast_rtp::ssrc, ast_rtp::themssrc, and ast_rtp::txcount.

Referenced by acf_channel_read(), ast_rtp_set_vars(), handle_request_bye(), and sip_hangup().

{
   if (qual && rtp) {
      qual->local_ssrc   = rtp->ssrc;
      qual->local_jitter = rtp->rxjitter;
      qual->local_count  = rtp->rxcount;
      qual->remote_ssrc  = rtp->themssrc;
      qual->remote_count = rtp->txcount;

      if (rtp->rtcp) {
         qual->local_lostpackets  = rtp->rtcp->expected_prior - rtp->rtcp->received_prior;
         qual->remote_lostpackets = rtp->rtcp->reported_lost;
         qual->remote_jitter      = rtp->rtcp->reported_jitter / 65536.0;
         qual->rtt                = rtp->rtcp->rtt;
      }
   }

   switch (qtype) {
   case RTPQOS_SUMMARY:
      return __ast_rtp_get_quality(rtp);
   case RTPQOS_JITTER:
      return __ast_rtp_get_quality_jitter(rtp);
   case RTPQOS_LOSS:
      return __ast_rtp_get_quality_loss(rtp);
   case RTPQOS_RTT:
      return __ast_rtp_get_quality_rtt(rtp);
   }

   return NULL;
}
int ast_rtp_get_rtpholdtimeout ( struct ast_rtp rtp)

Get rtp hold timeout.

Definition at line 777 of file rtp.c.

References ast_rtp::rtpholdtimeout, and ast_rtp::rtptimeout.

Referenced by check_rtp_timeout().

{
   if (rtp->rtptimeout < 0)   /* We're not checking, but remembering the setting (during T.38 transmission) */
      return 0;
   return rtp->rtpholdtimeout;
}
int ast_rtp_get_rtpkeepalive ( struct ast_rtp rtp)

Get RTP keepalive interval.

Definition at line 785 of file rtp.c.

References ast_rtp::rtpkeepalive.

Referenced by check_rtp_timeout().

{
   return rtp->rtpkeepalive;
}
int ast_rtp_get_rtptimeout ( struct ast_rtp rtp)

Get rtp timeout.

Definition at line 769 of file rtp.c.

References ast_rtp::rtptimeout.

Referenced by check_rtp_timeout().

{
   if (rtp->rtptimeout < 0)   /* We're not checking, but remembering the setting (during T.38 transmission) */
      return 0;
   return rtp->rtptimeout;
}
void ast_rtp_get_us ( struct ast_rtp rtp,
struct sockaddr_in *  us 
)
int ast_rtp_getnat ( struct ast_rtp rtp)

Definition at line 805 of file rtp.c.

References ast_test_flag, and FLAG_NAT_ACTIVE.

Referenced by sip_get_rtp_peer().

{
   return ast_test_flag(rtp, FLAG_NAT_ACTIVE);
}
void ast_rtp_init ( void  )

Initialize the RTP system in Asterisk.

Definition at line 4877 of file rtp.c.

References __ast_rtp_reload(), and ast_cli_register_multiple().

Referenced by main().

int ast_rtp_lookup_code ( struct ast_rtp rtp,
const int  isAstFormat,
const int  code 
)

Looks up an RTP code out of our *static* outbound list.

Definition at line 2403 of file rtp.c.

References rtpPayloadType::code, ast_rtp::current_RTP_PT, rtpPayloadType::isAstFormat, MAX_RTP_PT, rtp_bridge_lock(), rtp_bridge_unlock(), ast_rtp::rtp_lookup_code_cache_code, ast_rtp::rtp_lookup_code_cache_isAstFormat, and ast_rtp::rtp_lookup_code_cache_result.

Referenced by add_codec_to_answer(), add_codec_to_sdp(), add_noncodec_to_sdp(), add_sdp(), add_tcodec_to_sdp(), add_vcodec_to_sdp(), ast_rtp_sendcng(), ast_rtp_senddigit_begin(), ast_rtp_write(), bridge_p2p_rtp_write(), and start_rtp().

{
   int pt = 0;

   rtp_bridge_lock(rtp);

   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 */
      pt = rtp->rtp_lookup_code_cache_result;
      rtp_bridge_unlock(rtp);
      return pt;
   }

   /* Check the dynamic list first */
   for (pt = 0; pt < MAX_RTP_PT; ++pt) {
      if (rtp->current_RTP_PT[pt].code == code && rtp->current_RTP_PT[pt].isAstFormat == isAstFormat) {
         rtp->rtp_lookup_code_cache_isAstFormat = isAstFormat;
         rtp->rtp_lookup_code_cache_code = code;
         rtp->rtp_lookup_code_cache_result = pt;
         rtp_bridge_unlock(rtp);
         return pt;
      }
   }

   /* Then the static list */
   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;
         rtp_bridge_unlock(rtp);
         return pt;
      }
   }

   rtp_bridge_unlock(rtp);

   return -1;
}
char* ast_rtp_lookup_mime_multiple ( char *  buf,
size_t  size,
const int  capability,
const int  isAstFormat,
enum ast_rtp_options  options 
)

Build a string of MIME subtype names from a capability list.

Definition at line 2476 of file rtp.c.

References ast_copy_string(), ast_rtp_lookup_mime_subtype(), AST_RTP_MAX, buf, format, len(), and name.

Referenced by process_sdp().

{
   int format;
   unsigned len;
   char *end = buf;
   char *start = buf;

   if (!buf || !size)
      return NULL;

   snprintf(end, size, "0x%x (", capability);

   len = strlen(end);
   end += len;
   size -= len;
   start = end;

   for (format = 1; format < AST_RTP_MAX; format <<= 1) {
      if (capability & format) {
         const char *name = ast_rtp_lookup_mime_subtype(isAstFormat, format, options);

         snprintf(end, size, "%s|", name);
         len = strlen(end);
         end += len;
         size -= len;
      }
   }

   if (start == end)
      ast_copy_string(start, "nothing)", size); 
   else if (size > 1)
      *(end -1) = ')';
   
   return buf;
}
const char* ast_rtp_lookup_mime_subtype ( const int  isAstFormat,
const int  code,
enum ast_rtp_options  options 
)

Mapping an Asterisk code into a MIME subtype (string):

Definition at line 2444 of file rtp.c.

References ARRAY_LEN, AST_FORMAT_G726_AAL2, AST_RTP_OPT_G726_NONSTANDARD, rtpPayloadType::isAstFormat, mimeTypes, mimeType::payloadType, and mimeType::subtype.

Referenced by add_codec_to_sdp(), add_noncodec_to_sdp(), add_sdp(), add_tcodec_to_sdp(), add_vcodec_to_sdp(), ast_rtp_lookup_mime_multiple(), transmit_connect_with_sdp(), and transmit_modify_with_sdp().

{
   unsigned int i;

   for (i = 0; i < ARRAY_LEN(mimeTypes); ++i) {
      if ((mimeTypes[i].payloadType.code == code) && (mimeTypes[i].payloadType.isAstFormat == isAstFormat)) {
         if (isAstFormat &&
             (code == AST_FORMAT_G726_AAL2) &&
             (options & AST_RTP_OPT_G726_NONSTANDARD))
            return "G726-32";
         else
            return mimeTypes[i].subtype;
      }
   }

   return "";
}
struct rtpPayloadType ast_rtp_lookup_pt ( struct ast_rtp rtp,
int  pt 
) [read]

Mapping between RTP payload format codes and Asterisk codes:

Definition at line 2381 of file rtp.c.

References rtpPayloadType::code, rtpPayloadType::isAstFormat, MAX_RTP_PT, rtp_bridge_lock(), and rtp_bridge_unlock().

Referenced by ast_rtp_read(), bridge_p2p_rtp_write(), process_sdp_a_audio(), and setup_rtp_connection().

{
   struct rtpPayloadType result;

   result.isAstFormat = result.code = 0;

   if (pt < 0 || pt >= MAX_RTP_PT) 
      return result; /* bogus payload type */

   /* Start with negotiated codecs */
   rtp_bridge_lock(rtp);
   result = rtp->current_RTP_PT[pt];
   rtp_bridge_unlock(rtp);

   /* If it doesn't exist, check our static RTP type list, just in case */
   if (!result.code) 
      result = static_RTP_PT[pt];

   return result;
}
unsigned int ast_rtp_lookup_sample_rate ( int  isAstFormat,
int  code 
)

Get the sample rate associated with known RTP payload types.

Parameters:
isAstFormatTrue if the value in the 'code' parameter is an AST_FORMAT value
codeFormat code, either from AST_FORMAT list or from AST_RTP list
Returns:
the sample rate if the format was found, zero if it was not found

Definition at line 2463 of file rtp.c.

References ARRAY_LEN, rtpPayloadType::isAstFormat, mimeTypes, mimeType::payloadType, and mimeType::sample_rate.

Referenced by add_codec_to_sdp(), add_noncodec_to_sdp(), add_tcodec_to_sdp(), and add_vcodec_to_sdp().

{
   unsigned int i;

   for (i = 0; i < ARRAY_LEN(mimeTypes); ++i) {
      if ((mimeTypes[i].payloadType.code == code) && (mimeTypes[i].payloadType.isAstFormat == isAstFormat)) {
         return mimeTypes[i].sample_rate;
      }
   }

   return 0;
}
int ast_rtp_make_compatible ( struct ast_channel dest,
struct ast_channel src,
int  media 
)

Definition at line 2200 of file rtp.c.

References ast_channel_lock, ast_channel_trylock, ast_channel_unlock, ast_debug, ast_log(), AST_RTP_GET_FAILED, ast_rtp_pt_copy(), AST_RTP_TRY_NATIVE, ast_test_flag, FLAG_NAT_ACTIVE, ast_rtp_protocol::get_codec, get_proto(), ast_rtp_protocol::get_rtp_info, ast_rtp_protocol::get_trtp_info, ast_rtp_protocol::get_vrtp_info, LOG_WARNING, ast_channel::name, and ast_rtp_protocol::set_rtp_peer.

Referenced by dial_exec_full(), and do_forward().

{
   struct ast_rtp *destp = NULL, *srcp = NULL;     /* Audio RTP Channels */
   struct ast_rtp *vdestp = NULL, *vsrcp = NULL;      /* Video RTP channels */
   struct ast_rtp *tdestp = NULL, *tsrcp = NULL;      /* Text RTP channels */
   struct ast_rtp_protocol *destpr = NULL, *srcpr = NULL;
   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; 
   int srccodec, destcodec;

   /* Lock channels */
   ast_channel_lock(dest);
   while (ast_channel_trylock(src)) {
      ast_channel_unlock(dest);
      usleep(1);
      ast_channel_lock(dest);
   }

   /* Find channel driver interfaces */
   if (!(destpr = get_proto(dest))) {
      ast_debug(1, "Channel '%s' has no RTP, not doing anything\n", dest->name);
      ast_channel_unlock(dest);
      ast_channel_unlock(src);
      return 0;
   }
   if (!(srcpr = get_proto(src))) {
      ast_debug(1, "Channel '%s' has no RTP, not doing anything\n", src->name);
      ast_channel_unlock(dest);
      ast_channel_unlock(src);
      return 0;
   }

   /* Get audio and video interface (if native bridge is possible) */
   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;
   text_dest_res = destpr->get_trtp_info ? destpr->get_trtp_info(dest, &tdestp) : AST_RTP_GET_FAILED;
   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;
   text_src_res = srcpr->get_trtp_info ? srcpr->get_trtp_info(src, &tsrcp) : AST_RTP_GET_FAILED;

   /* 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;

   /* Check if bridge is still possible (In SIP directmedia=no stops this, like NAT) */
   if (audio_dest_res != AST_RTP_TRY_NATIVE || (video_dest_res != AST_RTP_GET_FAILED && video_dest_res != AST_RTP_TRY_NATIVE) || audio_src_res != AST_RTP_TRY_NATIVE || (video_src_res != AST_RTP_GET_FAILED && video_src_res != AST_RTP_TRY_NATIVE) || !(srccodec & destcodec)) {
      /* Somebody doesn't want to play... */
      ast_channel_unlock(dest);
      ast_channel_unlock(src);
      return 0;
   }
   ast_rtp_pt_copy(destp, srcp);
   if (vdestp && vsrcp)
      ast_rtp_pt_copy(vdestp, vsrcp);
   if (tdestp && tsrcp)
      ast_rtp_pt_copy(tdestp, tsrcp);
   if (media) {
      /* Bridge early */
      if (destpr->set_rtp_peer(dest, srcp, vsrcp, tsrcp, srccodec, ast_test_flag(srcp, FLAG_NAT_ACTIVE)))
         ast_log(LOG_WARNING, "Channel '%s' failed to setup early bridge to '%s'\n", dest->name, src->name);
   }
   ast_channel_unlock(dest);
   ast_channel_unlock(src);
   ast_debug(1, "Seeded SDP of '%s' with that of '%s'\n", dest->name, src->name);
   return 1;
}
struct ast_rtp* ast_rtp_new ( struct sched_context sched,
struct io_context io,
int  rtcpenable,
int  callbackmode 
) [read]

Initializate a RTP session.

Parameters:
sched
io
rtcpenable
callbackmode
Returns:
A representation (structure) of an RTP session.

Definition at line 2671 of file rtp.c.

References ast_rtp_new_with_bindaddr().

{
   struct in_addr ia;

   memset(&ia, 0, sizeof(ia));
   return ast_rtp_new_with_bindaddr(sched, io, rtcpenable, callbackmode, ia);
}
void ast_rtp_new_init ( struct ast_rtp rtp)

Initialize a new RTP structure.

reload rtp configuration

Definition at line 2562 of file rtp.c.

References ast_mutex_init(), ast_random(), ast_set_flag, FLAG_HAS_DTMF, ast_rtp::seqno, ast_rtp::ssrc, STRICT_RTP_LEARN, STRICT_RTP_OPEN, ast_rtp::strict_rtp_state, ast_rtp::them, and ast_rtp::us.

Referenced by ast_rtp_new_with_bindaddr(), and process_sdp().

{
#ifdef P2P_INTENSE
   ast_mutex_init(&rtp->bridge_lock);
#endif

   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);
   rtp->strict_rtp_state = (strictrtp ? STRICT_RTP_LEARN : STRICT_RTP_OPEN);
}
void ast_rtp_new_source ( struct ast_rtp rtp)

Indicate that we need to set the marker bit.

Definition at line 2684 of file rtp.c.

References ast_debug, and ast_rtp::set_marker_bit.

Referenced by mgcp_indicate(), oh323_indicate(), sip_answer(), sip_indicate(), sip_write(), and skinny_indicate().

{
   if (rtp) {
      rtp->set_marker_bit = 1;
      ast_debug(3, "Setting the marker bit due to a source update\n");
   }
}
struct ast_rtp* ast_rtp_new_with_bindaddr ( struct sched_context sched,
struct io_context io,
int  rtcpenable,
int  callbackmode,
struct in_addr  in 
) [read]

Initializate a RTP session using an in_addr structure.

This fuction gets called by ast_rtp_new().

Parameters:
sched
io
rtcpenable
callbackmode
in
Returns:
A representation (structure) of an RTP session.

Definition at line 2576 of file rtp.c.

References ast_calloc, ast_free, ast_io_add(), AST_IO_IN, ast_log(), ast_random(), ast_rtcp_new(), ast_rtp_new_init(), ast_rtp_pt_default(), ast_set_flag, errno, FLAG_CALLBACK_MODE, io, ast_rtp::io, ast_rtp::ioid, LOG_ERROR, ast_rtp::rtcp, rtp_socket(), rtpread(), rtpstart, ast_rtcp::s, ast_rtp::s, sched, ast_rtp::sched, ast_rtcp::us, and ast_rtp::us.

Referenced by __oh323_rtp_create(), ast_rtp_new(), gtalk_alloc(), jingle_alloc(), sip_alloc(), and start_rtp().

{
   struct ast_rtp *rtp;
   int x;
   int startplace;
   
   if (!(rtp = ast_calloc(1, sizeof(*rtp))))
      return NULL;

   ast_rtp_new_init(rtp);

   rtp->s = rtp_socket("RTP");
   if (rtp->s < 0)
      goto fail;
   if (sched && rtcpenable) {
      rtp->sched = sched;
      rtp->rtcp = ast_rtcp_new();
   }
   
   /*
    * 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.
    */
   x = (rtpend == rtpstart) ? rtpstart : (ast_random() % (rtpend - rtpstart)) + rtpstart;
   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;
   for (;;) {
      rtp->us.sin_port = htons(x);
      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 */
         rtp->rtcp->us.sin_port = htons(x + 1);
         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.
          */
         close(rtp->s);
         rtp->s = rtp_socket("RTP");
         if (rtp->s < 0)
            goto fail;
      }
      /*
       * If we get here, there was an error in one of the bind()
       * calls, so make sure it is nothing unexpected.
       */
      if (errno != EADDRINUSE) {
         /* We got an error that wasn't expected, abort! */
         ast_log(LOG_ERROR, "Unexpected bind error: %s\n", strerror(errno));
         goto fail;
      }
      /*
       * 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.
       */
      x += 2;
      if (x > rtpend)
         x = (rtpstart + 1) & ~1;
      if (x == startplace) {
         ast_log(LOG_ERROR, "No RTP ports remaining. Can't setup media stream for this call.\n");
         goto fail;
      }
   }
   rtp->sched = sched;
   rtp->io = io;
   if (callbackmode) {
      rtp->ioid = ast_io_add(rtp->io, rtp->s, rtpread, AST_IO_IN, rtp);
      ast_set_flag(rtp, FLAG_CALLBACK_MODE);
   }
   ast_rtp_pt_default(rtp);
   return rtp;

fail:
   if (rtp->s >= 0)
      close(rtp->s);
   if (rtp->rtcp) {
      close(rtp->rtcp->s);
      ast_free(rtp->rtcp);
   }
   ast_free(rtp);
   return NULL;
}
int ast_rtp_proto_register ( struct ast_rtp_protocol proto)

Register interface to channel driver.

Register an RTP channel client.

Definition at line 3954 of file rtp.c.

References ast_log(), AST_RWLIST_INSERT_HEAD, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_rtp_protocol::list, LOG_WARNING, and ast_rtp_protocol::type.

Referenced by load_module().

{
   struct ast_rtp_protocol *cur;

   AST_RWLIST_WRLOCK(&protos);
   AST_RWLIST_TRAVERSE(&protos, cur, list) { 
      if (!strcmp(cur->type, proto->type)) {
         ast_log(LOG_WARNING, "Tried to register same protocol '%s' twice\n", cur->type);
         AST_RWLIST_UNLOCK(&protos);
         return -1;
      }
   }
   AST_RWLIST_INSERT_HEAD(&protos, proto, list);
   AST_RWLIST_UNLOCK(&protos);
   
   return 0;
}
void ast_rtp_proto_unregister ( struct ast_rtp_protocol proto)

Unregister interface to channel driver.

Unregister an RTP channel client.

Definition at line 3946 of file rtp.c.

References AST_RWLIST_REMOVE, AST_RWLIST_UNLOCK, and AST_RWLIST_WRLOCK.

Referenced by load_module(), and unload_module().

void ast_rtp_pt_clear ( struct ast_rtp rtp)
static int ast_rtp_raw_write ( struct ast_rtp rtp,
struct ast_frame f,
int  codec 
) [static]

Write RTP packet with audio or video media frames into UDP packet.

Definition at line 3667 of file rtp.c.

References ast_debug, AST_FORMAT_G722, AST_FRAME_VIDEO, AST_FRAME_VOICE, AST_FRFLAG_HAS_TIMING_INFO, ast_inet_ntoa(), ast_rtcp_calc_interval(), ast_rtcp_write(), ast_sched_add(), ast_set_flag, ast_test_flag, ast_tvzero(), ast_verbose(), calc_txstamp(), ast_frame::data, ast_frame::datalen, ast_frame::delivery, errno, FLAG_NAT_ACTIVE, FLAG_NAT_INACTIVE, FLAG_NAT_INACTIVE_NOWARN, ast_frame::frametype, ast_rtp::lastdigitts, ast_rtp::lastotexttimestamp, ast_rtp::lastovidtimestamp, ast_rtp::lastts, MAX_TIMESTAMP_SKEW, ast_rtp::nat, option_debug, ast_frame::ptr, put_unaligned_uint32(), ast_rtp::rtcp, rtp_debug_test_addr(), rtp_get_rate(), ast_rtp::s, ast_frame::samples, ast_rtp::sched, ast_rtcp::schedid, ast_rtp::sending_digit, ast_rtp::seqno, ast_rtp::set_marker_bit, ast_rtp::ssrc, ast_frame::subclass, ast_rtcp::them, ast_rtp::them, ast_frame::ts, ast_rtp::txcount, and ast_rtp::txoctetcount.

Referenced by ast_rtp_write().

{
   unsigned char *rtpheader;
   int hdrlen = 12;
   int res;
   unsigned int ms;
   int pred;
   int mark = 0;
   int rate = rtp_get_rate(f->subclass) / 1000;

   if (f->subclass == AST_FORMAT_G722) {
      f->samples /= 2;
   }

   if (rtp->sending_digit) {
      return 0;
   }

   ms = calc_txstamp(rtp, &f->delivery);
   /* Default prediction */
   if (f->frametype == AST_FRAME_VOICE) {
      pred = rtp->lastts + f->samples;

      /* Re-calculate last TS */
      rtp->lastts = rtp->lastts + ms * rate;
      if (ast_tvzero(f->delivery)) {
         /* If this isn't an absolute delivery time, Check if it is close to our prediction, 
            and if so, go with our prediction */
         if (abs(rtp->lastts - pred) < MAX_TIMESTAMP_SKEW)
            rtp->lastts = pred;
         else {
            ast_debug(3, "Difference is %d, ms is %d\n", abs(rtp->lastts - pred), ms);
            mark = 1;
         }
      }
   } else if (f->frametype == AST_FRAME_VIDEO) {
      mark = f->subclass & 0x1;
      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 */
      if (ast_tvzero(f->delivery)) {
         if (abs(rtp->lastts - pred) < 7200) {
            rtp->lastts = pred;
            rtp->lastovidtimestamp += f->samples;
         } else {
            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);
            rtp->lastovidtimestamp = rtp->lastts;
         }
      }
   } else {
      pred = rtp->lastotexttimestamp + f->samples;
      /* Re-calculate last TS */
      rtp->lastts = rtp->lastts + ms;
      /* 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 {
            ast_debug(3, "Difference is %d, ms is %d, pred/ts/samples %d/%d/%d\n", abs(rtp->lastts - pred), ms, rtp->lastts, pred, f->samples);
            rtp->lastotexttimestamp = rtp->lastts;
         }
      }
   }

   /* If we have been explicitly told to set the marker bit do so */
   if (rtp->set_marker_bit) {
      mark = 1;
      rtp->set_marker_bit = 0;
   }

   /* 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;

   if (ast_test_flag(f, AST_FRFLAG_HAS_TIMING_INFO))
      rtp->lastts = f->ts * rate;

   /* Get a pointer to the header */
   rtpheader = (unsigned char *)(f->data.ptr - hdrlen);

   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)); 

   if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
      res = sendto(rtp->s, (void *)rtpheader, f->datalen + hdrlen, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
      if (res < 0) {
         if (!rtp->nat || (rtp->nat && (ast_test_flag(rtp, FLAG_NAT_ACTIVE) == FLAG_NAT_ACTIVE))) {
            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));
         } else if (((ast_test_flag(rtp, FLAG_NAT_ACTIVE) == FLAG_NAT_INACTIVE) || rtpdebug) && !ast_test_flag(rtp, FLAG_NAT_INACTIVE_NOWARN)) {
            /* Only give this error message once if we are not RTP debugging */
            if (option_debug || rtpdebug)
               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));
            ast_set_flag(rtp, FLAG_NAT_INACTIVE_NOWARN);
         }
      } else {
         rtp->txcount++;
         rtp->txoctetcount +=(res - hdrlen);
         
         /* Do not schedule RR if RTCP isn't run */
         if (rtp->rtcp && rtp->rtcp->them.sin_addr.s_addr && rtp->rtcp->schedid < 1) {
            rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, rtp);
         }
      }
            
      if (rtp_debug_test_addr(&rtp->them))
         ast_verbose("Sent RTP packet to      %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
               ast_inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port), codec, rtp->seqno, rtp->lastts,res - hdrlen);
   }

   rtp->seqno++;

   return 0;
}
struct ast_frame* ast_rtp_read ( struct ast_rtp rtp) [read]

Definition at line 1576 of file rtp.c.

References ast_rtp::altthem, ast_assert, ast_codec_get_samples(), AST_CONTROL_SRCCHANGE, ast_debug, AST_FORMAT_AUDIO_MASK, ast_format_rate(), AST_FORMAT_SLINEAR, AST_FORMAT_T140, AST_FORMAT_T140RED, AST_FORMAT_VIDEO_MASK, ast_frame_byteswap_be, AST_FRAME_CONTROL, AST_FRAME_DTMF_END, AST_FRAME_TEXT, AST_FRAME_VIDEO, AST_FRAME_VOICE, AST_FRFLAG_HAS_TIMING_INFO, AST_FRIENDLY_OFFSET, ast_frisolate(), ast_inet_ntoa(), AST_LIST_EMPTY, AST_LIST_FIRST, AST_LIST_HEAD_INIT_NOLOCK, AST_LIST_INSERT_TAIL, ast_log(), ast_null_frame, ast_rtcp_calc_interval(), ast_rtcp_write(), AST_RTP_CISCO_DTMF, AST_RTP_CN, AST_RTP_DTMF, ast_rtp_get_bridged(), ast_rtp_lookup_pt(), ast_rtp_senddigit_continuation(), ast_samp2tv(), ast_sched_add(), ast_set_flag, ast_tv(), ast_tvdiff_ms(), ast_verbose(), bridge_p2p_rtp_write(), ast_rtp::bridged, calc_rxstamp(), rtpPayloadType::code, create_dtmf_frame(), ast_rtp::cycles, ast_frame::data, ast_frame::datalen, ast_frame::delivery, ast_rtp::dtmf_duration, ast_rtp::dtmf_timeout, errno, ext, ast_rtp::f, f, FLAG_NAT_ACTIVE, ast_frame::frametype, rtpPayloadType::isAstFormat, ast_rtp::lastevent, ast_rtp::lastitexttimestamp, ast_rtp::lastividtimestamp, ast_rtp::lastrxformat, ast_rtp::lastrxseqno, ast_rtp::lastrxts, ast_frame::len, len(), LOG_NOTICE, LOG_WARNING, ast_frame::mallocd, ast_rtp::nat, ast_frame::offset, option_debug, process_cisco_dtmf(), process_rfc2833(), process_rfc3389(), ast_frame::ptr, ast_rtp::rawdata, ast_rtp::resp, ast_rtp::rtcp, rtp_debug_test_addr(), rtp_get_rate(), RTP_SEQ_MOD, ast_rtp::rxcount, ast_rtp::rxseqno, ast_rtp::rxssrc, ast_rtp::s, ast_frame::samples, ast_rtp::sched, ast_rtcp::schedid, ast_rtp::seedrxseqno, ast_rtp::sending_digit, ast_frame::seqno, ast_frame::src, ast_rtp::strict_rtp_address, STRICT_RTP_CLOSED, STRICT_RTP_LEARN, ast_rtp::strict_rtp_state, STUN_ACCEPT, stun_handle_packet(), ast_frame::subclass, ast_rtcp::them, ast_rtp::them, ast_rtp::themssrc, ast_frame::ts, and version.

Referenced by gtalk_rtp_read(), jingle_rtp_read(), mgcp_rtp_read(), oh323_rtp_read(), rtpread(), sip_rtp_read(), skinny_rtp_read(), and unistim_rtp_read().

{
   int res;
   struct sockaddr_in sock_in;
   socklen_t len;
   unsigned int seqno;
   int version;
   int payloadtype;
   int hdrlen = 12;
   int padding;
   int mark;
   int ext;
   int cc;
   unsigned int ssrc;
   unsigned int timestamp;
   unsigned int *rtpheader;
   struct rtpPayloadType rtpPT;
   struct ast_rtp *bridged = NULL;
   int prev_seqno;
   struct frame_list frames;
   
   /* If time is up, kill it */
   if (rtp->sending_digit)
      ast_rtp_senddigit_continuation(rtp);

   len = sizeof(sock_in);
   
   /* Cache where the header will go */
   res = recvfrom(rtp->s, rtp->rawdata + AST_FRIENDLY_OFFSET, sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET,
               0, (struct sockaddr *)&sock_in, &len);

   /* If strict RTP protection is enabled see if we need to learn this address or if the packet should be dropped */
   if (rtp->strict_rtp_state == STRICT_RTP_LEARN) {
      /* Copy over address that this packet was received on */
      memcpy(&rtp->strict_rtp_address, &sock_in, sizeof(rtp->strict_rtp_address));
      /* Now move over to actually protecting the RTP port */
      rtp->strict_rtp_state = STRICT_RTP_CLOSED;
      ast_debug(1, "Learned remote address is %s:%d for strict RTP purposes, now protecting the port.\n", ast_inet_ntoa(rtp->strict_rtp_address.sin_addr), ntohs(rtp->strict_rtp_address.sin_port));
   } else if (rtp->strict_rtp_state == STRICT_RTP_CLOSED) {
      /* If the address we previously learned doesn't match the address this packet came in on simply drop it */
      if ((rtp->strict_rtp_address.sin_addr.s_addr != sock_in.sin_addr.s_addr) || (rtp->strict_rtp_address.sin_port != sock_in.sin_port)) {
         ast_debug(1, "Received RTP packet from %s:%d, dropping due to strict RTP protection. Expected it to be from %s:%d\n", ast_inet_ntoa(sock_in.sin_addr), ntohs(sock_in.sin_port), ast_inet_ntoa(rtp->strict_rtp_address.sin_addr), ntohs(rtp->strict_rtp_address.sin_port));
         return &ast_null_frame;
      }
   }

   rtpheader = (unsigned int *)(rtp->rawdata + AST_FRIENDLY_OFFSET);
   if (res < 0) {
      ast_assert(errno != EBADF);
      if (errno != EAGAIN) {
         ast_log(LOG_WARNING, "RTP Read error: %s.  Hanging up.\n", strerror(errno));
         return NULL;
      }
      return &ast_null_frame;
   }
   
   if (res < hdrlen) {
      ast_log(LOG_WARNING, "RTP Read too short\n");
      return &ast_null_frame;
   }

   /* Get fields */
   seqno = ntohl(rtpheader[0]);

   /* Check RTP version */
   version = (seqno & 0xC0000000) >> 30;
   if (!version) {
      /* 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.
       */
      if ((stun_handle_packet(rtp->s, &sock_in, rtp->rawdata + AST_FRIENDLY_OFFSET, res, NULL, NULL) == STUN_ACCEPT) &&
         (!rtp->them.sin_port && !rtp->them.sin_addr.s_addr)) {
         memcpy(&rtp->them, &sock_in, sizeof(rtp->them));
      }
      return &ast_null_frame;
   }

#if 0 /* Allow to receive RTP stream with closed transmission path */
   /* If we don't have the other side's address, then ignore this */
   if (!rtp->them.sin_addr.s_addr || !rtp->them.sin_port)
      return &ast_null_frame;
#endif

   /* Send to whoever send to us if NAT is turned on */
   if (rtp->nat) {
      if (((rtp->them.sin_addr.s_addr != sock_in.sin_addr.s_addr) ||
          (rtp->them.sin_port != sock_in.sin_port)) && 
          ((rtp->altthem.sin_addr.s_addr != sock_in.sin_addr.s_addr) ||
          (rtp->altthem.sin_port != sock_in.sin_port))) {
         rtp->them = sock_in;
         if (rtp->rtcp) {
            int h = 0;
            memcpy(&rtp->rtcp->them, &sock_in, sizeof(rtp->rtcp->them));
            h = ntohs(rtp->them.sin_port);
            rtp->rtcp->them.sin_port = htons(h + 1);
         }
         rtp->rxseqno = 0;
         ast_set_flag(rtp, FLAG_NAT_ACTIVE);
         if (option_debug || rtpdebug)
            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));
      }
   }

   /* If we are bridged to another RTP stream, send direct */
   if ((bridged = ast_rtp_get_bridged(rtp)) && !bridge_p2p_rtp_write(rtp, bridged, rtpheader, res, hdrlen))
      return &ast_null_frame;

   if (version != 2)
      return &ast_null_frame;

   payloadtype = (seqno & 0x7f0000) >> 16;
   padding = seqno & (1 << 29);
   mark = seqno & (1 << 23);
   ext = seqno & (1 << 28);
   cc = (seqno & 0xF000000) >> 24;
   seqno &= 0xffff;
   timestamp = ntohl(rtpheader[1]);
   ssrc = ntohl(rtpheader[2]);
   
   AST_LIST_HEAD_INIT_NOLOCK(&frames);
   /* Force a marker bit and change SSRC if the SSRC changes */
   if (rtp->rxssrc && rtp->rxssrc != ssrc) {
      struct ast_frame *f, srcupdate = {
         AST_FRAME_CONTROL,
         .subclass = AST_CONTROL_SRCCHANGE,
      };

      if (!mark) {
         if (option_debug || rtpdebug) {
            ast_debug(0, "Forcing Marker bit, because SSRC has changed\n");
         }
         mark = 1;
      }
      f = ast_frisolate(&srcupdate);
      AST_LIST_INSERT_TAIL(&frames, f, frame_list);
   }

   rtp->rxssrc = ssrc;
   
   if (padding) {
      /* Remove padding bytes */
      res -= rtp->rawdata[AST_FRIENDLY_OFFSET + res - 1];
   }
   
   if (cc) {
      /* CSRC fields present */
      hdrlen += cc*4;
   }

   if (ext) {
      /* RTP Extension present */
      hdrlen += (ntohl(rtpheader[hdrlen/4]) & 0xffff) << 2;
      hdrlen += 4;
      if (option_debug) {
         int profile;
         profile = (ntohl(rtpheader[3]) & 0xffff0000) >> 16;
         if (profile == 0x505a)
            ast_debug(1, "Found Zfone extension in RTP stream - zrtp - not supported.\n");
         else
            ast_debug(1, "Found unknown RTP Extensions %x\n", profile);
      }
   }

   if (res < hdrlen) {
      ast_log(LOG_WARNING, "RTP Read too short (%d, expecting %d)\n", res, hdrlen);
      return AST_LIST_FIRST(&frames) ? AST_LIST_FIRST(&frames) : &ast_null_frame;
   }

   rtp->rxcount++; /* Only count reasonably valid packets, this'll make the rtcp stats more accurate */

   if (rtp->rxcount==1) {
      /* This is the first RTP packet successfully received from source */
      rtp->seedrxseqno = seqno;
   }

   /* Do not schedule RR if RTCP isn't run */
   if (rtp->rtcp && rtp->rtcp->them.sin_addr.s_addr && rtp->rtcp->schedid < 1) {
      /* Schedule transmission of Receiver Report */
      rtp->rtcp->schedid = ast_sched_add(rtp->sched, ast_rtcp_calc_interval(rtp), ast_rtcp_write, rtp);
   }
   if ((int)rtp->lastrxseqno - (int)seqno  > 100) /* if so it would indicate that the sender cycled; allow for misordering */
      rtp->cycles += RTP_SEQ_MOD;
   
   prev_seqno = rtp->lastrxseqno;

   rtp->lastrxseqno = seqno;
   
   if (!rtp->themssrc)
      rtp->themssrc = ntohl(rtpheader[2]); /* Record their SSRC to put in future RR */
   
   if (rtp_debug_test_addr(&sock_in))
      ast_verbose("Got  RTP packet from    %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
         ast_inet_ntoa(sock_in.sin_addr), ntohs(sock_in.sin_port), payloadtype, seqno, timestamp,res - hdrlen);

   rtpPT = ast_rtp_lookup_pt(rtp, payloadtype);
   if (!rtpPT.isAstFormat) {
      struct ast_frame *f = NULL;

      /* This is special in-band data that's not one of our codecs */
      if (rtpPT.code == AST_RTP_DTMF) {
         /* It's special -- rfc2833 process it */
         if (rtp_debug_test_addr(&sock_in)) {
            unsigned char *data;
            unsigned int event;
            unsigned int event_end;
            unsigned int duration;
            data = rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen;
            event = ntohl(*((unsigned int *)(data)));
            event >>= 24;
            event_end = ntohl(*((unsigned int *)(data)));
            event_end <<= 8;
            event_end >>= 24;
            duration = ntohl(*((unsigned int *)(data)));
            duration &= 0xFFFF;
            ast_verbose("Got  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(sock_in.sin_addr), ntohs(sock_in.sin_port), payloadtype, seqno, timestamp, res - hdrlen, (mark?1:0), event, ((event_end & 0x80)?1:0), duration);
         }
         /* process_rfc2833 may need to return multiple frames. We do this
          * by passing the pointer to the frame list to it so that the method
          * can append frames to the list as needed
          */
         process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno, timestamp, &frames);
      } else if (rtpPT.code == AST_RTP_CISCO_DTMF) {
         /* It's really special -- process it the Cisco way */
         if (rtp->lastevent <= seqno || (rtp->lastevent >= 65530 && seqno <= 6)) {
            f = process_cisco_dtmf(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
            rtp->lastevent = seqno;
         }
      } else if (rtpPT.code == AST_RTP_CN) {
         /* Comfort Noise */
         f = process_rfc3389(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
      } else {
         ast_log(LOG_NOTICE, "Unknown RTP codec %d received from '%s'\n", payloadtype, ast_inet_ntoa(rtp->them.sin_addr));
      }
      if (f) {
         AST_LIST_INSERT_TAIL(&frames, f, frame_list);
      }
      /* Even if no frame was returned by one of the above methods,
       * we may have a frame to return in our frame list
       */
      if (!AST_LIST_EMPTY(&frames)) {
         return AST_LIST_FIRST(&frames);
      }
      return &ast_null_frame;
   }
   rtp->lastrxformat = rtp->f.subclass = rtpPT.code;
   rtp->f.frametype = (rtp->f.subclass & AST_FORMAT_AUDIO_MASK) ? AST_FRAME_VOICE : (rtp->f.subclass & AST_FORMAT_VIDEO_MASK) ? AST_FRAME_VIDEO : AST_FRAME_TEXT;

   rtp->rxseqno = seqno;

   if (rtp->dtmf_timeout && rtp->dtmf_timeout < timestamp) {
      rtp->dtmf_timeout = 0;

      if (rtp->resp) {
         struct ast_frame *f;
         f = create_dtmf_frame(rtp, AST_FRAME_DTMF_END);
         f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass)), ast_tv(0, 0));
         rtp->resp = 0;
         rtp->dtmf_timeout = rtp->dtmf_duration = 0;
         AST_LIST_INSERT_TAIL(&frames, f, frame_list);
         return AST_LIST_FIRST(&frames);
      }
   }

   /* Record received timestamp as last received now */
   rtp->lastrxts = timestamp;

   rtp->f.mallocd = 0;
   rtp->f.datalen = res - hdrlen;
   rtp->f.data.ptr = rtp->rawdata + hdrlen + AST_FRIENDLY_OFFSET;
   rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET;
   rtp->f.seqno = seqno;

   if (rtp->f.subclass == AST_FORMAT_T140 && (int)seqno - (prev_seqno+1) > 0 && (int)seqno - (prev_seqno+1) < 10) {
        unsigned char *data = rtp->f.data.ptr;
        
        memmove(rtp->f.data.ptr+3, rtp->f.data.ptr, rtp->f.datalen);
        rtp->f.datalen +=3;
        *data++ = 0xEF;
        *data++ = 0xBF;
        *data = 0xBD;
   }
 
   if (rtp->f.subclass == AST_FORMAT_T140RED) {
      unsigned char *data = rtp->f.data.ptr;
      unsigned char *header_end;
      int num_generations;
      int header_length;
      int length;
      int diff =(int)seqno - (prev_seqno+1); /* if diff = 0, no drop*/
      int x;

      rtp->f.subclass = AST_FORMAT_T140;
      header_end = memchr(data, ((*data) & 0x7f), rtp->f.datalen);
      if (header_end == NULL) {
         return &ast_null_frame;
      }
      header_end++;
      
      header_length = header_end - data;
      num_generations = header_length / 4;
      length = header_length;

      if (!diff) {
         for (x = 0; x < num_generations; x++)
            length += data[x * 4 + 3];
         
         if (!(rtp->f.datalen - length))
            return &ast_null_frame;
         
         rtp->f.data.ptr += length;
         rtp->f.datalen -= length;
      } else if (diff > num_generations && diff < 10) {
         length -= 3;
         rtp->f.data.ptr += length;
         rtp->f.datalen -= length;
         
         data = rtp->f.data.ptr;
         *data++ = 0xEF;
         *data++ = 0xBF;
         *data = 0xBD;
      } else   {
         for ( x = 0; x < num_generations - diff; x++) 
            length += data[x * 4 + 3];
         
         rtp->f.data.ptr += length;
         rtp->f.datalen -= length;
      }
   }

   if (rtp->f.subclass & AST_FORMAT_AUDIO_MASK) {
      rtp->f.samples = ast_codec_get_samples(&rtp->f);
      if (rtp->f.subclass == AST_FORMAT_SLINEAR) 
         ast_frame_byteswap_be(&rtp->f);
      calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);
      /* Add timing data to let ast_generic_bridge() put the frame into a jitterbuf */
      ast_set_flag(&rtp->f, AST_FRFLAG_HAS_TIMING_INFO);
      rtp->f.ts = timestamp / (rtp_get_rate(rtp->f.subclass) / 1000);
      rtp->f.len = rtp->f.samples / ((ast_format_rate(rtp->f.subclass) / 1000));
   } else if (rtp->f.subclass & AST_FORMAT_VIDEO_MASK) {
      /* Video -- samples is # of samples vs. 90000 */
      if (!rtp->lastividtimestamp)
         rtp->lastividtimestamp = timestamp;
      rtp->f.samples = timestamp - rtp->lastividtimestamp;
      rtp->lastividtimestamp = timestamp;
      rtp->f.delivery.tv_sec = 0;
      rtp->f.delivery.tv_usec = 0;
      /* Pass the RTP marker bit as bit 0 in the subclass field.
       * This is ok because subclass is actually a bitmask, and
       * the low bits represent audio formats, that are not
       * involved here since we deal with video.
       */
      if (mark)
         rtp->f.subclass |= 0x1;
   } 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;
   }
   rtp->f.src = "RTP";

   AST_LIST_INSERT_TAIL(&frames, &rtp->f, frame_list);
   return AST_LIST_FIRST(&frames);
}
int ast_rtp_reload ( void  )

Initialize RTP subsystem

Definition at line 4871 of file rtp.c.

References __ast_rtp_reload().

{
   return __ast_rtp_reload(1);
}
int ast_rtp_sendcng ( struct ast_rtp rtp,
int  level 
)

generate comfort noice (CNG)

Definition at line 3632 of file rtp.c.

References ast_inet_ntoa(), ast_log(), AST_RTP_CN, ast_rtp_lookup_code(), ast_tv(), ast_tvadd(), ast_tvnow(), ast_verbose(), ast_rtp::data, ast_rtp::dtmfmute, errno, ast_rtp::lastts, LOG_ERROR, rtp_debug_test_addr(), ast_rtp::s, ast_rtp::seqno, ast_rtp::ssrc, and ast_rtp::them.

Referenced by check_rtp_timeout().

{
   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;

   rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));

   /* Get a pointer to the header */
   rtpheader = (unsigned int *)data;
   rtpheader[0] = htonl((2 << 30) | (1 << 23) | (payload << 16) | (rtp->seqno++));
   rtpheader[1] = htonl(rtp->lastts);
   rtpheader[2] = htonl(rtp->ssrc); 
   data[12] = level;
   if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
      res = sendto(rtp->s, (void *)rtpheader, hdrlen + 1, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
      if (res <0) 
         ast_log(LOG_ERROR, "RTP Comfort Noise Transmission error to %s:%d: %s\n", ast_inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port), strerror(errno));
      if (rtp_debug_test_addr(&rtp->them))
         ast_verbose("Sent Comfort Noise RTP packet to %s:%u (type %d, seq %u, ts %u, len %d)\n"
               , ast_inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port), payload, rtp->seqno, rtp->lastts,res - hdrlen);         
         
   }
   return 0;
}
int ast_rtp_senddigit_begin ( struct ast_rtp rtp,
char  digit 
)

Send begin frames for DTMF.

Definition at line 3188 of file rtp.c.

References ast_inet_ntoa(), ast_log(), AST_RTP_DTMF, ast_rtp_lookup_code(), ast_tv(), ast_tvadd(), ast_tvnow(), ast_verbose(), ast_rtp::dtmfmute, errno, ast_rtp::lastdigitts, ast_rtp::lastts, LOG_ERROR, LOG_WARNING, rtp_debug_test_addr(), ast_rtp::s, ast_rtp::send_digit, ast_rtp::send_duration, ast_rtp::send_payload, ast_rtp::sending_digit, ast_rtp::seqno, ast_rtp::ssrc, and ast_rtp::them.

Referenced by mgcp_senddigit_begin(), oh323_digit_begin(), and sip_senddigit_begin().

{
   unsigned int *rtpheader;
   int hdrlen = 12, res = 0, i = 0, payload = 0;
   char data[256];

   if ((digit <= '9') && (digit >= '0'))
      digit -= '0';
   else if (digit == '*')
      digit = 10;
   else if (digit == '#')
      digit = 11;
   else if ((digit >= 'A') && (digit <= 'D'))
      digit = digit - 'A' + 12;
   else if ((digit >= 'a') && (digit <= 'd'))
      digit = digit - 'a' + 12;
   else {
      ast_log(LOG_WARNING, "Don't know how to represent '%c'\n", digit);
      return 0;
   }

   /* If we have no peer, return immediately */ 
   if (!rtp->them.sin_addr.s_addr || !rtp->them.sin_port)
      return 0;

   payload = ast_rtp_lookup_code(rtp, 0, AST_RTP_DTMF);

   rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
   rtp->send_duration = 160;
   rtp->lastdigitts = rtp->lastts + rtp->send_duration;
   
   /* 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->lastdigitts);
   rtpheader[2] = htonl(rtp->ssrc); 

   for (i = 0; i < 2; i++) {
      rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (rtp->send_duration));
      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:%u: %s\n",
            ast_inet_ntoa(rtp->them.sin_addr),
            ntohs(rtp->them.sin_port), strerror(errno));
      if (rtp_debug_test_addr(&rtp->them))
         ast_verbose("Sent RTP DTMF packet to %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
                ast_inet_ntoa(rtp->them.sin_addr),
                ntohs(rtp->them.sin_port), payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
      /* Increment sequence number */
      rtp->seqno++;
      /* Increment duration */
      rtp->send_duration += 160;
      /* Clear marker bit and set seqno */
      rtpheader[0] = htonl((2 << 30) | (payload << 16) | (rtp->seqno));
   }

   /* Since we received a begin, we can safely store the digit and disable any compensation */
   rtp->sending_digit = 1;
   rtp->send_digit = digit;
   rtp->send_payload = payload;

   return 0;
}
static int ast_rtp_senddigit_continuation ( struct ast_rtp rtp) [static]

Send continuation frame for DTMF.

Definition at line 3253 of file rtp.c.

References ast_inet_ntoa(), ast_log(), ast_verbose(), errno, ast_rtp::lastdigitts, LOG_ERROR, rtp_debug_test_addr(), ast_rtp::s, ast_rtp::send_digit, ast_rtp::send_duration, ast_rtp::send_payload, ast_rtp::seqno, ast_rtp::ssrc, and ast_rtp::them.

Referenced by ast_rtp_read().

{
   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);
   rtpheader[3] = htonl((rtp->send_digit << 24) | (0xa << 16) | (rtp->send_duration));
   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))
      ast_verbose("Sent RTP DTMF packet to %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
             ast_inet_ntoa(rtp->them.sin_addr),
             ntohs(rtp->them.sin_port), rtp->send_payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);

   /* Increment sequence number */
   rtp->seqno++;
   /* Increment duration */
   rtp->send_duration += 160;

   return 0;
}
int ast_rtp_senddigit_end ( struct ast_rtp rtp,
char  digit 
)

Definition at line 3289 of file rtp.c.

References ast_rtp_senddigit_end_with_duration().

Referenced by mgcp_senddigit_end(), and oh323_digit_end().

{
   return ast_rtp_senddigit_end_with_duration(rtp, digit, 0);
}
int ast_rtp_senddigit_end_with_duration ( struct ast_rtp rtp,
char  digit,
unsigned int  duration 
)

Send end packets for DTMF.

Definition at line 3295 of file rtp.c.

References ast_debug, ast_inet_ntoa(), ast_log(), ast_tv(), ast_tvadd(), ast_tvnow(), ast_verbose(), ast_rtp::dtmfmute, errno, ast_rtp::f, ast_rtp::lastdigitts, ast_rtp::lastts, LOG_ERROR, LOG_WARNING, rtp_debug_test_addr(), rtp_get_rate(), ast_rtp::s, ast_rtp::send_digit, ast_rtp::send_duration, ast_rtp::send_payload, ast_rtp::sending_digit, ast_rtp::seqno, ast_rtp::ssrc, ast_frame::subclass, and ast_rtp::them.

Referenced by ast_rtp_senddigit_end(), and sip_senddigit_end().

{
   unsigned int *rtpheader;
   int hdrlen = 12, res = 0, i = 0;
   char data[256];
   unsigned int measured_samples;
   
   /* If no address, then bail out */
   if (!rtp->them.sin_addr.s_addr || !rtp->them.sin_port)
      return 0;
   
   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;
   }

   rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));

   if (duration > 0 && (measured_samples = duration * rtp_get_rate(rtp->f.subclass) / 1000) > rtp->send_duration) {
      ast_debug(2, "Adjusting final end duration from %u to %u\n", rtp->send_duration, measured_samples);
      rtp->send_duration = measured_samples;
   }

   rtpheader = (unsigned int *)data;
   rtpheader[1] = htonl(rtp->lastdigitts);
   rtpheader[2] = htonl(rtp->ssrc);
   rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (rtp->send_duration));
   /* Set end bit */
   rtpheader[3] |= htonl((1 << 23));

   /* Send 3 termination packets */
   for (i = 0; i < 3; i++) {
      rtpheader[0] = htonl((2 << 30) | (rtp->send_payload << 16) | (rtp->seqno));
      res = sendto(rtp->s, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &rtp->them, sizeof(rtp->them));
      rtp->seqno++;
      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))
         ast_verbose("Sent RTP DTMF packet to %s:%u (type %-2.2d, seq %-6.6u, ts %-6.6u, len %-6.6u)\n",
                ast_inet_ntoa(rtp->them.sin_addr),
                ntohs(rtp->them.sin_port), rtp->send_payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
   }
   rtp->lastts += rtp->send_duration;
   rtp->sending_digit = 0;
   rtp->send_digit = 0;

   return res;
}
void ast_rtp_set_alt_peer ( struct ast_rtp rtp,
struct sockaddr_in *  alt 
)

set potential alternate source for RTP media

Since:
1.4.26 This function may be used to give the RTP stack a hint that there is a potential second source of media. One case where this is used is when the SIP stack receives a REINVITE to which it will be replying with a 491. In such a scenario, the IP and port information in the SDP of that REINVITE lets us know that we may receive media from that source/those sources even though the SIP transaction was unable to be completed successfully
Parameters:
rtpThe RTP structure we wish to set up an alternate host/port on
altThe address information for the alternate media source
Return values:
void

Definition at line 2718 of file rtp.c.

References ast_rtcp::altthem, ast_rtp::altthem, and ast_rtp::rtcp.

Referenced by handle_request_invite().

{
   rtp->altthem.sin_port = alt->sin_port;
   rtp->altthem.sin_addr = alt->sin_addr;
   if (rtp->rtcp) {
      rtp->rtcp->altthem.sin_port = htons(ntohs(alt->sin_port) + 1);
      rtp->rtcp->altthem.sin_addr = alt->sin_addr;
   }
}
void ast_rtp_set_callback ( struct ast_rtp rtp,
ast_rtp_callback  callback 
)

Definition at line 795 of file rtp.c.

References ast_rtp::callback.

Referenced by start_rtp().

{
   rtp->callback = callback;
}
void ast_rtp_set_data ( struct ast_rtp rtp,
void *  data 
)

Definition at line 790 of file rtp.c.

References ast_rtp::data.

Referenced by start_rtp().

{
   rtp->data = data;
}
void ast_rtp_set_m_type ( struct ast_rtp rtp,
int  pt 
)

Make a note of a RTP payload type that was seen in a SDP "m=" line. By default, use the well-known value for this type (although it may still be set to a different value by a subsequent "a=rtpmap:" line)

Activate payload type.

Definition at line 2277 of file rtp.c.

References ast_rtp::current_RTP_PT, MAX_RTP_PT, rtp_bridge_lock(), and rtp_bridge_unlock().

Referenced by gtalk_is_answered(), gtalk_newcall(), jingle_newcall(), and process_sdp().

{
   if (pt < 0 || pt >= MAX_RTP_PT || static_RTP_PT[pt].code == 0) 
      return; /* bogus payload type */

   rtp_bridge_lock(rtp);
   rtp->current_RTP_PT[pt] = static_RTP_PT[pt];
   rtp_bridge_unlock(rtp);
} 
void ast_rtp_set_peer ( struct ast_rtp rtp,
struct sockaddr_in *  them 
)

Definition at line 2703 of file rtp.c.

References ast_rtp::rtcp, ast_rtp::rxseqno, STRICT_RTP_LEARN, ast_rtp::strict_rtp_state, ast_rtcp::them, and ast_rtp::them.

Referenced by handle_open_receive_channel_ack_message(), process_sdp(), setup_rtp_connection(), and start_rtp().

{
   rtp->them.sin_port = them->sin_port;
   rtp->them.sin_addr = them->sin_addr;
   if (rtp->rtcp) {
      int h = ntohs(them->sin_port);
      rtp->rtcp->them.sin_port = htons(h + 1);
      rtp->rtcp->them.sin_addr = them->sin_addr;
   }
   rtp->rxseqno = 0;
   /* If strict RTP protection is enabled switch back to the learn state so we don't drop packets from above */
   if (strictrtp)
      rtp->strict_rtp_state = STRICT_RTP_LEARN;
}
void ast_rtp_set_rtpholdtimeout ( struct ast_rtp rtp,
int  timeout 
)

Set rtp hold timeout.

Definition at line 757 of file rtp.c.

References ast_rtp::rtpholdtimeout.

Referenced by check_rtp_timeout(), create_addr_from_peer(), and sip_alloc().

{
   rtp->rtpholdtimeout = timeout;
}
void ast_rtp_set_rtpkeepalive ( struct ast_rtp rtp,
int  period 
)

set RTP keepalive interval

Definition at line 763 of file rtp.c.

References ast_rtp::rtpkeepalive.

Referenced by create_addr_from_peer(), and sip_alloc().

{
   rtp->rtpkeepalive = period;
}
int ast_rtp_set_rtpmap_type ( struct ast_rtp rtp,
int  pt,
char *  mimeType,
char *  mimeSubtype,
enum ast_rtp_options  options 
)

Set payload type to a known MIME media type for a codec.

Parameters:
rtpRTP structure to modify
ptPayload type entry to modify
mimeTypetop-level MIME type of media stream (typically "audio", "video", "text", etc.)
mimeSubtypeMIME subtype of media stream (typically a codec name)
optionsZero or more flags from the ast_rtp_options enum

This function 'fills in' an entry in the list of possible formats for a media stream associated with an RTP structure.

Return values:
0on success
-1if the payload type is out of range
-2if the mimeType/mimeSubtype combination was not found

Definition at line 2353 of file rtp.c.

References ast_rtp_set_rtpmap_type_rate().

Referenced by __oh323_rtp_create(), gtalk_is_answered(), gtalk_newcall(), jingle_newcall(), process_sdp(), process_sdp_a_text(), set_dtmf_payload(), and setup_rtp_connection().

{
   return ast_rtp_set_rtpmap_type_rate(rtp, pt, mimeType, mimeSubtype, options, 0);
}
int ast_rtp_set_rtpmap_type_rate ( struct ast_rtp rtp,
int  pt,
char *  mimeType,
char *  mimeSubtype,
enum ast_rtp_options  options,
unsigned int  sample_rate 
)

Make a note of a RTP payload type (with MIME type) that was seen in an SDP "a=rtpmap:" line.

Set payload type to a known MIME media type for a codec with a specific sample rate.

Returns:
0 if the MIME type was found and set, -1 if it wasn't found

Definition at line 2304 of file rtp.c.

References ARRAY_LEN, AST_FORMAT_G726, AST_FORMAT_G726_AAL2, AST_RTP_OPT_G726_NONSTANDARD, rtpPayloadType::code, ast_rtp::current_RTP_PT, rtpPayloadType::isAstFormat, MAX_RTP_PT, mimeTypes, mimeType::payloadType, rtp_bridge_lock(), rtp_bridge_unlock(), mimeType::sample_rate, mimeType::subtype, and mimeType::type.

Referenced by ast_rtp_set_rtpmap_type(), process_sdp_a_audio(), and process_sdp_a_video().

{
   unsigned int i;
   int found = 0;

   if (pt < 0 || pt >= MAX_RTP_PT)
      return -1; /* bogus payload type */

   rtp_bridge_lock(rtp);

   for (i = 0; i < ARRAY_LEN(mimeTypes); ++i) {
      const struct mimeType *t = &mimeTypes[i];

      if (strcasecmp(mimeSubtype, t->subtype)) {
         continue;
      }

      if (strcasecmp(mimeType, t->type)) {
         continue;
      }

      /* if both sample rates have been supplied, and they don't match,
         then this not a match; if one has not been supplied, then the
         rates are not compared */
      if (sample_rate && t->sample_rate &&
          (sample_rate != t->sample_rate)) {
         continue;
      }

      found = 1;
      rtp->current_RTP_PT[pt] = t->payloadType;

      if ((t->payloadType.code == AST_FORMAT_G726) &&
          t->payloadType.isAstFormat &&
          (options & AST_RTP_OPT_G726_NONSTANDARD)) {
         rtp->current_RTP_PT[pt].code = AST_FORMAT_G726_AAL2;
      }

      break;
   }

   rtp_bridge_unlock(rtp);

   return (found ? 0 : -2);
}
void ast_rtp_set_rtptimeout ( struct ast_rtp rtp,
int  timeout 
)

Set rtp timeout.

Definition at line 751 of file rtp.c.

References ast_rtp::rtptimeout.

Referenced by check_rtp_timeout(), create_addr_from_peer(), and sip_alloc().

{
   rtp->rtptimeout = timeout;
}
void ast_rtp_set_rtptimers_onhold ( struct ast_rtp rtp)

Definition at line 744 of file rtp.c.

References ast_rtp::rtpholdtimeout, and ast_rtp::rtptimeout.

Referenced by handle_response_invite().

{
   rtp->rtptimeout = (-1) * rtp->rtptimeout;
   rtp->rtpholdtimeout = (-1) * rtp->rtpholdtimeout;
}
void ast_rtp_set_vars ( struct ast_channel chan,
struct ast_rtp rtp 
)

Set RTPAUDIOQOS(...) variables on a channel when it is being hung up.

Since:
1.6.1

Definition at line 2882 of file rtp.c.

References ast_bridged_channel(), ast_rtp_get_quality(), ast_channel::bridge, pbx_builtin_setvar_helper(), RTPQOS_JITTER, RTPQOS_LOSS, RTPQOS_RTT, and RTPQOS_SUMMARY.

Referenced by handle_request_bye(), and sip_hangup().

                                                                     {
   char *audioqos;
   char *audioqos_jitter;
   char *audioqos_loss;
   char *audioqos_rtt;
   struct ast_channel *bridge;

   if (!rtp || !chan)
      return;

   bridge = ast_bridged_channel(chan);

   audioqos        = ast_rtp_get_quality(rtp, NULL, RTPQOS_SUMMARY);
   audioqos_jitter = ast_rtp_get_quality(rtp, NULL, RTPQOS_JITTER);
   audioqos_loss   = ast_rtp_get_quality(rtp, NULL, RTPQOS_LOSS);
   audioqos_rtt    = ast_rtp_get_quality(rtp, NULL, RTPQOS_RTT);

   pbx_builtin_setvar_helper(chan, "RTPAUDIOQOS", audioqos);
   pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSJITTER", audioqos_jitter);
   pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSLOSS", audioqos_loss);
   pbx_builtin_setvar_helper(chan, "RTPAUDIOQOSRTT", audioqos_rtt);

   if (!bridge)
      return;

   pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSBRIDGED", audioqos);
   pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSJITTERBRIDGED", audioqos_jitter);
   pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSLOSSBRIDGED", audioqos_loss);
   pbx_builtin_setvar_helper(bridge, "RTPAUDIOQOSRTTBRIDGED", audioqos_rtt);
}
void ast_rtp_setdtmf ( struct ast_rtp rtp,
int  dtmf 
)

Indicate whether this RTP session is carrying DTMF or not.

Definition at line 810 of file rtp.c.

References ast_set2_flag, and FLAG_HAS_DTMF.

Referenced by create_addr_from_peer(), handle_request_invite(), process_sdp(), sip_alloc(), and sip_dtmfmode().

{
   ast_set2_flag(rtp, dtmf ? 1 : 0, FLAG_HAS_DTMF);
}
void ast_rtp_setdtmfcompensate ( struct ast_rtp rtp,
int  compensate 
)

Compensate for devices that send RFC2833 packets all at once.

Definition at line 815 of file rtp.c.

References ast_set2_flag, and FLAG_DTMF_COMPENSATE.

Referenced by create_addr_from_peer(), handle_request_invite(), process_sdp(), and sip_alloc().

{
   ast_set2_flag(rtp, compensate ? 1 : 0, FLAG_DTMF_COMPENSATE);
}
void ast_rtp_setnat ( struct ast_rtp rtp,
int  nat 
)

Definition at line 800 of file rtp.c.

References nat, and ast_rtp::nat.

Referenced by __oh323_rtp_create(), do_setnat(), oh323_rtp_read(), and start_rtp().

{
   rtp->nat = nat;
}
int ast_rtp_setqos ( struct ast_rtp rtp,
int  type_of_service,
int  class_of_service,
char *  desc 
)

Definition at line 2679 of file rtp.c.

References ast_netsock_set_qos(), and ast_rtp::s.

Referenced by __oh323_rtp_create(), sip_alloc(), and start_rtp().

{
   return ast_netsock_set_qos(rtp->s, type_of_service, class_of_service, desc);
}
void ast_rtp_setstun ( struct ast_rtp rtp,
int  stun_enable 
)

Enable STUN capability.

Definition at line 820 of file rtp.c.

References ast_set2_flag, and FLAG_HAS_STUN.

Referenced by gtalk_new().

{
   ast_set2_flag(rtp, stun_enable ? 1 : 0, FLAG_HAS_STUN);
}
void ast_rtp_stop ( struct ast_rtp rtp)

Stop RTP session, do not destroy structure

Definition at line 2757 of file rtp.c.

References ast_clear_flag, AST_SCHED_DEL, FLAG_P2P_SENT_MARK, free, ast_rtp::red, ast_rtp::rtcp, ast_rtp::sched, rtp_red::schedid, ast_rtcp::schedid, ast_rtcp::them, and ast_rtp::them.

Referenced by process_sdp(), setup_rtp_connection(), and stop_media_flows().

{
   if (rtp->rtcp) {
      AST_SCHED_DEL(rtp->sched, rtp->rtcp->schedid);
   }
   if (rtp->red) {
      AST_SCHED_DEL(rtp->sched, rtp->red->schedid);
      free(rtp->red);
      rtp->red = NULL;
   }

   memset(&rtp->them.sin_addr, 0, sizeof(rtp->them.sin_addr));
   memset(&rtp->them.sin_port, 0, sizeof(rtp->them.sin_port));
   if (rtp->rtcp) {
      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));
   }
   
   ast_clear_flag(rtp, FLAG_P2P_SENT_MARK);
}
void ast_rtp_stun_request ( struct ast_rtp rtp,
struct sockaddr_in *  suggestion,
const char *  username 
)

send a STUN BIND request to the given destination. Optionally, add a username if specified.

Send STUN request for an RTP socket Deprecated, this is just a wrapper for ast_rtp_stun_request()

Definition at line 699 of file rtp.c.

References ast_stun_request(), and ast_rtp::s.

Referenced by gtalk_update_stun(), and jingle_update_stun().

{
   ast_stun_request(rtp->s, suggestion, username, NULL);
}
void ast_rtp_unset_m_type ( struct ast_rtp rtp,
int  pt 
)

remove setting from payload type list if the rtpmap header indicates an unknown media type

clear payload type

Definition at line 2289 of file rtp.c.

References rtpPayloadType::code, ast_rtp::current_RTP_PT, rtpPayloadType::isAstFormat, MAX_RTP_PT, rtp_bridge_lock(), and rtp_bridge_unlock().

Referenced by process_sdp_a_audio(), and process_sdp_a_video().

{
   if (pt < 0 || pt >= MAX_RTP_PT)
      return; /* bogus payload type */

   rtp_bridge_lock(rtp);
   rtp->current_RTP_PT[pt].isAstFormat = 0;
   rtp->current_RTP_PT[pt].code = 0;
   rtp_bridge_unlock(rtp);
}
int ast_rtp_write ( struct ast_rtp rtp,
struct ast_frame _f 
)

Bug:
XXX this might never be free'd. Why do we do this?

Definition at line 3848 of file rtp.c.

References ast_codec_pref_getsize(), ast_debug, AST_FORMAT_G723_1, AST_FORMAT_SIREN14, AST_FORMAT_SIREN7, AST_FORMAT_SPEEX, AST_FRAME_TEXT, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frdup(), ast_frfree, ast_getformatname(), ast_log(), ast_rtp_lookup_code(), ast_rtp_raw_write(), ast_smoother_feed, ast_smoother_feed_be, AST_SMOOTHER_FLAG_BE, ast_smoother_free(), ast_smoother_new(), ast_smoother_read(), ast_smoother_set_flags(), ast_smoother_test_flag(), ast_format_list::cur_ms, ast_frame::data, ast_frame::datalen, f, ast_format_list::flags, ast_format_list::fr_len, ast_frame::frametype, ast_format_list::inc_ms, ast_rtp::lasttxformat, LOG_WARNING, ast_frame::offset, ast_rtp::pref, ast_frame::ptr, ast_rtp::red, red_t140_to_red(), ast_rtp::smoother, ast_frame::subclass, and ast_rtp::them.

Referenced by gtalk_write(), jingle_write(), mgcp_write(), oh323_write(), red_write(), sip_write(), skinny_write(), and unistim_write().

{
   struct ast_frame *f;
   int codec;
   int hdrlen = 12;
   int subclass;
   

   /* If we have no peer, return immediately */ 
   if (!rtp->them.sin_addr.s_addr)
      return 0;

   /* If there is no data length, return immediately */
   if (!_f->datalen && !rtp->red)
      return 0;
   
   /* Make sure we have enough space for RTP header */
   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");
      return -1;
   }

   if (rtp->red) {
      /* return 0; */
      /* no primary data or generations to send */
      if ((_f = red_t140_to_red(rtp->red)) == NULL) 
         return 0;
   }

   /* The bottom bit of a video subclass contains the marker bit */
   subclass = _f->subclass;
   if (_f->frametype == AST_FRAME_VIDEO)
      subclass &= ~0x1;

   codec = ast_rtp_lookup_code(rtp, 1, subclass);
   if (codec < 0) {
      ast_log(LOG_WARNING, "Don't know how to send format %s packets with RTP\n", ast_getformatname(_f->subclass));
      return -1;
   }

   if (rtp->lasttxformat != subclass) {
      /* New format, reset the smoother */
      ast_debug(1, "Ooh, format changed from %s to %s\n", ast_getformatname(rtp->lasttxformat), ast_getformatname(subclass));
      rtp->lasttxformat = subclass;
      if (rtp->smoother)
         ast_smoother_free(rtp->smoother);
      rtp->smoother = NULL;
   }

   if (!rtp->smoother) {
      struct ast_format_list fmt = ast_codec_pref_getsize(&rtp->pref, subclass);

      switch (subclass) {
      case AST_FORMAT_SPEEX:
      case AST_FORMAT_G723_1:
      case AST_FORMAT_SIREN7:
      case AST_FORMAT_SIREN14:
         /* these are all frame-based codecs and cannot be safely run through
            a smoother */
         break;
      default:
         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);
            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));
         }
      }
   }
   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);
      }

      while ((f = ast_smoother_read(rtp->smoother)) && (f->data.ptr)) {
         ast_rtp_raw_write(rtp, f, codec);
      }
   } else {
      /* Don't buffer outgoing frames; send them one-per-packet: */
      if (_f->offset < hdrlen) 
         f = ast_frdup(_f);   /*! \bug XXX this might never be free'd. Why do we do this? */
      else
         f = _f;
      if (f->data.ptr)
         ast_rtp_raw_write(rtp, f, codec);
      if (f != _f)
         ast_frfree(f);
   }
      
   return 0;
}
int ast_stun_request ( int  s,
struct sockaddr_in *  dst,
const char *  username,
struct sockaddr_in *  answer 
)

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).

Generic STUN request send a generic stun request to the server specified.

Parameters:
sthe socket used to send the request
dstthe address of the STUN server
usernameif non null, add the username in the request
answerif non null, the function waits for a response and puts here the externally visible address.
Returns:
0 on success, other values on error.

Definition at line 636 of file rtp.c.

References append_attr_string(), ast_log(), ast_poll, stun_attr::attr, stun_header::ies, LOG_WARNING, stun_header::msglen, stun_header::msgtype, s, STUN_BINDREQ, stun_get_mapped(), stun_handle_packet(), stun_req_id(), stun_send(), and STUN_USERNAME.

Referenced by ast_rtp_stun_request(), ast_sip_ouraddrfor(), and reload_config().

{
   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];
      struct pollfd pfds = { .fd = s, .events = POLLIN, };
      struct sockaddr_in src;
      socklen_t srclen;

      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;
      res = ast_poll(&pfds, 1, 3000);
      if (res <= 0)  /* timeout or error */
         continue;
      memset(&src, '\0', 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;
      }
      memset(answer, '\0', sizeof(struct sockaddr_in));
      stun_handle_packet(s, &src, reply_buf, res,
         stun_get_mapped, answer);
      res = 0; /* signal regular exit */
      break;
   }
   return res;
}
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 
) [static]

Bridge loop for true native bridge (reinvite)

Definition at line 3973 of file rtp.c.

References AST_BRIDGE_COMPLETE, AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, AST_BRIDGE_FAILED, AST_BRIDGE_IGNORE_SIGS, AST_BRIDGE_RETRY, ast_channel_unlock, ast_check_hangup(), AST_CONTROL_HOLD, AST_CONTROL_SRCUPDATE, AST_CONTROL_T38_PARAMETERS, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_debug, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_HTML, AST_FRAME_IMAGE, AST_FRAME_MODEM, AST_FRAME_TEXT, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_indicate_data(), ast_inet_ntoa(), ast_log(), ast_poll_channel_add(), ast_poll_channel_del(), ast_read(), ast_rtp_get_peer(), ast_test_flag, ast_waitfor_n(), ast_write(), ast_channel::audiohooks, ast_frame::data, ast_frame::datalen, FLAG_NAT_ACTIVE, ast_frame::frametype, ast_rtp_protocol::get_codec, inaddrcmp(), LOG_WARNING, ast_channel::masq, ast_channel::masqr, ast_channel::monitor, ast_channel::name, ast_frame::ptr, ast_rtp_protocol::set_rtp_peer, ast_frame::subclass, and ast_channel::tech_pvt.

Referenced by ast_rtp_bridge().

{
   struct ast_frame *fr = NULL;
   struct ast_channel *who = NULL, *other = NULL, *cs[3] = {NULL, };
   int oldcodec0 = codec0, oldcodec1 = codec1;
   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,};
   
   /* Set it up so audio goes directly between the two endpoints */

   /* Test the first channel */
   if (!(pr0->set_rtp_peer(c0, p1, vp1, tp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE)))) {
      ast_rtp_get_peer(p1, &ac1);
      if (vp1)
         ast_rtp_get_peer(vp1, &vac1);
      if (tp1)
         ast_rtp_get_peer(tp1, &tac1);
   } else
      ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name);
   
   /* Test the second channel */
   if (!(pr1->set_rtp_peer(c1, p0, vp0, tp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))) {
      ast_rtp_get_peer(p0, &ac0);
      if (vp0)
         ast_rtp_get_peer(vp0, &vac0);
      if (tp0)
         ast_rtp_get_peer(tp0, &tac0);
   } 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 */
   ast_channel_unlock(c0);
   ast_channel_unlock(c1);

   ast_poll_channel_add(c0, c1);

   /* Throw our channels into the structure and enter the loop */
   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) ||
          (c0->monitor || c0->audiohooks || c1->monitor || c1->audiohooks)) {
         ast_debug(1, "Oooh, something is weird, backing out\n");
         if (c0->tech_pvt == pvt0)
            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 (c1->tech_pvt == pvt1)
            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);
         ast_poll_channel_del(c0, c1);
         return AST_BRIDGE_RETRY;
      }

      /* Check if they have changed their address */
      ast_rtp_get_peer(p1, &t1);
      if (vp1)
         ast_rtp_get_peer(vp1, &vt1);
      if (tp1)
         ast_rtp_get_peer(tp1, &tt1);
      if (pr1->get_codec)
         codec1 = pr1->get_codec(c1);
      ast_rtp_get_peer(p0, &t0);
      if (vp0)
         ast_rtp_get_peer(vp0, &vt0);
      if (tp0)
         ast_rtp_get_peer(tp0, &tt0);
      if (pr0->get_codec)
         codec0 = pr0->get_codec(c0);
      if ((inaddrcmp(&t1, &ac1)) ||
          (vp1 && inaddrcmp(&vt1, &vac1)) ||
          (tp1 && inaddrcmp(&tt1, &tac1)) ||
          (codec1 != oldcodec1)) {
         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);
         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)))
            ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c0->name, c1->name);
         memcpy(&ac1, &t1, sizeof(ac1));
         memcpy(&vac1, &vt1, sizeof(vac1));
         memcpy(&tac1, &tt1, sizeof(tac1));
         oldcodec1 = codec1;
      }
      if ((inaddrcmp(&t0, &ac0)) ||
          (vp0 && inaddrcmp(&vt0, &vac0)) ||
          (tp0 && inaddrcmp(&tt0, &tac0)) ||
          (codec0 != oldcodec0)) {
         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);
         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)))
            ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c1->name, c0->name);
         memcpy(&ac0, &t0, sizeof(ac0));
         memcpy(&vac0, &vt0, sizeof(vac0));
         memcpy(&tac0, &tt0, sizeof(tac0));
         oldcodec0 = codec0;
      }

      /* Wait for frame to come in on the channels */
      if (!(who = ast_waitfor_n(cs, 2, &timeoutms))) {
         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);
            return AST_BRIDGE_RETRY;
         }
         ast_debug(1, "Ooh, empty read...\n");
         if (ast_check_hangup(c0) || ast_check_hangup(c1))
            break;
         continue;
      }
      fr = ast_read(who);
      other = (who == c0) ? c1 : c0;
      if (!fr || ((fr->frametype == AST_FRAME_DTMF_BEGIN || fr->frametype == AST_FRAME_DTMF_END) &&
             (((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) ||
              ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))))) {
         /* Break out of bridge */
         *fo = fr;
         *rc = who;
         ast_debug(1, "Oooh, got a %s\n", fr ? "digit" : "hangup");
         if (c0->tech_pvt == pvt0)
            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 (c1->tech_pvt == pvt1)
            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);
         ast_poll_channel_del(c0, c1);
         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) ||
             (fr->subclass == AST_CONTROL_SRCUPDATE) ||
             (fr->subclass == AST_CONTROL_T38_PARAMETERS)) {
            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)
                  pr1->set_rtp_peer(c1, NULL, NULL, NULL, 0, 0);
               else
                  pr0->set_rtp_peer(c0, NULL, NULL, NULL, 0, 0);
            } else if (fr->subclass == AST_CONTROL_UNHOLD) {
               /* If they went off hold they should go back to being direct */
               if (who == c0)
                  pr1->set_rtp_peer(c1, p0, vp0, tp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE));
               else
                  pr0->set_rtp_peer(c0, p1, vp1, tp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE));
            }
            /* Update local address information */
            ast_rtp_get_peer(p0, &t0);
            memcpy(&ac0, &t0, sizeof(ac0));
            ast_rtp_get_peer(p1, &t1);
            memcpy(&ac1, &t1, sizeof(ac1));
            /* Update codec information */
            if (pr0->get_codec && c0->tech_pvt)
               oldcodec0 = codec0 = pr0->get_codec(c0);
            if (pr1->get_codec && c1->tech_pvt)
               oldcodec1 = codec1 = pr1->get_codec(c1);
            ast_indicate_data(other, fr->subclass, fr->data.ptr, fr->datalen);
            ast_frfree(fr);
         } else {
            *fo = fr;
            *rc = who;
            ast_debug(1, "Got a FRAME_CONTROL (%d) frame on channel %s\n", fr->subclass, who->name);
            return AST_BRIDGE_COMPLETE;
         }
      } else {
         if ((fr->frametype == AST_FRAME_DTMF_BEGIN) ||
             (fr->frametype == AST_FRAME_DTMF_END) ||
             (fr->frametype == AST_FRAME_VOICE) ||
             (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)) {
            ast_write(other, fr);
         }
         ast_frfree(fr);
      }
      /* Swap priority */
#ifndef HAVE_EPOLL
      cs[2] = cs[0];
      cs[0] = cs[1];
      cs[1] = cs[2];
#endif
   }

   ast_poll_channel_del(c0, c1);

   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);

   return AST_BRIDGE_FAILED;
}
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 
) [static]

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

Definition at line 4281 of file rtp.c.

References AST_BRIDGE_COMPLETE, AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, AST_BRIDGE_FAILED, AST_BRIDGE_FAILED_NOWARN, AST_BRIDGE_IGNORE_SIGS, AST_BRIDGE_RETRY, ast_channel_unlock, ast_check_hangup(), ast_clear_flag, AST_CONTROL_HOLD, AST_CONTROL_SRCUPDATE, AST_CONTROL_T38_PARAMETERS, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, ast_debug, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, AST_FRAME_HTML, AST_FRAME_IMAGE, AST_FRAME_MODEM, AST_FRAME_TEXT, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_indicate_data(), ast_log(), ast_poll_channel_add(), ast_poll_channel_del(), ast_read(), ast_waitfor_n(), ast_write(), ast_channel::audiohooks, ast_frame::data, ast_frame::datalen, FLAG_P2P_SENT_MARK, ast_frame::frametype, LOG_NOTICE, ast_channel::masq, ast_channel::masqr, ast_channel::monitor, ast_channel::name, option_debug, p2p_callback_disable(), p2p_callback_enable(), p2p_set_bridge(), ast_frame::ptr, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_frame::subclass, and ast_channel::tech_pvt.

Referenced by ast_rtp_bridge().

{
   struct ast_frame *fr = NULL;
   struct ast_channel *who = NULL, *other = NULL, *cs[3] = {NULL, };
   int *p0_iod[2] = {NULL, NULL}, *p1_iod[2] = {NULL, NULL};
   int p0_callback = 0, p1_callback = 0;
   enum ast_bridge_result res = AST_BRIDGE_FAILED;

   /* Okay, setup each RTP structure to do P2P forwarding */
   ast_clear_flag(p0, FLAG_P2P_SENT_MARK);
   p2p_set_bridge(p0, p1);
   ast_clear_flag(p1, FLAG_P2P_SENT_MARK);
   p2p_set_bridge(p1, p0);

   /* Activate callback modes if possible */
   p0_callback = p2p_callback_enable(c0, p0, &p0_iod[0]);
   p1_callback = p2p_callback_enable(c1, p1, &p1_iod[0]);

   /* Now let go of the channel locks and be on our way */
   ast_channel_unlock(c0);
   ast_channel_unlock(c1);

   ast_poll_channel_add(c0, c1);

   /* Go into a loop forwarding frames until we don't need to anymore */
   cs[0] = c0;
   cs[1] = c1;
   cs[2] = NULL;
   for (;;) {
      /* If the underlying formats have changed force this bridge to break */
      if ((c0->rawreadformat != c1->rawwriteformat) || (c1->rawreadformat != c0->rawwriteformat)) {
         ast_debug(3, "p2p-rtp-bridge: Oooh, formats changed, backing out\n");
         res = AST_BRIDGE_FAILED_NOWARN;
         break;
      }
      /* Check if anything changed */
      if ((c0->tech_pvt != pvt0) ||
          (c1->tech_pvt != pvt1) ||
          (c0->masq || c0->masqr || c1->masq || c1->masqr) ||
          (c0->monitor || c0->audiohooks || c1->monitor || c1->audiohooks)) {
         ast_debug(3, "p2p-rtp-bridge: Oooh, something is weird, backing out\n");
         /* 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 */
         if ((c0->masq || c0->masqr) && (fr = ast_read(c0)))
            ast_frfree(fr);
         if ((c1->masq || c1->masqr) && (fr = ast_read(c1)))
            ast_frfree(fr);
         res = AST_BRIDGE_RETRY;
         break;
      }
      /* Wait on a channel to feed us a frame */
      if (!(who = ast_waitfor_n(cs, 2, &timeoutms))) {
         if (!timeoutms) {
            res = AST_BRIDGE_RETRY;
            break;
         }
         if (option_debug > 2)
            ast_log(LOG_NOTICE, "p2p-rtp-bridge: Ooh, empty read...\n");
         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;
      /* Depending on the frame we may need to break out of our bridge */
      if (!fr || ((fr->frametype == AST_FRAME_DTMF_BEGIN || fr->frametype == AST_FRAME_DTMF_END) &&
             ((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;
         ast_debug(3, "p2p-rtp-bridge: Ooh, got a %s\n", fr ? "digit" : "hangup");
         res = AST_BRIDGE_COMPLETE;
         break;
      } 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) ||
             (fr->subclass == AST_CONTROL_SRCUPDATE) ||
             (fr->subclass == AST_CONTROL_T38_PARAMETERS)) {
            /* If we are going on hold, then break callback mode and P2P bridging */
            if (fr->subclass == AST_CONTROL_HOLD) {
               if (p0_callback)
                  p0_callback = p2p_callback_disable(c0, p0, &p0_iod[0]);
               if (p1_callback)
                  p1_callback = p2p_callback_disable(c1, p1, &p1_iod[0]);
               p2p_set_bridge(p0, NULL);
               p2p_set_bridge(p1, NULL);
            } else if (fr->subclass == AST_CONTROL_UNHOLD) {
               /* If we are off hold, then go back to callback mode and P2P bridging */
               ast_clear_flag(p0, FLAG_P2P_SENT_MARK);
               p2p_set_bridge(p0, p1);
               ast_clear_flag(p1, FLAG_P2P_SENT_MARK);
               p2p_set_bridge(p1, p0);
               p0_callback = p2p_callback_enable(c0, p0, &p0_iod[0]);
               p1_callback = p2p_callback_enable(c1, p1, &p1_iod[0]);
            }
            ast_indicate_data(other, fr->subclass, fr->data.ptr, fr->datalen);
            ast_frfree(fr);
         } else {
            *fo = fr;
            *rc = who;
            ast_debug(3, "p2p-rtp-bridge: Got a FRAME_CONTROL (%d) frame on channel %s\n", fr->subclass, who->name);
            res = AST_BRIDGE_COMPLETE;
            break;
         }
      } else {
         if ((fr->frametype == AST_FRAME_DTMF_BEGIN) ||
             (fr->frametype == AST_FRAME_DTMF_END) ||
             (fr->frametype == AST_FRAME_VOICE) ||
             (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)) {
            ast_write(other, fr);
         }

         ast_frfree(fr);
      }
      /* Swap priority */
#ifndef HAVE_EPOLL
      cs[2] = cs[0];
      cs[0] = cs[1];
      cs[1] = cs[2];
#endif
   }

   /* If we are totally avoiding the core, then restore our link to it */
   if (p0_callback)
      p0_callback = p2p_callback_disable(c0, p0, &p0_iod[0]);
   if (p1_callback)
      p1_callback = p2p_callback_disable(c1, p1, &p1_iod[0]);

   /* Break out of the direct bridge */
   p2p_set_bridge(p0, NULL);
   p2p_set_bridge(p1, NULL);

   ast_poll_channel_del(c0, c1);

   return res;
}
static int bridge_p2p_rtp_write ( struct ast_rtp rtp,
struct ast_rtp bridged,
unsigned int *  rtpheader,
int  len,
int  hdrlen 
) [static]

Perform a Packet2Packet RTP write.

Definition at line 1522 of file rtp.c.

References ast_debug, ast_inet_ntoa(), AST_RTP_DTMF, ast_rtp_lookup_code(), ast_rtp_lookup_pt(), ast_set_flag, ast_test_flag, ast_verbose(), rtpPayloadType::code, ast_rtp::current_RTP_PT, errno, FLAG_NAT_ACTIVE, FLAG_NAT_INACTIVE, FLAG_NAT_INACTIVE_NOWARN, FLAG_P2P_NEED_DTMF, FLAG_P2P_SENT_MARK, rtpPayloadType::isAstFormat, ast_rtp::nat, option_debug, reconstruct(), rtp_debug_test_addr(), ast_rtp::s, and ast_rtp::them.

Referenced by ast_rtp_read().

{
   int res = 0, payload = 0, bridged_payload = 0, mark;
   struct rtpPayloadType rtpPT;
   int reconstruct = ntohl(rtpheader[0]);

   /* Get fields from packet */
   payload = (reconstruct & 0x7f0000) >> 16;
   mark = (((reconstruct & 0x800000) >> 23) != 0);

   /* 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 */
   if (ast_test_flag(rtp, FLAG_P2P_NEED_DTMF) && !rtpPT.isAstFormat && rtpPT.code == AST_RTP_DTMF)
      return -1;

   /* Otherwise adjust bridged payload to match */
   bridged_payload = ast_rtp_lookup_code(bridged, rtpPT.isAstFormat, rtpPT.code);

   /* If the payload coming in is not one of the negotiated ones then send it to the core, this will cause formats to change and the bridge to break */
   if (!bridged->current_RTP_PT[bridged_payload].code)
      return -1;


   /* 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 */
   reconstruct &= 0xFF80FFFF;
   reconstruct |= (bridged_payload << 16);
   reconstruct |= (mark << 23);
   rtpheader[0] = htonl(reconstruct);

   /* 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))) {
         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));
      } 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)
            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));
         ast_set_flag(bridged, FLAG_NAT_INACTIVE_NOWARN);
      }
      return 0;
   } else if (rtp_debug_test_addr(&bridged->them))
         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);

   return 0;
}
static void calc_rxstamp ( struct timeval *  when,
struct ast_rtp rtp,
unsigned int  timestamp,
int  mark 
) [static]

Definition at line 1467 of file rtp.c.

References ast_samp2tv(), ast_tvadd(), ast_tvsub(), ast_rtp::drxcore, ast_rtp::f, ast_rtcp::maxrxjitter, ast_rtcp::minrxjitter, normdev_compute(), ast_rtcp::normdev_rxjitter, ast_rtp::rtcp, rtp_get_rate(), ast_rtp::rxcore, ast_rtp::rxjitter, ast_rtcp::rxjitter_count, ast_rtp::rxtransit, ast_rtp::seedrxts, stddev_compute(), ast_rtcp::stdev_rxjitter, and ast_frame::subclass.

Referenced by ast_rtp_read().

{
   struct timeval now;
   struct timeval tmp;
   double transit;
   double current_time;
   double d;
   double dtv;
   double prog;
   double normdev_rxjitter_current;
   int rate = rtp_get_rate(rtp->f.subclass);

   if ((!rtp->rxcore.tv_sec && !rtp->rxcore.tv_usec) || mark) {
      gettimeofday(&rtp->rxcore, NULL);
      rtp->drxcore = (double) rtp->rxcore.tv_sec + (double) rtp->rxcore.tv_usec / 1000000;
      /* map timestamp to a real time */
      rtp->seedrxts = timestamp; /* Their RTP timestamp started with this */
      tmp = ast_samp2tv(timestamp, rate);
      rtp->rxcore = ast_tvsub(rtp->rxcore, tmp);
      /* Round to 0.1ms for nice, pretty timestamps */
      rtp->rxcore.tv_usec -= rtp->rxcore.tv_usec % 100;
   }

   gettimeofday(&now,NULL);
   /* rxcore is the mapping between the RTP timestamp and _our_ real time from gettimeofday() */
   tmp = ast_samp2tv(timestamp, rate);
   *when = ast_tvadd(rtp->rxcore, tmp);

   prog = (double)((timestamp-rtp->seedrxts)/(float)(rate));
   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;
   if (d<0)
      d=-d;
   rtp->rxjitter += (1./16.) * (d - rtp->rxjitter);

   if (rtp->rtcp) {
      if (rtp->rxjitter > rtp->rtcp->maxrxjitter)
         rtp->rtcp->maxrxjitter = rtp->rxjitter;
      if (rtp->rtcp->rxjitter_count == 1) 
         rtp->rtcp->minrxjitter = rtp->rxjitter;
      if (rtp->rxjitter < rtp->rtcp->minrxjitter)
         rtp->rtcp->minrxjitter = rtp->rxjitter;
         
      normdev_rxjitter_current = normdev_compute(rtp->rtcp->normdev_rxjitter,rtp->rxjitter,rtp->rtcp->rxjitter_count);
      rtp->rtcp->stdev_rxjitter = stddev_compute(rtp->rtcp->stdev_rxjitter,rtp->rxjitter,rtp->rtcp->normdev_rxjitter,normdev_rxjitter_current,rtp->rtcp->rxjitter_count);

      rtp->rtcp->normdev_rxjitter = normdev_rxjitter_current;
      rtp->rtcp->rxjitter_count++;
   }
}
static unsigned int calc_txstamp ( struct ast_rtp rtp,
struct timeval *  delivery 
) [static]

Definition at line 3168 of file rtp.c.

References ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), and ast_rtp::txcore.

Referenced by ast_rtp_raw_write().

{
   struct timeval t;
   long ms;
   if (ast_tvzero(rtp->txcore)) {
      rtp->txcore = ast_tvnow();
      /* Round to 20ms for nice, pretty timestamps */
      rtp->txcore.tv_usec -= rtp->txcore.tv_usec % 20000;
   }
   /* Use previous txcore if available */
   t = (delivery && !ast_tvzero(*delivery)) ? *delivery : ast_tvnow();
   ms = ast_tvdiff_ms(t, rtp->txcore);
   if (ms < 0)
      ms = 0;
   /* Use what we just got for next time */
   rtp->txcore = t;
   return (unsigned int) ms;
}
static struct ast_frame* create_dtmf_frame ( struct ast_rtp rtp,
enum ast_frame_type  type 
) [static, read]

Definition at line 870 of file rtp.c.

References AST_CONTROL_FLASH, ast_debug, AST_FRAME_CONTROL, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_inet_ntoa(), AST_LIST_NEXT, ast_null_frame, ast_test_flag, ast_tvcmp(), ast_tvnow(), ast_frame::datalen, ast_rtp::dtmfmute, ast_rtp::dtmfsamples, ast_rtp::f, FLAG_DTMF_COMPENSATE, ast_frame::frametype, ast_frame::mallocd, ast_rtp::resp, ast_frame::samples, ast_frame::src, ast_frame::subclass, ast_rtp::them, and type.

Referenced by ast_rtp_read(), process_cisco_dtmf(), and process_rfc2833().

{
   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) {
      ast_debug(1, "Ignore potential DTMF echo from '%s'\n", ast_inet_ntoa(rtp->them.sin_addr));
      rtp->resp = 0;
      rtp->dtmfsamples = 0;
      return &ast_null_frame;
   }
   ast_debug(1, "Sending dtmf: %d (%c), at %s\n", rtp->resp, rtp->resp, ast_inet_ntoa(rtp->them.sin_addr));
   if (rtp->resp == 'X') {
      rtp->f.frametype = AST_FRAME_CONTROL;
      rtp->f.subclass = AST_CONTROL_FLASH;
   } else {
      rtp->f.frametype = type;
      rtp->f.subclass = rtp->resp;
   }
   rtp->f.datalen = 0;
   rtp->f.samples = 0;
   rtp->f.mallocd = 0;
   rtp->f.src = "RTP";
   AST_LIST_NEXT(&rtp->f, frame_list) = NULL;
   return &rtp->f;
   
}
static struct ast_rtp_protocol* get_proto ( struct ast_channel chan) [static, read]

Get channel driver interface structure.

Definition at line 2100 of file rtp.c.

References AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_rtp_protocol::list, ast_channel::tech, ast_channel_tech::type, and ast_rtp_protocol::type.

Referenced by ast_rtp_bridge(), ast_rtp_early_bridge(), and ast_rtp_make_compatible().

{
   struct ast_rtp_protocol *cur = NULL;

   AST_RWLIST_RDLOCK(&protos);
   AST_RWLIST_TRAVERSE(&protos, cur, list) {
      if (cur->type == chan->tech->type)
         break;
   }
   AST_RWLIST_UNLOCK(&protos);

   return cur;
}
static char* handle_cli_rtcp_set_debug ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 4704 of file rtp.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, rtcp_do_debug_ip(), rtcpdebugaddr, and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "rtcp set debug {on|off|ip}";
      e->usage =
         "Usage: rtcp set debug {on|off|ip host[:port]}\n"
         "       Enable/Disable dumping of all RTCP packets. If 'ip' is\n"
         "       specified, limit the dumped packets to those to and from\n"
         "       the specified 'host' with optional port.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc == e->args) { /* set on or off */
      if (!strncasecmp(a->argv[e->args-1], "on", 2)) {
         rtcpdebug = 1;
         memset(&rtcpdebugaddr, 0, sizeof(rtcpdebugaddr));
         ast_cli(a->fd, "RTCP Debugging Enabled\n");
         return CLI_SUCCESS;
      } else if (!strncasecmp(a->argv[e->args-1], "off", 3)) {
         rtcpdebug = 0;
         ast_cli(a->fd, "RTCP Debugging Disabled\n");
         return CLI_SUCCESS;
      }
   } else if (a->argc == e->args +1) { /* ip */
      return rtcp_do_debug_ip(a);
   }

   return CLI_SHOWUSAGE;   /* default, failure */
}
static char* handle_cli_rtcp_set_stats ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 4737 of file rtp.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "rtcp set stats {on|off}";
      e->usage =
         "Usage: rtcp set stats {on|off}\n"
         "       Enable/Disable dumping of RTCP stats.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != e->args)
      return CLI_SHOWUSAGE;

   if (!strncasecmp(a->argv[e->args-1], "on", 2))
      rtcpstats = 1;
   else if (!strncasecmp(a->argv[e->args-1], "off", 3))
      rtcpstats = 0;
   else
      return CLI_SHOWUSAGE;

   ast_cli(a->fd, "RTCP Stats %s\n", rtcpstats ? "Enabled" : "Disabled");
   return CLI_SUCCESS;
}
static char* handle_cli_rtp_set_debug ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 4671 of file rtp.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, rtp_do_debug_ip(), rtpdebugaddr, and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "rtp set debug {on|off|ip}";
      e->usage =
         "Usage: rtp set debug {on|off|ip host[:port]}\n"
         "       Enable/Disable dumping of all RTP packets. If 'ip' is\n"
         "       specified, limit the dumped packets to those to and from\n"
         "       the specified 'host' with optional port.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc == e->args) { /* set on or off */
      if (!strncasecmp(a->argv[e->args-1], "on", 2)) {
         rtpdebug = 1;
         memset(&rtpdebugaddr, 0, sizeof(rtpdebugaddr));
         ast_cli(a->fd, "RTP Debugging Enabled\n");
         return CLI_SUCCESS;
      } else if (!strncasecmp(a->argv[e->args-1], "off", 3)) {
         rtpdebug = 0;
         ast_cli(a->fd, "RTP Debugging Disabled\n");
         return CLI_SUCCESS;
      }
   } else if (a->argc == e->args +1) { /* ip */
      return rtp_do_debug_ip(a);
   }

   return CLI_SHOWUSAGE;   /* default, failure */
}
static char* handle_cli_stun_set_debug ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 4764 of file rtp.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "stun set debug {on|off}";
      e->usage =
         "Usage: stun set debug {on|off}\n"
         "       Enable/Disable STUN (Simple Traversal of UDP through NATs)\n"
         "       debugging\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != e->args)
      return CLI_SHOWUSAGE;

   if (!strncasecmp(a->argv[e->args-1], "on", 2))
      stundebug = 1;
   else if (!strncasecmp(a->argv[e->args-1], "off", 3))
      stundebug = 0;
   else
      return CLI_SHOWUSAGE;

   ast_cli(a->fd, "STUN Debugging %s\n", stundebug ? "Enabled" : "Disabled");
   return CLI_SUCCESS;
}
static double normdev_compute ( double  normdev,
double  sample,
unsigned int  sample_count 
) [static]

Calculate normal deviation.

Definition at line 842 of file rtp.c.

Referenced by ast_rtcp_read(), ast_rtcp_write_rr(), and calc_rxstamp().

{
   normdev = normdev * sample_count + sample;
   sample_count++;

   return normdev / sample_count;
}
static int p2p_callback_disable ( struct ast_channel chan,
struct ast_rtp rtp,
int **  iod 
) [static]

Helper function to switch a channel and RTP stream out of callback mode.

Definition at line 4249 of file rtp.c.

References ast_channel_lock, ast_channel_unlock, ast_io_add(), AST_IO_IN, ast_io_remove(), ast_rtp_fd(), ast_test_flag, ast_channel::fds, FLAG_CALLBACK_MODE, ast_rtp::io, ast_rtp::ioid, and rtpread().

Referenced by bridge_p2p_loop().

{
   ast_channel_lock(chan);

   /* Remove the callback from the IO context */
   ast_io_remove(rtp->io, iod[0]);

   /* Restore file descriptors */
   chan->fds[0] = ast_rtp_fd(rtp);
   ast_channel_unlock(chan);

   /* Restore callback mode if previously used */
   if (ast_test_flag(rtp, FLAG_CALLBACK_MODE))
      rtp->ioid = ast_io_add(rtp->io, ast_rtp_fd(rtp), rtpread, AST_IO_IN, rtp);

   return 0;
}
static int p2p_callback_enable ( struct ast_channel chan,
struct ast_rtp rtp,
int **  iod 
) [static]

P2P RTP Callback.

Definition at line 4242 of file rtp.c.

Referenced by bridge_p2p_loop().

{
   return 0;
}
static void p2p_set_bridge ( struct ast_rtp rtp0,
struct ast_rtp rtp1 
) [static]

Helper function that sets what an RTP structure is bridged to.

Definition at line 4268 of file rtp.c.

References ast_rtp::bridged, rtp_bridge_lock(), and rtp_bridge_unlock().

Referenced by bridge_p2p_loop().

{
   rtp_bridge_lock(rtp0);
   rtp0->bridged = rtp1;
   rtp_bridge_unlock(rtp0);
}
static struct ast_frame* process_cisco_dtmf ( struct ast_rtp rtp,
unsigned char *  data,
int  len 
) [static, read]

Definition at line 923 of file rtp.c.

References ast_debug, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_test_flag, create_dtmf_frame(), ast_rtp::dtmf_timeout, ast_rtp::dtmfsamples, dtmftimeout, f, FLAG_DTMF_COMPENSATE, ast_frame::flags, ast_rtp::lastrxformat, option_debug, ast_rtp::resp, rtp_get_rate(), ast_frame::samples, and seq.

Referenced by ast_rtp_read().

{
   unsigned int event;
   char resp = 0;
   struct ast_frame *f = NULL;
   unsigned char seq;
   unsigned int flags;
   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)
      +1          - set of flags
      +1 (bit 0)     - flaps by different DTMF digits delimited by audio
                    or repeated digit without audio???
      +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 0A 02 20 02
         28 06 20 02 00 02 0A 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];
   flags = data[1];
   power = data[2];
   event = data[3] & 0x1f;

   if (option_debug > 2 || rtpdebug)
      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);
   if (event < 10) {
      resp = '0' + event;
   } else if (event < 11) {
      resp = '*';
   } else if (event < 12) {
      resp = '#';
   } else if (event < 16) {
      resp = 'A' + (event - 12);
   } else if (event < 17) {
      resp = 'X';
   }
   if ((!rtp->resp && power) || (rtp->resp && (rtp->resp != resp))) {
      rtp->resp = resp;
      /* Why we should care on DTMF compensation at reception? */
      if (!ast_test_flag(rtp, FLAG_DTMF_COMPENSATE)) {
         f = create_dtmf_frame(rtp, AST_FRAME_DTMF_BEGIN);
         rtp->dtmfsamples = 0;
      }
   } else if ((rtp->resp == resp) && !power) {
      f = create_dtmf_frame(rtp, AST_FRAME_DTMF_END);
      f->samples = rtp->dtmfsamples * (rtp->lastrxformat ? (rtp_get_rate(rtp->lastrxformat) / 1000) : 8);
      rtp->resp = 0;
   } else if (rtp->resp == resp)
      rtp->dtmfsamples += 20 * (rtp->lastrxformat ? (rtp_get_rate(rtp->lastrxformat) / 1000) : 8);
   rtp->dtmf_timeout = dtmftimeout;
   return f;
}
static void process_rfc2833 ( struct ast_rtp rtp,
unsigned char *  data,
int  len,
unsigned int  seqno,
unsigned int  timestamp,
struct frame_list frames 
) [static]

Process RTP DTMF and events according to RFC 2833.

RFC 2833 is "RTP Payload for DTMF Digits, Telephony Tones and Telephony Signals".

Parameters:
rtp
data
len
seqno
timestamp
frames
Returns:

Definition at line 1014 of file rtp.c.

References ast_debug, AST_FRAME_DTMF_BEGIN, AST_FRAME_DTMF_END, ast_frdup(), AST_LIST_INSERT_TAIL, ast_log(), ast_samp2tv(), ast_test_flag, ast_tv(), ast_tvdiff_ms(), create_dtmf_frame(), ast_rtp::dtmf_duration, ast_rtp::dtmf_timeout, ast_rtp::dtmfsamples, dtmftimeout, f, FLAG_DTMF_COMPENSATE, ast_rtp::lastevent, ast_frame::len, LOG_DEBUG, option_debug, ast_rtp::resp, rtp_get_rate(), ast_frame::samples, ast_frame::seqno, and ast_frame::subclass.

Referenced by ast_rtp_read().

{
   unsigned int event;
   unsigned int event_end;
   unsigned int samples;
   char resp = 0;
   struct ast_frame *f = NULL;

   /* Figure out event, event end, and samples */
   event = ntohl(*((unsigned int *)(data)));
   event >>= 24;
   event_end = ntohl(*((unsigned int *)(data)));
   event_end <<= 8;
   event_end >>= 24;
   samples = ntohl(*((unsigned int *)(data)));
   samples &= 0xFFFF;

   /* Print out debug if turned on */
   if (rtpdebug || option_debug > 2)
      ast_debug(0, "- RTP 2833 Event: %08x (len = %d)\n", event, len);

   /* Figure out what digit was pressed */
   if (event < 10) {
      resp = '0' + event;
   } else if (event < 11) {
      resp = '*';
   } else if (event < 12) {
      resp = '#';
   } else if (event < 16) {
      resp = 'A' + (event - 12);
   } else if (event < 17) {   /* Event 16: Hook flash */
      resp = 'X'; 
   } else {
      /* Not a supported event */
      ast_log(LOG_DEBUG, "Ignoring RTP 2833 Event: %08x. Not a DTMF Digit.\n", event);
      return;
   }

   if (ast_test_flag(rtp, FLAG_DTMF_COMPENSATE)) {
      if ((rtp->lastevent != timestamp) || (rtp->resp && rtp->resp != resp)) {
         rtp->resp = resp;
         rtp->dtmf_timeout = 0;
         f = ast_frdup(create_dtmf_frame(rtp, AST_FRAME_DTMF_END));
         f->len = 0;
         rtp->lastevent = timestamp;
         AST_LIST_INSERT_TAIL(frames, f, frame_list);
      }
   } else {
      /*  The duration parameter measures the complete
          duration of the event (from the beginning) - RFC2833.
          Account for the fact that duration is only 16 bits long
          (about 8 seconds at 8000 Hz) and can wrap is digit
          is hold for too long. */
      unsigned int new_duration = rtp->dtmf_duration;
      unsigned int last_duration = new_duration & 0xFFFF;

      if (last_duration > 64000 && samples < last_duration)
         new_duration += 0xFFFF + 1;
      new_duration = (new_duration & ~0xFFFF) | samples;
      /* The second portion of this check is to not mistakenly
       * stop accepting DTMF if the seqno rolls over beyond
       * 65535.
       */
      if (rtp->lastevent > seqno && rtp->lastevent - seqno < 50) {
         /* Out of order frame. Processing this can cause us to
          * improperly duplicate incoming DTMF, so just drop
          * this.
          */
         return;
      }

      if (event_end & 0x80) {
         /* End event */
         if ((rtp->lastevent != seqno) && rtp->resp) {
            rtp->dtmf_duration = new_duration;
            f = ast_frdup(create_dtmf_frame(rtp, AST_FRAME_DTMF_END));
            f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass)), ast_tv(0, 0));
            rtp->resp = 0;
            rtp->dtmf_duration = rtp->dtmf_timeout = 0;
            AST_LIST_INSERT_TAIL(frames, f, frame_list);
         }
      } else {
         /* Begin/continuation */

         if (rtp->resp && rtp->resp != resp) {
            /* Another digit already began. End it */
            f = ast_frdup(create_dtmf_frame(rtp, AST_FRAME_DTMF_END));
            f->len = ast_tvdiff_ms(ast_samp2tv(rtp->dtmf_duration, rtp_get_rate(f->subclass)), ast_tv(0, 0));
            rtp->resp = 0;
            rtp->dtmf_duration = rtp->dtmf_timeout = 0;
            AST_LIST_INSERT_TAIL(frames, f, frame_list);
         }


         if (rtp->resp) {
            /* Digit continues */
            rtp->dtmf_duration = new_duration;
         } else {
            /* New digit began */
            rtp->resp = resp;
            f = ast_frdup(create_dtmf_frame(rtp, AST_FRAME_DTMF_BEGIN));
            rtp->dtmf_duration = samples;
            AST_LIST_INSERT_TAIL(frames, f, frame_list);
         }

         rtp->dtmf_timeout = timestamp + rtp->dtmf_duration + dtmftimeout;
      }

      rtp->lastevent = seqno;
   }

   rtp->dtmfsamples = samples;
}
static struct ast_frame* process_rfc3389 ( struct ast_rtp rtp,
unsigned char *  data,
int  len 
) [static, read]

Process Comfort Noise RTP.

This is incomplete at the moment.

Definition at line 1134 of file rtp.c.

References ast_debug, AST_FRAME_CNG, AST_FRIENDLY_OFFSET, ast_inet_ntoa(), ast_log(), ast_set_flag, ast_test_flag, ast_frame::data, ast_frame::datalen, ast_frame::delivery, ast_rtp::f, f, FLAG_3389_WARNING, ast_frame::frametype, ast_rtp::lastrxformat, LOG_NOTICE, ast_frame::offset, ast_frame::ptr, ast_rtp::rawdata, ast_frame::samples, ast_frame::subclass, and ast_rtp::them.

Referenced by ast_rtp_read().

{
   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 20ms or anything */
   if (rtpdebug)
      ast_debug(0, "- RTP 3389 Comfort noise event: Level %d (len = %d)\n", rtp->lastrxformat, len);

   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",
         ast_inet_ntoa(rtp->them.sin_addr));
      ast_set_flag(rtp, FLAG_3389_WARNING);
   }
   
   /* Must have at least one byte */
   if (!len)
      return NULL;
   if (len < 24) {
      rtp->f.data.ptr = rtp->rawdata + AST_FRIENDLY_OFFSET;
      rtp->f.datalen = len - 1;
      rtp->f.offset = AST_FRIENDLY_OFFSET;
      memcpy(rtp->f.data.ptr, data + 1, len - 1);
   } else {
      rtp->f.data.ptr = NULL;
      rtp->f.offset = 0;
      rtp->f.datalen = 0;
   }
   rtp->f.frametype = AST_FRAME_CNG;
   rtp->f.subclass = data[0] & 0x7f;
   rtp->f.samples = 0;
   rtp->f.delivery.tv_usec = rtp->f.delivery.tv_sec = 0;
   f = &rtp->f;
   return f;
}
void red_buffer_t140 ( struct ast_rtp rtp,
struct ast_frame f 
)

Buffer t140 from chan_sip.

Buffer t.140 data.

Parameters:
rtp
fframe

Definition at line 4981 of file rtp.c.

References rtp_red::buf_data, ast_frame::data, ast_frame::datalen, ast_frame::ptr, ast_rtp::red, rtp_red::t140, and ast_frame::ts.

Referenced by sip_write().

{
   if (f->datalen > -1) {
      struct rtp_red *red = rtp->red;
      memcpy(&red->buf_data[red->t140.datalen], f->data.ptr, f->datalen);
      red->t140.datalen += f->datalen;
      red->t140.ts = f->ts;
   }
}
static struct ast_frame * red_t140_to_red ( struct rtp_red red) [static, read]

Construct a redundant frame.

Parameters:
redredundant data structure

Definition at line 4898 of file rtp.c.

References ast_frame::data, ast_frame::datalen, rtp_red::hdrlen, rtp_red::len, rtp_red::num_gen, ast_frame::ptr, rtp_red::t140, and rtp_red::t140red.

Referenced by ast_rtp_write().

                                                              {
   unsigned char *data = red->t140red.data.ptr;
   int len = 0;
   int i;

   /* replace most aged generation */
   if (red->len[0]) {
      for (i = 1; i < red->num_gen+1; i++)
         len += red->len[i];

      memmove(&data[red->hdrlen], &data[red->hdrlen+red->len[0]], len); 
   }
   
   /* Store length of each generation and primary data length*/
   for (i = 0; i < red->num_gen; i++)
      red->len[i] = red->len[i+1];
   red->len[i] = red->t140.datalen;
   
   /* write each generation length in red header */
   len = red->hdrlen;
   for (i = 0; i < red->num_gen; i++)
      len += data[i*4+3] = red->len[i];
   
   /* add primary data to buffer */
   memcpy(&data[len], red->t140.data.ptr, red->t140.datalen); 
   red->t140red.datalen = len + red->t140.datalen;
   
   /* no primary data and no generations to send */
   if (len == red->hdrlen && !red->t140.datalen)
      return NULL;

   /* reset t.140 buffer */
   red->t140.datalen = 0; 
   
   return &red->t140red;
}
static int red_write ( const void *  data) [static]

Write t140 redundacy frame.

Parameters:
dataprimary data to be buffered

Definition at line 4886 of file rtp.c.

References ast_rtp_write(), ast_rtp::red, and rtp_red::t140.

Referenced by rtp_red_init().

{
   struct ast_rtp *rtp = (struct ast_rtp*) data;
   
   ast_rtp_write(rtp, &rtp->red->t140); 

   return 1;   
}
static int rtcp_debug_test_addr ( struct sockaddr_in *  addr) [inline, static]

Definition at line 909 of file rtp.c.

References rtcpdebugaddr.

Referenced by ast_rtcp_read(), ast_rtcp_write_rr(), ast_rtcp_write_sr(), and ast_rtp_destroy().

{
   if (rtcpdebug == 0)
      return 0;
   if (rtcpdebugaddr.sin_addr.s_addr) {
      if (((ntohs(rtcpdebugaddr.sin_port) != 0)
           && (rtcpdebugaddr.sin_port != addr->sin_port))
          || (rtcpdebugaddr.sin_addr.s_addr != addr->sin_addr.s_addr))
         return 0;
   }
   return 1;
}
static char* rtcp_do_debug_ip ( struct ast_cli_args a) [static]

Definition at line 4640 of file rtp.c.

References ast_cli_args::argv, ast_cli(), ast_gethostbyname(), ast_inet_ntoa(), CLI_FAILURE, CLI_SUCCESS, ast_cli_args::fd, hp, and rtcpdebugaddr.

Referenced by handle_cli_rtcp_set_debug().

{
   struct hostent *hp;
   struct ast_hostent ahp;
   int port = 0;
   char *p, *arg;

   arg = a->argv[4];
   p = strstr(arg, ":");
   if (p) {
      *p = '\0';
      p++;
      port = atoi(p);
   }
   hp = ast_gethostbyname(arg, &ahp);
   if (hp == NULL) {
      ast_cli(a->fd, "Lookup failed for '%s'\n", arg);
      return CLI_FAILURE;
   }
   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(a->fd, "RTCP Debugging Enabled for IP: %s\n", ast_inet_ntoa(rtcpdebugaddr.sin_addr));
    } else {
      ast_cli(a->fd, "RTCP Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(rtcpdebugaddr.sin_addr), port);
   }
   rtcpdebug = 1;
   return CLI_SUCCESS;
}
static void rtp_bridge_lock ( struct ast_rtp rtp) [static]
static void rtp_bridge_unlock ( struct ast_rtp rtp) [static]
static int rtp_debug_test_addr ( struct sockaddr_in *  addr) [inline, static]

Definition at line 896 of file rtp.c.

References rtpdebugaddr.

Referenced by ast_rtp_raw_write(), ast_rtp_read(), ast_rtp_sendcng(), ast_rtp_senddigit_begin(), ast_rtp_senddigit_continuation(), ast_rtp_senddigit_end_with_duration(), and bridge_p2p_rtp_write().

{
   if (rtpdebug == 0)
      return 0;
   if (rtpdebugaddr.sin_addr.s_addr) {
      if (((ntohs(rtpdebugaddr.sin_port) != 0)
           && (rtpdebugaddr.sin_port != addr->sin_port))
          || (rtpdebugaddr.sin_addr.s_addr != addr->sin_addr.s_addr))
         return 0;
   }
   return 1;
}
static char* rtp_do_debug_ip ( struct ast_cli_args a) [static]

Definition at line 4609 of file rtp.c.

References ast_cli_args::argv, ast_cli(), ast_gethostbyname(), ast_inet_ntoa(), CLI_FAILURE, CLI_SUCCESS, ast_cli_args::fd, hp, and rtpdebugaddr.

Referenced by handle_cli_rtp_set_debug().

{
   struct hostent *hp;
   struct ast_hostent ahp;
   int port = 0;
   char *p, *arg;

   arg = a->argv[4];
   p = strstr(arg, ":");
   if (p) {
      *p = '\0';
      p++;
      port = atoi(p);
   }
   hp = ast_gethostbyname(arg, &ahp);
   if (hp == NULL) {
      ast_cli(a->fd, "Lookup failed for '%s'\n", arg);
      return CLI_FAILURE;
   }
   rtpdebugaddr.sin_family = AF_INET;
   memcpy(&rtpdebugaddr.sin_addr, hp->h_addr, sizeof(rtpdebugaddr.sin_addr));
   rtpdebugaddr.sin_port = htons(port);
   if (port == 0) {
      ast_cli(a->fd, "RTP Debugging Enabled for IP: %s\n", ast_inet_ntoa(rtpdebugaddr.sin_addr));
    } else {
      ast_cli(a->fd, "RTP Debugging Enabled for IP: %s:%d\n", ast_inet_ntoa(rtpdebugaddr.sin_addr), port);
   }
   rtpdebug = 1;
   return CLI_SUCCESS;
}
static int rtp_get_rate ( int  subclass) [static]
int rtp_red_init ( struct ast_rtp rtp,
int  ti,
int *  red_data_pt,
int  num_gen 
)

Initialize t140 redundancy.

Initalize t.140 redudancy.

Parameters:
rtp
tibuffer t140 for ti (msecs) before sending redundant frame
red_data_ptPayloadtypes for primary- and generation-data
num_gennumbers of generations (primary generation not encounted)

Definition at line 4942 of file rtp.c.

References ast_calloc, AST_FORMAT_T140RED, AST_FRAME_TEXT, ast_sched_add(), rtp_red::buf_data, ast_frame::data, ast_frame::datalen, ast_frame::frametype, rtp_red::hdrlen, rtp_red::num_gen, rtp_red::prev_ts, rtp_red::pt, ast_frame::ptr, ast_rtp::red, red_write(), ast_rtp::sched, rtp_red::schedid, ast_frame::subclass, rtp_red::t140, rtp_red::t140red, rtp_red::t140red_data, rtp_red::ti, and ast_frame::ts.

Referenced by process_sdp().

{
   struct rtp_red *r;
   int x;
   
   if (!(r = ast_calloc(1, sizeof(struct rtp_red))))
      return -1;

   r->t140.frametype = AST_FRAME_TEXT;
   r->t140.subclass = AST_FORMAT_T140RED;
   r->t140.data.ptr = &r->buf_data; 

   r->t140.ts = 0;
   r->t140red = r->t140;
   r->t140red.data.ptr = &r->t140red_data;
   r->t140red.datalen = 0;
   r->ti = ti;
   r->num_gen = num_gen;
   r->hdrlen = num_gen * 4 + 1;
   r->prev_ts = 0;

   for (x = 0; x < num_gen; x++) {
      r->pt[x] = red_data_pt[x];
      r->pt[x] |= 1 << 7; /* mark redundant generations pt */ 
      r->t140red_data[x*4] = r->pt[x];
   }
   r->t140red_data[x*4] = r->pt[x] = red_data_pt[x]; /* primary pt */
   r->schedid = ast_sched_add(rtp->sched, ti, red_write, rtp);
   rtp->red = r;

   r->t140.datalen = 0;
   
   return 0;
}
static int rtp_socket ( const char *  type) [static]

Open RTP or RTCP socket for a session. Print a message on failure.

Definition at line 2516 of file rtp.c.

References ast_log(), errno, LOG_WARNING, and s.

Referenced by ast_rtcp_new(), and ast_rtp_new_with_bindaddr().

{
   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);
      fcntl(s, F_SETFL, flags | O_NONBLOCK);
#ifdef SO_NO_CHECK
      if (nochecksums)
         setsockopt(s, SOL_SOCKET, SO_NO_CHECK, &nochecksums, sizeof(nochecksums));
#endif
   }
   return s;
}
static int rtpread ( int *  id,
int  fd,
short  events,
void *  cbdata 
) [static]

Definition at line 1170 of file rtp.c.

References ast_rtp_read(), ast_rtp::callback, ast_rtp::data, and f.

Referenced by ast_rtp_new_with_bindaddr(), and p2p_callback_disable().

{
   struct ast_rtp *rtp = cbdata;
   struct ast_frame *f;
   f = ast_rtp_read(rtp);
   if (f) {
      if (rtp->callback)
         rtp->callback(rtp, f, rtp->data);
   }
   return 1;
}
static double stddev_compute ( double  stddev,
double  sample,
double  normdev,
double  normdev_curent,
unsigned int  sample_count 
) [static]

Definition at line 850 of file rtp.c.

References SQUARE.

Referenced by ast_rtcp_read(), ast_rtcp_write_rr(), and calc_rxstamp().

{
/*
      for the formula check http://www.cs.umd.edu/~austinjp/constSD.pdf
      return sqrt( (sample_count*pow(stddev,2) + sample_count*pow((sample-normdev)/(sample_count+1),2) + pow(sample-normdev_curent,2)) / (sample_count+1));
      we can compute the sigma^2 and that way we would have to do the sqrt only 1 time at the end and would save another pow 2 compute
      optimized formula
*/
#define SQUARE(x) ((x) * (x))

   stddev = sample_count * stddev;
   sample_count++;

   return stddev + 
          ( sample_count * SQUARE( (sample - normdev) / sample_count ) ) + 
          ( SQUARE(sample - normdev_curent) / sample_count );

#undef SQUARE
}
static const char* stun_attr2str ( int  msg) [static]

helper function to print attribute names

Definition at line 393 of file rtp.c.

References STUN_CHANGE_REQUEST, STUN_CHANGED_ADDRESS, STUN_ERROR_CODE, STUN_MAPPED_ADDRESS, STUN_MESSAGE_INTEGRITY, STUN_PASSWORD, STUN_REFLECTED_FROM, STUN_RESPONSE_ADDRESS, STUN_SOURCE_ADDRESS, STUN_UNKNOWN_ATTRIBUTES, and STUN_USERNAME.

Referenced by stun_handle_packet(), and stun_process_attr().

{
   switch (msg) {
   case STUN_MAPPED_ADDRESS:
      return "Mapped Address";
   case STUN_RESPONSE_ADDRESS:
      return "Response Address";
   case STUN_CHANGE_REQUEST:
      return "Change Request";
   case STUN_SOURCE_ADDRESS:
      return "Source Address";
   case STUN_CHANGED_ADDRESS:
      return "Changed Address";
   case STUN_USERNAME:
      return "Username";
   case STUN_PASSWORD:
      return "Password";
   case STUN_MESSAGE_INTEGRITY:
      return "Message Integrity";
   case STUN_ERROR_CODE:
      return "Error Code";
   case STUN_UNKNOWN_ATTRIBUTES:
      return "Unknown Attributes";
   case STUN_REFLECTED_FROM:
      return "Reflected From";
   }
   return "Non-RFC3489 Attribute";
}
static int stun_get_mapped ( struct stun_attr attr,
void *  arg 
) [static]

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.

Definition at line 610 of file rtp.c.

References stun_addr::addr, stun_attr::attr, stun_attr::len, stun_addr::port, and STUN_MAPPED_ADDRESS.

Referenced by ast_stun_request().

{
   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;
}
static int stun_handle_packet ( int  s,
struct sockaddr_in *  src,
unsigned char *  data,
size_t  len,
stun_cb_f stun_cb,
void *  arg 
) [static]

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. If a callback is specified, invoke it with the attribute.

Definition at line 512 of file rtp.c.

References append_attr_address(), append_attr_string(), ast_debug, ast_verbose(), stun_attr::attr, stun_header::id, stun_header::ies, stun_attr::len, stun_header::msglen, stun_header::msgtype, STUN_ACCEPT, stun_attr2str(), STUN_BINDREQ, STUN_BINDRESP, STUN_IGNORE, STUN_MAPPED_ADDRESS, stun_msg2str(), stun_process_attr(), stun_send(), STUN_USERNAME, and stun_state::username.

Referenced by ast_rtp_read(), and ast_stun_request().

{
   struct stun_header *hdr = (struct stun_header *)data;
   struct stun_attr *attr;
   struct stun_state st;
   int ret = STUN_IGNORE;  
   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.
    */
   if (len < sizeof(struct stun_header)) {
      ast_debug(1, "Runt STUN packet (only %d, wanting at least %d)\n", (int) len, (int) sizeof(struct stun_header));
      return -1;
   }
   len -= sizeof(struct stun_header);
   data += sizeof(struct stun_header);
   x = ntohs(hdr->msglen); /* len as advertised in the message */
   if (stundebug)
      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);
   } else
      len = x;
   memset(&st, 0, sizeof(st));
   while (len) {
      if (len < sizeof(struct stun_attr)) {
         ast_debug(1, "Runt Attribute (got %d, expecting %d)\n", (int)len, (int) sizeof(struct stun_attr));
         break;
      }
      attr = (struct stun_attr *)data;
      /* 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);
         break;
      }
      if (stun_cb)
         stun_cb(attr, arg);
      if (stun_process_attr(&st, attr)) {
         ast_debug(1, "Failed to handle attribute %s (%04x)\n", stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr));
         break;
      }
      /* Clear attribute id: in case previous entry was a string,
       * this will act as the terminator for the string.
       */
      attr->attr = 0;
      data += x;
      len -= x;
   }
   /* 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
    */
   *data = '\0';

   /* 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;
      switch (ntohs(hdr->msgtype)) {
      case STUN_BINDREQ:
         if (stundebug)
            ast_verbose("STUN Bind Request, username: %s\n", 
                   st.username ? st.username : "<none>");
         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;
}
static const char* stun_msg2str ( int  msg) [static]

helper function to print message names

Definition at line 373 of file rtp.c.

References STUN_BINDERR, STUN_BINDREQ, STUN_BINDRESP, STUN_SECERR, STUN_SECREQ, and STUN_SECRESP.

Referenced by stun_handle_packet().

{
   switch (msg) {
   case STUN_BINDREQ:
      return "Binding Request";
   case STUN_BINDRESP:
      return "Binding Response";
   case STUN_BINDERR:
      return "Binding Error Response";
   case STUN_SECREQ:
      return "Shared Secret Request";
   case STUN_SECRESP:
      return "Shared Secret Response";
   case STUN_SECERR:
      return "Shared Secret Error Response";
   }
   return "Non-RFC3489 Message";
}
static int stun_process_attr ( struct stun_state state,
struct stun_attr attr 
) [static]

Definition at line 428 of file rtp.c.

References ast_verbose(), stun_attr::attr, stun_attr::len, stun_state::password, stun_attr2str(), STUN_PASSWORD, STUN_USERNAME, stun_state::username, and stun_attr::value.

Referenced by stun_handle_packet().

{
   if (stundebug)
      ast_verbose("Found STUN Attribute %s (%04x), length %d\n",
             stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
   switch (ntohs(attr->attr)) {
   case STUN_USERNAME:
      state->username = (const char *) (attr->value);
      break;
   case STUN_PASSWORD:
      state->password = (const char *) (attr->value);
      break;
   default:
      if (stundebug)
         ast_verbose("Ignoring STUN attribute %s (%04x), length %d\n", 
                stun_attr2str(ntohs(attr->attr)), ntohs(attr->attr), ntohs(attr->len));
   }
   return 0;
}
static void stun_req_id ( struct stun_header req) [static]

helper function to generate a random request id

Definition at line 489 of file rtp.c.

References ast_random(), stun_trans_id::id, and stun_header::id.

Referenced by ast_stun_request().

{
   int x;
   for (x = 0; x < 4; x++)
      req->id.id[x] = ast_random();
}
static int stun_send ( int  s,
struct sockaddr_in *  dst,
struct stun_header resp 
) [static]

wrapper to send an STUN message

Definition at line 482 of file rtp.c.

References stun_header::msglen.

Referenced by ast_stun_request(), and stun_handle_packet().

{
   return sendto(s, resp, ntohs(resp->msglen) + sizeof(*resp), 0,
            (struct sockaddr *)dst, sizeof(*dst));
}
static void timeval2ntp ( struct timeval  tv,
unsigned int *  msw,
unsigned int *  lsw 
) [static]

Definition at line 707 of file rtp.c.

References sec.

Referenced by ast_rtcp_read(), and ast_rtcp_write_sr().

{
   unsigned int sec, usec, frac;
   sec = when.tv_sec + 2208988800u; /* Sec between 1900 and 1970 */
   usec = when.tv_usec;
   frac = (usec << 12) + (usec << 8) - ((usec * 3650) >> 6);
   *msw = sec;
   *lsw = frac;
}

Variable Documentation

struct ast_cli_entry cli_rtp[] [static]

Definition at line 4792 of file rtp.c.

int dtmftimeout = DEFAULT_DTMF_TIMEOUT [static]

Definition at line 69 of file rtp.c.

Referenced by process_cisco_dtmf(), and process_rfc2833().

struct protos protos [static]
int rtcpdebug [static]

Are we debugging RTCP?

Definition at line 74 of file rtp.c.

struct sockaddr_in rtcpdebugaddr [static]

Debug RTCP packets to/from this host

Definition at line 79 of file rtp.c.

Referenced by handle_cli_rtcp_set_debug(), rtcp_debug_test_addr(), and rtcp_do_debug_ip().

int rtcpinterval = RTCP_DEFAULT_INTERVALMS [static]

Time between rtcp reports in millisecs

Definition at line 76 of file rtp.c.

Referenced by ast_rtcp_calc_interval().

int rtcpstats [static]

Are we debugging RTCP?

Definition at line 75 of file rtp.c.

int rtpdebug [static]

Are we debugging?

Definition at line 73 of file rtp.c.

struct sockaddr_in rtpdebugaddr [static]

Debug packets to/from this host

Definition at line 78 of file rtp.c.

Referenced by handle_cli_rtp_set_debug(), rtp_debug_test_addr(), and rtp_do_debug_ip().

int rtpend = 31000 [static]

Last port for RTP sessions (set in rtp.conf)

Definition at line 72 of file rtp.c.

int rtpstart = 5000 [static]

First port for RTP sessions (set in rtp.conf)

Definition at line 71 of file rtp.c.

Referenced by ast_rtp_new_with_bindaddr().

struct rtpPayloadType static_RTP_PT[MAX_RTP_PT] [static]

Mapping between Asterisk codecs and rtp payload types.

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

See http://www.iana.org/assignments/rtp-parameters for a list of assigned values

Definition at line 2000 of file rtp.c.

int strictrtp [static]

Definition at line 83 of file rtp.c.

int stundebug [static]

Are we debugging stun?

Definition at line 77 of file rtp.c.