Newer
Older
Mark Spencer
committed
ast_cdr_answer(chan->cdr);
Kevin P. Fleming
committed
}
}
break;
case AST_FRAME_DTMF:
ast_log(LOG_DTMF, "DTMF '%c' received on %s\n", f->subclass, chan->name);
if (ast_test_flag(chan, AST_FLAG_DEFER_DTMF)) {
if (strlen(chan->dtmfq) < sizeof(chan->dtmfq) - 2)
chan->dtmfq[strlen(chan->dtmfq)] = f->subclass;
else
ast_log(LOG_WARNING, "Dropping deferred DTMF digits on %s\n", chan->name);
f = &ast_null_frame;
Kevin P. Fleming
committed
}
break;
case AST_FRAME_DTMF_BEGIN:
ast_log(LOG_DTMF, "DTMF begin '%c' received on %s\n", f->subclass, chan->name);
break;
case AST_FRAME_DTMF_END:
ast_log(LOG_DTMF, "DTMF end '%c' received on %s\n", f->subclass, chan->name);
break;
case AST_FRAME_VOICE:
if (dropaudio) {
ast_frfree(f);
f = &ast_null_frame;
Kevin P. Fleming
committed
} else if (!(f->subclass & chan->nativeformats)) {
/* This frame can't be from the current native formats -- drop it on the
floor */
ast_log(LOG_NOTICE, "Dropping incompatible voice frame on %s of format %s since our native format has changed to %s\n",
chan->name, ast_getformatname(f->subclass), ast_getformatname(chan->nativeformats));
ast_frfree(f);
f = &ast_null_frame;
Kevin P. Fleming
committed
} else {
if (chan->spies)
queue_frame_to_spies(chan, f, SPY_READ);
if (chan->monitor && chan->monitor->read_stream ) {
Kevin P. Fleming
committed
int jump = chan->outsmpl - chan->insmpl - 4 * f->samples;
if (jump >= 0) {
if (ast_seekstream(chan->monitor->read_stream, jump + f->samples, SEEK_FORCECUR) == -1)
ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n");
chan->insmpl += jump + 4 * f->samples;
} else
chan->insmpl+= f->samples;
Kevin P. Fleming
committed
int jump = chan->outsmpl - chan->insmpl;
if (jump - MONITOR_DELAY >= 0) {
if (ast_seekstream(chan->monitor->read_stream, jump - f->samples, SEEK_FORCECUR) == -1)
ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n");
chan->insmpl += jump;
} else
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 > 4)
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)
Kevin P. Fleming
committed
{
return ast_indicate_data(chan, condition, NULL, 0);
}
int ast_indicate_data(struct ast_channel *chan, int condition, const void *data, size_t datalen)
/* 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)
Kevin P. Fleming
committed
res = chan->tech->indicate(chan, condition, data, datalen);
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);
/*
* 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);
case AST_FRAME_MODEM:
res = (chan->tech->write == NULL) ? 0 :
chan->tech->write(chan, fr);
break;
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);
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
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() */
Kevin P. Fleming
committed
/* Ignore these */
case AST_CONTROL_PROGRESS:
case AST_CONTROL_PROCEEDING:
case AST_CONTROL_HOLD:
case AST_CONTROL_UNHOLD:
case AST_CONTROL_VIDUPDATE:
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;
int videoformat = format & AST_FORMAT_VIDEO_MASK;
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 & AST_FORMAT_AUDIO_MASK;
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 (!(c = chan->tech->requester(type, capabilities | videoformat, 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 */
Mark Spencer
committed
if (!ast_test_flag(chan, AST_FLAG_ZOMBIE) && !ast_check_hangup(chan)) {
if (chan->tech->call)
res = chan->tech->call(chan, addr, timeout);
Mark Spencer
committed
ast_set_flag(chan, AST_FLAG_OUTGOING);
}
\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 (;;) {
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
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;
/* each of these channels may be sitting behind a channel proxy (i.e. chan_agent)
and if so, we don't really want to masquerade it, but its proxy */
if (original->_bridge && (original->_bridge != ast_bridged_channel(original)))
original = original->_bridge;
if (clone->_bridge && (clone->_bridge != ast_bridged_channel(clone)))
clone = clone->_bridge;
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);