Tue Aug 24 2010 19:42:00

Asterisk developer's documentation


Data Structures | Defines | Typedefs | Enumerations | Functions

rtp.h File Reference

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

#include "asterisk/network.h"
#include "asterisk/frame.h"
#include "asterisk/io.h"
#include "asterisk/sched.h"
#include "asterisk/channel.h"
#include "asterisk/linkedlists.h"
Include dependency graph for rtp.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  ast_rtp_protocol
 This is the structure that binds a channel (SIP/Jingle/H.323) to the RTP subsystem. More...
struct  ast_rtp_quality
 RTCP quality report storage. More...
struct  rtpPayloadType
 The value of each payload format mapping: More...

Defines

#define AST_RTP_CISCO_DTMF   (1 << 2)
#define AST_RTP_CN   (1 << 1)
#define AST_RTP_DTMF   (1 << 0)
#define AST_RTP_MAX   AST_RTP_CISCO_DTMF
#define FLAG_3389_WARNING   (1 << 0)
#define MAX_RTP_PT   256
#define RED_MAX_GENERATION   5

Typedefs

typedef int(* ast_rtp_callback )(struct ast_rtp *rtp, struct ast_frame *f, void *data)

Enumerations

enum  ast_rtp_get_result { AST_RTP_GET_FAILED = 0, AST_RTP_TRY_PARTIAL, AST_RTP_TRY_NATIVE }
enum  ast_rtp_options { AST_RTP_OPT_G726_NONSTANDARD = (1 << 0) }
enum  ast_rtp_qos_vars {
  AST_RTP_TXCOUNT, AST_RTP_RXCOUNT, AST_RTP_TXJITTER, AST_RTP_RXJITTER,
  AST_RTP_RXPLOSS, AST_RTP_TXPLOSS, AST_RTP_RTT
}
 

Variables used in ast_rtcp_get function.

More...
enum  ast_rtp_quality_type { RTPQOS_SUMMARY = 0, RTPQOS_JITTER, RTPQOS_LOSS, RTPQOS_RTT }

Functions

int ast_rtcp_fd (struct ast_rtp *rtp)
struct ast_frameast_rtcp_read (struct ast_rtp *rtp)
int ast_rtcp_send_h261fur (void *data)
 Send an H.261 fast update request. Some devices need this rather than the XML message in SIP.
size_t ast_rtp_alloc_size (void)
 Get the amount of space required to hold an RTP session.
int ast_rtp_bridge (struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
 The RTP bridge.
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, int isAstFormat, 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 (int isAstFormat, 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 in)
 Initializate a RTP session using an in_addr structure.
int ast_rtp_proto_register (struct ast_rtp_protocol *proto)
 Register an RTP channel client.
void ast_rtp_proto_unregister (struct ast_rtp_protocol *proto)
 Unregister an RTP channel client.
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.
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.
int ast_rtp_senddigit_end (struct ast_rtp *rtp, char digit)
 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)
 Activate payload type.
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)
 Set payload type to a known MIME media type for a codec with a specific sample rate.
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 tos, int cos, 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 STUN request for an RTP socket Deprecated, this is just a wrapper for ast_rtp_stun_request().
void ast_rtp_unset_m_type (struct ast_rtp *rtp, int pt)
 clear payload 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.
void red_buffer_t140 (struct ast_rtp *rtp, struct ast_frame *f)
 Buffer t.140 data.
int rtp_red_init (struct ast_rtp *rtp, int ti, int *pt, int num_gen)
 Initalize t.140 redudancy.

Detailed Description

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

RTP is defined in RFC 3550.

Definition in file rtp.h.


Define Documentation

#define AST_RTP_CISCO_DTMF   (1 << 2)

DTMF (Cisco Proprietary)

Definition at line 47 of file rtp.h.

Referenced by ast_rtp_read().

#define AST_RTP_CN   (1 << 1)

'Comfort Noise' (RFC3389)

Definition at line 45 of file rtp.h.

Referenced by ast_rtp_read(), and ast_rtp_sendcng().

#define AST_RTP_DTMF   (1 << 0)

DTMF (RFC2833)

Definition at line 43 of file rtp.h.

Referenced by add_noncodec_to_sdp(), add_sdp(), ast_rtp_read(), ast_rtp_senddigit_begin(), bridge_p2p_rtp_write(), and process_sdp().

#define AST_RTP_MAX   AST_RTP_CISCO_DTMF

Maximum RTP-specific code

Definition at line 49 of file rtp.h.

#define FLAG_3389_WARNING   (1 << 0)

Definition at line 57 of file rtp.h.

#define MAX_RTP_PT   256

Maxmum number of payload defintions for a RTP session

Definition at line 52 of file rtp.h.

Referenced by ast_rtp_codec_getformat(), ast_rtp_lookup_pt(), ast_rtp_set_m_type(), ast_rtp_set_rtpmap_type_rate(), and ast_rtp_unset_m_type().

#define RED_MAX_GENERATION   5

T.140 Redundancy Maxium number of generations

Definition at line 55 of file rtp.h.

Referenced by process_sdp_a_text().


Typedef Documentation

typedef int(* ast_rtp_callback)(struct ast_rtp *rtp, struct ast_frame *f, void *data)

RTP callback structure

Definition at line 130 of file rtp.h.


Enumeration Type Documentation

Enumerator:
AST_RTP_GET_FAILED 

Failed to find the RTP structure

AST_RTP_TRY_PARTIAL 

RTP structure exists but true native bridge can not occur so try partial

AST_RTP_TRY_NATIVE 

RTP structure exists and native bridge can occur

Definition at line 63 of file rtp.h.

                        {
   /*! Failed to find the RTP structure */
   AST_RTP_GET_FAILED = 0,
   /*! RTP structure exists but true native bridge can not occur so try partial */
   AST_RTP_TRY_PARTIAL,
   /*! RTP structure exists and native bridge can occur */
   AST_RTP_TRY_NATIVE,
};

Enumerator:
AST_RTP_OPT_G726_NONSTANDARD 

Definition at line 59 of file rtp.h.

                     {
   AST_RTP_OPT_G726_NONSTANDARD = (1 << 0),
};

Variables used in ast_rtcp_get function.

Enumerator:
AST_RTP_TXCOUNT 
AST_RTP_RXCOUNT 
AST_RTP_TXJITTER 
AST_RTP_RXJITTER 
AST_RTP_RXPLOSS 
AST_RTP_TXPLOSS 
AST_RTP_RTT 

Definition at line 73 of file rtp.h.

                      {
   AST_RTP_TXCOUNT,
   AST_RTP_RXCOUNT,
   AST_RTP_TXJITTER,
   AST_RTP_RXJITTER,
   AST_RTP_RXPLOSS,
   AST_RTP_TXPLOSS,
   AST_RTP_RTT
};

Enumerator:
RTPQOS_SUMMARY 
RTPQOS_JITTER 
RTPQOS_LOSS 
RTPQOS_RTT 

Definition at line 109 of file rtp.h.

                          {
   RTPQOS_SUMMARY = 0,
   RTPQOS_JITTER,
   RTPQOS_LOSS,
   RTPQOS_RTT
};


Function Documentation

int ast_rtcp_fd ( struct ast_rtp rtp  ) 

Definition at line 724 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;
}

struct ast_frame* ast_rtcp_read ( struct ast_rtp rtp  )  [read]

Definition at line 1184 of file rtp.c.

References ast_rtcp::accumulated_transit, ast_rtcp::altthem, ast_assert, ast_debug, 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, ast_frame::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  ) 

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

Definition at line 3348 of file rtp.c.

References ast_rtcp_write(), 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;
}

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 495 of file rtp.c.

Referenced by process_sdp().

{
   return sizeof(struct ast_rtp);
}

int ast_rtp_bridge ( struct ast_channel c0,
struct ast_channel c1,
int  flags,
struct ast_frame **  fo,
struct ast_channel **  rc,
int  timeoutms 
)

The RTP bridge.

Definition at line 4447 of file rtp.c.

References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, 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 2694 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 3828 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 3823 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 3777 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, 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 3107 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 2116 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 2748 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 2364 of file rtp.c.

References rtpPayloadType::code, ast_rtp::current_RTP_PT, rtpPayloadType::isAstFormat, 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 2730 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 2869 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.

Since:
1.6.1

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

Definition at line 2803 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:
rtp An rtp structure to get qos information about.
qual An (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.
qtype The 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 3076 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 779 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 787 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 771 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 807 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 4868 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,
int  isAstFormat,
int  code 
)

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

Definition at line 2405 of file rtp.c.

References rtpPayloadType::code, ast_rtp::current_RTP_PT, rtpPayloadType::isAstFormat, 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 2478 of file rtp.c.

References ast_copy_string(), ast_rtp_lookup_mime_subtype(), format, 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 ( int  isAstFormat,
int  code,
enum ast_rtp_options  options 
)

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

Definition at line 2446 of file rtp.c.

References ARRAY_LEN, AST_FORMAT_G726_AAL2, 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 2383 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:
isAstFormat True if the value in the 'code' parameter is an AST_FORMAT value
code Format 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 2465 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 2202 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 2673 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 2564 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, 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 2686 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 2578 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, ast_rtp::io, ast_rtp::ioid, LOG_ERROR, ast_rtp::rtcp, rtp_socket(), rtpread(), ast_rtcp::s, ast_rtp::s, 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 an RTP channel client.

Definition at line 3945 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 an RTP channel client.

Definition at line 3937 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  ) 

Setting RTP payload types from lines in a SDP description:

Definition at line 2040 of file rtp.c.

References rtpPayloadType::code, ast_rtp::current_RTP_PT, rtpPayloadType::isAstFormat, 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 gtalk_alloc(), and process_sdp().

{
   int i;

   if (!rtp)
      return;

   rtp_bridge_lock(rtp);

   for (i = 0; i < MAX_RTP_PT; ++i) {
      rtp->current_RTP_PT[i].isAstFormat = 0;
      rtp->current_RTP_PT[i].code = 0;
   }

   rtp->rtp_lookup_code_cache_isAstFormat = 0;
   rtp->rtp_lookup_code_cache_code = 0;
   rtp->rtp_lookup_code_cache_result = 0;

   rtp_bridge_unlock(rtp);
}

void ast_rtp_pt_copy ( struct ast_rtp dest,
struct ast_rtp src 
)
void ast_rtp_pt_default ( struct ast_rtp rtp  ) 
struct ast_frame* ast_rtp_read ( struct ast_rtp rtp  )  [read]

Definition at line 1578 of file rtp.c.

References ast_rtp::altthem, ast_assert, ast_codec_get_samples(), 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_DTMF_END, 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, 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(), 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 4862 of file rtp.c.

References __ast_rtp_reload().

{
   return __ast_rtp_reload(1);
}

void ast_rtp_reset ( struct ast_rtp rtp  ) 
int ast_rtp_sendcng ( struct ast_rtp rtp,
int  level 
)

generate comfort noice (CNG)

Definition at line 3623 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 3190 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;
}

int ast_rtp_senddigit_end ( struct ast_rtp rtp,
char  digit 
)

Send end packets for DTMF.

Definition at line 3292 of file rtp.c.

References ast_inet_ntoa(), ast_log(), 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_end(), oh323_digit_end(), and sip_senddigit_end().

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

   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:
rtp The RTP structure we wish to set up an alternate host/port on
alt The address information for the alternate media source
Return values:
void 

Definition at line 2720 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 797 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 792 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 
)

Activate payload type.

Definition at line 2279 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 2705 of file rtp.c.

References ast_rtp::rtcp, ast_rtp::rxseqno, 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 759 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 765 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:
rtp RTP structure to modify
pt Payload type entry to modify
mimeType top-level MIME type of media stream (typically "audio", "video", "text", etc.)
mimeSubtype MIME subtype of media stream (typically a codec name)
options Zero 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:
0 on success
-1 if the payload type is out of range
-2 if the mimeType/mimeSubtype combination was not found

Definition at line 2355 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 
)

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

Parameters:
rtp RTP structure to modify
pt Payload type entry to modify
mimeType top-level MIME type of media stream (typically "audio", "video", "text", etc.)
mimeSubtype MIME subtype of media stream (typically a codec name)
options Zero or more flags from the ast_rtp_options enum
sample_rate The sample rate of the media stream

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

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

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 2306 of file rtp.c.

References ARRAY_LEN, AST_FORMAT_G726, 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 753 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 746 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 2884 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 812 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 817 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 802 of file rtp.c.

References 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  tos,
int  cos,
char *  desc 
)

Definition at line 2681 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 822 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 2759 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 STUN request for an RTP socket Deprecated, this is just a wrapper for ast_rtp_stun_request().

Definition at line 701 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 
)

clear payload type

Definition at line 2291 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 3839 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.

Parameters:
s the socket used to send the request
dst the address of the STUN server
username if non null, add the username in the request
answer if non null, the function waits for a response and puts here the externally visible address.
Returns:
0 on success, other values on error. The interface it may change in the future.

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

Parameters:
s the socket used to send the request
dst the address of the STUN server
username if non null, add the username in the request
answer if 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 635 of file rtp.c.

References append_attr_string(), ast_log(), ast_select(), stun_header::ies, LOG_WARNING, stun_header::msglen, stun_header::msgtype, 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];
      fd_set rfds;
      struct timeval to = { 3, 0 }; /* timeout, make it configurable */
      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;
      FD_ZERO(&rfds);
      FD_SET(s, &rfds);
      res = ast_select(s + 1, &rfds, NULL, NULL, &to);
      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;
}

void red_buffer_t140 ( struct ast_rtp rtp,
struct ast_frame f 
)

Buffer t.140 data.

Buffer t.140 data.

Parameters:
rtp 
f frame

Definition at line 4972 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;
   }
}

int rtp_red_init ( struct ast_rtp rtp,
int  ti,
int *  red_data_pt,
int  num_gen 
)

Initalize t.140 redudancy.

Parameters:
ti time between each t140red frame is sent
red_pt payloadtype for RTP packet
pt payloadtype numbers for each generation including primary data
num_gen number of redundant generations, primary data excluded
Since:
1.6.1

Initalize t.140 redudancy.

Parameters:
rtp 
ti buffer t140 for ti (msecs) before sending redundant frame
red_data_pt Payloadtypes for primary- and generation-data
num_gen numbers of generations (primary generation not encounted)

Definition at line 4933 of file rtp.c.

References ast_calloc, 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;
}