Newer
Older
int ast_transfer(struct ast_channel *chan, char *dest)
{
/* Place an outgoing call, but don't wait any longer than timeout ms before returning.
If the remote end does not answer within the timeout, then do NOT hang up, but
return anyway. */
int res = -1;
/* Stop if we're a zombie or need a soft hangup */
ast_mutex_lock(&chan->lock);
if (!chan->zombie && !ast_check_hangup(chan)) {
if (chan->pvt->transfer) {
res = chan->pvt->transfer(chan, dest);
if (!res)
res = 1;
} else
res = 0;
}
ast_mutex_unlock(&chan->lock);
int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int ftimeout, char *enders)
{
int pos=0;
int to = ftimeout;
char d;
/* XXX Merge with full version? XXX */
/* Stop if we're a zombie or need a soft hangup */
d = ast_waitstream(c, AST_DIGIT_ANY);
ast_stopstream(c);
if (!d)
d = ast_waitfordigit(c, to);
} else {
d = ast_waitfordigit(c, to);
}
if (d < 0)
return -1;
if (d == 0) {
s[pos]='\0';
return 1;
}
return 0;
}
to = timeout;
} while(1);
/* Never reached */
return 0;
}
int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, int ftimeout, char *enders, int audiofd, int ctrlfd)
{
int pos=0;
int to = ftimeout;
char d;
/* Stop if we're a zombie or need a soft hangup */
if (c->zombie || ast_check_hangup(c))
return -1;
if (!len)
return -1;
do {
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
d = ast_waitstream_full(c, AST_DIGIT_ANY, audiofd, ctrlfd);
ast_stopstream(c);
usleep(1000);
if (!d)
d = ast_waitfordigit_full(c, to, audiofd, ctrlfd);
} else {
d = ast_waitfordigit_full(c, to, audiofd, ctrlfd);
}
if (d < 0)
return -1;
if (d == 0) {
s[pos]='\0';
return 1;
}
if (d == 1) {
s[pos]='\0';
return 2;
}
if (!strchr(enders, d))
s[pos++] = d;
if (strchr(enders, d) || (pos >= len)) {
s[pos]='\0';
return 0;
}
to = timeout;
} while(1);
/* Never reached */
return 0;
}
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
int ast_channel_supports_html(struct ast_channel *chan)
{
if (chan->pvt->send_html)
return 1;
return 0;
}
int ast_channel_sendhtml(struct ast_channel *chan, int subclass, char *data, int datalen)
{
if (chan->pvt->send_html)
return chan->pvt->send_html(chan, subclass, data, datalen);
return -1;
}
int ast_channel_sendurl(struct ast_channel *chan, char *url)
{
if (chan->pvt->send_html)
return chan->pvt->send_html(chan, AST_HTML_URL, url, strlen(url) + 1);
return -1;
}
int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
{
int peerf;
int chanf;
int res;
ast_mutex_lock(&peer->lock);
ast_mutex_unlock(&peer->lock);
ast_mutex_lock(&chan->lock);
ast_mutex_unlock(&chan->lock);
res = ast_translator_best_choice(&peerf, &chanf);
if (res < 0) {
ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", chan->name, chan->nativeformats, peer->name, peer->nativeformats);
return -1;
}
/* Set read format on channel */
Mark Spencer
committed
res = ast_set_read_format(chan, peerf);
ast_log(LOG_WARNING, "Unable to set read format on channel %s to %d\n", chan->name, chanf);
return -1;
}
/* Set write format on peer channel */
Mark Spencer
committed
res = ast_set_write_format(peer, peerf);
ast_log(LOG_WARNING, "Unable to set write format on channel %s to %d\n", peer->name, peerf);
return -1;
}
/* Now we go the other way */
peerf = peer->nativeformats;
chanf = chan->nativeformats;
res = ast_translator_best_choice(&chanf, &peerf);
if (res < 0) {
ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", peer->name, peer->nativeformats, chan->name, chan->nativeformats);
return -1;
}
/* Set writeformat on channel */
Mark Spencer
committed
res = ast_set_write_format(chan, chanf);
ast_log(LOG_WARNING, "Unable to set write format on channel %s to %d\n", chan->name, chanf);
return -1;
}
/* Set read format on peer channel */
Mark Spencer
committed
res = ast_set_read_format(peer, chanf);
ast_log(LOG_WARNING, "Unable to set read format on channel %s to %d\n", peer->name, peerf);
int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone)
{
struct ast_frame null = { AST_FRAME_NULL, };
int res = -1;
ast_mutex_lock(&original->lock);
while(ast_mutex_trylock(&clone->lock)) {
ast_mutex_unlock(&original->lock);
usleep(1);
ast_mutex_lock(&original->lock);
}
ast_log(LOG_DEBUG, "Planning to masquerade %s into the structure of %s\n",
clone->name, original->name);
if (original->masq) {
ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n",
original->masq->name, original->name);
} else if (clone->masqr) {
ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n",
clone->name, clone->masqr->name);
} else {
original->masq = clone;
clone->masqr = original;
ast_queue_frame(original, &null);
ast_queue_frame(clone, &null);
ast_log(LOG_DEBUG, "Done planning to masquerade %s into the structure of %s\n", original->name, clone->name);
res = 0;
}
ast_mutex_unlock(&clone->lock);
ast_mutex_unlock(&original->lock);
return res;
void ast_change_name(struct ast_channel *chan, char *newname)
{
char tmp[256];
strncpy(tmp, chan->name, sizeof(tmp) - 1);
strncpy(chan->name, newname, sizeof(chan->name) - 1);
manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", tmp, chan->name, chan->uniqueid);
Mark Spencer
committed
int ast_do_masquerade(struct ast_channel *original)
struct ast_callerid tmpcid;
int rformat = original->readformat;
int wformat = original->writeformat;
char newn[100];
char orig[100];
char masqn[100];
char zombn[100];
ast_log(LOG_DEBUG, "Actually Masquerading %s(%d) into the structure of %s(%d)\n",
clone->name, clone->_state, original->name, original->_state);
/* XXX This is a seriously wacked out operation. We're essentially putting the guts of
the clone channel into the original channel. Start by killing off the original
channel's backend. I'm not sure we're going to keep this function, because
while the features are nice, the cost is very high in terms of pure nastiness. XXX */
Mark Spencer
committed
/* We need the clone's lock, too */
ast_mutex_lock(&clone->lock);
Mark Spencer
committed
ast_log(LOG_DEBUG, "Got clone lock on '%s' at %p\n", clone->name, &clone->lock);
/* Having remembered the original read/write formats, we turn off any translation on either
one */
free_translation(clone);
free_translation(original);
/* Unlink the masquerade */
original->masq = NULL;
clone->masqr = NULL;
/* Save the original name */
strncpy(orig, original->name, sizeof(orig) - 1);
/* Save the new name */
strncpy(newn, clone->name, sizeof(newn) - 1);
/* Create the masq name */
snprintf(masqn, sizeof(masqn), "%s<MASQ>", newn);
strncpy(original->name, newn, sizeof(original->name)-1);
strncpy(clone->name, masqn, sizeof(clone->name) - 1);
/* Notify any managers of the change, first the masq then the other */
manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", newn, masqn, clone->uniqueid);
manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", orig, newn, original->uniqueid);
p = original->pvt;
original->pvt = clone->pvt;
clone->pvt = p;
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
/* Save any pending frames on both sides. Start by counting
* how many we're going to need... */
prev = NULL;
cur = clone->pvt->readq;
x = 0;
while(cur) {
x++;
prev = cur;
cur = cur->next;
}
/* If we had any, prepend them to the ones already in the queue, and
* load up the alertpipe */
if (prev) {
prev->next = original->pvt->readq;
original->pvt->readq = clone->pvt->readq;
clone->pvt->readq = NULL;
if (original->pvt->alertpipe[1] > -1) {
for (i=0;i<x;i++)
write(original->pvt->alertpipe[1], &x, sizeof(x));
}
}
/* And of course, so does our current state. Note we need not
call ast_setstate since the event manager doesn't really consider
these separate. We do this early so that the clone has the proper
state of the original channel. */
origstate = original->_state;
original->_state = clone->_state;
clone->_state = origstate;
Mark Spencer
committed
res = clone->pvt->fixup(original, clone);
if (res)
ast_log(LOG_WARNING, "Fixup failed on channel %s, strange things may happen.\n", clone->name);
}
/* Start by disconnecting the original's physical side */
if (clone->pvt->hangup)
res = clone->pvt->hangup(clone);
if (res) {
ast_log(LOG_WARNING, "Hangup failed! Strange things may happen!\n");
Mark Spencer
committed
ast_mutex_unlock(&clone->lock);
snprintf(zombn, sizeof(zombn), "%s<ZOMBIE>", orig);
strncpy(clone->name, zombn, sizeof(clone->name) - 1);
manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", masqn, zombn, clone->uniqueid);
/* Update the type. */
original->type = clone->type;
/* Copy the FD's */
/* Append variables from clone channel into original channel */
/* XXX Is this always correct? We have to in order to keep MACROS working XXX */
varptr = original->varshead.first;
if (varptr) {
while(varptr->entries.next) {
varptr = varptr->entries.next;
}
varptr->entries.next = clone->varshead.first;
} else {
original->varshead.first = clone->varshead.first;
}
clone->varshead.first = NULL;
/* Presense of ADSI capable CPE follows clone */
original->adsicpe = clone->adsicpe;
/* Bridge remains the same */
/* CDR fields remain the same */
/* XXX What about blocking, softhangup, blocker, and lock and blockproc? XXX */
/* Application and data remain the same */
/* Clone exception becomes real one, as with fdno */
original->exception = clone->exception;
original->fdno = clone->fdno;
/* Schedule context remains the same */
/* Stream stuff stays the same */
/* Keep the original state. The fixup code will need to work with it most likely */
/* Just swap the whole structures, nevermind the allocations, they'll work themselves
out. */
tmpcid = original->cid;
original->cid = clone->cid;
clone->cid = tmpcid;
/* Restore original timing file descriptor */
original->fds[AST_MAX_FDS - 2] = original->timingfd;
/* Our native formats are different now */
original->nativeformats = clone->nativeformats;
/* Context, extension, priority, app data, jump table, remain the same */
/* pvt switches. pbx stays the same, as does next */
/* Set the write format */
Mark Spencer
committed
ast_set_write_format(original, wformat);
Mark Spencer
committed
ast_set_read_format(original, rformat);
ast_log(LOG_DEBUG, "Putting channel %s in %d/%d formats\n", original->name, wformat, rformat);
/* Okay. Last thing is to let the channel driver know about all this mess, so he
can fix up everything as best as possible */
if (original->pvt->fixup) {
Mark Spencer
committed
res = original->pvt->fixup(clone, original);
if (res) {
ast_log(LOG_WARNING, "Driver for '%s' could not fixup channel %s\n",
original->type, original->name);
Mark Spencer
committed
ast_mutex_unlock(&clone->lock);
return -1;
}
} else
ast_log(LOG_WARNING, "Driver '%s' does not have a fixup routine (for %s)! Bad things may happen.\n",
original->type, original->name);
/* Now, at this point, the "clone" channel is totally F'd up. We mark it as
a zombie so nothing tries to touch it. If it's already been marked as a
zombie, then free it now (since it already is considered invalid). */
if (clone->zombie) {
ast_log(LOG_DEBUG, "Destroying clone '%s'\n", clone->name);
Mark Spencer
committed
ast_mutex_unlock(&clone->lock);
ast_channel_free(clone);
manager_event(EVENT_FLAG_CALL, "Hangup", "Channel: %s\r\n", zombn);
} else {
ast_log(LOG_DEBUG, "Released clone lock on '%s'\n", clone->name);
clone->zombie=1;
Mark Spencer
committed
ast_mutex_unlock(&clone->lock);
/* Signal any blocker */
if (original->blocking)
pthread_kill(original->blocker, SIGURG);
ast_log(LOG_DEBUG, "Done Masquerading %s (%d)\n",
original->name, original->_state);
void ast_set_callerid(struct ast_channel *chan, const char *callerid, const char *calleridname, const char *ani)
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
if (chan->cid.cid_num)
free(chan->cid.cid_num);
if (ast_strlen_zero(callerid))
chan->cid.cid_num = NULL;
else
chan->cid.cid_num = strdup(callerid);
}
if (calleridname) {
if (chan->cid.cid_name)
free(chan->cid.cid_name);
if (ast_strlen_zero(calleridname))
chan->cid.cid_name = NULL;
else
chan->cid.cid_name = strdup(calleridname);
}
if (ani) {
if (chan->cid.cid_ani)
free(chan->cid.cid_ani);
if (ast_strlen_zero(ani))
chan->cid.cid_ani = NULL;
else
chan->cid.cid_ani = strdup(ani);
}
if (chan->cdr)
ast_cdr_setcid(chan->cdr, chan);
manager_event(EVENT_FLAG_CALL, "Newcallerid",
"Channel: %s\r\n"
chan->name, chan->cid.cid_num ?
chan->cid.cid_num : "<Unknown>",
chan->cid.cid_name ?
chan->cid.cid_name : "<Unknown>",
}
int ast_setstate(struct ast_channel *chan, int state)
{
if (chan->_state != state) {
int oldstate = chan->_state;
chan->_state = state;
if (oldstate == AST_STATE_DOWN) {
ast_device_state_changed(chan->name);
manager_event(EVENT_FLAG_CALL, "Newchannel",
"Channel: %s\r\n"
"State: %s\r\n"
chan->name, ast_state2str(chan->_state),
chan->cid.cid_num ? chan->cid.cid_num : "<unknown>",
chan->cid.cid_name ? chan->cid.cid_name : "<unknown>",
chan->uniqueid);
} else {
manager_event(EVENT_FLAG_CALL, "Newstate",
"Channel: %s\r\n"
"State: %s\r\n"
chan->name, ast_state2str(chan->_state),
chan->cid.cid_num ? chan->cid.cid_num : "<unknown>",
chan->cid.cid_name ? chan->cid.cid_name : "<unknown>",
chan->uniqueid);
static long tvdiff(struct timeval *now, struct timeval *then)
{
return (((now->tv_sec * 1000) + now->tv_usec / 1000) - ((then->tv_sec * 1000) + then->tv_usec / 1000));
}
Mark Spencer
committed
struct ast_channel *ast_bridged_channel(struct ast_channel *chan)
{
struct ast_channel *bridged;
bridged = chan->_bridge;
if (bridged && bridged->pvt->bridged_channel)
bridged = bridged->pvt->bridged_channel(chan, bridged);
return bridged;
}
Anthony Minessale II
committed
static void bridge_playfile(struct ast_channel *chan, struct ast_channel *peer, char *sound, int remain)
Anthony Minessale II
committed
int res=0, min=0, sec=0,check=0;
check = ast_autoservice_start(peer);
if(check)
return;
if (remain > 0) {
if (remain / 60 > 1) {
min = remain / 60;
sec = remain % 60;
sec = remain;
}
}
if (!strcmp(sound,"timeleft")) {
res = ast_streamfile(chan, "vm-youhave", chan->language);
res = ast_waitstream(chan, "");
if (min) {
res = ast_say_number(chan, min, AST_DIGIT_ANY, chan->language, (char *) NULL);
res = ast_streamfile(chan, "queue-minutes", chan->language);
res = ast_waitstream(chan, "");
}
if (sec) {
res = ast_say_number(chan, sec, AST_DIGIT_ANY, chan->language, (char *) NULL);
res = ast_streamfile(chan, "queue-seconds", chan->language);
res = ast_waitstream(chan, "");
}
} else {
res = ast_streamfile(chan, sound, chan->language);
res = ast_waitstream(chan, "");
}
Anthony Minessale II
committed
check = ast_autoservice_stop(peer);
int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, struct ast_bridge_config *config, struct ast_frame **fo, struct ast_channel **rc)
{
/* Copy voice back and forth between the two channels. Give the peer
the ability to transfer calls with '#<extension' syntax. */
int flags;
struct ast_channel *cs[3];
int to = -1;
struct ast_frame *f;
int res=0;
int o0nativeformats;
int o1nativeformats;
struct timeval start_time,precise_now;
long elapsed_ms=0, time_left_ms=0;
int playit=0, playitagain=1, first_time=1;
flags = (config->allowdisconnect_out||config->allowredirect_out ? AST_BRIDGE_DTMF_CHANNEL_0 : 0) + (config->allowdisconnect_in||config->allowredirect_in ? AST_BRIDGE_DTMF_CHANNEL_1 : 0);
firstpass = config->firstpass;
config->firstpass = 0;
/* timestamp */
gettimeofday(&start_time,NULL);
time_left_ms = config->timelimit;
if (config->play_to_caller && config->start_sound && firstpass)
Anthony Minessale II
committed
bridge_playfile(c0,c1,config->start_sound,time_left_ms / 1000);
if (config->play_to_callee && config->start_sound && firstpass)
Anthony Minessale II
committed
bridge_playfile(c1,c0,config->start_sound,time_left_ms / 1000);
/* Stop if we're a zombie or need a soft hangup */
if (c0->zombie || ast_check_hangup_locked(c0) || c1->zombie || ast_check_hangup_locked(c1))
Mark Spencer
committed
if (c0->_bridge) {
ast_log(LOG_WARNING, "%s is already in a bridge with %s\n",
Mark Spencer
committed
c0->name, c0->_bridge->name);
Mark Spencer
committed
if (c1->_bridge) {
ast_log(LOG_WARNING, "%s is already in a bridge with %s\n",
Mark Spencer
committed
c1->name, c1->_bridge->name);
return -1;
}
/* Keep track of bridge */
Mark Spencer
committed
c0->_bridge = c1;
c1->_bridge = c0;
manager_event(EVENT_FLAG_CALL, "Link",
"Channel1: %s\r\n"
James Golovich
committed
"Channel2: %s\r\n"
"Uniqueid1: %s\r\n"
"Uniqueid2: %s\r\n",
c0->name, c1->name, c0->uniqueid, c1->uniqueid);
o1nativeformats = c1->nativeformats;
o0nativeformats = c0->nativeformats;
/* timestamp */
gettimeofday(&precise_now,NULL);
elapsed_ms = tvdiff(&precise_now,&start_time);
time_left_ms = config->timelimit - elapsed_ms;
if (playitagain && (config->play_to_caller || config->play_to_callee) && (config->play_warning && time_left_ms <= config->play_warning)) {
/* narrowing down to the end */
playit = 1;
first_time=0;
playitagain=0;
playit = 1;
first_time=0;
} else {
if ((time_left_ms % config->warning_freq) <= 50) {
playit = 1;
}
}
}
if (time_left_ms <= 0) {
if (config->play_to_caller && config->end_sound)
Anthony Minessale II
committed
bridge_playfile(c0,c1,config->end_sound,0);
if (config->play_to_callee && config->end_sound)
Anthony Minessale II
committed
bridge_playfile(c1,c0,config->end_sound,0);
break;
}
if (time_left_ms >= 5000 && playit) {
if (config->play_to_caller && config->warning_sound && config->play_warning)
Anthony Minessale II
committed
bridge_playfile(c0,c1,config->warning_sound,time_left_ms / 1000);
if (config->play_to_callee && config->warning_sound && config->play_warning)
Anthony Minessale II
committed
bridge_playfile(c1,c0,config->warning_sound,time_left_ms / 1000);
playit = 0;
}
}
/* Stop if we're a zombie or need a soft hangup */
if (c0->zombie || ast_check_hangup_locked(c0) || c1->zombie || ast_check_hangup_locked(c1)) {
*fo = NULL;
if (who) *rc = who;
res = 0;
ast_log(LOG_DEBUG, "Bridge stops because we're zombie or need a soft hangup: c0=%s, c1=%s, flags: %s,%s,%s,%s\n",c0->name,c1->name,c0->zombie?"Yes":"No",ast_check_hangup(c0)?"Yes":"No",c1->zombie?"Yes":"No",ast_check_hangup(c1)?"Yes":"No");
if (c0->pvt->bridge && config->timelimit==0 &&
(c0->pvt->bridge == c1->pvt->bridge) && !nativefailed && !c0->monitor && !c1->monitor) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Attempting native bridge of %s and %s\n", c0->name, c1->name);
if (!(res = c0->pvt->bridge(c0, c1, flags, fo, rc))) {
Mark Spencer
committed
c0->_bridge = NULL;
c1->_bridge = NULL;
manager_event(EVENT_FLAG_CALL, "Unlink",
"Channel1: %s\r\n"
James Golovich
committed
"Channel2: %s\r\n"
"Uniqueid1: %s\r\n"
"Uniqueid2: %s\r\n",
c0->name, c1->name, c0->uniqueid, c1->uniqueid);
ast_log(LOG_DEBUG, "Returning from native bridge, channels: %s, %s\n",c0->name ,c1->name);
return 0;
}
/* If they return non-zero then continue on normally. Let "-2" mean don't worry about
my not wanting to bridge */
if ((res != -2) && (res != -3))
ast_log(LOG_WARNING, "Private bridge between %s and %s failed\n", c0->name, c1->name);
if (res != -3) nativefailed++;
}
if (((c0->writeformat != c1->readformat) || (c0->readformat != c1->writeformat) || (c0->nativeformats != o0nativeformats) || (c1->nativeformats != o1nativeformats)) &&
if (ast_channel_make_compatible(c0, c1)) {
ast_log(LOG_WARNING, "Can't make %s and %s compatible\n", c0->name, c1->name);
manager_event(EVENT_FLAG_CALL, "Unlink",
"Channel1: %s\r\n"
James Golovich
committed
"Channel2: %s\r\n"
"Uniqueid1: %s\r\n"
"Uniqueid2: %s\r\n",
c0->name, c1->name, c0->uniqueid, c1->uniqueid);
o0nativeformats = c0->nativeformats;
o1nativeformats = c1->nativeformats;
who = ast_waitfor_n(cs, 2, &to);
if (!who) {
ast_log(LOG_DEBUG, "Nobody there, continuing...\n");
continue;
}
f = ast_read(who);
if (!f) {
*fo = NULL;
*rc = who;
ast_log(LOG_DEBUG, "Didn't get a frame from channel: %s\n",who->name);
if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
*fo = f;
*rc = who;
ast_log(LOG_DEBUG, "Got a FRAME_CONTROL (%d) frame on channel %s\n", f->subclass, who->name);
}
if ((f->frametype == AST_FRAME_VOICE) ||
(f->frametype == AST_FRAME_TEXT) ||
(f->frametype == AST_FRAME_VIDEO) ||
(f->frametype == AST_FRAME_IMAGE) ||
(f->frametype == AST_FRAME_DTMF)) {
if ((f->frametype == AST_FRAME_DTMF) &&
(flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) {
if ((who == c0)) {
if ((flags & AST_BRIDGE_DTMF_CHANNEL_0)) {
*rc = c0;
*fo = f;
/* Take out of conference mode */
res = 0;
ast_log(LOG_DEBUG, "Got AST_BRIDGE_DTMF_CHANNEL_0 on c0 (%s)\n",c0->name);
if ((who == c1)) {
if (flags & AST_BRIDGE_DTMF_CHANNEL_1) {
*rc = c1;
*fo = f;
res = 0;
ast_log(LOG_DEBUG, "Got AST_BRIDGE_DTMF_CHANNEL_1 on c1 (%s)\n",c1->name);
}
} else {
#if 0
ast_log(LOG_DEBUG, "Read from %s\n", who->name);
if (who == last)
ast_log(LOG_DEBUG, "Servicing channel %s twice in a row?\n", last->name);
last = who;
#endif
/* Don't copy packets if there is a generator on either one, since they're
not supposed to be listening anyway */
if (who == c0)
ast_write(c1, f);
else
ast_write(c0, f);
}
ast_frfree(f);
} else
ast_frfree(f);
/* Swap who gets priority */
cs[2] = cs[0];
cs[0] = cs[1];
cs[1] = cs[2];
}
Mark Spencer
committed
c0->_bridge = NULL;
c1->_bridge = NULL;
manager_event(EVENT_FLAG_CALL, "Unlink",
"Channel1: %s\r\n"
James Golovich
committed
"Channel2: %s\r\n"
"Uniqueid1: %s\r\n"
"Uniqueid2: %s\r\n",
c0->name, c1->name, c0->uniqueid, c1->uniqueid);
ast_log(LOG_DEBUG, "Bridge stops bridging channels %s and %s\n",c0->name,c1->name);
return res;
}
int ast_channel_setoption(struct ast_channel *chan, int option, void *data, int datalen, int block)
{
int res;
if (chan->pvt->setoption) {
res = chan->pvt->setoption(chan, option, data, datalen);
if (res < 0)
return res;
} else {
errno = ENOSYS;
return -1;
}
if (block) {
/* XXX Implement blocking -- just wait for our option frame reply, discarding
intermediate packets. XXX */
ast_log(LOG_ERROR, "XXX Blocking not implemented yet XXX\n");
return -1;
}
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
struct tonepair_def {
int freq1;
int freq2;
int duration;
int vol;
};
struct tonepair_state {
float freq1;
float freq2;
float vol;
int duration;
int pos;
int origwfmt;
struct ast_frame f;
unsigned char offset[AST_FRIENDLY_OFFSET];
short data[4000];
};
static void tonepair_release(struct ast_channel *chan, void *params)
{
struct tonepair_state *ts = params;
if (chan) {
Mark Spencer
committed
ast_set_write_format(chan, ts->origwfmt);
}
free(ts);
}
static void * tonepair_alloc(struct ast_channel *chan, void *params)
{
struct tonepair_state *ts;
struct tonepair_def *td = params;
ts = malloc(sizeof(struct tonepair_state));
if (!ts)
return NULL;
memset(ts, 0, sizeof(struct tonepair_state));
ts->origwfmt = chan->writeformat;
Mark Spencer
committed
if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", chan->name);
tonepair_release(NULL, ts);
ts = NULL;
} else {
ts->freq1 = td->freq1;
ts->freq2 = td->freq2;
ts->duration = td->duration;
ts->vol = td->vol;
}
/* Let interrupts interrupt :) */
chan->writeinterrupt = 1;
return ts;
}
static int tonepair_generator(struct ast_channel *chan, void *data, int len, int samples)
{
struct tonepair_state *ts = data;
int x;
/* we need to prepare a frame with 16 * timelen samples as we're
* generating SLIN audio
*/
len = samples * 2;
if (len > sizeof(ts->data) / 2 - 1) {
ast_log(LOG_WARNING, "Can't generate that much data!\n");
return -1;
}
memset(&ts->f, 0, sizeof(ts->f));
for (x=0;x<len/2;x++) {
ts->data[x] = ts->vol * (
sin((ts->freq1 * 2.0 * M_PI / 8000.0) * (ts->pos + x)) +
sin((ts->freq2 * 2.0 * M_PI / 8000.0) * (ts->pos + x))
);
}
ts->f.frametype = AST_FRAME_VOICE;
ts->f.subclass = AST_FORMAT_SLINEAR;
ts->f.datalen = len;
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
ts->f.offset = AST_FRIENDLY_OFFSET;
ts->f.data = ts->data;
ast_write(chan, &ts->f);
ts->pos += x;
if (ts->duration > 0) {
if (ts->pos >= ts->duration * 8)
return -1;
}
return 0;
}
static struct ast_generator tonepair = {
alloc: tonepair_alloc,
release: tonepair_release,
generate: tonepair_generator,
};
int ast_tonepair_start(struct ast_channel *chan, int freq1, int freq2, int duration, int vol)
{
struct tonepair_def d = { 0, };
d.freq1 = freq1;
d.freq2 = freq2;
d.duration = duration;
if (vol < 1)
d.vol = 8192;
else
d.vol = vol;
if (ast_activate_generator(chan, &tonepair, &d))
return -1;
return 0;
}
void ast_tonepair_stop(struct ast_channel *chan)
{
ast_deactivate_generator(chan);
}
int ast_tonepair(struct ast_channel *chan, int freq1, int freq2, int duration, int vol)
{
struct ast_frame *f;
int res;
if ((res = ast_tonepair_start(chan, freq1, freq2, duration, vol)))
return res;
/* Give us some wiggle room */
while(chan->generatordata && (ast_waitfor(chan, 100) >= 0)) {
f = ast_read(chan);
if (f)
ast_frfree(f);
else
return -1;
}
return 0;
}
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
unsigned int ast_get_group(char *s)
{
char *copy;
char *piece;
char *c=NULL;
int start=0, finish=0,x;
unsigned int group = 0;
copy = ast_strdupa(s);
if (!copy) {
ast_log(LOG_ERROR, "Out of memory\n");
return 0;
}
c = copy;
while((piece = strsep(&c, ","))) {
if (sscanf(piece, "%d-%d", &start, &finish) == 2) {
/* Range */
} else if (sscanf(piece, "%d", &start)) {
/* Just one */
finish = start;
} else {
ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'. Using '0'\n", s,piece);
return 0;
}
for (x=start;x<=finish;x++) {
if ((x > 31) || (x < 0)) {
ast_log(LOG_WARNING, "Ignoring invalid group %d (maximum group is 31)\n", x);
} else
group |= (1 << x);
}
}
return group;
}