Newer
Older
if (strchr(enders, d) || (pos >= len)) {
s[pos]='\0';
return 0;
}
to = timeout;
} while(1);
/* Never reached */
return 0;
}
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
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, 256);
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_channel_pvt *p;
struct ast_channel *clone = original->masq;
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\n", newn, masqn);
manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\n", orig, newn);
p = original->pvt;
original->pvt = clone->pvt;
clone->pvt = p;
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
/* 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));
}
}
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\n", masqn, zombn);
/* 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 */
/* dnid and callerid change to become the new, HOWEVER, we also link the original's
fields back into the defunct 'clone' so that they will be freed when
ast_frfree is eventually called */
tmp = original->dnid;
original->dnid = clone->dnid;
clone->dnid = tmp;
tmp = original->callerid;
original->callerid = clone->callerid;
clone->callerid = tmp;
/* Restore original timing file descriptor */
original->fds[AST_MAX_FDS - 2] = original->timingfd;
/* Our native formats are different now */
original->nativeformats = clone->nativeformats;
/* 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 */
original->_state = clone->_state;
/* 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, char *callerid, int anitoo)
{
if (chan->callerid)
free(chan->callerid);
if (anitoo && chan->ani)
free(chan->ani);
if (callerid) {
if (anitoo)
chan->ani = strdup(callerid);
} else {
if (anitoo)
chan->ani = NULL;
}
if (chan->cdr)
ast_cdr_setcid(chan->cdr, chan);
manager_event(EVENT_FLAG_CALL, "Newcallerid",
"Channel: %s\r\n"
}
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"
"Callerid: %s\r\n"
"Uniqueid: %s\r\n",
chan->name, ast_state2str(chan->_state), chan->callerid ? chan->callerid : "<unknown>", chan->uniqueid);
} else {
manager_event(EVENT_FLAG_CALL, "Newstate",
"Channel: %s\r\n"
"State: %s\r\n"
"Callerid: %s\r\n"
"Uniqueid: %s\r\n",
chan->name, ast_state2str(chan->_state), chan->callerid ? chan->callerid : "<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));
}
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, "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, "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;
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||config->allowredirect_out ? AST_BRIDGE_DTMF_CHANNEL_0 : 0) + (config->allowredirect_in ? AST_BRIDGE_DTMF_CHANNEL_1 : 0);
/* timestamp */
gettimeofday(&start_time,NULL);
time_left_ms = config->timelimit;
if (config->play_to_caller && config->start_sound)
Anthony Minessale II
committed
bridge_playfile(c0,c1,config->start_sound,time_left_ms / 1000);
if (config->play_to_callee && config->start_sound)
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))
return -1;
if (c0->bridge) {
ast_log(LOG_WARNING, "%s is already in a bridge with %s\n",
c0->name, c0->bridge->name);
return -1;
}
if (c1->bridge) {
ast_log(LOG_WARNING, "%s is already in a bridge with %s\n",
c1->name, c1->bridge->name);
return -1;
}
/* Keep track of bridge */
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);
/* 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))) {
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->generator || c1->generator)) {
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);
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];
}
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;
}
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
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;
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
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;
}
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
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;
}