Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

rtp.h File Reference

#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_DTMF   (1 << 0)
#define AST_RTP_CN   (1 << 1)
#define AST_RTP_CISCO_DTMF   (1 << 2)
#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

ast_rtpast_rtp_new (struct sched_context *sched, struct io_context *io, int rtcpenable, int callbackmode)
void ast_rtp_set_peer (struct ast_rtp *rtp, struct sockaddr_in *them)
void 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_destroy (struct ast_rtp *rtp)
void ast_rtp_set_callback (struct ast_rtp *rtp, ast_rtp_callback callback)
void ast_rtp_set_data (struct ast_rtp *rtp, void *data)
int ast_rtp_write (struct ast_rtp *rtp, struct ast_frame *f)
ast_frameast_rtp_read (struct ast_rtp *rtp)
ast_frameast_rtcp_read (struct ast_rtp *rtp)
int ast_rtp_fd (struct ast_rtp *rtp)
int ast_rtcp_fd (struct ast_rtp *rtp)
int ast_rtp_senddigit (struct ast_rtp *rtp, char digit)
int ast_rtp_settos (struct ast_rtp *rtp, int tos)
void ast_rtp_pt_clear (struct ast_rtp *rtp)
void ast_rtp_pt_default (struct ast_rtp *rtp)
void ast_rtp_set_m_type (struct ast_rtp *rtp, int pt)
void ast_rtp_set_rtpmap_type (struct ast_rtp *rtp, int pt, char *mimeType, char *mimeSubtype)
rtpPayloadType ast_rtp_lookup_pt (struct ast_rtp *rtp, int pt)
int ast_rtp_lookup_code (struct ast_rtp *rtp, int isAstFormat, int code)
void ast_rtp_get_current_formats (struct ast_rtp *rtp, int *astFormats, int *nonAstFormats)
char * ast_rtp_lookup_mime_subtype (int isAstFormat, int code)
void ast_rtp_setnat (struct ast_rtp *rtp, int nat)
int ast_rtp_bridge (struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
int ast_rtp_proto_register (struct ast_rtp_protocol *proto)
void ast_rtp_proto_unregister (struct ast_rtp_protocol *proto)
void ast_rtp_stop (struct ast_rtp *rtp)
void ast_rtp_init (void)
void ast_rtp_reload (void)


Define Documentation

#define AST_RTP_CISCO_DTMF   (1 << 2)
 

DTMF (Cisco Proprietary)

Definition at line 34 of file rtp.h.

Referenced by ast_rtp_read().

#define AST_RTP_CN   (1 << 1)
 

'Comfort Noise' (RFC3389)

Definition at line 32 of file rtp.h.

Referenced by ast_rtp_read().

#define AST_RTP_DTMF   (1 << 0)
 

DTMF (RFC2833)

Definition at line 30 of file rtp.h.

Referenced by ast_rtp_read().

#define AST_RTP_MAX   AST_RTP_CISCO_DTMF
 

Maximum RTP-specific code

Definition at line 36 of file rtp.h.


Typedef Documentation

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

Definition at line 49 of file rtp.h.

Referenced by ast_rtp_set_callback().


Function Documentation

int ast_rtcp_fd struct ast_rtp rtp  ) 
 

Definition at line 106 of file rtp.c.

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

00107 {
00108    if (rtp->rtcp)
00109       return rtp->rtcp->s;
00110    return -1;
00111 }

struct ast_frame* ast_rtcp_read struct ast_rtp rtp  ) 
 

Definition at line 310 of file rtp.c.

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

00311 {
00312    static struct ast_frame null_frame = { AST_FRAME_NULL, };
00313    int len;
00314    int hdrlen = 8;
00315    int res;
00316    struct sockaddr_in sin;
00317    unsigned int rtcpdata[1024];
00318    
00319    if (!rtp->rtcp)
00320       return &null_frame;
00321 
00322    len = sizeof(sin);
00323    
00324    res = recvfrom(rtp->rtcp->s, rtcpdata, sizeof(rtcpdata),
00325                0, (struct sockaddr *)&sin, &len);
00326    
00327    if (res < 0) {
00328       ast_log(LOG_WARNING, "RTP Read error: %s\n", strerror(errno));
00329       if (errno == EBADF)
00330          CRASH;
00331       return &null_frame;
00332    }
00333 
00334    if (res < hdrlen) {
00335       ast_log(LOG_WARNING, "RTP Read too short\n");
00336       return &null_frame;
00337    }
00338 
00339    if (rtp->nat) {
00340       /* Send to whoever sent to us */
00341       if ((rtp->rtcp->them.sin_addr.s_addr != sin.sin_addr.s_addr) ||
00342           (rtp->rtcp->them.sin_port != sin.sin_port)) {
00343          memcpy(&rtp->them, &sin, sizeof(rtp->them));
00344          ast_log(LOG_DEBUG, "RTP NAT: Using address %s:%d\n", inet_ntoa(rtp->rtcp->them.sin_addr), ntohs(rtp->rtcp->them.sin_port));
00345       }
00346    }
00347    if (option_debug)
00348       ast_log(LOG_DEBUG, "Got RTCP report of %d bytes\n", res);
00349    return &null_frame;
00350 }

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

Definition at line 1134 of file rtp.c.

References ast_autoservice_start(), ast_autoservice_stop(), AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, ast_check_hangup(), AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree(), ast_log(), ast_mutex_lock, ast_mutex_unlock, ast_read(), ast_rtp_get_peer(), ast_waitfor_n(), ast_write(), ast_frame::frametype, inaddrcmp(), ast_channel::lock, LOG_DEBUG, LOG_WARNING, ast_channel::name, ast_channel_pvt::pvt, and ast_channel::pvt.

01135 {
01136    struct ast_frame *f;
01137    struct ast_channel *who, *cs[3];
01138    struct ast_rtp *p0, *p1;
01139    struct ast_rtp *vp0, *vp1;
01140    struct ast_rtp_protocol *pr0, *pr1;
01141    struct sockaddr_in ac0, ac1;
01142    struct sockaddr_in vac0, vac1;
01143    struct sockaddr_in t0, t1;
01144    struct sockaddr_in vt0, vt1;
01145    
01146    void *pvt0, *pvt1;
01147    int to;
01148    memset(&vt0, 0, sizeof(vt0));
01149    memset(&vt1, 0, sizeof(vt1));
01150    memset(&vac0, 0, sizeof(vac0));
01151    memset(&vac1, 0, sizeof(vac1));
01152 
01153    /* XXX Wait a half a second for things to settle up 
01154          this really should be fixed XXX */
01155    ast_autoservice_start(c0);
01156    ast_autoservice_start(c1);
01157    usleep(500000);
01158    ast_autoservice_stop(c0);
01159    ast_autoservice_stop(c1);
01160 
01161    /* if need DTMF, cant native bridge */
01162    if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))
01163       return -2;
01164    ast_mutex_lock(&c0->lock);
01165    ast_mutex_lock(&c1->lock);
01166    pr0 = get_proto(c0);
01167    pr1 = get_proto(c1);
01168    if (!pr0) {
01169       ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c0->name);
01170       ast_mutex_unlock(&c0->lock);
01171       ast_mutex_unlock(&c1->lock);
01172       return -1;
01173    }
01174    if (!pr1) {
01175       ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c1->name);
01176       ast_mutex_unlock(&c0->lock);
01177       ast_mutex_unlock(&c1->lock);
01178       return -1;
01179    }
01180    pvt0 = c0->pvt->pvt;
01181    pvt1 = c1->pvt->pvt;
01182    p0 = pr0->get_rtp_info(c0);
01183    if (pr0->get_vrtp_info)
01184       vp0 = pr0->get_vrtp_info(c0);
01185    else
01186       vp0 = NULL;
01187    p1 = pr1->get_rtp_info(c1);
01188    if (pr1->get_vrtp_info)
01189       vp1 = pr1->get_vrtp_info(c1);
01190    else
01191       vp1 = NULL;
01192    if (!p0 || !p1) {
01193       /* Somebody doesn't want to play... */
01194       ast_mutex_unlock(&c0->lock);
01195       ast_mutex_unlock(&c1->lock);
01196       return -2;
01197    }
01198    if (pr0->get_codec && pr1->get_codec) {
01199       int codec0,codec1;
01200       codec0 = pr0->get_codec(c0);
01201       codec1 = pr1->get_codec(c1);
01202       /* Hey, we can't do reinvite if both parties speak diffrent codecs */
01203       if (codec0 != codec1) {
01204          ast_log(LOG_WARNING, "codec0 = %d is not codec1 = %d, cannot native bridge.\n",codec0,codec1);
01205          ast_mutex_unlock(&c0->lock);
01206          ast_mutex_unlock(&c1->lock);
01207          return -2;
01208       }
01209    }
01210    if (pr0->set_rtp_peer(c0, p1, vp1)) 
01211       ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name);
01212    else {
01213       /* Store RTP peer */
01214       ast_rtp_get_peer(p1, &ac1);
01215       if (vp1)
01216          ast_rtp_get_peer(p1, &vac1);
01217    }
01218    if (pr1->set_rtp_peer(c1, p0, vp0))
01219       ast_log(LOG_WARNING, "Channel '%s' failed to talk back to '%s'\n", c1->name, c0->name);
01220    else {
01221       /* Store RTP peer */
01222       ast_rtp_get_peer(p0, &ac0);
01223       if (vp0)
01224          ast_rtp_get_peer(p0, &vac0);
01225    }
01226    ast_mutex_unlock(&c0->lock);
01227    ast_mutex_unlock(&c1->lock);
01228    cs[0] = c0;
01229    cs[1] = c1;
01230    cs[2] = NULL;
01231    for (;;) {
01232       if ((c0->pvt->pvt != pvt0)  ||
01233          (c1->pvt->pvt != pvt1) ||
01234          (c0->masq || c0->masqr || c1->masq || c1->masqr)) {
01235             ast_log(LOG_DEBUG, "Oooh, something is weird, backing out\n");
01236             if (c0->pvt->pvt == pvt0) {
01237                if (pr0->set_rtp_peer(c0, NULL, NULL)) 
01238                   ast_log(LOG_WARNING, "Channel '%s' failed to revert\n", c0->name);
01239             }
01240             if (c1->pvt->pvt == pvt1) {
01241                if (pr1->set_rtp_peer(c1, NULL, NULL)) 
01242                   ast_log(LOG_WARNING, "Channel '%s' failed to revert back\n", c1->name);
01243             }
01244             /* Tell it to try again later */
01245             return -3;
01246       }
01247       to = -1;
01248       ast_rtp_get_peer(p1, &t1);
01249       ast_rtp_get_peer(p0, &t0);
01250       if (vp1)
01251          ast_rtp_get_peer(vp1, &vt1);
01252       if (vp0)
01253          ast_rtp_get_peer(vp0, &vt0);
01254       if (inaddrcmp(&t1, &ac1) || (vp1 && inaddrcmp(&vt1, &vac1))) {
01255          ast_log(LOG_DEBUG, "Oooh, '%s' changed end address\n", c1->name);
01256          if (pr0->set_rtp_peer(c0, t1.sin_addr.s_addr ? p1 : NULL, vt1.sin_addr.s_addr ? vp1 : NULL)) 
01257             ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c0->name, c1->name);
01258          memcpy(&ac1, &t1, sizeof(ac1));
01259          memcpy(&vac1, &vt1, sizeof(vac1));
01260       }
01261       if (inaddrcmp(&t0, &ac0) || (vp0 && inaddrcmp(&vt0, &vac0))) {
01262          ast_log(LOG_DEBUG, "Oooh, '%s' changed end address\n", c0->name);
01263          if (pr1->set_rtp_peer(c1, t0.sin_addr.s_addr ? p0 : NULL, vt0.sin_addr.s_addr ? vp0 : NULL))
01264             ast_log(LOG_WARNING, "Channel '%s' failed to update to '%s'\n", c1->name, c0->name);
01265          memcpy(&ac0, &t0, sizeof(ac0));
01266          memcpy(&vac0, &vt0, sizeof(vac0));
01267       }
01268       who = ast_waitfor_n(cs, 2, &to);
01269       if (!who) {
01270          ast_log(LOG_DEBUG, "Ooh, empty read...\n");
01271          /* check for hagnup / whentohangup */
01272          if (ast_check_hangup(c0) || ast_check_hangup(c1))
01273             break;
01274          continue;
01275       }
01276       f = ast_read(who);
01277       if (!f || ((f->frametype == AST_FRAME_DTMF) &&
01278                (((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) || 
01279                 ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))))) {
01280          *fo = f;
01281          *rc = who;
01282          ast_log(LOG_DEBUG, "Oooh, got a %s\n", f ? "digit" : "hangup");
01283          if ((c0->pvt->pvt == pvt0) && (!c0->_softhangup)) {
01284             if (pr0->set_rtp_peer(c0, NULL, NULL)) 
01285                ast_log(LOG_WARNING, "Channel '%s' failed to revert\n", c0->name);
01286          }
01287          if ((c1->pvt->pvt == pvt1) && (!c1->_softhangup)) {
01288             if (pr1->set_rtp_peer(c1, NULL, NULL)) 
01289                ast_log(LOG_WARNING, "Channel '%s' failed to revert back\n", c1->name);
01290          }
01291          /* That's all we needed */
01292          return 0;
01293       } else {
01294          if ((f->frametype == AST_FRAME_DTMF) || 
01295             (f->frametype == AST_FRAME_VOICE) || 
01296             (f->frametype == AST_FRAME_VIDEO)) {
01297             /* Forward voice or DTMF frames if they happen upon us */
01298             if (who == c0) {
01299                ast_write(c1, f);
01300             } else if (who == c1) {
01301                ast_write(c0, f);
01302             }
01303          }
01304          ast_frfree(f);
01305       }
01306       /* Swap priority not that it's a big deal at this point */
01307       cs[2] = cs[0];
01308       cs[0] = cs[1];
01309       cs[1] = cs[2];
01310       
01311    }
01312    return -1;
01313 }

void ast_rtp_destroy struct ast_rtp rtp  ) 
 

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

00805 {
00806    if (rtp->smoother)
00807       ast_smoother_free(rtp->smoother);
00808    if (rtp->ioid)
00809       ast_io_remove(rtp->io, rtp->ioid);
00810    if (rtp->s > -1)
00811       close(rtp->s);
00812    if (rtp->rtcp) {
00813       close(rtp->rtcp->s);
00814       free(rtp->rtcp);
00815    }
00816    free(rtp);
00817 }

int ast_rtp_fd struct ast_rtp rtp  ) 
 

Definition at line 101 of file rtp.c.

References ast_rtp::s.

00102 {
00103    return rtp->s;
00104 }

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

Definition at line 613 of file rtp.c.

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

00614                                                    {
00615   int pt;
00616 
00617   *astFormats = *nonAstFormats = 0;
00618   for (pt = 0; pt < MAX_RTP_PT; ++pt) {
00619     if (rtp->current_RTP_PT[pt].isAstFormat) {
00620       *astFormats |= rtp->current_RTP_PT[pt].code;
00621     } else {
00622       *nonAstFormats |= rtp->current_RTP_PT[pt].code;
00623     }
00624   }
00625 }

void ast_rtp_get_peer struct ast_rtp rtp,
struct sockaddr_in *  them
 

Definition at line 782 of file rtp.c.

References ast_rtp::them.

Referenced by ast_rtp_bridge().

00783 {
00784    them->sin_family = AF_INET;
00785    them->sin_port = rtp->them.sin_port;
00786    them->sin_addr = rtp->them.sin_addr;
00787 }

void ast_rtp_get_us struct ast_rtp rtp,
struct sockaddr_in *  us
 

Definition at line 789 of file rtp.c.

References ast_rtp::us.

00790 {
00791    memcpy(us, &rtp->us, sizeof(rtp->us));
00792 }

void ast_rtp_init void   ) 
 

Definition at line 1348 of file rtp.c.

References ast_rtp_reload().

Referenced by main().

01349 {
01350    ast_rtp_reload();
01351 }

int ast_rtp_lookup_code struct ast_rtp rtp,
int  isAstFormat,
int  code
 

Definition at line 637 of file rtp.c.

References rtpPayloadType::code, 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_write().

00637                                                                         {
00638   int pt;
00639 
00640   /* Looks up an RTP code out of our *static* outbound list */
00641 
00642   if (isAstFormat == rtp->rtp_lookup_code_cache_isAstFormat &&
00643       code == rtp->rtp_lookup_code_cache_code) {
00644     // Use our cached mapping, to avoid the overhead of the loop below
00645     return rtp->rtp_lookup_code_cache_result;
00646   }
00647 
00648   for (pt = 0; pt < MAX_RTP_PT; ++pt) {
00649     if (static_RTP_PT[pt].code == code &&
00650       static_RTP_PT[pt].isAstFormat == isAstFormat) {
00651       rtp->rtp_lookup_code_cache_isAstFormat = isAstFormat;
00652       rtp->rtp_lookup_code_cache_code = code;
00653       rtp->rtp_lookup_code_cache_result = pt;
00654       return pt;
00655     }
00656   }
00657   return -1;
00658 }

char* ast_rtp_lookup_mime_subtype int  isAstFormat,
int  code
 

Definition at line 660 of file rtp.c.

00660                                                              {
00661   int i;
00662 
00663   for (i = 0; i < sizeof mimeTypes/sizeof mimeTypes[0]; ++i) {
00664     if (mimeTypes[i].payloadType.code == code &&
00665    mimeTypes[i].payloadType.isAstFormat == isAstFormat) {
00666       return mimeTypes[i].subtype;
00667     }
00668   }
00669   return "";
00670 }

struct rtpPayloadType ast_rtp_lookup_pt struct ast_rtp rtp,
int  pt
 

Definition at line 627 of file rtp.c.

References ast_rtp_lookup_pt(), rtpPayloadType::code, rtpPayloadType::isAstFormat, and MAX_RTP_PT.

Referenced by ast_rtp_lookup_pt(), and ast_rtp_read().

00627                                                                      {
00628   if (pt < 0 || pt > MAX_RTP_PT) {
00629     struct rtpPayloadType result;
00630     result.isAstFormat = result.code = 0;
00631     return result; // bogus payload type
00632   }
00633   /* Gotta use our static one, since that's what we sent against */
00634   return static_RTP_PT[pt];
00635 }

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

Definition at line 692 of file rtp.c.

References ast_io_add(), AST_IO_IN, ast_log(), ast_rtp_pt_default(), free, LOG_WARNING, and malloc.

00693 {
00694    struct ast_rtp *rtp;
00695    int x;
00696    int flags;
00697    int startplace;
00698    rtp = malloc(sizeof(struct ast_rtp));
00699    if (!rtp)
00700       return NULL;
00701    memset(rtp, 0, sizeof(struct ast_rtp));
00702    rtp->them.sin_family = AF_INET;
00703    rtp->us.sin_family = AF_INET;
00704    rtp->s = socket(AF_INET, SOCK_DGRAM, 0);
00705    rtp->ssrc = rand();
00706    rtp->seqno = rand() & 0xffff;
00707    if (rtp->s < 0) {
00708       free(rtp);
00709       ast_log(LOG_WARNING, "Unable to allocate socket: %s\n", strerror(errno));
00710       return NULL;
00711    }
00712    if (sched && rtcpenable) {
00713       rtp->sched = sched;
00714       rtp->rtcp = ast_rtcp_new();
00715    }
00716    flags = fcntl(rtp->s, F_GETFL);
00717    fcntl(rtp->s, F_SETFL, flags | O_NONBLOCK);
00718    /* Find us a place */
00719    x = (rand() % (rtpend-rtpstart)) + rtpstart;
00720    x = x & ~1;
00721    startplace = x;
00722    for (;;) {
00723       /* Must be an even port number by RTP spec */
00724       rtp->us.sin_port = htons(x);
00725       if (rtp->rtcp)
00726          rtp->rtcp->us.sin_port = htons(x + 1);
00727       if (!bind(rtp->s, (struct sockaddr *)&rtp->us, sizeof(rtp->us)) &&
00728          (!rtp->rtcp || !bind(rtp->rtcp->s, (struct sockaddr *)&rtp->rtcp->us, sizeof(rtp->rtcp->us))))
00729          break;
00730       if (errno != EADDRINUSE) {
00731          ast_log(LOG_WARNING, "Unexpected bind error: %s\n", strerror(errno));
00732          close(rtp->s);
00733          if (rtp->rtcp) {
00734             close(rtp->rtcp->s);
00735             free(rtp->rtcp);
00736          }
00737          free(rtp);
00738          return NULL;
00739       }
00740       x += 2;
00741       if (x > rtpend)
00742          x = (rtpstart + 1) & ~1;
00743       if (x == startplace) {
00744          ast_log(LOG_WARNING, "No RTP ports remaining\n");
00745          close(rtp->s);
00746          if (rtp->rtcp) {
00747             close(rtp->rtcp->s);
00748             free(rtp->rtcp);
00749          }
00750          free(rtp);
00751          return NULL;
00752       }
00753    }
00754    if (io && sched && callbackmode) {
00755       /* Operate this one in a callback mode */
00756       rtp->sched = sched;
00757       rtp->io = io;
00758       rtp->ioid = ast_io_add(rtp->io, rtp->s, rtpread, AST_IO_IN, rtp);
00759    }
00760    ast_rtp_pt_default(rtp);
00761    return rtp;
00762 }

int ast_rtp_proto_register struct ast_rtp_protocol proto  ) 
 

Definition at line 1105 of file rtp.c.

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

01106 {
01107    struct ast_rtp_protocol *cur;
01108    cur = protos;
01109    while(cur) {
01110       if (cur->type == proto->type) {
01111          ast_log(LOG_WARNING, "Tried to register same protocol '%s' twice\n", cur->type);
01112          return -1;
01113       }
01114       cur = cur->next;
01115    }
01116    proto->next = protos;
01117    protos = proto;
01118    return 0;
01119 }

void ast_rtp_proto_unregister struct ast_rtp_protocol proto  ) 
 

Definition at line 1087 of file rtp.c.

References ast_rtp_protocol::next.

01088 {
01089    struct ast_rtp_protocol *cur, *prev;
01090    cur = protos;
01091    prev = NULL;
01092    while(cur) {
01093       if (cur == proto) {
01094          if (prev)
01095             prev->next = proto->next;
01096          else
01097             protos = proto->next;
01098          return;
01099       }
01100       prev = cur;
01101       cur = cur->next;
01102    }
01103 }

void ast_rtp_pt_clear struct ast_rtp rtp  ) 
 

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

00556 {
00557   int i;
00558 
00559   for (i = 0; i < MAX_RTP_PT; ++i) {
00560     rtp->current_RTP_PT[i].isAstFormat = 0;
00561     rtp->current_RTP_PT[i].code = 0;
00562   }
00563 
00564   rtp->rtp_lookup_code_cache_isAstFormat = 0;
00565   rtp->rtp_lookup_code_cache_code = 0;
00566   rtp->rtp_lookup_code_cache_result = 0;
00567 }

void ast_rtp_pt_default struct ast_rtp rtp  ) 
 

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

00570 {
00571   int i;
00572   /* Initialize to default payload types */
00573   for (i = 0; i < MAX_RTP_PT; ++i) {
00574     rtp->current_RTP_PT[i].isAstFormat = static_RTP_PT[i].isAstFormat;
00575     rtp->current_RTP_PT[i].code = static_RTP_PT[i].code;
00576   }
00577 
00578   rtp->rtp_lookup_code_cache_isAstFormat = 0;
00579   rtp->rtp_lookup_code_cache_code = 0;
00580   rtp->rtp_lookup_code_cache_result = 0;
00581 }

struct ast_frame* ast_rtp_read struct ast_rtp rtp  ) 
 

Definition at line 352 of file rtp.c.

References AST_FORMAT_ADPCM, AST_FORMAT_ALAW, AST_FORMAT_G723_1, AST_FORMAT_G729A, AST_FORMAT_GSM, AST_FORMAT_ILBC, AST_FORMAT_MAX_AUDIO, AST_FORMAT_SLINEAR, AST_FORMAT_SPEEX, AST_FORMAT_ULAW, AST_FRAME_NULL, AST_FRAME_VIDEO, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_getformatname(), ast_log(), AST_RTP_CISCO_DTMF, AST_RTP_CN, AST_RTP_DTMF, ast_rtp_lookup_pt(), rtpPayloadType::code, CRASH, ast_frame::data, ast_frame::datalen, ast_rtp::dtmfcount, ast_rtp::f, ast_frame::frametype, rtpPayloadType::isAstFormat, ast_rtp::lastividtimestamp, ast_rtp::lastrxformat, ast_rtp::lastrxts, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, ast_frame::mallocd, ast_rtp::nat, ast_frame::offset, ast_rtp::rawdata, ast_rtp::resp, ast_rtp::s, ast_frame::samples, ast_frame::src, ast_frame::subclass, and ast_rtp::them.

00353 {
00354    int res;
00355    struct sockaddr_in sin;
00356    int len;
00357    unsigned int seqno;
00358    int payloadtype;
00359    int hdrlen = 12;
00360    int mark;
00361    unsigned int timestamp;
00362    unsigned int *rtpheader;
00363    static struct ast_frame *f, null_frame = { AST_FRAME_NULL, };
00364    struct rtpPayloadType rtpPT;
00365    
00366    len = sizeof(sin);
00367    
00368    /* Cache where the header will go */
00369    res = recvfrom(rtp->s, rtp->rawdata + AST_FRIENDLY_OFFSET, sizeof(rtp->rawdata) - AST_FRIENDLY_OFFSET,
00370                0, (struct sockaddr *)&sin, &len);
00371 
00372 
00373    rtpheader = (unsigned int *)(rtp->rawdata + AST_FRIENDLY_OFFSET);
00374    if (res < 0) {
00375       ast_log(LOG_WARNING, "RTP Read error: %s\n", strerror(errno));
00376       if (errno == EBADF)
00377          CRASH;
00378       return &null_frame;
00379    }
00380    if (res < hdrlen) {
00381       ast_log(LOG_WARNING, "RTP Read too short\n");
00382       return &null_frame;
00383    }
00384    if (rtp->nat) {
00385       /* Send to whoever sent to us */
00386       if ((rtp->them.sin_addr.s_addr != sin.sin_addr.s_addr) ||
00387           (rtp->them.sin_port != sin.sin_port)) {
00388          memcpy(&rtp->them, &sin, sizeof(rtp->them));
00389          ast_log(LOG_DEBUG, "RTP NAT: Using address %s:%d\n", inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port));
00390       }
00391    }
00392    /* Get fields */
00393    seqno = ntohl(rtpheader[0]);
00394    payloadtype = (seqno & 0x7f0000) >> 16;
00395    mark = seqno & (1 << 23);
00396    seqno &= 0xffff;
00397    timestamp = ntohl(rtpheader[1]);
00398 
00399 #if 0
00400    printf("Got RTP packet from %s:%d (type %d, seq %d, ts %d, len = %d)\n", inet_ntoa(sin.sin_addr), ntohs(sin.sin_port), payloadtype, seqno, timestamp,res - hdrlen);
00401 #endif   
00402    rtpPT = ast_rtp_lookup_pt(rtp, payloadtype);
00403    if (!rtpPT.isAstFormat) {
00404      // This is special in-band data that's not one of our codecs
00405      if (rtpPT.code == AST_RTP_DTMF) {
00406        /* It's special -- rfc2833 process it */
00407        f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
00408        if (f) return f; else return &null_frame;
00409      } else if (rtpPT.code == AST_RTP_CISCO_DTMF) {
00410        /* It's really special -- process it the Cisco way */
00411        f = process_cisco_dtmf(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
00412        if (f) return f; else return &null_frame;
00413      } else if (rtpPT.code == AST_RTP_CN) {
00414        /* Comfort Noise */
00415        f = process_rfc3389(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen);
00416        if (f) return f; else return &null_frame;
00417      } else {
00418        ast_log(LOG_NOTICE, "Unknown RTP codec %d received\n", payloadtype);
00419        return &null_frame;
00420      }
00421    }
00422    rtp->f.subclass = rtpPT.code;
00423    if (rtp->f.subclass < AST_FORMAT_MAX_AUDIO)
00424       rtp->f.frametype = AST_FRAME_VOICE;
00425    else
00426       rtp->f.frametype = AST_FRAME_VIDEO;
00427    rtp->lastrxformat = rtp->f.subclass;
00428 
00429    if (!rtp->lastrxts)
00430       rtp->lastrxts = timestamp;
00431 
00432    if (rtp->dtmfcount) {
00433 #if 0
00434       printf("dtmfcount was %d\n", rtp->dtmfcount);
00435 #endif      
00436       rtp->dtmfcount -= (timestamp - rtp->lastrxts);
00437       if (rtp->dtmfcount < 0)
00438          rtp->dtmfcount = 0;
00439 #if 0
00440       if (dtmftimeout != rtp->dtmfcount)
00441          printf("dtmfcount is %d\n", rtp->dtmfcount);
00442 #endif
00443    }
00444    rtp->lastrxts = timestamp;
00445 
00446    /* Send any pending DTMF */
00447    if (rtp->resp && !rtp->dtmfcount) {
00448       ast_log(LOG_DEBUG, "Sending pending DTMF\n");
00449       return send_dtmf(rtp);
00450    }
00451    rtp->f.mallocd = 0;
00452    rtp->f.datalen = res - hdrlen;
00453    rtp->f.data = rtp->rawdata + hdrlen + AST_FRIENDLY_OFFSET;
00454    rtp->f.offset = hdrlen + AST_FRIENDLY_OFFSET;
00455    if (rtp->f.subclass < AST_FORMAT_MAX_AUDIO) {
00456       switch(rtp->f.subclass) {
00457       case AST_FORMAT_ULAW:
00458       case AST_FORMAT_ALAW:
00459          rtp->f.samples = rtp->f.datalen;
00460          break;
00461       case AST_FORMAT_SLINEAR:
00462          rtp->f.samples = rtp->f.datalen / 2;
00463          break;
00464       case AST_FORMAT_GSM:
00465          rtp->f.samples = 160 * (rtp->f.datalen / 33);
00466          break;
00467       case AST_FORMAT_ILBC:
00468          rtp->f.samples = 240 * (rtp->f.datalen / 50);
00469          break;
00470       case AST_FORMAT_ADPCM:
00471          rtp->f.samples = rtp->f.datalen * 2;
00472          break;
00473       case AST_FORMAT_G729A:
00474          rtp->f.samples = rtp->f.datalen * 8;
00475          break;
00476       case AST_FORMAT_G723_1:
00477          rtp->f.samples = g723_samples(rtp->f.data, rtp->f.datalen);
00478          break;
00479       case AST_FORMAT_SPEEX:
00480               rtp->f.samples = 160;
00481          // assumes that the RTP packet contained one Speex frame
00482          break;
00483       default:
00484          ast_log(LOG_NOTICE, "Unable to calculate samples for format %s\n", ast_getformatname(rtp->f.subclass));
00485          break;
00486       }
00487    } else {
00488       /* Video -- samples is # of samples vs. 90000 */
00489       if (!rtp->lastividtimestamp)
00490          rtp->lastividtimestamp = timestamp;
00491       rtp->f.samples = timestamp - rtp->lastividtimestamp;
00492       rtp->lastividtimestamp = timestamp;
00493       if (mark)
00494          rtp->f.subclass |= 0x1;
00495       
00496    }
00497    rtp->f.src = "RTP";
00498    return &rtp->f;
00499 }

void ast_rtp_reload void   ) 
 

Definition at line 1315 of file rtp.c.

References ast_destroy(), ast_load(), ast_log(), ast_variable_retrieve(), ast_verbose(), LOG_WARNING, option_verbose, s, and VERBOSE_PREFIX_2.

Referenced by ast_module_reload(), and ast_rtp_init().

01316 {
01317    struct ast_config *cfg;
01318    char *s;
01319    rtpstart = 5000;
01320    rtpend = 31000;
01321    cfg = ast_load("rtp.conf");
01322    if (cfg) {
01323       if ((s = ast_variable_retrieve(cfg, "general", "rtpstart"))) {
01324          rtpstart = atoi(s);
01325          if (rtpstart < 1024)
01326             rtpstart = 1024;
01327          if (rtpstart > 65535)
01328             rtpstart = 65535;
01329       }
01330       if ((s = ast_variable_retrieve(cfg, "general", "rtpend"))) {
01331          rtpend = atoi(s);
01332          if (rtpend < 1024)
01333             rtpend = 1024;
01334          if (rtpend > 65535)
01335             rtpend = 65535;
01336       }
01337       ast_destroy(cfg);
01338    }
01339    if (rtpstart >= rtpend) {
01340       ast_log(LOG_WARNING, "Unreasonable values for RTP start/end\n");
01341       rtpstart = 5000;
01342       rtpend = 31000;
01343    }
01344    if (option_verbose > 1)
01345       ast_verbose(VERBOSE_PREFIX_2 "RTP Allocating from port range %d -> %d\n", rtpstart, rtpend);
01346 }

int ast_rtp_senddigit struct ast_rtp rtp,
char  digit
 

Definition at line 835 of file rtp.c.

References ast_log(), ast_rtp::lastts, LOG_NOTICE, LOG_WARNING, ast_rtp::s, ast_rtp::seqno, ast_rtp::ssrc, and ast_rtp::them.

00836 {
00837    unsigned int *rtpheader;
00838    int hdrlen = 12;
00839    int res;
00840    int ms;
00841    int pred;
00842    int x;
00843    char data[256];
00844 
00845    if ((digit <= '9') && (digit >= '0'))
00846       digit -= '0';
00847    else if (digit == '*')
00848       digit = 10;
00849    else if (digit == '#')
00850       digit = 11;
00851    else if ((digit >= 'A') && (digit <= 'D')) 
00852       digit = digit - 'A' + 12;
00853    else if ((digit >= 'a') && (digit <= 'd')) 
00854       digit = digit - 'a' + 12;
00855    else {
00856       ast_log(LOG_WARNING, "Don't know how to represent '%c'\n", digit);
00857       return -1;
00858    }
00859    
00860 
00861    /* If we have no peer, return immediately */ 
00862    if (!rtp->them.sin_addr.s_addr)
00863       return 0;
00864 
00865    ms = calc_txstamp(rtp);
00866    /* Default prediction */
00867    pred = rtp->lastts + ms * 8;
00868    
00869    /* Get a pointer to the header */
00870    rtpheader = (unsigned int *)data;
00871    rtpheader[0] = htonl((2 << 30) | (1 << 23) | (101 << 16) | (rtp->seqno++));
00872    rtpheader[1] = htonl(rtp->lastts);
00873    rtpheader[2] = htonl(rtp->ssrc); 
00874    rtpheader[3] = htonl((digit << 24) | (0xa << 16) | (0));
00875    for (x=0;x<4;x++) {
00876       if (rtp->them.sin_port && rtp->them.sin_addr.s_addr) {
00877          res = sendto(rtp->s, (void *)rtpheader, hdrlen + 4, 0, (struct sockaddr *)&rtp->them, sizeof(rtp->them));
00878          if (res <0) 
00879             ast_log(LOG_NOTICE, "RTP Transmission error to %s:%d: %s\n", inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port), strerror(errno));
00880    #if 0
00881       printf("Sent %d bytes of RTP data to %s:%d\n", res, inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port));
00882    #endif      
00883       }
00884       if (x ==0) {
00885          /* Clear marker bit and increment seqno */
00886          rtpheader[0] = htonl((2 << 30)  | (101 << 16) | (rtp->seqno++));
00887          /* Make duration 240 */
00888          rtpheader[3] |= htonl((240));
00889          /* Set the End bit for the last 3 */
00890          rtpheader[3] |= htonl((1 << 23));
00891       }
00892    }
00893    return 0;
00894 }

void ast_rtp_set_callback struct ast_rtp rtp,
ast_rtp_callback  callback
 

Definition at line 154 of file rtp.c.

References ast_rtp_callback, and ast_rtp::callback.

00155 {
00156    rtp->callback = callback;
00157 }

void ast_rtp_set_data struct ast_rtp rtp,
void *  data
 

Definition at line 149 of file rtp.c.

References ast_rtp::data.

00150 {
00151    rtp->data = data;
00152 }

void ast_rtp_set_m_type struct ast_rtp rtp,
int  pt
 

Definition at line 586 of file rtp.c.

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

00586                                                      {
00587   if (pt < 0 || pt > MAX_RTP_PT) return; // bogus payload type
00588 
00589   if (static_RTP_PT[pt].code != 0) {
00590     rtp->current_RTP_PT[pt] = static_RTP_PT[pt];
00591   }
00592 } 

void ast_rtp_set_peer struct ast_rtp rtp,
struct sockaddr_in *  them
 

Definition at line 772 of file rtp.c.

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

00773 {
00774    rtp->them.sin_port = them->sin_port;
00775    rtp->them.sin_addr = them->sin_addr;
00776    if (rtp->rtcp) {
00777       rtp->rtcp->them.sin_port = htons(ntohs(them->sin_port) + 1);
00778       rtp->rtcp->them.sin_addr = them->sin_addr;
00779    }
00780 }

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

Definition at line 596 of file rtp.c.

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

00597                                              {
00598   int i;
00599 
00600   if (pt < 0 || pt > MAX_RTP_PT) return; // bogus payload type
00601 
00602   for (i = 0; i < sizeof mimeTypes/sizeof mimeTypes[0]; ++i) {
00603     if (strcasecmp(mimeSubtype, mimeTypes[i].subtype) == 0 &&
00604    strcasecmp(mimeType, mimeTypes[i].type) == 0) {
00605       rtp->current_RTP_PT[pt] = mimeTypes[i].payloadType;
00606       return;
00607     }
00608   }
00609 } 

void ast_rtp_setnat struct ast_rtp rtp,
int  nat
 

Definition at line 159 of file rtp.c.

References ast_rtp::nat.

00160 {
00161    rtp->nat = nat;
00162 }

int ast_rtp_settos struct ast_rtp rtp,
int  tos
 

Definition at line 764 of file rtp.c.

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

00765 {
00766    int res;
00767    if ((res = setsockopt(rtp->s, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)))) 
00768       ast_log(LOG_WARNING, "Unable to set TOS to %d\n", tos);
00769    return res;
00770 }

void ast_rtp_stop struct ast_rtp rtp  ) 
 

Definition at line 794 of file rtp.c.

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

00795 {
00796    memset(&rtp->them.sin_addr, 0, sizeof(rtp->them.sin_addr));
00797    memset(&rtp->them.sin_port, 0, sizeof(rtp->them.sin_port));
00798    if (rtp->rtcp) {
00799       memset(&rtp->rtcp->them.sin_addr, 0, sizeof(rtp->them.sin_addr));
00800       memset(&rtp->rtcp->them.sin_port, 0, sizeof(rtp->them.sin_port));
00801    }
00802 }

int ast_rtp_write struct ast_rtp rtp,
struct ast_frame f
 

Definition at line 974 of file rtp.c.

References AST_FORMAT_ALAW, AST_FORMAT_G723_1, AST_FORMAT_G729A, AST_FORMAT_GSM, AST_FORMAT_H261, AST_FORMAT_H263, AST_FORMAT_ILBC, AST_FORMAT_SPEEX, AST_FORMAT_ULAW, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frdup(), ast_getformatname(), ast_log(), ast_rtp_lookup_code(), ast_smoother_feed(), ast_smoother_free(), ast_smoother_new(), ast_smoother_read(), ast_frame::datalen, ast_frame::frametype, ast_rtp::lasttxformat, LOG_DEBUG, LOG_WARNING, ast_frame::offset, ast_rtp::smoother, ast_frame::subclass, and ast_rtp::them.

00975 {
00976    struct ast_frame *f;
00977    int codec;
00978    int hdrlen = 12;
00979    int subclass;
00980    
00981 
00982    /* If we have no peer, return immediately */ 
00983    if (!rtp->them.sin_addr.s_addr)
00984       return 0;
00985 
00986    /* If there is no data length, return immediately */
00987    if (!_f->datalen) 
00988       return 0;
00989    
00990    /* Make sure we have enough space for RTP header */
00991    if ((_f->frametype != AST_FRAME_VOICE) && (_f->frametype != AST_FRAME_VIDEO)) {
00992       ast_log(LOG_WARNING, "RTP can only send voice\n");
00993       return -1;
00994    }
00995 
00996    subclass = _f->subclass;
00997    if (_f->frametype == AST_FRAME_VIDEO)
00998       subclass &= ~0x1;
00999 
01000    codec = ast_rtp_lookup_code(rtp, 1, subclass);
01001    if (codec < 0) {
01002       ast_log(LOG_WARNING, "Don't know how to send format %s packets with RTP\n", ast_getformatname(_f->subclass));
01003       return -1;
01004    }
01005 
01006    if (rtp->lasttxformat != subclass) {
01007       /* New format, reset the smoother */
01008       ast_log(LOG_DEBUG, "Ooh, format changed from %s to %s\n", ast_getformatname(rtp->lasttxformat), ast_getformatname(subclass));
01009       rtp->lasttxformat = subclass;
01010       if (rtp->smoother)
01011          ast_smoother_free(rtp->smoother);
01012       rtp->smoother = NULL;
01013    }
01014 
01015 
01016    switch(subclass) {
01017    case AST_FORMAT_ULAW:
01018    case AST_FORMAT_ALAW:
01019       if (!rtp->smoother) {
01020          rtp->smoother = ast_smoother_new(160);
01021       }
01022       if (!rtp->smoother) {
01023          ast_log(LOG_WARNING, "Unable to create smoother :(\n");
01024          return -1;
01025       }
01026       ast_smoother_feed(rtp->smoother, _f);
01027       
01028       while((f = ast_smoother_read(rtp->smoother)))
01029          ast_rtp_raw_write(rtp, f, codec);
01030       break;
01031    case AST_FORMAT_G729A:
01032       if (!rtp->smoother) {
01033          rtp->smoother = ast_smoother_new(20);
01034       }
01035       if (!rtp->smoother) {
01036          ast_log(LOG_WARNING, "Unable to create g729 smoother :(\n");
01037          return -1;
01038       }
01039       ast_smoother_feed(rtp->smoother, _f);
01040       
01041       while((f = ast_smoother_read(rtp->smoother)))
01042          ast_rtp_raw_write(rtp, f, codec);
01043       break;
01044    case AST_FORMAT_GSM:
01045       if (!rtp->smoother) {
01046          rtp->smoother = ast_smoother_new(33);
01047       }
01048       if (!rtp->smoother) {
01049          ast_log(LOG_WARNING, "Unable to create GSM smoother :(\n");
01050          return -1;
01051       }
01052       ast_smoother_feed(rtp->smoother, _f);
01053       while((f = ast_smoother_read(rtp->smoother)))
01054          ast_rtp_raw_write(rtp, f, codec);
01055       break;
01056    case AST_FORMAT_ILBC:
01057       if (!rtp->smoother) {
01058          rtp->smoother = ast_smoother_new(50);
01059       }
01060       if (!rtp->smoother) {
01061          ast_log(LOG_WARNING, "Unable to create ILBC smoother :(\n");
01062          return -1;
01063       }
01064       ast_smoother_feed(rtp->smoother, _f);
01065       while((f = ast_smoother_read(rtp->smoother)))
01066          ast_rtp_raw_write(rtp, f, codec);
01067       break;
01068    default: 
01069       ast_log(LOG_WARNING, "Not sure about sending format %s packets\n", ast_getformatname(subclass));
01070       // fall through to...
01071    case AST_FORMAT_H261:
01072    case AST_FORMAT_H263:
01073    case AST_FORMAT_G723_1:
01074    case AST_FORMAT_SPEEX:
01075            // Don't buffer outgoing frames; send them one-per-packet:
01076       if (_f->offset < hdrlen) {
01077          f = ast_frdup(_f);
01078       } else {
01079          f = _f;
01080       }
01081       ast_rtp_raw_write(rtp, f, codec);
01082    }
01083       
01084    return 0;
01085 }


Generated on Fri Feb 27 12:19:53 2004 for Asterisk by doxygen 1.3.5