Sat Sep 16 05:48:06 2006

Asterisk developer's documentation


rtp.h File Reference

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

#include "asterisk/frame.h"
#include "asterisk/io.h"
#include "asterisk/sched.h"
#include "asterisk/channel.h"
#include <netinet/in.h>

Go to the source code of this file.

Data Structures

struct  ast_rtp_protocol

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

Typedefs

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

Functions

int ast_rtcp_fd (struct ast_rtp *rtp)
ast_frameast_rtcp_read (struct ast_rtp *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)
void ast_rtp_destroy (struct ast_rtp *rtp)
int ast_rtp_fd (struct ast_rtp *rtp)
void ast_rtp_get_current_formats (struct ast_rtp *rtp, int *astFormats, int *nonAstFormats)
int ast_rtp_get_peer (struct ast_rtp *rtp, struct sockaddr_in *them)
void ast_rtp_get_us (struct ast_rtp *rtp, struct sockaddr_in *us)
void ast_rtp_init (void)
int ast_rtp_lookup_code (struct ast_rtp *rtp, int isAstFormat, int code)
char * ast_rtp_lookup_mime_multiple (char *buf, int size, const int capability, const int isAstFormat)
char * ast_rtp_lookup_mime_subtype (int isAstFormat, int code)
rtpPayloadType ast_rtp_lookup_pt (struct ast_rtp *rtp, int pt)
ast_rtpast_rtp_new (struct sched_context *sched, struct io_context *io, int rtcpenable, int callbackmode)
 Initializate a RTP session.
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.
void ast_rtp_offered_from_local (struct ast_rtp *rtp, int local)
int ast_rtp_proto_register (struct ast_rtp_protocol *proto)
void ast_rtp_proto_unregister (struct ast_rtp_protocol *proto)
void ast_rtp_pt_clear (struct ast_rtp *rtp)
void ast_rtp_pt_default (struct ast_rtp *rtp)
ast_frameast_rtp_read (struct ast_rtp *rtp)
void ast_rtp_reload (void)
void ast_rtp_reset (struct ast_rtp *rtp)
int ast_rtp_sendcng (struct ast_rtp *rtp, int level)
int ast_rtp_senddigit (struct ast_rtp *rtp, char digit)
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)
void ast_rtp_set_peer (struct ast_rtp *rtp, struct sockaddr_in *them)
void ast_rtp_set_rtpmap_type (struct ast_rtp *rtp, int pt, char *mimeType, char *mimeSubtype)
void ast_rtp_setnat (struct ast_rtp *rtp, int nat)
int ast_rtp_settos (struct ast_rtp *rtp, int tos)
void ast_rtp_stop (struct ast_rtp *rtp)
int ast_rtp_write (struct ast_rtp *rtp, struct ast_frame *f)


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 46 of file rtp.h.

Referenced by ast_rtp_read().

#define AST_RTP_CN   (1 << 1)

'Comfort Noise' (RFC3389)

Definition at line 44 of file rtp.h.

Referenced by ast_rtp_read(), and ast_rtp_sendcng().

#define AST_RTP_DTMF   (1 << 0)

DTMF (RFC2833)

Definition at line 42 of file rtp.h.

Referenced by add_noncodec_to_sdp(), ast_rtp_read(), ast_rtp_senddigit(), check_user_full(), create_addr(), create_addr_from_peer(), oh323_alloc(), oh323_request(), process_sdp(), and sip_alloc().

#define AST_RTP_MAX   AST_RTP_CISCO_DTMF

Maximum RTP-specific code

Definition at line 48 of file rtp.h.

Referenced by add_sdp(), and ast_rtp_lookup_mime_multiple().


Typedef Documentation

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

Definition at line 70 of file rtp.h.


Function Documentation

int ast_rtcp_fd ( struct ast_rtp rtp  ) 

Definition at line 158 of file rtp.c.

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

Referenced by sip_new().

00159 {
00160    if (rtp->rtcp)
00161       return rtp->rtcp->s;
00162    return -1;
00163 }

struct ast_frame* ast_rtcp_read ( struct ast_rtp rtp  ) 

Definition at line 370 of file rtp.c.

References AST_FRAME_NULL, ast_inet_ntoa(), ast_log(), CRASH, LOG_DEBUG, LOG_WARNING, ast_rtp::nat, option_debug, ast_rtp::rtcp, ast_rtcp::s, and ast_rtcp::them.

Referenced by sip_rtp_read().

00371 {
00372    static struct ast_frame null_frame = { AST_FRAME_NULL, };
00373    socklen_t len;
00374    int hdrlen = 8;
00375    int res;
00376    struct sockaddr_in sin;
00377    unsigned int rtcpdata[1024];
00378    char iabuf[INET_ADDRSTRLEN];
00379    
00380    if (!rtp || !rtp->rtcp)
00381       return &null_frame;
00382 
00383    len = sizeof(sin);
00384    
00385    res = recvfrom(rtp->rtcp->s, rtcpdata, sizeof(rtcpdata),
00386                0, (struct sockaddr *)&sin, &len);
00387    
00388    if (res < 0) {
00389       if (errno != EAGAIN)
00390          ast_log(LOG_WARNING, "RTP Read error: %s\n", strerror(errno));
00391       if (errno == EBADF)
00392          CRASH;
00393       return &null_frame;
00394    }
00395 
00396    if (res < hdrlen) {
00397       ast_log(LOG_WARNING, "RTP Read too short\n");
00398       return &null_frame;
00399    }
00400 
00401    if (rtp->nat) {
00402       /* Send to whoever sent to us */
00403       if ((rtp->rtcp->them.sin_addr.s_addr != sin.sin_addr.s_addr) ||
00404           (rtp->rtcp->them.sin_port != sin.sin_port)) {
00405          memcpy(&rtp->rtcp->them, &sin, sizeof(rtp->rtcp->them));
00406          if (option_debug || rtpdebug)
00407             ast_log(LOG_DEBUG, "RTCP NAT: Got RTCP from other end. Now sending to address %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
00408       }
00409    }
00410    if (option_debug)
00411       ast_log(LOG_DEBUG, "Got RTCP report of %d bytes\n", res);
00412    return &null_frame;
00413 }

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

Definition at line 1524 of file rtp.c.

References AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, AST_BRIDGE_FAILED, AST_BRIDGE_FAILED_NOWARN, AST_BRIDGE_RETRY, ast_log(), ast_mutex_lock(), ast_mutex_trylock(), ast_mutex_unlock(), ast_rtp_get_peer(), ast_test_flag, FLAG_NAT_ACTIVE, ast_rtp_protocol::get_codec, get_proto(), ast_rtp_protocol::get_rtp_info, ast_rtp_protocol::get_vrtp_info, ast_channel::lock, LOG_DEBUG, LOG_WARNING, ast_channel::masq, ast_channel::masqr, ast_channel::name, option_debug, ast_rtp_protocol::set_rtp_peer, and ast_channel::tech_pvt.

01525 {
01526    struct ast_frame *f;
01527    struct ast_channel *who, *cs[3];
01528    struct ast_rtp *p0, *p1;      /* Audio RTP Channels */
01529    struct ast_rtp *vp0, *vp1;    /* Video RTP channels */
01530    struct ast_rtp_protocol *pr0, *pr1;
01531    struct sockaddr_in ac0, ac1;
01532    struct sockaddr_in vac0, vac1;
01533    struct sockaddr_in t0, t1;
01534    struct sockaddr_in vt0, vt1;
01535    char iabuf[INET_ADDRSTRLEN];
01536    
01537    void *pvt0, *pvt1;
01538    int codec0,codec1, oldcodec0, oldcodec1;
01539    
01540    memset(&vt0, 0, sizeof(vt0));
01541    memset(&vt1, 0, sizeof(vt1));
01542    memset(&vac0, 0, sizeof(vac0));
01543    memset(&vac1, 0, sizeof(vac1));
01544 
01545    /* if need DTMF, cant native bridge */
01546    if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))
01547       return AST_BRIDGE_FAILED_NOWARN;
01548 
01549    /* Lock channels */
01550    ast_mutex_lock(&c0->lock);
01551    while(ast_mutex_trylock(&c1->lock)) {
01552       ast_mutex_unlock(&c0->lock);
01553       usleep(1);
01554       ast_mutex_lock(&c0->lock);
01555    }
01556 
01557    /* Find channel driver interfaces */
01558    pr0 = get_proto(c0);
01559    pr1 = get_proto(c1);
01560    if (!pr0) {
01561       ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c0->name);
01562       ast_mutex_unlock(&c0->lock);
01563       ast_mutex_unlock(&c1->lock);
01564       return AST_BRIDGE_FAILED;
01565    }
01566    if (!pr1) {
01567       ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c1->name);
01568       ast_mutex_unlock(&c0->lock);
01569       ast_mutex_unlock(&c1->lock);
01570       return AST_BRIDGE_FAILED;
01571    }
01572 
01573    /* Get channel specific interface structures */
01574    pvt0 = c0->tech_pvt;
01575    pvt1 = c1->tech_pvt;
01576 
01577    /* Get audio and video interface (if native bridge is possible) */
01578    p0 = pr0->get_rtp_info(c0);
01579    if (pr0->get_vrtp_info)
01580       vp0 = pr0->get_vrtp_info(c0);
01581    else
01582       vp0 = NULL;
01583    p1 = pr1->get_rtp_info(c1);
01584    if (pr1->get_vrtp_info)
01585       vp1 = pr1->get_vrtp_info(c1);
01586    else
01587       vp1 = NULL;
01588 
01589    /* Check if bridge is still possible (In SIP canreinvite=no stops this, like NAT) */
01590    if (!p0 || !p1) {
01591       /* Somebody doesn't want to play... */
01592       ast_mutex_unlock(&c0->lock);
01593       ast_mutex_unlock(&c1->lock);
01594       return AST_BRIDGE_FAILED_NOWARN;
01595    }
01596    /* Get codecs from both sides */
01597    if (pr0->get_codec)
01598       codec0 = pr0->get_codec(c0);
01599    else
01600       codec0 = 0;
01601    if (pr1->get_codec)
01602       codec1 = pr1->get_codec(c1);
01603    else
01604       codec1 = 0;
01605    if (pr0->get_codec && pr1->get_codec) {
01606       /* Hey, we can't do reinvite if both parties speak different codecs */
01607       if (!(codec0 & codec1)) {
01608          if (option_debug)
01609             ast_log(LOG_DEBUG, "Channel codec0 = %d is not codec1 = %d, cannot native bridge in RTP.\n", codec0, codec1);
01610          ast_mutex_unlock(&c0->lock);
01611          ast_mutex_unlock(&c1->lock);
01612          return AST_BRIDGE_FAILED_NOWARN;
01613       }
01614    }
01615 
01616    /* Ok, we should be able to redirect the media. Start with one channel */
01617    if (pr0->set_rtp_peer(c0, p1, vp1, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE))) 
01618       ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name);
01619    else {
01620       /* Store RTP peer */
01621       ast_rtp_get_peer(p1, &ac1);
01622       if (vp1)
01623          ast_rtp_get_peer(vp1, &vac1);
01624    }
01625    /* Then test the other channel */
01626    if (pr1->set_rtp_peer(c1, p0, vp0, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))
01627       ast_log(LOG_WARNING, "Channel '%s' failed to talk back to '%s'\n", c1->name, c0->name);
01628    else {
01629       /* Store RTP peer */
01630       ast_rtp_get_peer(p0, &ac0);
01631       if (vp0)
01632          ast_rtp_get_peer(vp0, &vac0);
01633    }
01634    ast_mutex_unlock(&c0->lock);
01635    ast_mutex_unlock(&c1->lock);
01636    /* External RTP Bridge up, now loop and see if something happes that force us to take the
01637       media back to Asterisk */
01638    cs[0] = c0;
01639    cs[1] = c1;
01640    cs[2] = NULL;
01641    oldcodec0 = codec0;
01642    oldcodec1 = codec1;
01643    for (;;) {
01644       /* Check if something changed... */
01645       if ((c0->tech_pvt != pvt0)  ||
01646          (c1->tech_pvt != pvt1) ||
01647          (c0->masq || c0->masqr || c1->masq || c1->masqr)) {
01648             ast_log(LOG_DEBUG, "Oooh, something is weird, backing out\n");
01649             if (c0->tech_pvt == pvt0) {
01650                if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0)) 
01651                   ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name);
01652             }
01653             if (c1->tech_pvt == pvt1) {
01654                if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0)) 
01655                   ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
01656             }
01657             return AST_BRIDGE_RETRY;
01658       }
01659       /* Now check if they have changed address */
01660       ast_rtp_get_peer(p1, &t1);
01661       ast_rtp_get_peer(p0, &t0);
01662       if (pr0->get_codec)
01663          codec0 = pr0->get_codec(c0);
01664       if (pr1->get_codec)
01665          codec1 = pr1->get_codec(c1);
01666       if (vp1)
01667          ast_rtp_get_peer(vp1, &vt1);
01668       if (vp0)
01669          ast_rtp_get_peer(vp0, &vt0);
01670       if (inaddrcmp(&t1, &ac1) || (vp1 && inaddrcmp(&vt1, &vac1)) || (codec1 != oldcodec1)) {
01671          if (option_debug > 1) {
01672             ast_log(LOG_DEBUG, "Oooh, '%s' changed end address to %s:%d (format %d)\n", 
01673                c1->name, ast_inet_ntoa(iabuf, sizeof(iabuf), t1.sin_addr), ntohs(t1.sin_port), codec1);
01674             ast_log(LOG_DEBUG, "Oooh, '%s' changed end vaddress to %s:%d (format %d)\n", 
01675                c1->name, ast_inet_ntoa(iabuf, sizeof(iabuf), vt1.sin_addr), ntohs(vt1.sin_port), codec1);
01676             ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n", 
01677                c1->name, ast_inet_ntoa(iabuf, sizeof(iabuf), ac1.sin_addr), ntohs(ac1.sin_port), oldcodec1);
01678             ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n", 
01679                c1->name, ast_inet_ntoa(iabuf, sizeof(iabuf), vac1.sin_addr), ntohs(vac1.sin_port), oldcodec1);
01680          }
01681          if (pr0->set_rtp_peer(c0, t1.sin_addr.s_addr ? p1 : NULL, vt1.sin_addr.s_addr ? vp1 : NULL, codec1, ast_test_flag(p1, FLAG_NAT_ACTIVE))) 
01682             ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c0->name, c1->name);
01683          memcpy(&ac1, &t1, sizeof(ac1));
01684          memcpy(&vac1, &vt1, sizeof(vac1));
01685          oldcodec1 = codec1;
01686       }
01687       if (inaddrcmp(&t0, &ac0) || (vp0 && inaddrcmp(&vt0, &vac0))) {
01688          if (option_debug) {
01689             ast_log(LOG_DEBUG, "Oooh, '%s' changed end address to %s:%d (format %d)\n", 
01690                c0->name, ast_inet_ntoa(iabuf, sizeof(iabuf), t0.sin_addr), ntohs(t0.sin_port), codec0);
01691             ast_log(LOG_DEBUG, "Oooh, '%s' was %s:%d/(format %d)\n", 
01692                c0->name, ast_inet_ntoa(iabuf, sizeof(iabuf), ac0.sin_addr), ntohs(ac0.sin_port), oldcodec0);
01693          }
01694          if (pr1->set_rtp_peer(c1, t0.sin_addr.s_addr ? p0 : NULL, vt0.sin_addr.s_addr ? vp0 : NULL, codec0, ast_test_flag(p0, FLAG_NAT_ACTIVE)))
01695             ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c1->name, c0->name);
01696          memcpy(&ac0, &t0, sizeof(ac0));
01697          memcpy(&vac0, &vt0, sizeof(vac0));
01698          oldcodec0 = codec0;
01699       }
01700       who = ast_waitfor_n(cs, 2, &timeoutms);
01701       if (!who) {
01702          if (!timeoutms) 
01703             return AST_BRIDGE_RETRY;
01704          if (option_debug)
01705             ast_log(LOG_DEBUG, "Ooh, empty read...\n");
01706          /* check for hangup / whentohangup */
01707          if (ast_check_hangup(c0) || ast_check_hangup(c1))
01708             break;
01709          continue;
01710       }
01711       f = ast_read(who);
01712       if (!f || ((f->frametype == AST_FRAME_DTMF) &&
01713                (((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) || 
01714                 ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))))) {
01715          *fo = f;
01716          *rc = who;
01717          if (option_debug)
01718             ast_log(LOG_DEBUG, "Oooh, got a %s\n", f ? "digit" : "hangup");
01719          if ((c0->tech_pvt == pvt0) && (!c0->_softhangup)) {
01720             if (pr0->set_rtp_peer(c0, NULL, NULL, 0, 0)) 
01721                ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c0->name);
01722          }
01723          if ((c1->tech_pvt == pvt1) && (!c1->_softhangup)) {
01724             if (pr1->set_rtp_peer(c1, NULL, NULL, 0, 0)) 
01725                ast_log(LOG_WARNING, "Channel '%s' failed to break RTP bridge\n", c1->name);
01726          }
01727          return AST_BRIDGE_COMPLETE;
01728       } else if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
01729          if ((f->subclass == AST_CONTROL_HOLD) || (f->subclass == AST_CONTROL_UNHOLD) ||
01730              (f->subclass == AST_CONTROL_VIDUPDATE)) {
01731             ast_indicate(who == c0 ? c1 : c0, f->subclass);
01732             ast_frfree(f);
01733          } else {
01734             *fo = f;
01735             *rc = who;
01736             ast_log(LOG_DEBUG, "Got a FRAME_CONTROL (%d) frame on channel %s\n", f->subclass, who->name);
01737             return AST_BRIDGE_COMPLETE;
01738          }
01739       } else {
01740          if ((f->frametype == AST_FRAME_DTMF) || 
01741             (f->frametype == AST_FRAME_VOICE) || 
01742             (f->frametype == AST_FRAME_VIDEO)) {
01743             /* Forward voice or DTMF frames if they happen upon us */
01744             if (who == c0) {
01745                ast_write(c1, f);
01746             } else if (who == c1) {
01747                ast_write(c0, f);
01748             }
01749          }
01750          ast_frfree(f);
01751       }
01752       /* Swap priority not that it's a big deal at this point */
01753       cs[2] = cs[0];
01754       cs[0] = cs[1];
01755       cs[1] = cs[2];
01756       
01757    }
01758    return AST_BRIDGE_FAILED;
01759 }

void ast_rtp_destroy ( struct ast_rtp rtp  ) 

Definition at line 1092 of file rtp.c.

References ast_io_remove(), ast_smoother_free(), free, ast_rtp::io, ast_rtp::ioid, ast_rtp::rtcp, ast_rtcp::s, ast_rtp::s, and ast_rtp::smoother.

Referenced by __oh323_destroy(), __sip_destroy(), cleanup_connection(), destroy_endpoint(), mgcp_hangup(), skinny_hangup(), start_rtp(), and unalloc_sub().

01093 {
01094    if (rtp->smoother)
01095       ast_smoother_free(rtp->smoother);
01096    if (rtp->ioid)
01097       ast_io_remove(rtp->io, rtp->ioid);
01098    if (rtp->s > -1)
01099       close(rtp->s);
01100    if (rtp->rtcp) {
01101       close(rtp->rtcp->s);
01102       free(rtp->rtcp);
01103    }
01104    free(rtp);
01105 }

int ast_rtp_fd ( struct ast_rtp rtp  ) 

Definition at line 153 of file rtp.c.

References ast_rtp::s.

Referenced by __oh323_new(), mgcp_new(), sip_new(), skinny_new(), and start_rtp().

00154 {
00155    return rtp->s;
00156 }

void ast_rtp_get_current_formats ( struct ast_rtp rtp,
int *  astFormats,
int *  nonAstFormats 
)

Definition at line 771 of file rtp.c.

References rtpPayloadType::code, ast_rtp::current_RTP_PT, rtpPayloadType::isAstFormat, and MAX_RTP_PT.

Referenced by process_sdp().

00772                                                    {
00773    int pt;
00774 
00775    *astFormats = *nonAstFormats = 0;
00776    for (pt = 0; pt < MAX_RTP_PT; ++pt) {
00777       if (rtp->current_RTP_PT[pt].isAstFormat) {
00778          *astFormats |= rtp->current_RTP_PT[pt].code;
00779       } else {
00780          *nonAstFormats |= rtp->current_RTP_PT[pt].code;
00781       }
00782    }
00783 }

int ast_rtp_get_peer ( struct ast_rtp rtp,
struct sockaddr_in *  them 
)

Definition at line 1044 of file rtp.c.

References ast_rtp::them.

Referenced by add_sdp(), ast_rtp_bridge(), do_monitor(), oh323_set_rtp_peer(), sip_set_rtp_peer(), and transmit_modify_with_sdp().

01045 {
01046    if ((them->sin_family != AF_INET) ||
01047        (them->sin_port != rtp->them.sin_port) ||
01048        (them->sin_addr.s_addr != rtp->them.sin_addr.s_addr)) {
01049       them->sin_family = AF_INET;
01050       them->sin_port = rtp->them.sin_port;
01051       them->sin_addr = rtp->them.sin_addr;
01052       return 1;
01053    }
01054    return 0;
01055 }

void ast_rtp_get_us ( struct ast_rtp rtp,
struct sockaddr_in *  us 
)

Definition at line 1057 of file rtp.c.

References ast_rtp::us.

Referenced by add_sdp(), external_rtp_create(), handle_message(), and oh323_set_rtp_peer().

01058 {
01059    memcpy(us, &rtp->us, sizeof(rtp->us));
01060 }

void ast_rtp_init ( void   ) 

Definition at line 1887 of file rtp.c.

References ast_cli_register(), ast_rtp_reload(), cli_debug, cli_debug_ip, and cli_no_debug.

Referenced by main().

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

Definition at line 811 of file rtp.c.

References rtpPayloadType::code, ast_rtp::current_RTP_PT, rtpPayloadType::isAstFormat, MAX_RTP_PT, 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_sdp(), add_noncodec_to_sdp(), add_sdp(), ast_rtp_sendcng(), ast_rtp_senddigit(), and ast_rtp_write().

00811                                                                                     {
00812 
00813    int pt;
00814 
00815    if (isAstFormat == rtp->rtp_lookup_code_cache_isAstFormat &&
00816       code == rtp->rtp_lookup_code_cache_code) {
00817 
00818       /* Use our cached mapping, to avoid the overhead of the loop below */
00819       return rtp->rtp_lookup_code_cache_result;
00820    }
00821 
00822    /* Check the dynamic list first */
00823    for (pt = 0; pt < MAX_RTP_PT; ++pt) {
00824       if (rtp->current_RTP_PT[pt].code == code && rtp->current_RTP_PT[pt].isAstFormat == isAstFormat) {
00825          rtp->rtp_lookup_code_cache_isAstFormat = isAstFormat;
00826          rtp->rtp_lookup_code_cache_code = code;
00827          rtp->rtp_lookup_code_cache_result = pt;
00828          return pt;
00829       }
00830    }
00831 
00832    /* Then the static list */
00833    for (pt = 0; pt < MAX_RTP_PT; ++pt) {
00834       if (static_RTP_PT[pt].code == code && static_RTP_PT[pt].isAstFormat == isAstFormat) {
00835          rtp->rtp_lookup_code_cache_isAstFormat = isAstFormat;
00836          rtp->rtp_lookup_code_cache_code = code;
00837          rtp->rtp_lookup_code_cache_result = pt;
00838          return pt;
00839       }
00840    }
00841    return -1;
00842 }

char* ast_rtp_lookup_mime_multiple ( char *  buf,
int  size,
const int  capability,
const int  isAstFormat 
)

Definition at line 856 of file rtp.c.

References ast_rtp_lookup_mime_subtype(), AST_RTP_MAX, format, and name.

Referenced by process_sdp().

00857 {
00858    int format;
00859    unsigned len;
00860    char *end = buf;
00861    char *start = buf;
00862 
00863    if (!buf || !size)
00864       return NULL;
00865 
00866    snprintf(end, size, "0x%x (", capability);
00867 
00868    len = strlen(end);
00869    end += len;
00870    size -= len;
00871    start = end;
00872 
00873    for (format = 1; format < AST_RTP_MAX; format <<= 1) {
00874       if (capability & format) {
00875          const char *name = ast_rtp_lookup_mime_subtype(isAstFormat, format);
00876          snprintf(end, size, "%s|", name);
00877          len = strlen(end);
00878          end += len;
00879          size -= len;
00880       }
00881    }
00882 
00883    if (start == end)
00884       snprintf(start, size, "nothing)"); 
00885    else if (size > 1)
00886       *(end -1) = ')';
00887    
00888    return buf;
00889 }

char* ast_rtp_lookup_mime_subtype ( int  isAstFormat,
int  code 
)

Definition at line 844 of file rtp.c.

References rtpPayloadType::code, mimeTypes, and payloadType.

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

00844                                                                          {
00845 
00846    int i;
00847 
00848    for (i = 0; i < sizeof mimeTypes/sizeof mimeTypes[0]; ++i) {
00849    if (mimeTypes[i].payloadType.code == code && mimeTypes[i].payloadType.isAstFormat == isAstFormat) {
00850             return mimeTypes[i].subtype;
00851       }
00852    }
00853    return "";
00854 }

struct rtpPayloadType ast_rtp_lookup_pt ( struct ast_rtp rtp,
int  pt 
)

Definition at line 792 of file rtp.c.

References MAX_RTP_PT, result, and static_RTP_PT.

Referenced by ast_rtp_read(), and setup_rtp_connection().

00793 {
00794    struct rtpPayloadType result;
00795 
00796    result.isAstFormat = result.code = 0;
00797    if (pt < 0 || pt > MAX_RTP_PT) 
00798       return result; /* bogus payload type */
00799 
00800    /* Start with the negotiated codecs */
00801    if (!rtp->rtp_offered_from_local)
00802       result = rtp->current_RTP_PT[pt];
00803 
00804    /* If it doesn't exist, check our static RTP type list, just in case */
00805    if (!result.code) 
00806       result = static_RTP_PT[pt];
00807    return result;
00808 }

struct ast_rtp* ast_rtp_new ( struct sched_context sched,
struct io_context io,
int  rtcpenable,
int  callbackmode 
)

Initializate a RTP session.

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

Definition at line 1016 of file rtp.c.

References ast_rtp_new_with_bindaddr(), io, and sched.

Referenced by start_rtp().

01017 {
01018    struct in_addr ia;
01019 
01020    memset(&ia, 0, sizeof(ia));
01021    return ast_rtp_new_with_bindaddr(sched, io, rtcpenable, callbackmode, ia);
01022 }

struct ast_rtp* ast_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.

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

References ast_io_add(), AST_IO_IN, ast_log(), ast_rtcp_new(), ast_rtp_pt_default(), free, ast_rtp::io, io, ast_rtp::ioid, LOG_ERROR, malloc, ast_rtp::rtcp, rtp_socket(), rtpend, rtpread(), rtpstart, ast_rtcp::s, ast_rtp::s, ast_rtp::sched, sched, ast_rtp::seqno, ast_rtp::ssrc, ast_rtp::them, ast_rtcp::us, and ast_rtp::us.

Referenced by ast_rtp_new(), oh323_alloc(), sip_alloc(), and start_rtp().

00930 {
00931    struct ast_rtp *rtp;
00932    int x;
00933    int first;
00934    int startplace;
00935    rtp = malloc(sizeof(struct ast_rtp));
00936    if (!rtp)
00937       return NULL;
00938    memset(rtp, 0, sizeof(struct ast_rtp));
00939    rtp->them.sin_family = AF_INET;
00940    rtp->us.sin_family = AF_INET;
00941    rtp->s = rtp_socket();
00942    rtp->ssrc = rand();
00943    rtp->seqno = rand() & 0xffff;
00944    if (rtp->s < 0) {
00945       free(rtp);
00946       ast_log(LOG_ERROR, "Unable to allocate socket: %s\n", strerror(errno));
00947       return NULL;
00948    }
00949    if (sched && rtcpenable) {
00950       rtp->sched = sched;
00951       rtp->rtcp = ast_rtcp_new();
00952    }
00953    
00954    /* Select a random port number in the range of possible RTP */
00955    x = (rand() % (rtpend-rtpstart)) + rtpstart;
00956    x = x & ~1;
00957    /* Save it for future references. */
00958    startplace = x;
00959    /* Iterate tring to bind that port and incrementing it otherwise untill a port was found or no ports are available. */
00960    for (;;) {
00961       /* Must be an even port number by RTP spec */
00962       rtp->us.sin_port = htons(x);
00963       rtp->us.sin_addr = addr;
00964       /* If there's rtcp, initialize it as well. */
00965       if (rtp->rtcp)
00966          rtp->rtcp->us.sin_port = htons(x + 1);
00967       /* Try to bind it/them. */
00968       if (!(first = bind(rtp->s, (struct sockaddr *)&rtp->us, sizeof(rtp->us))) &&
00969          (!rtp->rtcp || !bind(rtp->rtcp->s, (struct sockaddr *)&rtp->rtcp->us, sizeof(rtp->rtcp->us))))
00970          break;
00971       if (!first) {
00972          /* Primary bind succeeded! Gotta recreate it */
00973          close(rtp->s);
00974          rtp->s = rtp_socket();
00975       }
00976       if (errno != EADDRINUSE) {
00977          /* We got an error that wasn't expected, abort! */
00978          ast_log(LOG_ERROR, "Unexpected bind error: %s\n", strerror(errno));
00979          close(rtp->s);
00980          if (rtp->rtcp) {
00981             close(rtp->rtcp->s);
00982             free(rtp->rtcp);
00983          }
00984          free(rtp);
00985          return NULL;
00986       }
00987       /* The port was used, increment it (by two). */
00988       x += 2;
00989       /* Did we go over the limit ? */
00990       if (x > rtpend)
00991          /* then, start from the begingig. */
00992          x = (rtpstart + 1) & ~1;
00993       /* Check if we reached the place were we started. */
00994       if (x == startplace) {
00995          /* If so, there's no ports available. */
00996          ast_log(LOG_ERROR, "No RTP ports remaining. Can't setup media stream for this call.\n");
00997          close(rtp->s);
00998          if (rtp->rtcp) {
00999             close(rtp->rtcp->s);
01000             free(rtp->rtcp);
01001          }
01002          free(rtp);
01003          return NULL;
01004       }
01005    }
01006    if (io && sched && callbackmode) {
01007       /* Operate this one in a callback mode */
01008       rtp->sched = sched;
01009       rtp->io = io;
01010       rtp->ioid = ast_io_add(rtp->io, rtp->s, rtpread, AST_IO_IN, rtp);
01011    }
01012    ast_rtp_pt_default(rtp);
01013    return rtp;
01014 }

void ast_rtp_offered_from_local ( struct ast_rtp rtp,
int  local 
)

Definition at line 785 of file rtp.c.

References ast_log(), LOG_WARNING, and ast_rtp::rtp_offered_from_local.

Referenced by transmit_invite(), transmit_reinvite_with_sdp(), and transmit_response_with_sdp().

00785                                                                 {
00786    if (rtp)
00787       rtp->rtp_offered_from_local = local;
00788    else
00789       ast_log(LOG_WARNING, "rtp structure is null\n");
00790 }

int ast_rtp_proto_register ( struct ast_rtp_protocol proto  ) 

Definition at line 1490 of file rtp.c.

References ast_log(), LOG_WARNING, ast_rtp_protocol::next, protos, and ast_rtp_protocol::type.

Referenced by load_module(), and unload_module().

01491 {
01492    struct ast_rtp_protocol *cur;
01493    cur = protos;
01494    while(cur) {
01495       if (cur->type == proto->type) {
01496          ast_log(LOG_WARNING, "Tried to register same protocol '%s' twice\n", cur->type);
01497          return -1;
01498       }
01499       cur = cur->next;
01500    }
01501    proto->next = protos;
01502    protos = proto;
01503    return 0;
01504 }

void ast_rtp_proto_unregister ( struct ast_rtp_protocol proto  ) 

Definition at line 1470 of file rtp.c.

References ast_rtp_protocol::next, and protos.

Referenced by unload_module().

01471 {
01472    struct ast_rtp_protocol *cur, *prev;
01473 
01474    cur = protos;
01475    prev = NULL;
01476    while(cur) {
01477       if (cur == proto) {
01478          if (prev)
01479             prev->next = proto->next;
01480          else
01481             protos = proto->next;
01482          return;
01483       }
01484       prev = cur;
01485       cur = cur->next;
01486    }
01487 }

void ast_rtp_pt_clear ( struct ast_rtp rtp  ) 

Definition at line 708 of file rtp.c.

References rtpPayloadType::code, ast_rtp::current_RTP_PT, rtpPayloadType::isAstFormat, MAX_RTP_PT, ast_rtp::rtp_lookup_code_cache_code, ast_rtp::rtp_lookup_code_cache_isAstFormat, and ast_rtp::rtp_lookup_code_cache_result.

Referenced by process_sdp().

00709 {
00710    int i;
00711    if (!rtp)
00712       return;
00713 
00714    for (i = 0; i < MAX_RTP_PT; ++i) {
00715       rtp->current_RTP_PT[i].isAstFormat = 0;
00716       rtp->current_RTP_PT[i].code = 0;
00717    }
00718 
00719    rtp->rtp_lookup_code_cache_isAstFormat = 0;
00720    rtp->rtp_lookup_code_cache_code = 0;
00721    rtp->rtp_lookup_code_cache_result = 0;
00722 }

void ast_rtp_pt_default ( struct ast_rtp rtp  ) 

Definition at line 724 of file rtp.c.

References rtpPayloadType::code, ast_rtp::current_RTP_PT, rtpPayloadType::isAstFormat, MAX_RTP_PT, ast_rtp::rtp_lookup_code_cache_code, ast_rtp::rtp_lookup_code_cache_isAstFormat, ast_rtp::rtp_lookup_code_cache_result, and static_RTP_PT.

Referenced by ast_rtp_new_with_bindaddr().

00725 {
00726    int i;
00727 
00728    /* Initialize to default payload types */
00729    for (i = 0; i < MAX_RTP_PT; ++i) {
00730       rtp->current_RTP_PT[i].isAstFormat = static_RTP_PT[i].isAstFormat;
00731       rtp->current_RTP_PT[i].code = static_RTP_PT[i].code;
00732    }
00733 
00734    rtp->rtp_lookup_code_cache_isAstFormat = 0;
00735    rtp->rtp_lookup_code_cache_code = 0;
00736    rtp->rtp_lookup_code_cache_result = 0;
00737 }

struct ast_frame* ast_rtp_read ( struct ast_rtp rtp  ) 

Definition at line 426 of file rtp.c.

References ast_codec_get_samples(), AST_FORMAT_MAX_AUDIO, AST_FORMAT_SLINEAR, ast_frame_byteswap_be, AST_FRAME_NULL, AST_FRAME_VIDEO, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_inet_ntoa(), ast_log(), AST_RTP_CISCO_DTMF, AST_RTP_CN, AST_RTP_DTMF, ast_rtp_lookup_pt(), ast_set_flag, ast_verbose(), calc_rxstamp(), rtpPayloadType::code, CRASH, ast_frame::data, ast_frame::datalen, ast_frame::delivery, ast_rtp::dtmfcount, ast_rtp::f, FLAG_NAT_ACTIVE, ast_frame::frametype, rtpPayloadType::isAstFormat, ast_rtp::lasteventseqn, ast_rtp::lastividtimestamp, ast_rtp::lastrxformat, ast_rtp::lastrxts, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, ast_frame::mallocd, ast_rtp::nat, ast_frame::offset, option_debug, process_cisco_dtmf(), process_rfc2833(), process_rfc3389(), ast_rtp::rawdata, ast_rtp::resp, rtp_debug_test_addr(), ast_rtp::rxseqno, ast_rtp::rxssrc, ast_rtp::s, ast_frame::samples, send_dtmf(), ast_frame::src, ast_frame::subclass, and ast_rtp::them.

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

00427 {
00428    int res;
00429    struct sockaddr_in sin;
00430    socklen_t len;
00431    unsigned int seqno;
00432    int version;
00433    int payloadtype;
00434    int hdrlen = 12;
00435    int padding;
00436    int mark;
00437    int ext;
00438    int x;
00439    char iabuf[INET_ADDRSTRLEN];
00440    unsigned int ssrc;
00441    unsigned int timestamp;
00442    unsigned int *rtpheader;
00443    struct ast_frame *f;
00444    static struct ast_frame null_frame = { AST_FRAME_NULL, };
00445    struct rtpPayloadType rtpPT;
00446    
00447    len = sizeof(sin);
00448    
00449    /* Cache where the header will go */
00450    res = recvfrom(rtp->s, rtp->rawdata + AST_FRIENDLY_OFFSET, sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET,
00451                0, (struct sockaddr *)&sin, &len);
00452 
00453 
00454    rtpheader = (unsigned int *)(rtp->rawdata + AST_FRIENDLY_OFFSET);
00455    if (res < 0) {
00456       if (errno != EAGAIN)
00457          ast_log(LOG_WARNING, "RTP Read error: %s\n", strerror(errno));
00458       if (errno == EBADF)
00459          CRASH;
00460       return &null_frame;
00461    }
00462    if (res < hdrlen) {
00463       ast_log(LOG_WARNING, "RTP Read too short\n");
00464       return &null_frame;
00465    }
00466 
00467    /* Ignore if the other side hasn't been given an address
00468       yet.  */
00469    if (!rtp->them.sin_addr.s_addr || !rtp->them.sin_port)
00470       return &null_frame;
00471 
00472    if (rtp->nat) {
00473       /* Send to whoever sent to us */
00474       if ((rtp->them.sin_addr.s_addr != sin.sin_addr.s_addr) ||
00475           (rtp->them.sin_port != sin.sin_port)) {
00476          memcpy(&rtp->them, &sin, sizeof(rtp->them));
00477          rtp->rxseqno = 0;
00478          ast_set_flag(rtp, FLAG_NAT_ACTIVE);
00479          if (option_debug || rtpdebug)
00480             ast_log(LOG_DEBUG, "RTP NAT: Got audio from other end. Now sending to address %s:%d\n", ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr), ntohs(rtp->them.sin_port));
00481       }
00482    }
00483 
00484    /* Get fields */
00485    seqno = ntohl(rtpheader[0]);
00486 
00487    /* Check RTP version */
00488    version = (seqno & 0xC0000000) >> 30;
00489    if (version != 2)
00490       return &null_frame;
00491    
00492    payloadtype = (seqno & 0x7f0000) >> 16;
00493    padding = seqno & (1 << 29);
00494    mark = seqno & (1 << 23);
00495    ext = seqno & (1 << 28);
00496    seqno &= 0xffff;
00497    timestamp = ntohl(rtpheader[1]);
00498    ssrc = ntohl(rtpheader[2]);
00499    
00500    if (!mark && rtp->rxssrc && rtp->rxssrc != ssrc) {
00501       if (option_debug || rtpdebug)
00502          ast_log(LOG_DEBUG, "Forcing Marker bit, because SSRC has changed\n");
00503       mark = 1;
00504    }
00505 
00506    rtp->rxssrc = ssrc;
00507    
00508    if (padding) {
00509       /* Remove padding bytes */
00510       res -= rtp->rawdata[AST_FRIENDLY_OFFSET + res - 1];
00511    }
00512    
00513    if (ext) {
00514       /* RTP Extension present */
00515       hdrlen += 4;
00516       hdrlen += (ntohl(rtpheader[3]) & 0xffff) << 2;
00517    }
00518 
00519    if (res < hdrlen) {
00520       ast_log(LOG_WARNING, "RTP Read too short (%d, expecting %d)\n", res, hdrlen);
00521       return &null_frame;
00522    }
00523 
00524    if(rtp_debug_test_addr(&sin))
00525       ast_verbose("Got RTP packet from %s:%d (type %d, seq %d, ts %d, len %d)\n"
00526          , ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port), payloadtype, seqno, timestamp,res - hdrlen);
00527 
00528    rtpPT = ast_rtp_lookup_pt(rtp, payloadtype);
00529    if (!rtpPT.isAstFormat) {
00530       /* This is special in-band data that's not one of our codecs */
00531       if (rtpPT.code == AST_RTP_DTMF) {
00532          /* It's special -- rfc2833 process it */
00533          if(rtp_debug_test_addr(&sin)) {
00534             unsigned char *data;
00535             unsigned int event;
00536             unsigned int event_end;
00537             unsigned int duration;
00538             data = rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen;
00539             event = ntohl(*((unsigned int *)(data)));
00540             event >>= 24;
00541             event_end = ntohl(*((unsigned int *)(data)));
00542             event_end <<= 8;
00543             event_end >>= 24;
00544             duration = ntohl(*((unsigned int *)(data)));
00545             duration &= 0xFFFF;
00546             ast_verbose("Got rfc2833 RTP packet from %s:%d (type %d, seq %d, ts %d, len %d, mark %d, event %08x, end %d, duration %d) \n", ast_inet_ntoa(iabuf, sizeof(iabuf), sin.sin_addr), ntohs(sin.sin_port), payloadtype, seqno, timestamp, res - hdrlen, (mark?1:0), event, ((event_end & 0x80)?1:0), duration);
00547          }
00548          if (rtp->lasteventseqn <= seqno || rtp->resp == 0 || (rtp->lasteventseqn >= 65530 && seqno <= 6)) {
00549             f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen, seqno);
00550             rtp->lasteventseqn = seqno;
00551          } else
00552             f = NULL;
00553          if (f)
00554             return f;
00555          else
00556             return &null_frame;
00557       } else if (rtpPT.code == AST_RTP_CISCO_DTMF) {
00558          /* It's really special -- process it the Cisco way */
00559          if (rtp->lasteventseqn <= seqno || rtp->resp == 0 || (rtp->lasteventseqn >= 65530 && seqno <= 6)) {
00560             f = process_cisco_dtmf(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
00561             rtp->lasteventseqn = seqno;
00562          } else 
00563             f = NULL;
00564             if (f) 
00565             return f; 
00566          else 
00567             return &null_frame;
00568       } else if (rtpPT.code == AST_RTP_CN) {
00569          /* Comfort Noise */
00570          f = process_rfc3389(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
00571          if (f) 
00572             return f; 
00573          else 
00574             return &null_frame;
00575       } else {
00576          ast_log(LOG_NOTICE, "Unknown RTP codec %d received\n", payloadtype);
00577          return &null_frame;
00578       }
00579    }
00580    rtp->f.subclass = rtpPT.code;
00581    if (rtp->f.subclass < AST_FORMAT_MAX_AUDIO)
00582       rtp->f.frametype = AST_FRAME_VOICE;
00583    else
00584       rtp->f.frametype = AST_FRAME_VIDEO;
00585    rtp->lastrxformat = rtp->f.subclass;
00586 
00587    if (!rtp->lastrxts)
00588       rtp->lastrxts = timestamp;
00589 
00590    if (rtp->rxseqno) {
00591       for (x=rtp->rxseqno + 1; x < seqno; x++) {
00592          /* Queue empty frames */
00593          rtp->f.mallocd = 0;
00594          rtp->f.datalen = 0;
00595          rtp->f.data = NULL;
00596          rtp->f.offset = 0;
00597          rtp->f.samples = 0;
00598          rtp->f.src = "RTPMissedFrame";
00599       }
00600    }
00601    rtp->rxseqno = seqno;
00602 
00603    if (rtp->dtmfcount) {
00604 #if 0
00605       printf("dtmfcount was %d\n", rtp->dtmfcount);
00606 #endif      
00607       rtp->dtmfcount -= (timestamp - rtp->lastrxts);
00608       if (rtp->dtmfcount < 0)
00609          rtp->dtmfcount = 0;
00610 #if 0
00611       if (dtmftimeout != rtp->dtmfcount)
00612          printf("dtmfcount is %d\n", rtp->dtmfcount);
00613 #endif
00614    }
00615    rtp->lastrxts = timestamp;
00616 
00617    /* Send any pending DTMF */
00618    if (rtp->resp && !rtp->dtmfcount) {
00619       if (option_debug)
00620          ast_log(LOG_DEBUG, "Sending pending DTMF\n");
00621       return send_dtmf(rtp);
00622    }
00623    rtp->f.mallocd = 0;
00624    rtp->f.datalen = res - hdrlen;
00625    rtp->f.data = rtp->rawdata + hdrlen + AST_FRIENDLY_OFFSET;
00626    rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET;
00627    if (rtp->f.subclass < AST_FORMAT_MAX_AUDIO) {
00628       rtp->f.samples = ast_codec_get_samples(&rtp->f);
00629       if (rtp->f.subclass == AST_FORMAT_SLINEAR) 
00630          ast_frame_byteswap_be(&rtp->f);
00631       calc_rxstamp(&rtp->f.delivery, rtp, timestamp, mark);
00632    } else {
00633       /* Video -- samples is # of samples vs. 90000 */
00634       if (!rtp->lastividtimestamp)
00635          rtp->lastividtimestamp = timestamp;
00636       rtp->f.samples = timestamp - rtp->lastividtimestamp;
00637       rtp->lastividtimestamp = timestamp;
00638       rtp->f.delivery.tv_sec = 0;
00639       rtp->f.delivery.tv_usec = 0;
00640       if (mark)
00641          rtp->f.subclass |= 0x1;
00642       
00643    }
00644    rtp->f.src = "RTP";
00645    return &rtp->f;
00646 }

void ast_rtp_reload ( void   ) 

Definition at line 1831 of file rtp.c.

References ast_config_destroy(), ast_config_load(), ast_false(), ast_log(), ast_variable_retrieve(), ast_verbose(), cfg, DEFAULT_DTMF_TIMEOUT, dtmftimeout, option_verbose, rtpend, rtpstart, s, and VERBOSE_PREFIX_2.

Referenced by ast_module_reload(), ast_rtp_init(), and main().

01832 {
01833    struct ast_config *cfg;
01834    char *s;
01835 
01836    rtpstart = 5000;
01837    rtpend = 31000;
01838    dtmftimeout = DEFAULT_DTMF_TIMEOUT;
01839    cfg = ast_config_load("rtp.conf");
01840    if (cfg) {
01841       if ((s = ast_variable_retrieve(cfg, "general", "rtpstart"))) {
01842          rtpstart = atoi(s);
01843          if (rtpstart < 1024)
01844             rtpstart = 1024;
01845          if (rtpstart > 65535)
01846             rtpstart = 65535;
01847       }
01848       if ((s = ast_variable_retrieve(cfg, "general", "rtpend"))) {
01849          rtpend = atoi(s);
01850          if (rtpend < 1024)
01851             rtpend = 1024;
01852          if (rtpend > 65535)
01853             rtpend = 65535;
01854       }
01855       if ((s = ast_variable_retrieve(cfg, "general", "rtpchecksums"))) {
01856 #ifdef SO_NO_CHECK
01857          if (ast_false(s))
01858             nochecksums = 1;
01859          else
01860             nochecksums = 0;
01861 #else
01862          if (ast_false(s))
01863             ast_log(LOG_WARNING, "Disabling RTP checksums is not supported on this operating system!\n");
01864 #endif
01865       }
01866       if ((s = ast_variable_retrieve(cfg, "general", "dtmftimeout"))) {
01867          dtmftimeout = atoi(s);
01868          if ((dtmftimeout < 0) || (dtmftimeout > 20000)) {
01869             ast_log(LOG_WARNING, "DTMF timeout of '%d' outside range, using default of '%d' instead\n",
01870                dtmftimeout, DEFAULT_DTMF_TIMEOUT);
01871             dtmftimeout = DEFAULT_DTMF_TIMEOUT;
01872          };
01873       }
01874       ast_config_destroy(cfg);
01875    }
01876    if (rtpstart >= rtpend) {
01877       ast_log(LOG_WARNING, "Unreasonable values for RTP start/end port in rtp.conf\n");
01878       rtpstart = 5000;
01879       rtpend = 31000;
01880    }
01881    if (option_verbose > 1)
01882       ast_verbose(VERBOSE_PREFIX_2 "RTP Allocating from port range %d -> %d\n", rtpstart, rtpend);
01883    
01884 }

void ast_rtp_reset ( struct ast_rtp rtp  ) 

Definition at line 1072 of file rtp.c.

References ast_rtp::dtmfcount, ast_rtp::dtmfduration, ast_rtp::dtmfmute, ast_rtp::lastdigitts, ast_rtp::lasteventendseqn, ast_rtp::lasteventseqn, ast_rtp::lastividtimestamp, ast_rtp::lastovidtimestamp, ast_rtp::lastrxformat, ast_rtp::lastrxts, ast_rtp::lastts, ast_rtp::lasttxformat, ast_rtp::rxcore, ast_rtp::rxseqno, ast_rtp::seqno, and ast_rtp::txcore.

01073 {
01074    memset(&rtp->rxcore, 0, sizeof(rtp->rxcore));
01075    memset(&rtp->txcore, 0, sizeof(rtp->txcore));
01076    memset(&rtp->dtmfmute, 0, sizeof(rtp->dtmfmute));
01077    rtp->lastts = 0;
01078    rtp->lastdigitts = 0;
01079    rtp->lastrxts = 0;
01080    rtp->lastividtimestamp = 0;
01081    rtp->lastovidtimestamp = 0;
01082    rtp->lasteventseqn = 0;
01083    rtp->lasteventendseqn = 0;
01084    rtp->lasttxformat = 0;
01085    rtp->lastrxformat = 0;
01086    rtp->dtmfcount = 0;
01087    rtp->dtmfduration = 0;
01088    rtp->seqno = 0;
01089    rtp->rxseqno = 0;
01090 }

int ast_rtp_sendcng ( struct ast_rtp rtp,
int  level 
)

Definition at line 1208 of file rtp.c.

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

Referenced by do_monitor().

01209 {
01210    unsigned int *rtpheader;
01211    int hdrlen = 12;
01212    int res;
01213    int payload;
01214    char data[256];
01215    char iabuf[INET_ADDRSTRLEN];
01216    level = 127 - (level & 0x7f);
01217    payload = ast_rtp_lookup_code(rtp, 0, AST_RTP_CN);
01218 
01219    /* If we have no peer, return immediately */ 
01220    if (!rtp->them.sin_addr.s_addr)
01221       return 0;
01222 
01223    rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
01224 
01225    /* Get a pointer to the header */
01226    rtpheader = (unsigned int *)data;
01227    rtpheader[0] = htonl((2 << 30) | (1 << 23) | (payload << 16) | (rtp->seqno++));
01228    rtpheader[1] = htonl(rtp->lastts);
01229    rtpheader[2] = htonl(rtp->ssrc); 
01230    data[12] = level;
01231    if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
01232       res = sendto(rtp->s, (void *)rtpheader, hdrlen + 1, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
01233       if (res <0) 
01234          ast_log(LOG_ERROR, "RTP Comfort Noise Transmission error to %s:%d: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr), ntohs(rtp->them.sin_port), strerror(errno));
01235       if(rtp_debug_test_addr(&rtp->them))
01236          ast_verbose("Sent Comfort Noise RTP packet to %s:%d (type %d, seq %d, ts %d, len %d)\n"
01237                , ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr), ntohs(rtp->them.sin_port), payload, rtp->seqno, rtp->lastts,res - hdrlen);        
01238          
01239    }
01240    return 0;
01241 }

int ast_rtp_senddigit ( struct ast_rtp rtp,
char  digit 
)

Definition at line 1126 of file rtp.c.

References ast_inet_ntoa(), ast_log(), AST_RTP_DTMF, ast_rtp_lookup_code(), ast_tvadd(), ast_verbose(), ast_rtp::dtmfmute, ast_rtp::lastdigitts, LOG_ERROR, LOG_WARNING, rtp_debug_test_addr(), ast_rtp::s, ast_rtp::seqno, ast_rtp::ssrc, and ast_rtp::them.

Referenced by oh323_digit(), and sip_senddigit().

01127 {
01128    unsigned int *rtpheader;
01129    int hdrlen = 12;
01130    int res;
01131    int x;
01132    int payload;
01133    char data[256];
01134    char iabuf[INET_ADDRSTRLEN];
01135 
01136    if ((digit <= '9') && (digit >= '0'))
01137       digit -= '0';
01138    else if (digit == '*')
01139       digit = 10;
01140    else if (digit == '#')
01141       digit = 11;
01142    else if ((digit >= 'A') && (digit <= 'D')) 
01143       digit = digit - 'A' + 12;
01144    else if ((digit >= 'a') && (digit <= 'd')) 
01145       digit = digit - 'a' + 12;
01146    else {
01147       ast_log(LOG_WARNING, "Don't know how to represent '%c'\n", digit);
01148       return -1;
01149    }
01150    payload = ast_rtp_lookup_code(rtp, 0, AST_RTP_DTMF);
01151 
01152    /* If we have no peer, return immediately */ 
01153    if (!rtp->them.sin_addr.s_addr)
01154       return 0;
01155 
01156    rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
01157    
01158    /* Get a pointer to the header */
01159    rtpheader = (unsigned int *)data;
01160    rtpheader[0] = htonl((2 << 30) | (1 << 23) | (payload << 16) | (rtp->seqno));
01161    rtpheader[1] = htonl(rtp->lastdigitts);
01162    rtpheader[2] = htonl(rtp->ssrc); 
01163    rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (0));
01164    for (x = 0; x < 6; x++) {
01165       if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
01166          res = sendto(rtp->s, (void *) rtpheader, hdrlen + 4, 0, (struct sockaddr *) &rtp->them, sizeof(rtp->them));
01167          if (res < 0) 
01168             ast_log(LOG_ERROR, "RTP Transmission error to %s:%d: %s\n",
01169                ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr),
01170                ntohs(rtp->them.sin_port), strerror(errno));
01171          if (rtp_debug_test_addr(&rtp->them))
01172             ast_verbose("Sent RTP packet to %s:%d (type %d, seq %u, ts %u, len %u)\n",
01173                    ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr),
01174                    ntohs(rtp->them.sin_port), payload, rtp->seqno, rtp->lastdigitts, res - hdrlen);
01175       }
01176       /* Sequence number of last two end packets does not get incremented */
01177       if (x < 3)
01178          rtp->seqno++;
01179       /* Clear marker bit and set seqno */
01180       rtpheader[0] = htonl((2 << 30) | (payload << 16) | (rtp->seqno));
01181       /* For the last three packets, set the duration and the end bit */
01182       if (x == 2) {
01183 #if 0
01184          /* No, this is wrong...  Do not increment lastdigitts, that's not according
01185             to the RFC, as best we can determine */
01186          rtp->lastdigitts++; /* or else the SPA3000 will click instead of beeping... */
01187          rtpheader[1] = htonl(rtp->lastdigitts);
01188 #endif         
01189          /* Make duration 800 (100ms) */
01190          rtpheader[3] |= htonl((800));
01191          /* Set the End bit */
01192          rtpheader[3] |= htonl((1 << 23));
01193       }
01194    }
01195    /* Increment the digit timestamp by 120ms, to ensure that digits
01196       sent sequentially with no intervening non-digit packets do not
01197       get sent with the same timestamp, and that sequential digits
01198       have some 'dead air' in between them
01199    */
01200    rtp->lastdigitts += 960;
01201    /* Increment the sequence number to reflect the last packet
01202       that was sent
01203    */
01204    rtp->seqno++;
01205    return 0;
01206 }

void ast_rtp_set_callback ( struct ast_rtp rtp,
ast_rtp_callback  callback 
)

Definition at line 170 of file rtp.c.

References ast_rtp::callback.

Referenced by start_rtp().

00171 {
00172    rtp->callback = callback;
00173 }

void ast_rtp_set_data ( struct ast_rtp rtp,
void *  data 
)

Definition at line 165 of file rtp.c.

References ast_rtp::data.

Referenced by start_rtp().

00166 {
00167    rtp->data = data;
00168 }

void ast_rtp_set_m_type ( struct ast_rtp rtp,
int  pt 
)

Definition at line 742 of file rtp.c.

References rtpPayloadType::code, ast_rtp::current_RTP_PT, MAX_RTP_PT, and static_RTP_PT.

Referenced by process_sdp().

00742                                                      {
00743    if (pt < 0 || pt > MAX_RTP_PT) 
00744       return; /* bogus payload type */
00745 
00746    if (static_RTP_PT[pt].code != 0) {
00747       rtp->current_RTP_PT[pt] = static_RTP_PT[pt];
00748    }
00749 } 

void ast_rtp_set_peer ( struct ast_rtp rtp,
struct sockaddr_in *  them 
)

Definition at line 1033 of file rtp.c.

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

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

01034 {
01035    rtp->them.sin_port = them->sin_port;
01036    rtp->them.sin_addr = them->sin_addr;
01037    if (rtp->rtcp) {
01038       rtp->rtcp->them.sin_port = htons(ntohs(them->sin_port) + 1);
01039       rtp->rtcp->them.sin_addr = them->sin_addr;
01040    }
01041    rtp->rxseqno = 0;
01042 }

void ast_rtp_set_rtpmap_type ( struct ast_rtp rtp,
int  pt,
char *  mimeType,
char *  mimeSubtype 
)

Definition at line 753 of file rtp.c.

References ast_rtp::current_RTP_PT, MAX_RTP_PT, mimeTypes, subtype, and type.

Referenced by process_sdp(), and set_dtmf_payload().

00754                                              {
00755    int i;
00756 
00757    if (pt < 0 || pt > MAX_RTP_PT) 
00758          return; /* bogus payload type */
00759 
00760    for (i = 0; i < sizeof mimeTypes/sizeof mimeTypes[0]; ++i) {
00761       if (strcasecmp(mimeSubtype, mimeTypes[i].subtype) == 0 &&
00762            strcasecmp(mimeType, mimeTypes[i].type) == 0) {
00763          rtp->current_RTP_PT[pt] = mimeTypes[i].payloadType;
00764       return;
00765       }
00766    }
00767 } 

void ast_rtp_setnat ( struct ast_rtp rtp,
int  nat 
)

Definition at line 175 of file rtp.c.

References ast_rtp::nat.

Referenced by check_user_full(), create_addr(), create_addr_from_peer(), oh323_request(), oh323_rtp_read(), sip_alloc(), and start_rtp().

00176 {
00177    rtp->nat = nat;
00178 }

int ast_rtp_settos ( struct ast_rtp rtp,
int  tos 
)

Definition at line 1024 of file rtp.c.

References ast_log(), LOG_WARNING, and ast_rtp::s.

Referenced by oh323_alloc(), and sip_alloc().

01025 {
01026    int res;
01027 
01028    if ((res = setsockopt(rtp->s, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)))) 
01029       ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos);
01030    return res;
01031 }

void ast_rtp_stop ( struct ast_rtp rtp  ) 

Definition at line 1062 of file rtp.c.

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

Referenced by handle_request_bye(), handle_request_cancel(), handle_response(), and process_sdp().

01063 {
01064    memset(&rtp->them.sin_addr, 0, sizeof(rtp->them.sin_addr));
01065    memset(&rtp->them.sin_port, 0, sizeof(rtp->them.sin_port));
01066    if (rtp->rtcp) {
01067       memset(&rtp->rtcp->them.sin_addr, 0, sizeof(rtp->them.sin_addr));
01068       memset(&rtp->rtcp->them.sin_port, 0, sizeof(rtp->them.sin_port));
01069    }
01070 }

int ast_rtp_write ( struct ast_rtp rtp,
struct ast_frame f 
)

Definition at line 1324 of file rtp.c.

References AST_FORMAT_ADPCM, AST_FORMAT_ALAW, AST_FORMAT_G723_1, AST_FORMAT_G726, AST_FORMAT_G729A, AST_FORMAT_GSM, AST_FORMAT_H261, AST_FORMAT_H263, AST_FORMAT_H263_PLUS, AST_FORMAT_ILBC, AST_FORMAT_LPC10, AST_FORMAT_SLINEAR, AST_FORMAT_SPEEX, AST_FORMAT_ULAW, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frdup(), ast_getformatname(), ast_log(), ast_rtp_lookup_code(), ast_rtp_raw_write(), ast_smoother_feed, ast_smoother_feed_be, AST_SMOOTHER_FLAG_G729, ast_smoother_free(), ast_smoother_new(), ast_smoother_read(), ast_smoother_set_flags(), ast_frame::datalen, ast_frame::frametype, ast_rtp::lasttxformat, LOG_DEBUG, LOG_WARNING, ast_frame::offset, option_debug, ast_rtp::smoother, ast_frame::subclass, and ast_rtp::them.

Referenced by mgcp_write(), oh323_write(), sip_write(), and skinny_write().

01325 {
01326    struct ast_frame *f;
01327    int codec;
01328    int hdrlen = 12;
01329    int subclass;
01330    
01331 
01332    /* If we have no peer, return immediately */ 
01333    if (!rtp->them.sin_addr.s_addr)
01334       return 0;
01335 
01336    /* If there is no data length, return immediately */
01337    if (!_f->datalen) 
01338       return 0;
01339    
01340    /* Make sure we have enough space for RTP header */
01341    if ((_f->frametype != AST_FRAME_VOICE) && (_f->frametype != AST_FRAME_VIDEO)) {
01342       ast_log(LOG_WARNING, "RTP can only send voice\n");
01343       return -1;
01344    }
01345 
01346    subclass = _f->subclass;
01347    if (_f->frametype == AST_FRAME_VIDEO)
01348       subclass &= ~0x1;
01349 
01350    codec = ast_rtp_lookup_code(rtp, 1, subclass);
01351    if (codec < 0) {
01352       ast_log(LOG_WARNING, "Don't know how to send format %s packets with RTP\n", ast_getformatname(_f->subclass));
01353       return -1;
01354    }
01355 
01356    if (rtp->lasttxformat != subclass) {
01357       /* New format, reset the smoother */
01358       if (option_debug)
01359          ast_log(LOG_DEBUG, "Ooh, format changed from %s to %s\n", ast_getformatname(rtp->lasttxformat), ast_getformatname(subclass));
01360       rtp->lasttxformat = subclass;
01361       if (rtp->smoother)
01362          ast_smoother_free(rtp->smoother);
01363       rtp->smoother = NULL;
01364    }
01365 
01366 
01367    switch(subclass) {
01368    case AST_FORMAT_SLINEAR:
01369       if (!rtp->smoother) {
01370          rtp->smoother = ast_smoother_new(320);
01371       }
01372       if (!rtp->smoother) {
01373          ast_log(LOG_WARNING, "Unable to create smoother :(\n");
01374          return -1;
01375       }
01376       ast_smoother_feed_be(rtp->smoother, _f);
01377       
01378       while((f = ast_smoother_read(rtp->smoother)))
01379          ast_rtp_raw_write(rtp, f, codec);
01380       break;
01381    case AST_FORMAT_ULAW:
01382    case AST_FORMAT_ALAW:
01383       if (!rtp->smoother) {
01384          rtp->smoother = ast_smoother_new(160);
01385       }
01386       if (!rtp->smoother) {
01387          ast_log(LOG_WARNING, "Unable to create smoother :(\n");
01388          return -1;
01389       }
01390       ast_smoother_feed(rtp->smoother, _f);
01391       
01392       while((f = ast_smoother_read(rtp->smoother)))
01393          ast_rtp_raw_write(rtp, f, codec);
01394       break;
01395    case AST_FORMAT_ADPCM:
01396    case AST_FORMAT_G726:
01397       if (!rtp->smoother) {
01398          rtp->smoother = ast_smoother_new(80);
01399       }
01400       if (!rtp->smoother) {
01401          ast_log(LOG_WARNING, "Unable to create smoother :(\n");
01402          return -1;
01403       }
01404       ast_smoother_feed(rtp->smoother, _f);
01405       
01406       while((f = ast_smoother_read(rtp->smoother)))
01407          ast_rtp_raw_write(rtp, f, codec);
01408       break;
01409    case AST_FORMAT_G729A:
01410       if (!rtp->smoother) {
01411          rtp->smoother = ast_smoother_new(20);
01412          if (rtp->smoother)
01413             ast_smoother_set_flags(rtp->smoother, AST_SMOOTHER_FLAG_G729);
01414       }
01415       if (!rtp->smoother) {
01416          ast_log(LOG_WARNING, "Unable to create g729 smoother :(\n");
01417          return -1;
01418       }
01419       ast_smoother_feed(rtp->smoother, _f);
01420       
01421       while((f = ast_smoother_read(rtp->smoother)))
01422          ast_rtp_raw_write(rtp, f, codec);
01423       break;
01424    case AST_FORMAT_GSM:
01425       if (!rtp->smoother) {
01426          rtp->smoother = ast_smoother_new(33);
01427       }
01428       if (!rtp->smoother) {
01429          ast_log(LOG_WARNING, "Unable to create GSM smoother :(\n");
01430          return -1;
01431       }
01432       ast_smoother_feed(rtp->smoother, _f);
01433       while((f = ast_smoother_read(rtp->smoother)))
01434          ast_rtp_raw_write(rtp, f, codec);
01435       break;
01436    case AST_FORMAT_ILBC:
01437       if (!rtp->smoother) {
01438          rtp->smoother = ast_smoother_new(50);
01439       }
01440       if (!rtp->smoother) {
01441          ast_log(LOG_WARNING, "Unable to create ILBC smoother :(\n");
01442          return -1;
01443       }
01444       ast_smoother_feed(rtp->smoother, _f);
01445       while((f = ast_smoother_read(rtp->smoother)))
01446          ast_rtp_raw_write(rtp, f, codec);
01447       break;
01448    default: 
01449       ast_log(LOG_WARNING, "Not sure about sending format %s packets\n", ast_getformatname(subclass));
01450       /* fall through to... */
01451    case AST_FORMAT_H261:
01452    case AST_FORMAT_H263:
01453    case AST_FORMAT_H263_PLUS:
01454    case AST_FORMAT_G723_1:
01455    case AST_FORMAT_LPC10:
01456    case AST_FORMAT_SPEEX:
01457            /* Don't buffer outgoing frames; send them one-per-packet: */
01458       if (_f->offset < hdrlen) {
01459          f = ast_frdup(_f);
01460       } else {
01461          f = _f;
01462       }
01463       ast_rtp_raw_write(rtp, f, codec);
01464    }
01465       
01466    return 0;
01467 }


Generated on Sat Sep 16 05:48:06 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.7