mirror of
https://github.com/asterisk/asterisk.git
synced 2026-05-04 04:16:54 +00:00
applied final release of bug 1353 per Mark's permission
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@2782 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
231
channel.c
231
channel.c
@@ -28,6 +28,7 @@
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/channel_pvt.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/say.h>
|
||||
#include <asterisk/file.h>
|
||||
#include <asterisk/translate.h>
|
||||
#include <asterisk/manager.h>
|
||||
@@ -40,7 +41,7 @@
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/zaptel.h>
|
||||
#ifndef ZT_TIMERPING
|
||||
#error "You need newer zaptel! Please cvs update zaptel"
|
||||
#error "You need newer zaptel! Please cvs update zaptel"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -140,17 +141,19 @@ void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset)
|
||||
time_t myt;
|
||||
|
||||
time(&myt);
|
||||
if (offset)
|
||||
if (offset)
|
||||
chan->whentohangup = myt + offset;
|
||||
else
|
||||
chan->whentohangup = 0;
|
||||
else
|
||||
chan->whentohangup = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int ast_channel_register(char *type, char *description, int capabilities,
|
||||
struct ast_channel *(*requester)(char *type, int format, void *data))
|
||||
{
|
||||
return ast_channel_register_ex(type, description, capabilities, requester, NULL);
|
||||
return ast_channel_register_ex(type, description, capabilities, requester, NULL);
|
||||
}
|
||||
|
||||
int ast_channel_register_ex(char *type, char *description, int capabilities,
|
||||
@@ -271,8 +274,8 @@ struct ast_channel *ast_channel_alloc(int needqueue)
|
||||
struct ast_channel_pvt *pvt;
|
||||
int x;
|
||||
int flags;
|
||||
struct varshead *headp;
|
||||
|
||||
struct varshead *headp;
|
||||
|
||||
|
||||
/* If shutting down, don't allocate any new channels */
|
||||
if (shutting_down)
|
||||
@@ -333,7 +336,7 @@ struct ast_channel *ast_channel_alloc(int needqueue)
|
||||
snprintf(tmp->uniqueid, sizeof(tmp->uniqueid), "%li.%d", (long)time(NULL), uniqueint++);
|
||||
headp=&tmp->varshead;
|
||||
ast_mutex_init(&tmp->lock);
|
||||
AST_LIST_HEAD_INIT(headp);
|
||||
AST_LIST_HEAD_INIT(headp);
|
||||
tmp->vars=ast_var_assign("tempvar","tempval");
|
||||
AST_LIST_INSERT_HEAD(headp,tmp->vars,entries);
|
||||
strncpy(tmp->context, "default", sizeof(tmp->context)-1);
|
||||
@@ -461,7 +464,7 @@ struct ast_channel *ast_channel_walk(struct ast_channel *prev)
|
||||
|
||||
}
|
||||
|
||||
int ast_safe_sleep_conditional( struct ast_channel *chan, int ms,
|
||||
int ast_safe_sleep_conditional( struct ast_channel *chan, int ms,
|
||||
int (*cond)(void*), void *data )
|
||||
{
|
||||
struct ast_frame *f;
|
||||
@@ -569,13 +572,13 @@ void ast_channel_free(struct ast_channel *chan)
|
||||
/* loop over the variables list, freeing all data and deleting list items */
|
||||
/* no need to lock the list, as the channel is already locked */
|
||||
|
||||
while (!AST_LIST_EMPTY(headp)) { /* List Deletion. */
|
||||
vardata = AST_LIST_FIRST(headp);
|
||||
AST_LIST_REMOVE_HEAD(headp, entries);
|
||||
// printf("deleting var %s=%s\n",ast_var_name(vardata),ast_var_value(vardata));
|
||||
ast_var_delete(vardata);
|
||||
while (!AST_LIST_EMPTY(headp)) { /* List Deletion. */
|
||||
vardata = AST_LIST_FIRST(headp);
|
||||
AST_LIST_REMOVE_HEAD(headp, entries);
|
||||
// printf("deleting var %s=%s\n",ast_var_name(vardata),ast_var_value(vardata));
|
||||
ast_var_delete(vardata);
|
||||
}
|
||||
|
||||
|
||||
|
||||
free(chan->pvt);
|
||||
chan->pvt = NULL;
|
||||
@@ -665,7 +668,7 @@ int ast_hangup(struct ast_channel *chan)
|
||||
}
|
||||
if (chan->blocking) {
|
||||
ast_log(LOG_WARNING, "Hard hangup called by thread %ld on %s, while fd "
|
||||
"is blocked by thread %ld in procedure %s! Expect a failure\n",
|
||||
"is blocked by thread %ld in procedure %s! Expect a failure\n",
|
||||
(long)pthread_self(), chan->name, (long)chan->blocker, chan->blockproc);
|
||||
CRASH;
|
||||
}
|
||||
@@ -681,9 +684,9 @@ int ast_hangup(struct ast_channel *chan)
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
manager_event(EVENT_FLAG_CALL, "Hangup",
|
||||
"Channel: %s\r\n"
|
||||
"Uniqueid: %s\r\n"
|
||||
"Cause: %i\r\n",
|
||||
chan->name, chan->uniqueid, chan->hangupcause);
|
||||
"Uniqueid: %s\r\n"
|
||||
"Cause: %i\r\n",
|
||||
chan->name, chan->uniqueid, chan->hangupcause);
|
||||
ast_channel_free(chan);
|
||||
return res;
|
||||
}
|
||||
@@ -1114,7 +1117,7 @@ struct ast_frame *ast_read(struct ast_channel *chan)
|
||||
ast_log(LOG_WARNING, "Failed to perform masquerade\n");
|
||||
f = NULL;
|
||||
} else
|
||||
f = &null_frame;
|
||||
f = &null_frame;
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
return f;
|
||||
}
|
||||
@@ -1128,7 +1131,7 @@ struct ast_frame *ast_read(struct ast_channel *chan)
|
||||
}
|
||||
|
||||
if (!chan->deferdtmf && strlen(chan->dtmfq)) {
|
||||
/* We have DTMF that has been deferred. Return it now */
|
||||
/* We have DTMF that has been deferred. Return it now */
|
||||
chan->dtmff.frametype = AST_FRAME_DTMF;
|
||||
chan->dtmff.subclass = chan->dtmfq[0];
|
||||
/* Drop first digit */
|
||||
@@ -1181,7 +1184,7 @@ struct ast_frame *ast_read(struct ast_channel *chan)
|
||||
chan->timingdata = NULL;
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
}
|
||||
f = &null_frame;
|
||||
f = &null_frame;
|
||||
return f;
|
||||
} else
|
||||
ast_log(LOG_NOTICE, "No/unknown event '%d' on timer for '%s'?\n", blah, chan->name);
|
||||
@@ -1361,10 +1364,10 @@ int ast_recvchar(struct ast_channel *chan, int timeout)
|
||||
f = ast_read(chan);
|
||||
if (f == NULL) return -1; /* if hangup */
|
||||
if ((f->frametype == AST_FRAME_CONTROL) &&
|
||||
(f->subclass == AST_CONTROL_HANGUP)) return -1; /* if hangup */
|
||||
if (f->frametype == AST_FRAME_TEXT) /* if a text frame */
|
||||
(f->subclass == AST_CONTROL_HANGUP)) return -1; /* if hangup */
|
||||
if (f->frametype == AST_FRAME_TEXT) /* if a text frame */
|
||||
{
|
||||
c = *((char *)f->data); /* get the data */
|
||||
c = *((char *)f->data); /* get the data */
|
||||
ast_frfree(f);
|
||||
return(c);
|
||||
}
|
||||
@@ -1397,21 +1400,21 @@ static int do_senddigit(struct ast_channel *chan, char digit)
|
||||
* 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+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" }; /* # */
|
||||
if (digit >= '0' && digit <='9')
|
||||
ast_playtones_start(chan,0,dtmf_tones[digit-'0'], 0);
|
||||
@@ -1462,7 +1465,7 @@ int ast_write(struct ast_channel *chan, struct ast_frame *fr)
|
||||
struct ast_frame *f = NULL;
|
||||
/* 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->zombie || ast_check_hangup(chan)) {
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
return -1;
|
||||
}
|
||||
@@ -1582,7 +1585,7 @@ int ast_set_write_format(struct ast_channel *chan, int fmts)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Now we have a good choice for both. We'll write using our native format. */
|
||||
/* Now we have a good choice for both. We'll write using our native format. */
|
||||
chan->pvt->rawwriteformat = native;
|
||||
/* User perspective is fmt */
|
||||
chan->writeformat = fmt;
|
||||
@@ -1615,7 +1618,7 @@ int ast_set_read_format(struct ast_channel *chan, int fmts)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Now we have a good choice for both. We'll write using our native format. */
|
||||
/* Now we have a good choice for both. We'll write using our native format. */
|
||||
chan->pvt->rawreadformat = native;
|
||||
/* User perspective is fmt */
|
||||
chan->readformat = fmt;
|
||||
@@ -1643,7 +1646,7 @@ struct ast_channel *__ast_request_and_dial(char *type, int format, void *data, i
|
||||
char *tmp, *var;
|
||||
/* JDG chanvar */
|
||||
tmp = oh->variable;
|
||||
/* FIXME replace this call with strsep NOT*/
|
||||
/* FIXME replace this call with strsep NOT*/
|
||||
while( (var = strtok_r(NULL, "|", &tmp)) ) {
|
||||
pbx_builtin_setvar( chan, var );
|
||||
} /* /JDG */
|
||||
@@ -1795,9 +1798,9 @@ int ast_parse_device_state(char *device)
|
||||
strncpy(name, chan->name, sizeof(name)-1);
|
||||
cut = strchr(name,'-');
|
||||
if (cut)
|
||||
*cut = 0;
|
||||
*cut = 0;
|
||||
if (!strcmp(name, device))
|
||||
return AST_DEVICE_INUSE;
|
||||
return AST_DEVICE_INUSE;
|
||||
chan = ast_channel_walk(chan);
|
||||
}
|
||||
return AST_DEVICE_UNKNOWN;
|
||||
@@ -1813,7 +1816,7 @@ int ast_device_state(char *device)
|
||||
strncpy(tech, device, sizeof(tech)-1);
|
||||
number = strchr(tech, '/');
|
||||
if (!number) {
|
||||
return AST_DEVICE_INVALID;
|
||||
return AST_DEVICE_INVALID;
|
||||
}
|
||||
*number = 0;
|
||||
number++;
|
||||
@@ -2090,8 +2093,8 @@ int ast_do_masquerade(struct ast_channel *original)
|
||||
clone->name, clone->_state, original->name, original->_state);
|
||||
#endif
|
||||
/* 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
|
||||
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 */
|
||||
|
||||
/* We need the clone's lock, too */
|
||||
@@ -2126,7 +2129,7 @@ int ast_do_masquerade(struct ast_channel *original)
|
||||
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);
|
||||
|
||||
/* Swap the guts */
|
||||
/* Swap the guts */
|
||||
p = original->pvt;
|
||||
original->pvt = clone->pvt;
|
||||
clone->pvt = p;
|
||||
@@ -2175,7 +2178,7 @@ int ast_do_masquerade(struct ast_channel *original)
|
||||
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. */
|
||||
/* Keep the same language. */
|
||||
/* Update the type. */
|
||||
original->type = clone->type;
|
||||
/* Copy the FD's */
|
||||
@@ -2183,7 +2186,7 @@ int ast_do_masquerade(struct ast_channel *original)
|
||||
original->fds[x] = clone->fds[x];
|
||||
}
|
||||
/* Append variables from clone channel into original channel */
|
||||
/* XXX Is this always correct? We have to in order to keep MACROS working XXX */
|
||||
/* 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) {
|
||||
@@ -2200,12 +2203,12 @@ int ast_do_masquerade(struct ast_channel *original)
|
||||
/* 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 */
|
||||
/* 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 */
|
||||
/* 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
|
||||
@@ -2229,7 +2232,7 @@ int ast_do_masquerade(struct ast_channel *original)
|
||||
these separate */
|
||||
original->_state = clone->_state;
|
||||
|
||||
/* Context, extension, priority, app data, jump table, remain the same */
|
||||
/* Context, extension, priority, app data, jump table, remain the same */
|
||||
/* pvt switches. pbx stays the same, as does next */
|
||||
|
||||
/* Set the write format */
|
||||
@@ -2327,16 +2330,73 @@ int ast_setstate(struct ast_channel *chan, int state)
|
||||
return 0;
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
static void bridge_playfile(struct ast_channel *chan,char *sound,int remain) {
|
||||
int res=0,min=0,sec=0;
|
||||
|
||||
if(remain > 0) {
|
||||
if(remain / 60 > 1) {
|
||||
min = remain / 60;
|
||||
sec = remain % 60;
|
||||
}
|
||||
else {
|
||||
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);
|
||||
res=ast_streamfile(chan,"minutes",chan->language);
|
||||
res = ast_waitstream(chan, "");
|
||||
}
|
||||
if(sec) {
|
||||
res = ast_say_number(chan,sec, AST_DIGIT_ANY, chan->language);
|
||||
res=ast_streamfile(chan,"seconds",chan->language);
|
||||
res = ast_waitstream(chan, "");
|
||||
}
|
||||
}
|
||||
else {
|
||||
res=ast_streamfile(chan,sound,chan->language);
|
||||
res = ast_waitstream(chan, "");
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
struct ast_channel *who = NULL;
|
||||
int res;
|
||||
int res=0;
|
||||
int nativefailed=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){
|
||||
bridge_playfile(c0,config->start_sound,time_left_ms / 1000);
|
||||
}
|
||||
if(config->play_to_callee && config->start_sound){
|
||||
bridge_playfile(c1,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))
|
||||
@@ -2366,6 +2426,57 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
|
||||
c0->name, c1->name, c0->uniqueid, c1->uniqueid);
|
||||
|
||||
for (/* ever */;;) {
|
||||
|
||||
/* timestamp */
|
||||
if(config->timelimit) {
|
||||
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 */
|
||||
if(config->warning_freq == 0) {
|
||||
playit = 1;
|
||||
first_time=0;
|
||||
playitagain=0;
|
||||
}
|
||||
else if(first_time) {
|
||||
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){
|
||||
bridge_playfile(c0,config->end_sound,0);
|
||||
}
|
||||
|
||||
if(config->play_to_callee && config->end_sound){
|
||||
bridge_playfile(c1,config->end_sound,0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(time_left_ms >= 5000 && playit) {
|
||||
if(config->play_to_caller && config->warning_sound && config->play_warning){
|
||||
bridge_playfile(c0,config->warning_sound,time_left_ms / 1000);
|
||||
}
|
||||
|
||||
if(config->play_to_callee && config->warning_sound && config->play_warning){
|
||||
bridge_playfile(c1,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;
|
||||
@@ -2374,7 +2485,7 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
|
||||
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");
|
||||
break;
|
||||
}
|
||||
if (c0->pvt->bridge &&
|
||||
if (c0->pvt->bridge && config->timelimit==0 &&
|
||||
(c0->pvt->bridge == c1->pvt->bridge) && !nativefailed && !c0->monitor && !c1->monitor) {
|
||||
/* Looks like they share a bridge code */
|
||||
if (option_verbose > 2)
|
||||
|
||||
Reference in New Issue
Block a user