Newer
Older
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));
}
}
if (clone->pvt->fixup){
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");
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);
/* Keep the same language. */
/* Update the type. */
original->type = clone->type;
/* Copy the FD's */
/* Move the variables */
tmpv = original->varshead.first;
original->varshead.first = clone->varshead.first;
clone->varshead.first = tmpv;
/* Presense of ADSI capable CPE follows clone */
original->adsicpe = clone->adsicpe;
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
/* 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 */
/* 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);
ast_mutex_unlock(&clone->lock);
manager_event(EVENT_FLAG_CALL, "Hangup", "Channel: %s\r\n", zombn);
ast_log(LOG_DEBUG, "Released clone lock on '%s'\n", clone->name);
ast_mutex_unlock(&clone->lock);
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) {
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);
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);
/* 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);
int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, 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. */
struct ast_channel *cs[3];
int to = -1;
struct ast_frame *f;
/* 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"
"Channel2: %s\r\n",
c0->name, c1->name);
/* 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");
(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"
"Channel2: %s\r\n",
c0->name, c1->name);
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"
"Channel2: %s\r\n",
c0->name, c1->name);
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 frame on channel %s\n",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"
"Channel2: %s\r\n",
c0->name, c1->name);
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;
}
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
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) {
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;
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;
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
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;
}