Wed Oct 28 15:49:17 2009

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>

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

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)
struct 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)
struct rtpPayloadType ast_rtp_lookup_pt (struct ast_rtp *rtp, int pt)
struct ast_rtpast_rtp_new (struct sched_context *sched, struct io_context *io, int rtcpenable, int callbackmode)
 Initializate a RTP session.
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.
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)
struct 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)

#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  )  [read]

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 == EBADF)
00390          CRASH;
00391       if (errno != EAGAIN) {
00392          ast_log(LOG_WARNING, "RTP Read error: %s.  Hanging up now.\n", strerror(errno));
00393          return NULL;
00394       }
00395       return &null_frame;
00396    }
00397 
00398    if (res < hdrlen) {
00399       ast_log(LOG_WARNING, "RTP Read too short\n");
00400       return &null_frame;
00401    }
00402 
00403    if (rtp->nat) {
00404       /* Send to whoever sent to us */
00405       if ((rtp->rtcp->them.sin_addr.s_addr != sin.sin_addr.s_addr) ||
00406           (rtp->rtcp->them.sin_port != sin.sin_port)) {
00407          memcpy(&rtp->rtcp->them, &sin, sizeof(rtp->rtcp->them));
00408          if (option_debug || rtpdebug)
00409             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));
00410       }
00411    }
00412    if (option_debug)
00413       ast_log(LOG_DEBUG, "Got RTCP report of %d bytes\n", res);
00414    return &null_frame;
00415 }

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

References ast_channel::_softhangup, AST_BRIDGE_COMPLETE, AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, AST_BRIDGE_FAILED, AST_BRIDGE_FAILED_NOWARN, AST_BRIDGE_IGNORE_SIGS, AST_BRIDGE_RETRY, ast_check_hangup(), AST_CONTROL_HOLD, AST_CONTROL_UNHOLD, AST_CONTROL_VIDUPDATE, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree(), ast_indicate(), ast_inet_ntoa(), ast_log(), ast_mutex_lock(), ast_mutex_trylock(), ast_mutex_unlock(), ast_read(), ast_rtp_get_peer(), ast_test_flag, ast_waitfor_n(), ast_write(), FLAG_NAT_ACTIVE, ast_frame::frametype, ast_rtp_protocol::get_codec, get_proto(), ast_rtp_protocol::get_rtp_info, ast_rtp_protocol::get_vrtp_info, inaddrcmp(), ast_channel::lock, LOG_DEBUG, LOG_WARNING, ast_channel::masq, ast_channel::masqr, ast_channel::name, option_debug, ast_rtp_protocol::set_rtp_peer, ast_frame::subclass, and ast_channel::tech_pvt.

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

void ast_rtp_destroy ( struct ast_rtp rtp  ) 

Definition at line 1105 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().

01106 {
01107    if (rtp->smoother)
01108       ast_smoother_free(rtp->smoother);
01109    if (rtp->ioid)
01110       ast_io_remove(rtp->io, rtp->ioid);
01111    if (rtp->s > -1)
01112       close(rtp->s);
01113    if (rtp->rtcp) {
01114       close(rtp->rtcp->s);
01115       free(rtp->rtcp);
01116    }
01117    free(rtp);
01118 }

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

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

Referenced by process_sdp().

00783                                                    {
00784    int pt;
00785 
00786    *astFormats = *nonAstFormats = 0;
00787    for (pt = 0; pt < MAX_RTP_PT; ++pt) {
00788       if (rtp->current_RTP_PT[pt].isAstFormat) {
00789          *astFormats |= rtp->current_RTP_PT[pt].code;
00790       } else {
00791          *nonAstFormats |= rtp->current_RTP_PT[pt].code;
00792       }
00793    }
00794 }

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

Definition at line 1057 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().

01058 {
01059    if ((them->sin_family != AF_INET) ||
01060        (them->sin_port != rtp->them.sin_port) ||
01061        (them->sin_addr.s_addr != rtp->them.sin_addr.s_addr)) {
01062       them->sin_family = AF_INET;
01063       them->sin_port = rtp->them.sin_port;
01064       them->sin_addr = rtp->them.sin_addr;
01065       return 1;
01066    }
01067    return 0;
01068 }

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

Definition at line 1070 of file rtp.c.

References ast_rtp::us.

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

01071 {
01072    memcpy(us, &rtp->us, sizeof(rtp->us));
01073 }

void ast_rtp_init ( void   ) 

Definition at line 1913 of file rtp.c.

References ast_cli_register(), and ast_rtp_reload().

Referenced by main().

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

Definition at line 822 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().

00822                                                                                     {
00823 
00824    int pt;
00825 
00826    if (isAstFormat == rtp->rtp_lookup_code_cache_isAstFormat &&
00827       code == rtp->rtp_lookup_code_cache_code) {
00828 
00829       /* Use our cached mapping, to avoid the overhead of the loop below */
00830       return rtp->rtp_lookup_code_cache_result;
00831    }
00832 
00833    /* Check the dynamic list first */
00834    for (pt = 0; pt < MAX_RTP_PT; ++pt) {
00835       if (rtp->current_RTP_PT[pt].code == code && rtp->current_RTP_PT[pt].isAstFormat == isAstFormat) {
00836          rtp->rtp_lookup_code_cache_isAstFormat = isAstFormat;
00837          rtp->rtp_lookup_code_cache_code = code;
00838          rtp->rtp_lookup_code_cache_result = pt;
00839          return pt;
00840       }
00841    }
00842 
00843    /* Then the static list */
00844    for (pt = 0; pt < MAX_RTP_PT; ++pt) {
00845       if (static_RTP_PT[pt].code == code && static_RTP_PT[pt].isAstFormat == isAstFormat) {
00846          rtp->rtp_lookup_code_cache_isAstFormat = isAstFormat;
00847          rtp->rtp_lookup_code_cache_code = code;
00848          rtp->rtp_lookup_code_cache_result = pt;
00849          return pt;
00850       }
00851    }
00852    return -1;
00853 }

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

Definition at line 867 of file rtp.c.

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

Referenced by process_sdp().

00868 {
00869    int format;
00870    unsigned len;
00871    char *end = buf;
00872    char *start = buf;
00873 
00874    if (!buf || !size)
00875       return NULL;
00876 
00877    snprintf(end, size, "0x%x (", capability);
00878 
00879    len = strlen(end);
00880    end += len;
00881    size -= len;
00882    start = end;
00883 
00884    for (format = 1; format < AST_RTP_MAX; format <<= 1) {
00885       if (capability & format) {
00886          const char *name = ast_rtp_lookup_mime_subtype(isAstFormat, format);
00887          snprintf(end, size, "%s|", name);
00888          len = strlen(end);
00889          end += len;
00890          size -= len;
00891       }
00892    }
00893 
00894    if (start == end)
00895       snprintf(start, size, "nothing)"); 
00896    else if (size > 1)
00897       *(end -1) = ')';
00898    
00899    return buf;
00900 }

char* ast_rtp_lookup_mime_subtype ( int  isAstFormat,
int  code 
)

Definition at line 855 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().

00855                                                                          {
00856 
00857    int i;
00858 
00859    for (i = 0; i < sizeof mimeTypes/sizeof mimeTypes[0]; ++i) {
00860    if (mimeTypes[i].payloadType.code == code && mimeTypes[i].payloadType.isAstFormat == isAstFormat) {
00861             return mimeTypes[i].subtype;
00862       }
00863    }
00864    return "";
00865 }

struct rtpPayloadType ast_rtp_lookup_pt ( struct ast_rtp rtp,
int  pt 
) [read]

Definition at line 803 of file rtp.c.

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

Referenced by ast_rtp_read(), and setup_rtp_connection().

00804 {
00805    struct rtpPayloadType result;
00806 
00807    result.isAstFormat = result.code = 0;
00808    if (pt < 0 || pt > MAX_RTP_PT) 
00809       return result; /* bogus payload type */
00810 
00811    /* Start with the negotiated codecs */
00812    if (!rtp->rtp_offered_from_local)
00813       result = rtp->current_RTP_PT[pt];
00814 
00815    /* If it doesn't exist, check our static RTP type list, just in case */
00816    if (!result.code) 
00817       result = static_RTP_PT[pt];
00818    return result;
00819 }

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

References ast_rtp_new_with_bindaddr().

Referenced by start_rtp().

01030 {
01031    struct in_addr ia;
01032 
01033    memset(&ia, 0, sizeof(ia));
01034    return ast_rtp_new_with_bindaddr(sched, io, rtcpenable, callbackmode, ia);
01035 }

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

References ast_io_add(), AST_IO_IN, ast_log(), ast_rtcp_new(), ast_rtp_pt_default(), free, ast_rtp::io, ast_rtp::ioid, LOG_ERROR, malloc, ast_rtp::rtcp, rtp_socket(), rtpread(), ast_rtcp::s, ast_rtp::s, ast_rtp::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().

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

void ast_rtp_offered_from_local ( struct ast_rtp rtp,
int  local 
)

Definition at line 796 of file rtp.c.

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

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

00796                                                                 {
00797    if (rtp)
00798       rtp->rtp_offered_from_local = local;
00799    else
00800       ast_log(LOG_WARNING, "rtp structure is null\n");
00801 }

int ast_rtp_proto_register ( struct ast_rtp_protocol proto  ) 

Definition at line 1505 of file rtp.c.

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

Referenced by load_module(), and unload_module().

01506 {
01507    struct ast_rtp_protocol *cur;
01508    cur = protos;
01509    while(cur) {
01510       if (cur->type == proto->type) {
01511          ast_log(LOG_WARNING, "Tried to register same protocol '%s' twice\n", cur->type);
01512          return -1;
01513       }
01514       cur = cur->next;
01515    }
01516    proto->next = protos;
01517    protos = proto;
01518    return 0;
01519 }

void ast_rtp_proto_unregister ( struct ast_rtp_protocol proto  ) 

Definition at line 1485 of file rtp.c.

References ast_rtp_protocol::next.

Referenced by unload_module().

01486 {
01487    struct ast_rtp_protocol *cur, *prev;
01488 
01489    cur = protos;
01490    prev = NULL;
01491    while(cur) {
01492       if (cur == proto) {
01493          if (prev)
01494             prev->next = proto->next;
01495          else
01496             protos = proto->next;
01497          return;
01498       }
01499       prev = cur;
01500       cur = cur->next;
01501    }
01502 }

void ast_rtp_pt_clear ( struct ast_rtp rtp  ) 

Definition at line 719 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().

00720 {
00721    int i;
00722    if (!rtp)
00723       return;
00724 
00725    for (i = 0; i < MAX_RTP_PT; ++i) {
00726       rtp->current_RTP_PT[i].isAstFormat = 0;
00727       rtp->current_RTP_PT[i].code = 0;
00728    }
00729 
00730    rtp->rtp_lookup_code_cache_isAstFormat = 0;
00731    rtp->rtp_lookup_code_cache_code = 0;
00732    rtp->rtp_lookup_code_cache_result = 0;
00733 }

void ast_rtp_pt_default ( struct ast_rtp rtp  ) 

Definition at line 735 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 ast_rtp_new_with_bindaddr().

00736 {
00737    int i;
00738 
00739    /* Initialize to default payload types */
00740    for (i = 0; i < MAX_RTP_PT; ++i) {
00741       rtp->current_RTP_PT[i].isAstFormat = static_RTP_PT[i].isAstFormat;
00742       rtp->current_RTP_PT[i].code = static_RTP_PT[i].code;
00743    }
00744 
00745    rtp->rtp_lookup_code_cache_isAstFormat = 0;
00746    rtp->rtp_lookup_code_cache_code = 0;
00747    rtp->rtp_lookup_code_cache_result = 0;
00748 }

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

Definition at line 428 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().

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

void ast_rtp_reload ( void   ) 

Definition at line 1857 of file rtp.c.

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

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

01858 {
01859    struct ast_config *cfg;
01860    char *s;
01861 
01862    rtpstart = 5000;
01863    rtpend = 31000;
01864    dtmftimeout = DEFAULT_DTMF_TIMEOUT;
01865    cfg = ast_config_load("rtp.conf");
01866    if (cfg) {
01867       if ((s = ast_variable_retrieve(cfg, "general", "rtpstart"))) {
01868          rtpstart = atoi(s);
01869          if (rtpstart < 1024)
01870             rtpstart = 1024;
01871          if (rtpstart > 65535)
01872             rtpstart = 65535;
01873       }
01874       if ((s = ast_variable_retrieve(cfg, "general", "rtpend"))) {
01875          rtpend = atoi(s);
01876          if (rtpend < 1024)
01877             rtpend = 1024;
01878          if (rtpend > 65535)
01879             rtpend = 65535;
01880       }
01881       if ((s = ast_variable_retrieve(cfg, "general", "rtpchecksums"))) {
01882 #ifdef SO_NO_CHECK
01883          if (ast_false(s))
01884             nochecksums = 1;
01885          else
01886             nochecksums = 0;
01887 #else
01888          if (ast_false(s))
01889             ast_log(LOG_WARNING, "Disabling RTP checksums is not supported on this operating system!\n");
01890 #endif
01891       }
01892       if ((s = ast_variable_retrieve(cfg, "general", "dtmftimeout"))) {
01893          dtmftimeout = atoi(s);
01894          if ((dtmftimeout < 0) || (dtmftimeout > 20000)) {
01895             ast_log(LOG_WARNING, "DTMF timeout of '%d' outside range, using default of '%d' instead\n",
01896                dtmftimeout, DEFAULT_DTMF_TIMEOUT);
01897             dtmftimeout = DEFAULT_DTMF_TIMEOUT;
01898          };
01899       }
01900       ast_config_destroy(cfg);
01901    }
01902    if (rtpstart >= rtpend) {
01903       ast_log(LOG_WARNING, "Unreasonable values for RTP start/end port in rtp.conf\n");
01904       rtpstart = 5000;
01905       rtpend = 31000;
01906    }
01907    if (option_verbose > 1)
01908       ast_verbose(VERBOSE_PREFIX_2 "RTP Allocating from port range %d -> %d\n", rtpstart, rtpend);
01909    
01910 }

void ast_rtp_reset ( struct ast_rtp rtp  ) 

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

01086 {
01087    memset(&rtp->rxcore, 0, sizeof(rtp->rxcore));
01088    memset(&rtp->txcore, 0, sizeof(rtp->txcore));
01089    memset(&rtp->dtmfmute, 0, sizeof(rtp->dtmfmute));
01090    rtp->lastts = 0;
01091    rtp->lastdigitts = 0;
01092    rtp->lastrxts = 0;
01093    rtp->lastividtimestamp = 0;
01094    rtp->lastovidtimestamp = 0;
01095    rtp->lasteventseqn = 0;
01096    rtp->lasteventendseqn = 0;
01097    rtp->lasttxformat = 0;
01098    rtp->lastrxformat = 0;
01099    rtp->dtmfcount = 0;
01100    rtp->dtmfduration = 0;
01101    rtp->seqno = 0;
01102    rtp->rxseqno = 0;
01103 }

int ast_rtp_sendcng ( struct ast_rtp rtp,
int  level 
)

Definition at line 1221 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().

01222 {
01223    unsigned int *rtpheader;
01224    int hdrlen = 12;
01225    int res;
01226    int payload;
01227    char data[256];
01228    char iabuf[INET_ADDRSTRLEN];
01229    level = 127 - (level & 0x7f);
01230    payload = ast_rtp_lookup_code(rtp, 0, AST_RTP_CN);
01231 
01232    /* If we have no peer, return immediately */ 
01233    if (!rtp->them.sin_addr.s_addr)
01234       return 0;
01235 
01236    rtp->dtmfmute = ast_tvadd(ast_tvnow(), ast_tv(0, 500000));
01237 
01238    /* Get a pointer to the header */
01239    rtpheader = (unsigned int *)data;
01240    rtpheader[0] = htonl((2 << 30) | (1 << 23) | (payload << 16) | (rtp->seqno++));
01241    rtpheader[1] = htonl(rtp->lastts);
01242    rtpheader[2] = htonl(rtp->ssrc); 
01243    data[12] = level;
01244    if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
01245       res = sendto(rtp->s, (void *)rtpheader, hdrlen + 1, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
01246       if (res <0) 
01247          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));
01248       if(rtp_debug_test_addr(&rtp->them))
01249          ast_verbose("Sent Comfort Noise RTP packet to %s:%d (type %d, seq %d, ts %d, len %d)\n"
01250                , ast_inet_ntoa(iabuf, sizeof(iabuf), rtp->them.sin_addr), ntohs(rtp->them.sin_port), payload, rtp->seqno, rtp->lastts,res - hdrlen);        
01251          
01252    }
01253    return 0;
01254 }

int ast_rtp_senddigit ( struct ast_rtp rtp,
char  digit 
)

Definition at line 1139 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().

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

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

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

Referenced by process_sdp().

00753                                                      {
00754    if (pt < 0 || pt > MAX_RTP_PT) 
00755       return; /* bogus payload type */
00756 
00757    if (static_RTP_PT[pt].code != 0) {
00758       rtp->current_RTP_PT[pt] = static_RTP_PT[pt];
00759    }
00760 } 

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

Definition at line 1046 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().

01047 {
01048    rtp->them.sin_port = them->sin_port;
01049    rtp->them.sin_addr = them->sin_addr;
01050    if (rtp->rtcp) {
01051       rtp->rtcp->them.sin_port = htons(ntohs(them->sin_port) + 1);
01052       rtp->rtcp->them.sin_addr = them->sin_addr;
01053    }
01054    rtp->rxseqno = 0;
01055 }

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

Definition at line 764 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().

00765                                              {
00766    int i;
00767 
00768    if (pt < 0 || pt > MAX_RTP_PT) 
00769          return; /* bogus payload type */
00770 
00771    for (i = 0; i < sizeof mimeTypes/sizeof mimeTypes[0]; ++i) {
00772       if (strcasecmp(mimeSubtype, mimeTypes[i].subtype) == 0 &&
00773            strcasecmp(mimeType, mimeTypes[i].type) == 0) {
00774          rtp->current_RTP_PT[pt] = mimeTypes[i].payloadType;
00775       return;
00776       }
00777    }
00778 } 

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

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

Referenced by oh323_alloc(), and sip_alloc().

01038 {
01039    int res;
01040 
01041    if ((res = setsockopt(rtp->s, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)))) 
01042       ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos);
01043    return res;
01044 }

void ast_rtp_stop ( struct ast_rtp rtp  ) 

Definition at line 1075 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().

01076 {
01077    memset(&rtp->them.sin_addr, 0, sizeof(rtp->them.sin_addr));
01078    memset(&rtp->them.sin_port, 0, sizeof(rtp->them.sin_port));
01079    if (rtp->rtcp) {
01080       memset(&rtp->rtcp->them.sin_addr, 0, sizeof(rtp->them.sin_addr));
01081       memset(&rtp->rtcp->them.sin_port, 0, sizeof(rtp->them.sin_port));
01082    }
01083 }

int ast_rtp_write ( struct ast_rtp rtp,
struct ast_frame f 
)

Definition at line 1337 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_frfree(), 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().

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


Generated on Wed Oct 28 15:49:17 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6