diff options
author | matteo <matteo@f38db490-d61c-443f-a65b-d21fe96a405b> | 2003-02-16 06:00:12 +0000 |
---|---|---|
committer | matteo <matteo@f38db490-d61c-443f-a65b-d21fe96a405b> | 2003-02-16 06:00:12 +0000 |
commit | 175c755fefa75d02deeff70541cd7821ce670678 (patch) | |
tree | 09bad30a14c0eef808c9d0d2720e797ff76c44f4 /rtp.c | |
parent | dae2009f9537257ba729035caa92eb3661c93aa1 (diff) |
Sun Feb 16 07:00:01 CET 2003
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@616 f38db490-d61c-443f-a65b-d21fe96a405b
Diffstat (limited to 'rtp.c')
-rwxr-xr-x | rtp.c | 204 |
1 files changed, 203 insertions, 1 deletions
@@ -30,6 +30,7 @@ #include <asterisk/logger.h> #include <asterisk/options.h> #include <asterisk/channel.h> +#include <asterisk/channel_pvt.h> #define TYPE_SILENCE 0x2 #define TYPE_HIGH 0x0 @@ -47,6 +48,7 @@ struct ast_rtp { unsigned int lastts; unsigned int lastrxts; int lasttxformat; + int lastrxformat; int dtmfcount; struct sockaddr_in us; struct sockaddr_in them; @@ -61,6 +63,8 @@ struct ast_rtp { ast_rtp_callback callback; }; +static struct ast_rtp_protocol *protos = NULL; + int ast_rtp_fd(struct ast_rtp *rtp) { return rtp->s; @@ -151,6 +155,49 @@ static struct ast_frame *process_rfc2833(struct ast_rtp *rtp, unsigned char *dat return f; } +static struct ast_frame *process_rfc3389(struct ast_rtp *rtp, unsigned char *data, int len) +{ + struct ast_frame *f = NULL; + /* Convert comfort noise into audio with various codecs. Unfortunately this doesn't + totally help us out becuase we don't have an engine to keep it going and we are not + guaranteed to have it every 20ms or anything */ +#if 0 + printf("RFC3389: %d bytes, format is %d\n", len, rtp->lastrxformat); +#endif + ast_log(LOG_NOTICE, "RFC3389 support incomplete. Turn off on client if possible\n"); + if (!rtp->lastrxformat) + return NULL; + switch(rtp->lastrxformat) { + case AST_FORMAT_ULAW: + rtp->f.frametype = AST_FRAME_VOICE; + rtp->f.subclass = AST_FORMAT_ULAW; + rtp->f.datalen = 160; + rtp->f.samples = 160; + memset(rtp->f.data, 0x7f, rtp->f.datalen); + f = &rtp->f; + break; + case AST_FORMAT_ALAW: + rtp->f.frametype = AST_FRAME_VOICE; + rtp->f.subclass = AST_FORMAT_ALAW; + rtp->f.datalen = 160; + rtp->f.samples = 160; + memset(rtp->f.data, 0x7e, rtp->f.datalen); /* XXX Is this right? XXX */ + f = &rtp->f; + break; + case AST_FORMAT_SLINEAR: + rtp->f.frametype = AST_FRAME_VOICE; + rtp->f.subclass = AST_FORMAT_SLINEAR; + rtp->f.datalen = 320; + rtp->f.samples = 160; + memset(rtp->f.data, 0x00, rtp->f.datalen); + f = &rtp->f; + break; + default: + ast_log(LOG_NOTICE, "Don't know how to handle RFC3389 for receive codec %d\n", rtp->lastrxformat); + } + return f; +} + static struct ast_frame *process_type121(struct ast_rtp *rtp, unsigned char *data, int len) { char resp = 0; @@ -247,6 +294,8 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp) } else if (payloadtype == 100) { /* CISCO's notso proprietary DTMF bridge */ f = process_rfc2833(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen); + } else if (payloadtype == 13) { + f = process_rfc3389(rtp, rtp->rawdata + AST_FRIENDLY_OFFSET + hdrlen, res - hdrlen); } else { ast_log(LOG_NOTICE, "Unknown RTP codec %d received\n", payloadtype); } @@ -254,7 +303,8 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp) return f; else return &null_frame; - } + } else + rtp->lastrxformat = rtp->f.subclass; if (!rtp->lastrxts) rtp->lastrxts = timestamp; @@ -651,3 +701,155 @@ int ast_rtp_write(struct ast_rtp *rtp, struct ast_frame *_f) return 0; } + +void ast_rtp_proto_unregister(struct ast_rtp_protocol *proto) +{ + struct ast_rtp_protocol *cur, *prev; + cur = protos; + prev = NULL; + while(cur) { + if (cur == proto) { + if (prev) + prev->next = proto->next; + else + protos = proto->next; + return; + } + prev = cur; + cur = cur->next; + } +} + +int ast_rtp_proto_register(struct ast_rtp_protocol *proto) +{ + struct ast_rtp_protocol *cur; + cur = protos; + while(cur) { + if (cur->type == proto->type) { + ast_log(LOG_WARNING, "Tried to register same protocol '%s' twice\n", cur->type); + return -1; + } + cur = cur->next; + } + proto->next = protos; + protos = proto; + return 0; +} + +static struct ast_rtp_protocol *get_proto(struct ast_channel *chan) +{ + struct ast_rtp_protocol *cur; + cur = protos; + while(cur) { + if (cur->type == chan->type) { + return cur; + } + cur = cur->next; + } + return NULL; +} + +int ast_rtp_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc) +{ + struct ast_frame *f; + struct ast_channel *who, *cs[3]; + struct ast_rtp *p0, *p1; + struct ast_rtp_protocol *pr0, *pr1; + void *pvt0, *pvt1; + int to; + + /* XXX Wait a half a second for things to settle up + this really should be fixed XXX */ + ast_autoservice_start(c0); + ast_autoservice_start(c1); + usleep(500000); + ast_autoservice_stop(c0); + ast_autoservice_stop(c1); + + /* if need DTMF, cant native bridge */ + if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1)) + return -2; + ast_pthread_mutex_lock(&c0->lock); + ast_pthread_mutex_lock(&c1->lock); + pr0 = get_proto(c0); + pr1 = get_proto(c1); + if (!pr0) { + ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c0->name); + ast_pthread_mutex_unlock(&c0->lock); + ast_pthread_mutex_unlock(&c1->lock); + return -1; + } + if (!pr1) { + ast_log(LOG_WARNING, "Can't find native functions for channel '%s'\n", c1->name); + ast_pthread_mutex_unlock(&c0->lock); + ast_pthread_mutex_unlock(&c1->lock); + return -1; + } + pvt0 = c0->pvt->pvt; + pvt1 = c1->pvt->pvt; + p0 = pr0->get_rtp_info(c0); + p1 = pr1->get_rtp_info(c1); + if (!p0 || !p1) { + /* Somebody doesn't want to play... */ + ast_pthread_mutex_unlock(&c0->lock); + ast_pthread_mutex_unlock(&c1->lock); + return -2; + } + if (pr0->set_rtp_peer(c0, p1)) + ast_log(LOG_WARNING, "Channel '%s' failed to talk to '%s'\n", c0->name, c1->name); + if (pr1->set_rtp_peer(c1, p0)) + ast_log(LOG_WARNING, "Channel '%s' failed to talk back to '%s'\n", c1->name, c0->name); + ast_pthread_mutex_unlock(&c0->lock); + ast_pthread_mutex_unlock(&c1->lock); + cs[0] = c0; + cs[1] = c1; + cs[2] = NULL; + for (;;) { + if ((c0->pvt->pvt != pvt0) || + (c1->pvt->pvt != pvt1) || + (c0->masq || c0->masqr || c1->masq || c1->masqr)) { + ast_log(LOG_DEBUG, "Oooh, something is weird, backing out\n"); + if (c0->pvt->pvt == pvt0) { + if (pr0->set_rtp_peer(c0, NULL)) + ast_log(LOG_WARNING, "Channel '%s' failed to revert\n", c0->name); + } + if (c1->pvt->pvt == pvt1) { + if (pr1->set_rtp_peer(c1, NULL)) + ast_log(LOG_WARNING, "Channel '%s' failed to revert back\n", c1->name); + } + /* Tell it to try again later */ + return -3; + } + to = -1; + who = ast_waitfor_n(cs, 2, &to); + if (!who) { + ast_log(LOG_DEBUG, "Ooh, empty read...\n"); + continue; + } + f = ast_read(who); + if (!f || ((f->frametype == AST_FRAME_DTMF) && + (((who == c0) && (flags & AST_BRIDGE_DTMF_CHANNEL_0)) || + ((who == c1) && (flags & AST_BRIDGE_DTMF_CHANNEL_1))))) { + *fo = f; + *rc = who; + ast_log(LOG_DEBUG, "Oooh, got a %s\n", f ? "digit" : "hangup"); + if ((c0->pvt->pvt == pvt0) && (!c0->_softhangup)) { + if (pr0->set_rtp_peer(c0, NULL)) + ast_log(LOG_WARNING, "Channel '%s' failed to revert\n", c0->name); + } + if ((c1->pvt->pvt == pvt1) && (!c1->_softhangup)) { + if (pr1->set_rtp_peer(c1, NULL)) + ast_log(LOG_WARNING, "Channel '%s' failed to revert back\n", c1->name); + } + /* That's all we needed */ + return 0; + } else + ast_frfree(f); + /* Swap priority not that it's a big deal at this point */ + cs[2] = cs[0]; + cs[0] = cs[1]; + cs[1] = cs[2]; + + } + return -1; +} |