Newer
Older
Kevin P. Fleming
committed
chan->insmpl += f->samples;
Kevin P. Fleming
committed
if (chan->monitor->state == AST_MONITOR_RUNNING) {
if (ast_writestream(chan->monitor->read_stream, f) < 0)
ast_log(LOG_WARNING, "Failed to write data to channel monitor read stream\n");
}
}
if (chan->readtrans && (f = ast_translate(chan->readtrans, f, 1)) == NULL)
f = &ast_null_frame;
Kevin P. Fleming
committed
/* Run generator sitting on the line if timing device not available
* and synchronous generation of outgoing frames is necessary */
if (chan->generatordata && !ast_internal_timing_enabled(chan)) {
void *tmp = chan->generatordata;
Kevin P. Fleming
committed
int res;
Kevin P. Fleming
committed
if (chan->timingfunc) {
if (option_debug > 1)
ast_log(LOG_DEBUG, "Generator got voice, switching to phase locked mode\n");
Kevin P. Fleming
committed
ast_settimeout(chan, 0, NULL, NULL);
}
chan->generatordata = NULL; /* reset, to let writes go through */
res = chan->generator->generate(chan, tmp, f->datalen, f->samples);
Kevin P. Fleming
committed
chan->generatordata = tmp;
if (res) {
if (option_debug > 1)
ast_log(LOG_DEBUG, "Auto-deactivating generator\n");
Kevin P. Fleming
committed
ast_deactivate_generator(chan);
}
Kevin P. Fleming
committed
} else if (f->frametype == AST_FRAME_CNG) {
if (chan->generator && !chan->timingfunc && (chan->timingfd > -1)) {
if (option_debug > 1)
ast_log(LOG_DEBUG, "Generator got CNG, switching to timed mode\n");
Kevin P. Fleming
committed
ast_settimeout(chan, 160, generator_force, chan);
}
Kevin P. Fleming
committed
} else {
/* Make sure we always return NULL in the future */
chan->_softhangup |= AST_SOFTHANGUP_DEV;
if (chan->generator)
/* End the CDR if appropriate */
if (chan->cdr)
ast_cdr_end(chan->cdr);
Kevin P. Fleming
committed
/* High bit prints debugging */
if (chan->fin & DEBUGCHAN_FLAG)
chan->fin = FRAMECOUNT_INC(chan->fin);
Kevin P. Fleming
committed
done:
int ast_internal_timing_enabled(struct ast_channel *chan)
{
int ret = ast_opt_internal_timing && chan->timingfd > -1;
if (option_debug > 3)
ast_log(LOG_DEBUG, "Internal timing is %s (option_internal_timing=%d chan->timingfd=%d)\n", ret? "enabled": "disabled", ast_opt_internal_timing, chan->timingfd);
return ret;
}
struct ast_frame *ast_read(struct ast_channel *chan)
{
return __ast_read(chan, 0);
}
struct ast_frame *ast_read_noaudio(struct ast_channel *chan)
{
return __ast_read(chan, 1);
}
int ast_indicate(struct ast_channel *chan, int condition)
{
int res = -1;
/* Stop if we're a zombie or need a soft hangup */
if (ast_test_flag(chan, AST_FLAG_ZOMBIE) || ast_check_hangup(chan)) {
if (chan->tech->indicate)
res = chan->tech->indicate(chan, condition);
if (!chan->tech->indicate || res) {
/*
* Device does not support (that) indication, lets fake
* it by doing our own tone generation. (PM2002)
*/
if (condition < 0)
ast_playtones_stop(chan);
else {
const struct tone_zone_sound *ts = NULL;
switch (condition) {
ts = ast_get_indication_tone(chan->zone, "ring");
break;
ts = ast_get_indication_tone(chan->zone, "busy");
break;
ts = ast_get_indication_tone(chan->zone, "congestion");
break;
}
if (ts && ts->data[0]) {
ast_log(LOG_DEBUG, "Driver for channel '%s' does not support indication %d, emulating it\n", chan->name, condition);
ast_playtones_start(chan,0,ts->data, 1);
} else if (condition == AST_CONTROL_PROGRESS) {
/* ast_playtones_stop(chan); */
} else if (condition == AST_CONTROL_PROCEEDING) {
/* Do nothing, really */
} else if (condition == AST_CONTROL_HOLD) {
/* Do nothing.... */
} else if (condition == AST_CONTROL_UNHOLD) {
/* Do nothing.... */
} else if (condition == AST_CONTROL_VIDUPDATE) {
/* Do nothing.... */
/* not handled */
ast_log(LOG_WARNING, "Unable to handle indication %d for '%s'\n", condition, chan->name);
int ast_recvchar(struct ast_channel *chan, int timeout)
{
int c;
char *buf = ast_recvtext(chan, timeout);
if (buf == NULL)
return -1; /* error or timeout */
c = *(unsigned char *)buf;
free(buf);
return c;
char *ast_recvtext(struct ast_channel *chan, int timeout)
{
int res, done = 0;
char *buf = NULL;
while (!done) {
struct ast_frame *f;
if (ast_check_hangup(chan))
break;
res = ast_waitfor(chan, timeout);
if (res <= 0) /* timeout or error */
break;
timeout = res; /* update timeout */
if (f == NULL)
break; /* no frame */
if (f->frametype == AST_FRAME_CONTROL && f->subclass == AST_CONTROL_HANGUP)
done = 1; /* force a break */
else if (f->frametype == AST_FRAME_TEXT) { /* what we want */
buf = ast_strndup((char *) f->data, f->datalen); /* dup and break */
}
ast_frfree(f);
}
int ast_sendtext(struct ast_channel *chan, const char *text)
/* Stop if we're a zombie or need a soft hangup */
if (ast_test_flag(chan, AST_FLAG_ZOMBIE) || ast_check_hangup(chan))
if (chan->tech->send_text)
res = chan->tech->send_text(chan, text);
ast_clear_flag(chan, AST_FLAG_BLOCKING);
static int do_senddigit(struct ast_channel *chan, char digit)
{
int res = -1;
if (chan->tech->send_digit)
res = chan->tech->send_digit(chan, digit);
Kevin P. Fleming
committed
if (!(chan->tech->send_digit && chan->tech->send_digit_begin) ||
res) {
/*
* Device does not support DTMF tones, lets fake
* it by doing our own generation. (PM2002)
*/
static const char* dtmf_tones[] = {
"!941+1336/100,!0/100", /* 0 */
"!697+1209/100,!0/100", /* 1 */
"!697+1336/100,!0/100", /* 2 */
"!697+1477/100,!0/100", /* 3 */
"!770+1209/100,!0/100", /* 4 */
"!770+1336/100,!0/100", /* 5 */
"!770+1477/100,!0/100", /* 6 */
"!852+1209/100,!0/100", /* 7 */
"!852+1336/100,!0/100", /* 8 */
"!852+1477/100,!0/100", /* 9 */
"!697+1633/100,!0/100", /* A */
"!770+1633/100,!0/100", /* B */
"!852+1633/100,!0/100", /* C */
"!941+1633/100,!0/100", /* D */
"!941+1209/100,!0/100", /* * */
"!941+1477/100,!0/100" }; /* # */
ast_playtones_start(chan, 0, dtmf_tones[digit-'0'], 0);
ast_playtones_start(chan, 0, dtmf_tones[digit-'A'+10], 0);
ast_playtones_start(chan, 0, dtmf_tones[14], 0);
ast_playtones_start(chan, 0, dtmf_tones[15], 0);
ast_log(LOG_DEBUG, "Unable to generate DTMF tone '%c' for '%s'\n", digit, chan->name);
int ast_senddigit(struct ast_channel *chan, char digit)
{
int ast_prod(struct ast_channel *chan)
{
struct ast_frame a = { AST_FRAME_VOICE };
char nothing[128];
/* Send an empty audio frame to get things moving */
if (chan->_state != AST_STATE_UP) {
ast_log(LOG_DEBUG, "Prodding channel '%s'\n", chan->name);
a.subclass = chan->rawwriteformat;
a.data = nothing + AST_FRIENDLY_OFFSET;
if (ast_write(chan, &a))
ast_log(LOG_WARNING, "Prodding channel '%s' failed\n", chan->name);
int ast_write_video(struct ast_channel *chan, struct ast_frame *fr)
{
int res;
if (!chan->tech->write_video)
return 0;
res = ast_write(chan, fr);
if (!res)
res = 1;
return res;
}
int ast_write(struct ast_channel *chan, struct ast_frame *fr)
{
int res = -1;
/* Stop if we're a zombie or need a soft hangup */
if (ast_test_flag(chan, AST_FLAG_ZOMBIE) || ast_check_hangup(chan))
goto done;
if (chan->masq && ast_do_masquerade(chan)) {
ast_log(LOG_WARNING, "Failed to perform masquerade\n");
goto done;
res = 0; /* XXX explain, why 0 ? */
goto done;
if (ast_test_flag(chan, AST_FLAG_WRITE_INT))
res = 0; /* XXX explain, why 0 ? */
goto done;
/* High bit prints debugging */
if (chan->fout & DEBUGCHAN_FLAG)
ast_frame_dump(chan->name, fr, ">>");
CHECK_BLOCKING(chan);
switch(fr->frametype) {
case AST_FRAME_CONTROL:
/* XXX Interpret control frames XXX */
ast_log(LOG_WARNING, "Don't know how to handle control frames yet\n");
break;
Kevin P. Fleming
committed
case AST_FRAME_DTMF_BEGIN:
res = (chan->tech->send_digit_begin == NULL) ? 0 :
chan->tech->send_digit_begin(chan, fr->subclass);
Kevin P. Fleming
committed
case AST_FRAME_DTMF_END:
res = (chan->tech->send_digit_end == NULL) ? 0 :
chan->tech->send_digit_end(chan);
Kevin P. Fleming
committed
break;
ast_clear_flag(chan, AST_FLAG_BLOCKING);
res = (chan->tech->send_text == NULL) ? 0 :
chan->tech->send_text(chan, (char *) fr->data);
res = (chan->tech->send_html == NULL) ? 0 :
chan->tech->send_html(chan, fr->subclass, (char *) fr->data, fr->datalen);
case AST_FRAME_VIDEO:
/* XXX Handle translation of video codecs one day XXX */
res = (chan->tech->write_video == NULL) ? 0 :
chan->tech->write_video(chan, fr);
Kevin P. Fleming
committed
case AST_FRAME_VOICE:
break; /*! \todo XXX should return 0 maybe ? */
/* Bypass translator if we're writing format in the raw write format. This
allows mixing of native / non-native formats */
if (fr->subclass == chan->rawwriteformat)
f = fr;
else
f = (chan->writetrans) ? ast_translate(chan->writetrans, fr, 0) : fr;
if (f == NULL) {
res = 0;
} else {
if (chan->spies)
queue_frame_to_spies(chan, f, SPY_WRITE);
if (chan->monitor && chan->monitor->write_stream) {
/* XXX must explain this code */
int jump = chan->insmpl - chan->outsmpl - 4 * f->samples;
if (jump >= 0) {
if (ast_seekstream(chan->monitor->write_stream, jump + f->samples, SEEK_FORCECUR) == -1)
ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
chan->outsmpl += jump + 4 * f->samples;
} else
chan->outsmpl += f->samples;
int jump = chan->insmpl - chan->outsmpl;
if (jump - MONITOR_DELAY >= 0) {
if (ast_seekstream(chan->monitor->write_stream, jump - f->samples, SEEK_FORCECUR) == -1)
ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
chan->outsmpl += jump;
} else
chan->outsmpl += f->samples;
if (chan->monitor->state == AST_MONITOR_RUNNING) {
if (ast_writestream(chan->monitor->write_stream, f) < 0)
ast_log(LOG_WARNING, "Failed to write data to channel monitor write stream\n");
Kevin P. Fleming
committed
ast_clear_flag(chan, AST_FLAG_BLOCKING);
/* Consider a write failure to force a soft hangup */
if (res < 0)
chan->fout = FRAMECOUNT_INC(chan->fout);
static int set_format(struct ast_channel *chan, int fmt, int *rawformat, int *format,
struct ast_trans_pvt **trans, const int direction)
/* Make sure we only consider audio */
fmt &= AST_FORMAT_AUDIO_MASK;
/* Find a translation path from the native format to one of the desired formats */
if (!direction)
/* reading */
res = ast_translator_best_choice(&fmt, &native);
else
/* writing */
res = ast_translator_best_choice(&native, &fmt);
ast_log(LOG_WARNING, "Unable to find a codec translation path from %s to %s\n",
ast_getformatname(native), ast_getformatname(fmt));
/* Now we have a good choice for both. */
*rawformat = native;
*format = fmt;
/* Free any read translation we have right now */
if (*trans)
ast_translator_free_path(*trans);
/* Build a translation path from the raw format to the desired format */
if (!direction)
/* reading */
*trans = ast_translator_build_path(*format, *rawformat);
else
/* writing */
*trans = ast_translator_build_path(*rawformat, *format);
if (option_debug)
ast_log(LOG_DEBUG, "Set channel %s to %s format %s\n", chan->name,
direction ? "write" : "read", ast_getformatname(fmt));
int ast_set_read_format(struct ast_channel *chan, int fmt)
return set_format(chan, fmt, &chan->rawreadformat, &chan->readformat,
&chan->readtrans, 0);
}
int ast_set_write_format(struct ast_channel *chan, int fmt)
{
return set_format(chan, fmt, &chan->rawwriteformat, &chan->writeformat,
&chan->writetrans, 1);
struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, struct outgoing_helper *oh)
int dummy_outstate;
Mark Spencer
committed
int cause = 0;
if (outstate)
*outstate = 0;
else
outstate = &dummy_outstate; /* make outstate always a valid pointer */
Mark Spencer
committed
chan = ast_request(type, format, data, &cause);
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
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
if (!chan) {
ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
/* compute error and return */
if (cause == AST_CAUSE_BUSY)
*outstate = AST_CONTROL_BUSY;
else if (cause == AST_CAUSE_CONGESTION)
*outstate = AST_CONTROL_CONGESTION;
return NULL;
}
if (oh) {
if (oh->vars)
ast_set_variables(chan, oh->vars);
/* XXX why is this necessary, for the parent_channel perhaps ? */
if (!ast_strlen_zero(oh->cid_num) && !ast_strlen_zero(oh->cid_name))
ast_set_callerid(chan, oh->cid_num, oh->cid_name, oh->cid_num);
if (oh->parent_channel)
ast_channel_inherit_variables(oh->parent_channel, chan);
if (oh->account)
ast_cdr_setaccount(chan, oh->account);
}
ast_set_callerid(chan, cid_num, cid_name, cid_num);
if (ast_call(chan, data, 0)) { /* ast_call failed... */
ast_log(LOG_NOTICE, "Unable to call channel %s/%s\n", type, (char *)data);
} else {
res = 1; /* mark success in case chan->_state is already AST_STATE_UP */
while (timeout && chan->_state != AST_STATE_UP) {
struct ast_frame *f;
res = ast_waitfor(chan, timeout);
if (res <= 0) /* error, timeout, or done */
break;
if (timeout > -1)
timeout = res;
f = ast_read(chan);
if (!f) {
*outstate = AST_CONTROL_HANGUP;
res = 0;
break;
}
if (f->frametype == AST_FRAME_CONTROL) {
switch (f->subclass) {
case AST_CONTROL_RINGING: /* record but keep going */
*outstate = f->subclass;
case AST_CONTROL_BUSY:
case AST_CONTROL_CONGESTION:
case AST_CONTROL_ANSWER:
*outstate = f->subclass;
timeout = 0; /* trick to force exit from the while() */
case AST_CONTROL_PROGRESS: /* Ignore */
case -1: /* Ignore -- just stopping indications */
default:
ast_log(LOG_NOTICE, "Don't know what to do with control frame %d\n", f->subclass);
Mark Spencer
committed
}
}
/* Final fixups */
if (oh) {
if (!ast_strlen_zero(oh->context))
ast_copy_string(chan->context, oh->context, sizeof(chan->context));
if (!ast_strlen_zero(oh->exten))
ast_copy_string(chan->exten, oh->exten, sizeof(chan->exten));
if (oh->priority)
chan->priority = oh->priority;
if (chan->_state == AST_STATE_UP)
*outstate = AST_CONTROL_ANSWER;
if (res <= 0) {
if (!chan->cdr && (chan->cdr = ast_cdr_alloc()))
ast_cdr_init(chan->cdr, chan);
snprintf(tmp, sizeof(tmp), "%s/%s", type, (char *)data);
ast_cdr_setapp(chan->cdr,"Dial",tmp);
ast_cdr_update(chan);
ast_cdr_start(chan->cdr);
ast_cdr_end(chan->cdr);
/* If the cause wasn't handled properly */
if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
ast_cdr_failed(chan->cdr);
struct ast_channel *ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, const char *cidnum, const char *cidname)
Martin Pycko
committed
{
return __ast_request_and_dial(type, format, data, timeout, outstate, cidnum, cidname, NULL);
Martin Pycko
committed
}
Mark Spencer
committed
struct ast_channel *ast_request(const char *type, int format, void *data, int *cause)
Mark Spencer
committed
int foo;
Mark Spencer
committed
if (!cause)
cause = &foo;
*cause = AST_CAUSE_NOTDEFINED;
if (AST_LIST_LOCK(&channels)) {
ast_log(LOG_WARNING, "Unable to lock channel list\n");
return NULL;
}
Russell Bryant
committed
AST_LIST_TRAVERSE(&backends, chan, list) {
if (strcasecmp(type, chan->tech->type))
continue;
capabilities = chan->tech->capabilities;
fmt = format;
res = ast_translator_best_choice(&fmt, &capabilities);
if (res < 0) {
ast_log(LOG_WARNING, "No translator path exists for channel type %s (native %d) to %d\n", type, chan->tech->capabilities, format);
AST_LIST_UNLOCK(&channels);
AST_LIST_UNLOCK(&channels);
if (!chan->tech->requester)
return NULL;
if (!(c = chan->tech->requester(type, capabilities, data, cause)))
return NULL;
if (c->_state == AST_STATE_DOWN) {
manager_event(EVENT_FLAG_CALL, "Newchannel",
"Channel: %s\r\n"
"State: %s\r\n"
"CallerID: %s\r\n"
"CallerIDName: %s\r\n"
"Uniqueid: %s\r\n",
c->name, ast_state2str(c->_state),
S_OR(c->cid.cid_num, "<unknown>"),
S_OR(c->cid.cid_name, "<unknown>"),
Mark Spencer
committed
}
ast_log(LOG_WARNING, "No channel type registered for '%s'\n", type);
*cause = AST_CAUSE_NOSUCHDRIVER;
AST_LIST_UNLOCK(&channels);
int ast_call(struct ast_channel *chan, char *addr, int timeout)
/* 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
/* Stop if we're a zombie or need a soft hangup */
if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan))
if (chan->tech->call)
res = chan->tech->call(chan, addr, timeout);
\brief Transfer a call to dest, if the channel supports transfer
\arg app_transfer
\arg the manager interface
*/
int ast_transfer(struct ast_channel *chan, char *dest)
/* Stop if we're a zombie or need a soft hangup */
if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan)) {
if (chan->tech->transfer) {
res = chan->tech->transfer(chan, dest);
if (!res)
res = 1;
} else
res = 0;
}
int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int ftimeout, char *enders)
{
return ast_readstring_full(c, s, len, timeout, ftimeout, enders, -1, -1);
}
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; /* index in the buffer where we accumulate digits */
/* Stop if we're a zombie or need a soft hangup */
if (ast_test_flag(c, AST_FLAG_ZOMBIE) || ast_check_hangup(c))
return -1;
if (!len)
return -1;
for (;;) {
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
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';
}
int ast_channel_supports_html(struct ast_channel *chan)
{
return (chan->tech->send_html) ? 1 : 0;
Mark Spencer
committed
int ast_channel_sendhtml(struct ast_channel *chan, int subclass, const char *data, int datalen)
if (chan->tech->send_html)
return chan->tech->send_html(chan, subclass, data, datalen);
Mark Spencer
committed
int ast_channel_sendurl(struct ast_channel *chan, const char *url)
return ast_channel_sendhtml(chan, AST_HTML_URL, url, strlen(url) + 1);
int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
{
Kevin P. Fleming
committed
int src;
int dst;
/* Set up translation from the chan to the peer */
Kevin P. Fleming
committed
src = chan->nativeformats;
dst = peer->nativeformats;
if (ast_translator_best_choice(&dst, &src) < 0) {
ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", chan->name, src, peer->name, dst);
Kevin P. Fleming
committed
/* if the best path is not 'pass through', then
transcoding is needed; if desired, force transcode path
Kevin P. Fleming
committed
to use SLINEAR between channels, but only if there is
no direct conversion available */
if ((src != dst) && ast_opt_transcode_via_slin &&
(ast_translate_path_steps(dst, src) != 1))
Kevin P. Fleming
committed
dst = AST_FORMAT_SLINEAR;
if (ast_set_read_format(chan, dst) < 0) {
ast_log(LOG_WARNING, "Unable to set read format on channel %s to %d\n", chan->name, dst);
Kevin P. Fleming
committed
if (ast_set_write_format(peer, dst) < 0) {
ast_log(LOG_WARNING, "Unable to set write format on channel %s to %d\n", peer->name, dst);
Kevin P. Fleming
committed
/* Set up translation from the peer to the chan */
src = peer->nativeformats;
dst = chan->nativeformats;
if (ast_translator_best_choice(&dst, &src) < 0) {
ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", peer->name, src, chan->name, dst);
Kevin P. Fleming
committed
Kevin P. Fleming
committed
/* if the best path is not 'pass through', then
transcoding is needed; if desired, force transcode path
Kevin P. Fleming
committed
to use SLINEAR between channels, but only if there is
no direct conversion available */
if ((src != dst) && ast_opt_transcode_via_slin &&
(ast_translate_path_steps(dst, src) != 1))
Kevin P. Fleming
committed
dst = AST_FORMAT_SLINEAR;
if (ast_set_read_format(peer, dst) < 0) {
ast_log(LOG_WARNING, "Unable to set read format on channel %s to %d\n", peer->name, dst);
Kevin P. Fleming
committed
if (ast_set_write_format(chan, dst) < 0) {
ast_log(LOG_WARNING, "Unable to set write format on channel %s to %d\n", chan->name, dst);
int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone)
{
int res = -1;
if (original == clone) {
ast_log(LOG_WARNING, "Can't masquerade channel '%s' into itself!\n", original->name);
return -1;
}
ast_channel_lock(original);
while(ast_channel_trylock(clone)) {
ast_channel_unlock(original);
usleep(1);
ast_log(LOG_DEBUG, "Planning to masquerade channel %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",
} else if (clone->masqr) {
ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n",
} else {
original->masq = clone;
clone->masqr = original;
ast_queue_frame(original, &ast_null_frame);
ast_queue_frame(clone, &ast_null_frame);
ast_log(LOG_DEBUG, "Done planning to masquerade channel %s into the structure of %s\n", clone->name, original->name);
res = 0;
}
ast_channel_unlock(clone);
ast_channel_unlock(original);
return res;
void ast_change_name(struct ast_channel *chan, char *newname)
{
manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", chan->name, newname, chan->uniqueid);
ast_string_field_set(chan, name, newname);
void ast_channel_inherit_variables(const struct ast_channel *parent, struct ast_channel *child)
{
struct ast_var_t *current, *newvar;
const char *varname;
AST_LIST_TRAVERSE(&parent->varshead, current, entries) {
int vartype = 0;
varname = ast_var_full_name(current);
if (!varname)
continue;
if (varname[0] == '_') {
vartype = 1;
if (varname[1] == '_')
vartype = 2;
}
switch (vartype) {
case 1:
newvar = ast_var_assign(&varname[1], ast_var_value(current));
if (newvar) {
AST_LIST_INSERT_TAIL(&child->varshead, newvar, entries);
if (option_debug)
ast_log(LOG_DEBUG, "Copying soft-transferable variable %s.\n", ast_var_name(newvar));
}
break;
case 2:
newvar = ast_var_assign(ast_var_full_name(current), ast_var_value(current));
if (newvar) {
AST_LIST_INSERT_TAIL(&child->varshead, newvar, entries);
if (option_debug)
ast_log(LOG_DEBUG, "Copying hard-transferable variable %s.\n", ast_var_name(newvar));
}
break;
default:
if (option_debug)
ast_log(LOG_DEBUG, "Not copying variable %s.\n", ast_var_name(current));
break;
}
}
}
/*!
\brief Clone channel variables from 'clone' channel into 'original' channel
All variables except those related to app_groupcount are cloned.
Variables are actually _removed_ from 'clone' channel, presumably
because it will subsequently be destroyed.
\note Assumes locks will be in place on both channels when called.
*/
static void clone_variables(struct ast_channel *original, struct ast_channel *clone)
{
struct ast_var_t *varptr;
/* we need to remove all app_groupcount related variables from the original
channel before merging in the clone's variables; any groups assigned to the
original channel should be released, only those assigned to the clone
should remain
*/
AST_LIST_TRAVERSE_SAFE_BEGIN(&original->varshead, varptr, entries) {
if (!strncmp(ast_var_name(varptr), GROUP_CATEGORY_PREFIX, strlen(GROUP_CATEGORY_PREFIX))) {
AST_LIST_REMOVE(&original->varshead, varptr, entries);
ast_var_delete(varptr);
}
}
AST_LIST_TRAVERSE_SAFE_END;
/* Append variables from clone channel into original channel */
/* XXX Is this always correct? We have to in order to keep MACROS working XXX */
if (AST_LIST_FIRST(&clone->varshead))
AST_LIST_INSERT_TAIL(&original->varshead, AST_LIST_FIRST(&clone->varshead), entries);
/*!
\brief Masquerade a channel
\note Assumes channel will be locked when called
Mark Spencer
committed
int ast_do_masquerade(struct ast_channel *original)
const struct ast_channel_tech *t;
void *t_pvt;
struct ast_callerid tmpcid;
int rformat = original->readformat;
int wformat = original->writeformat;
char newn[100];
char orig[100];
char masqn[100];
char zombn[100];
if (option_debug > 3)
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 */
if (option_debug > 1)
ast_log(LOG_DEBUG, "Got clone lock for masquerade 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;
ast_copy_string(orig, original->name, sizeof(orig));
ast_copy_string(newn, clone->name, sizeof(newn));
/* Create the masq name */
snprintf(masqn, sizeof(masqn), "%s<MASQ>", newn);
ast_string_field_set(original, name, newn);
ast_string_field_set(clone, name, masqn);
/* 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);
/* Swap the technologies */
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
t = original->tech;
original->tech = clone->tech;
clone->tech = t;
t_pvt = original->tech_pvt;
original->tech_pvt = clone->tech_pvt;
clone->tech_pvt = t_pvt;
/* Swap the readq's */
cur = original->readq;
original->readq = clone->readq;
clone->readq = cur;
/* Swap the alertpipes */
for (i = 0; i < 2; i++) {
x = original->alertpipe[i];
original->alertpipe[i] = clone->alertpipe[i];
clone->alertpipe[i] = x;
}
/* Swap the raw formats */
x = original->rawreadformat;
original->rawreadformat = clone->rawreadformat;
clone->rawreadformat = x;
x = original->rawwriteformat;
original->rawwriteformat = clone->rawwriteformat;
clone->rawwriteformat = x;
/* Save any pending frames on both sides. Start by counting
* how many we're going to need... */
prev = NULL;
x = 0;
/* If we had any, prepend them to the ones already in the queue, and