Version 0.1.7 from FTP
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@236 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
parent
ea452d3fd8
commit
dc884645e6
|
@ -116,48 +116,48 @@ static int intercom_exec(struct ast_channel *chan, void *data)
|
|||
int res = 0;
|
||||
struct localuser *u;
|
||||
struct ast_frame *f;
|
||||
struct ast_channel *trans;
|
||||
int oreadformat;
|
||||
if (!data) {
|
||||
ast_log(LOG_WARNING, "Playback requires an argument (filename)\n");
|
||||
return -1;
|
||||
}
|
||||
LOCAL_USER_ADD(u);
|
||||
/* See if we need a translator */
|
||||
if (!(chan->format & AST_FORMAT_SLINEAR))
|
||||
trans = ast_translator_create(chan, AST_FORMAT_SLINEAR, AST_DIRECTION_IN);
|
||||
else
|
||||
trans = chan;
|
||||
if (trans) {
|
||||
/* Read packets from the channel */
|
||||
while(!res) {
|
||||
res = ast_waitfor(trans, -1);
|
||||
if (res > 0) {
|
||||
res = 0;
|
||||
f = ast_read(trans);
|
||||
if (f) {
|
||||
if (f->frametype == AST_FRAME_DTMF) {
|
||||
ast_frfree(f);
|
||||
break;
|
||||
} else {
|
||||
if (f->frametype == AST_FRAME_VOICE) {
|
||||
if (f->subclass == AST_FORMAT_SLINEAR) {
|
||||
res = write_audio(f->data, f->datalen);
|
||||
if (res > 0)
|
||||
res = 0;
|
||||
} else
|
||||
ast_log(LOG_DEBUG, "Unable to handle non-signed linear frame (%d)\n", f->subclass);
|
||||
}
|
||||
}
|
||||
/* Remember original read format */
|
||||
oreadformat = chan->readformat;
|
||||
/* Set mode to signed linear */
|
||||
res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
|
||||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to set format to signed linear on channel %s\n", chan->name);
|
||||
return -1;
|
||||
}
|
||||
/* Read packets from the channel */
|
||||
while(!res) {
|
||||
res = ast_waitfor(chan, -1);
|
||||
if (res > 0) {
|
||||
res = 0;
|
||||
f = ast_read(chan);
|
||||
if (f) {
|
||||
if (f->frametype == AST_FRAME_DTMF) {
|
||||
ast_frfree(f);
|
||||
} else
|
||||
res = -1;
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
if (f->frametype == AST_FRAME_VOICE) {
|
||||
if (f->subclass == AST_FORMAT_SLINEAR) {
|
||||
res = write_audio(f->data, f->datalen);
|
||||
if (res > 0)
|
||||
res = 0;
|
||||
} else
|
||||
ast_log(LOG_DEBUG, "Unable to handle non-signed linear frame (%d)\n", f->subclass);
|
||||
}
|
||||
}
|
||||
ast_frfree(f);
|
||||
} else
|
||||
res = -1;
|
||||
}
|
||||
if (trans != chan)
|
||||
ast_translator_destroy(trans);
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Unable to build translator to signed linear format on '%s'\n", chan->name);
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
if (!res)
|
||||
ast_set_read_format(chan, oreadformat);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -187,3 +187,8 @@ int usecount(void)
|
|||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
|
157
apps/app_mp3.c
157
apps/app_mp3.c
|
@ -59,12 +59,13 @@ static int mp3_exec(struct ast_channel *chan, void *data)
|
|||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
struct ast_channel *trans;
|
||||
int fds[2];
|
||||
int rfds[2];
|
||||
int ms = -1;
|
||||
int pid;
|
||||
int us;
|
||||
int exception;
|
||||
int owriteformat;
|
||||
struct timeval tv;
|
||||
struct timeval last;
|
||||
struct ast_frame *f;
|
||||
|
@ -85,87 +86,90 @@ static int mp3_exec(struct ast_channel *chan, void *data)
|
|||
}
|
||||
LOCAL_USER_ADD(u);
|
||||
ast_stopstream(chan);
|
||||
if (chan->format & AST_FORMAT_SLINEAR)
|
||||
trans = chan;
|
||||
else
|
||||
trans = ast_translator_create(chan, AST_FORMAT_SLINEAR, AST_DIRECTION_OUT);
|
||||
if (trans) {
|
||||
res = mp3play((char *)data, fds[1]);
|
||||
if (res >= 0) {
|
||||
pid = res;
|
||||
/* Order is important -- there's almost always going to be mp3... we want to prioritize the
|
||||
user */
|
||||
rfds[0] = trans->fd;
|
||||
rfds[1] = fds[0];
|
||||
for (;;) {
|
||||
CHECK_BLOCKING(trans);
|
||||
res = ast_waitfor_n_fd(rfds, 2, &ms);
|
||||
trans->blocking = 0;
|
||||
if (res < 1) {
|
||||
ast_log(LOG_DEBUG, "Hangup detected\n");
|
||||
res = -1;
|
||||
break;
|
||||
} else if (res == trans->fd) {
|
||||
f = ast_read(trans);
|
||||
if (!f) {
|
||||
ast_log(LOG_DEBUG, "Null frame == hangup() detected\n");
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
if (f->frametype == AST_FRAME_DTMF) {
|
||||
ast_log(LOG_DEBUG, "User pressed a key\n");
|
||||
ast_frfree(f);
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
ast_frfree(f);
|
||||
} else if (res == fds[0]) {
|
||||
gettimeofday(&tv, NULL);
|
||||
if (last.tv_sec || last.tv_usec) {
|
||||
/* We should wait at least a frame length */
|
||||
us = sizeof(myf.frdata) / 16 * 1000;
|
||||
/* Subtract 1,000,000 us for each second late we've passed */
|
||||
us -= (tv.tv_sec - last.tv_sec) * 1000000;
|
||||
/* And one for each us late we've passed */
|
||||
us -= (tv.tv_usec - last.tv_usec);
|
||||
/* Sleep that long if needed */
|
||||
if (us > 0)
|
||||
usleep(us);
|
||||
}
|
||||
last = tv;
|
||||
res = read(fds[0], myf.frdata, sizeof(myf.frdata));
|
||||
if (res > 0) {
|
||||
myf.f.frametype = AST_FRAME_VOICE;
|
||||
myf.f.subclass = AST_FORMAT_SLINEAR;
|
||||
myf.f.datalen = res;
|
||||
myf.f.timelen = res / 16;
|
||||
myf.f.mallocd = 0;
|
||||
myf.f.offset = AST_FRIENDLY_OFFSET;
|
||||
myf.f.src = __PRETTY_FUNCTION__;
|
||||
myf.f.data = myf.frdata;
|
||||
if (ast_write(trans, &myf.f) < 0) {
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_DEBUG, "No more mp3\n");
|
||||
res = 0;
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_DEBUG, "HuhHHH?\n");
|
||||
|
||||
owriteformat = chan->writeformat;
|
||||
res = ast_set_write_format(chan, AST_FORMAT_SLINEAR);
|
||||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to set write format to signed linear\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = mp3play((char *)data, fds[1]);
|
||||
if (res >= 0) {
|
||||
pid = res;
|
||||
/* Order is important -- there's almost always going to be mp3... we want to prioritize the
|
||||
user */
|
||||
rfds[0] = chan->fd;
|
||||
rfds[1] = fds[0];
|
||||
for (;;) {
|
||||
CHECK_BLOCKING(chan);
|
||||
res = ast_waitfor_n_fd(rfds, 2, &ms, &exception);
|
||||
chan->blocking = 0;
|
||||
if (res < 1) {
|
||||
ast_log(LOG_DEBUG, "Hangup detected\n");
|
||||
res = -1;
|
||||
break;
|
||||
} else if (res == chan->fd) {
|
||||
if (exception)
|
||||
chan->exception = 1;
|
||||
f = ast_read(chan);
|
||||
if (!f) {
|
||||
ast_log(LOG_DEBUG, "Null frame == hangup() detected\n");
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
if (f->frametype == AST_FRAME_DTMF) {
|
||||
ast_log(LOG_DEBUG, "User pressed a key\n");
|
||||
ast_frfree(f);
|
||||
res = 0;
|
||||
break;
|
||||
}
|
||||
ast_frfree(f);
|
||||
} else if (res == fds[0]) {
|
||||
gettimeofday(&tv, NULL);
|
||||
if (last.tv_sec || last.tv_usec) {
|
||||
/* We should wait at least a frame length */
|
||||
us = sizeof(myf.frdata) / 16 * 1000;
|
||||
/* Subtract 1,000,000 us for each second late we've passed */
|
||||
us -= (tv.tv_sec - last.tv_sec) * 1000000;
|
||||
/* And one for each us late we've passed */
|
||||
us -= (tv.tv_usec - last.tv_usec);
|
||||
/* Sleep that long if needed */
|
||||
if (us > 0)
|
||||
usleep(us);
|
||||
}
|
||||
last = tv;
|
||||
res = read(fds[0], myf.frdata, sizeof(myf.frdata));
|
||||
if (res > 0) {
|
||||
myf.f.frametype = AST_FRAME_VOICE;
|
||||
myf.f.subclass = AST_FORMAT_SLINEAR;
|
||||
myf.f.datalen = res;
|
||||
myf.f.timelen = res / 16;
|
||||
myf.f.mallocd = 0;
|
||||
myf.f.offset = AST_FRIENDLY_OFFSET;
|
||||
myf.f.src = __PRETTY_FUNCTION__;
|
||||
myf.f.data = myf.frdata;
|
||||
if (ast_write(chan, &myf.f) < 0) {
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_DEBUG, "No more mp3\n");
|
||||
res = 0;
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_DEBUG, "HuhHHH?\n");
|
||||
res = -1;
|
||||
break;
|
||||
}
|
||||
kill(pid, SIGTERM);
|
||||
}
|
||||
if (trans != chan)
|
||||
ast_translator_destroy(trans);
|
||||
} else
|
||||
ast_log(LOG_WARNING, "No translator channel available\n");
|
||||
kill(pid, SIGTERM);
|
||||
}
|
||||
close(fds[0]);
|
||||
close(fds[1]);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
if (!res)
|
||||
ast_set_write_format(chan, owriteformat);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -191,3 +195,8 @@ int usecount(void)
|
|||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
|
|
@ -418,7 +418,7 @@ static int vm_execmain(struct ast_channel *chan, void *data)
|
|||
ast_verbose( VERBOSE_PREFIX_3 "User '%s' logged in on channel %s with %d messages\n", username, chan->name, maxmsg);
|
||||
if (!ast_streamfile(chan, "vm-instructions", chan->language)) {
|
||||
for(;;) {
|
||||
if (chan->stream || (chan->trans && chan->trans->stream)) {
|
||||
if (chan->stream) {
|
||||
d = ast_waitstream(chan, AST_DIGIT_ANY);
|
||||
ast_stopstream(chan);
|
||||
if (!d && (state == STATE_MESSAGE_PLAYING)) {
|
||||
|
@ -616,3 +616,8 @@ int usecount(void)
|
|||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
|
|
@ -227,7 +227,7 @@ int ast_modem_read_response(struct ast_modem_pvt *p, int timeout)
|
|||
timeout *= 1000;
|
||||
strncpy(p->response, "(No Response)", sizeof(p->response));
|
||||
do {
|
||||
res = ast_waitfor_n_fd(&p->fd, 1, &timeout);
|
||||
res = ast_waitfor_n_fd(&p->fd, 1, &timeout, NULL);
|
||||
if (res < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -244,7 +244,7 @@ int ast_modem_expect(struct ast_modem_pvt *p, char *result, int timeout)
|
|||
timeout *= 1000;
|
||||
strncpy(p->response, "(No Response)", sizeof(p->response));
|
||||
do {
|
||||
res = ast_waitfor_n_fd(&p->fd, 1, &timeout);
|
||||
res = ast_waitfor_n_fd(&p->fd, 1, &timeout, NULL);
|
||||
if (res < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -432,7 +432,7 @@ struct ast_channel *ast_modem_new(struct ast_modem_pvt *i, int state)
|
|||
snprintf(tmp->name, sizeof(tmp->name), "Modem[%s]/%s", i->mc->name, i->dev + 5);
|
||||
tmp->type = type;
|
||||
tmp->fd = i->fd;
|
||||
tmp->format = i->mc->formats;
|
||||
tmp->nativeformats = i->mc->formats;
|
||||
tmp->state = state;
|
||||
if (state == AST_STATE_RING)
|
||||
tmp->rings = 1;
|
||||
|
@ -855,3 +855,8 @@ char *description()
|
|||
return desc;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
|
|
|
@ -207,7 +207,7 @@ static int phone_setup(struct ast_channel *ast)
|
|||
p = ast->pvt->pvt;
|
||||
ioctl(p->fd, PHONE_CPT_STOP);
|
||||
/* Nothing to answering really, just start recording */
|
||||
if (ast->format & AST_FORMAT_G723_1) {
|
||||
if (ast->pvt->rawreadformat == AST_FORMAT_G723_1) {
|
||||
/* Prefer g723 */
|
||||
ioctl(p->fd, PHONE_REC_STOP);
|
||||
if (p->lastinput != AST_FORMAT_G723_1) {
|
||||
|
@ -217,7 +217,7 @@ static int phone_setup(struct ast_channel *ast)
|
|||
return -1;
|
||||
}
|
||||
}
|
||||
} else if (ast->format & AST_FORMAT_SLINEAR) {
|
||||
} else if (ast->pvt->rawreadformat == AST_FORMAT_SLINEAR) {
|
||||
ioctl(p->fd, PHONE_REC_STOP);
|
||||
if (p->lastinput != AST_FORMAT_SLINEAR) {
|
||||
p->lastinput = AST_FORMAT_SLINEAR;
|
||||
|
@ -227,7 +227,7 @@ static int phone_setup(struct ast_channel *ast)
|
|||
}
|
||||
}
|
||||
} else {
|
||||
ast_log(LOG_WARNING, "Can't do format %d\n", ast->format);
|
||||
ast_log(LOG_WARNING, "Can't do format %d\n", ast->pvt->rawreadformat);
|
||||
return -1;
|
||||
}
|
||||
if (ioctl(p->fd, PHONE_REC_START)) {
|
||||
|
@ -268,7 +268,7 @@ static char phone_2digit(char c)
|
|||
return '?';
|
||||
}
|
||||
|
||||
static struct ast_frame *phone_read(struct ast_channel *ast)
|
||||
static struct ast_frame *phone_exception(struct ast_channel *ast)
|
||||
{
|
||||
int res;
|
||||
union telephony_exception phonee;
|
||||
|
@ -286,7 +286,7 @@ static struct ast_frame *phone_read(struct ast_channel *ast)
|
|||
phonee.bytes = ioctl(p->fd, PHONE_EXCEPTION);
|
||||
if (phonee.bits.dtmf_ready) {
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "phone_read(): DTMF\n");
|
||||
ast_log(LOG_DEBUG, "phone_exception(): DTMF\n");
|
||||
|
||||
/* We've got a digit -- Just handle this nicely and easily */
|
||||
digit = ioctl(p->fd, PHONE_GET_DTMF_ASCII);
|
||||
|
@ -324,6 +324,25 @@ static struct ast_frame *phone_read(struct ast_channel *ast)
|
|||
if (phonee.bits.pstn_wink)
|
||||
ast_verbose("Detected Wink\n");
|
||||
#endif
|
||||
/* Strange -- nothing there.. */
|
||||
p->fr.frametype = AST_FRAME_NULL;
|
||||
p->fr.subclass = 0;
|
||||
return &p->fr;
|
||||
}
|
||||
|
||||
static struct ast_frame *phone_read(struct ast_channel *ast)
|
||||
{
|
||||
int res;
|
||||
struct phone_pvt *p = ast->pvt->pvt;
|
||||
|
||||
/* Some nice norms */
|
||||
p->fr.datalen = 0;
|
||||
p->fr.timelen = 0;
|
||||
p->fr.data = NULL;
|
||||
p->fr.src = type;
|
||||
p->fr.offset = 0;
|
||||
p->fr.mallocd=0;
|
||||
|
||||
/* Try to read some data... */
|
||||
CHECK_BLOCKING(ast);
|
||||
res = read(p->fd, p->buf, PHONE_MAX_BUF);
|
||||
|
@ -517,7 +536,7 @@ static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *conte
|
|||
tmp->type = type;
|
||||
tmp->fd = i->fd;
|
||||
/* XXX Switching formats silently causes kernel panics XXX */
|
||||
tmp->format = prefformat;
|
||||
tmp->nativeformats = prefformat;
|
||||
tmp->state = state;
|
||||
if (state == AST_STATE_RING)
|
||||
tmp->rings = 1;
|
||||
|
@ -528,6 +547,7 @@ static struct ast_channel *phone_new(struct phone_pvt *i, int state, char *conte
|
|||
tmp->pvt->answer = phone_answer;
|
||||
tmp->pvt->read = phone_read;
|
||||
tmp->pvt->write = phone_write;
|
||||
tmp->pvt->exception = phone_exception;
|
||||
strncpy(tmp->context, context, sizeof(tmp->context));
|
||||
if (strlen(i->ext))
|
||||
strncpy(tmp->exten, i->ext, sizeof(tmp->exten));
|
||||
|
@ -1052,3 +1072,7 @@ char *description()
|
|||
return desc;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
|
|
@ -795,7 +795,7 @@ static struct ast_channel *vofr_new(struct vofr_pvt *i, int state)
|
|||
tmp->type = type;
|
||||
tmp->fd = i->s;
|
||||
/* Adtran VoFR supports only G723.1 format data. G711 (ulaw) would be nice too */
|
||||
tmp->format = AST_FORMAT_G723_1;
|
||||
tmp->nativeformats = AST_FORMAT_G723_1;
|
||||
tmp->state = state;
|
||||
if (state == AST_STATE_RING)
|
||||
tmp->rings = 1;
|
||||
|
@ -1241,6 +1241,11 @@ int usecount()
|
|||
return res;
|
||||
}
|
||||
|
||||
char *key()
|
||||
{
|
||||
return ASTERISK_GPL_KEY;
|
||||
}
|
||||
|
||||
char *description()
|
||||
{
|
||||
return desc;
|
||||
|
|
12
cli.c
12
cli.c
|
@ -168,13 +168,13 @@ static int handle_showchan(int fd, int argc, char *argv[])
|
|||
" -- General --\n"
|
||||
" Name: %s\n"
|
||||
" Type: %s\n"
|
||||
" Translator: %s\n"
|
||||
" Master: %s\n"
|
||||
" Caller ID: %s\n"
|
||||
" DNID Digits: %s\n"
|
||||
" State: %d\n"
|
||||
" Rings: %d\n"
|
||||
" Format: %d\n"
|
||||
" WriteFormat: %d\n"
|
||||
" ReadFormat: %d\n"
|
||||
" NativeFormat: %d\n"
|
||||
"File Descriptor: %d\n"
|
||||
" -- PBX --\n"
|
||||
" Context: %s\n"
|
||||
|
@ -184,9 +184,9 @@ static int handle_showchan(int fd, int argc, char *argv[])
|
|||
" Data: %s\n"
|
||||
" Stack: %d\n"
|
||||
" Blocking in: %s\n",
|
||||
c->name, c->type, (c->trans ? c->trans->name : "(N/A)"),
|
||||
(c->master ? c->master->name : "(N/A)"), (c->callerid ? c->callerid : "(N/A)"),
|
||||
(c->dnid ? c->dnid : "(N/A)" ), c->state, c->rings, c->format,
|
||||
c->name, c->type,
|
||||
(c->callerid ? c->callerid : "(N/A)"),
|
||||
(c->dnid ? c->dnid : "(N/A)" ), c->state, c->rings, c->nativeformats, c->writeformat, c->readformat,
|
||||
c->fd, c->context, c->exten, c->priority, ( c->appl ? c->appl : "(N/A)" ),
|
||||
( c-> data ? (strlen(c->data) ? c->data : "(Empty)") : "(None)"),
|
||||
c->stack, (c->blocking ? c->blockproc : "(Not Blocking)"));
|
||||
|
|
77
file.c
77
file.c
|
@ -142,23 +142,17 @@ int ast_format_unregister(char *name)
|
|||
|
||||
int ast_stopstream(struct ast_channel *tmp)
|
||||
{
|
||||
if (tmp->trans)
|
||||
tmp = tmp->trans;
|
||||
/* Stop a running stream if there is one */
|
||||
if (!tmp->stream)
|
||||
return 0;
|
||||
tmp->stream->fmt->close(tmp->stream);
|
||||
if (tmp->master) {
|
||||
ast_translator_destroy(tmp);
|
||||
}
|
||||
if (ast_set_write_format(tmp, tmp->oldwriteformat))
|
||||
ast_log(LOG_WARNING, "Unable to restore format back to %d\n", tmp->oldwriteformat);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ast_closestream(struct ast_filestream *f)
|
||||
{
|
||||
if (f->trans) {
|
||||
ast_translator_free_path(f->trans);
|
||||
}
|
||||
/* Stop a running stream if there is one */
|
||||
f->fmt->close(f);
|
||||
return 0;
|
||||
|
@ -166,7 +160,7 @@ int ast_closestream(struct ast_filestream *f)
|
|||
|
||||
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
|
||||
{
|
||||
struct ast_frame_chain *fc, *f2;
|
||||
struct ast_frame *trf;
|
||||
int res = -1;
|
||||
if (f->frametype != AST_FRAME_VOICE) {
|
||||
ast_log(LOG_WARNING, "Tried to write non-voice frame\n");
|
||||
|
@ -183,24 +177,16 @@ int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
|
|||
/* XXX If they try to send us a type of frame that isn't the normal frame, and isn't
|
||||
the one we've setup a translator for, we do the "wrong thing" XXX */
|
||||
if (!fs->trans)
|
||||
fs->trans = ast_translator_build_path(f->subclass, fs->fmt->format);
|
||||
fs->trans = ast_translator_build_path(fs->fmt->format, f->subclass);
|
||||
if (!fs->trans)
|
||||
ast_log(LOG_WARNING, "Unable to translate to format %s, source format %d\n", fs->fmt->name, f->subclass);
|
||||
else {
|
||||
res = 0;
|
||||
/* Build a chain of translated frames */
|
||||
fc = ast_translate(fs->trans, f);
|
||||
f2 = fc;
|
||||
while(f2) {
|
||||
res = fs->fmt->write(fs, f2->fr);
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Translated frame write failed\n");
|
||||
break;
|
||||
}
|
||||
f2 = f2->next;
|
||||
}
|
||||
if (fc)
|
||||
ast_frchain(fc);
|
||||
/* Get the translated frame but don't consume the original in case they're using it on another stream */
|
||||
trf = ast_translate(fs->trans, f, 0);
|
||||
res = fs->fmt->write(fs, trf);
|
||||
if (res)
|
||||
ast_log(LOG_WARNING, "Translated frame write failed\n");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
@ -232,7 +218,7 @@ static int ast_filehelper(char *filename, char *filename2, char *fmt, int action
|
|||
struct ast_filestream *s;
|
||||
int res=0, ret = 0;
|
||||
char *ext=NULL, *exts, *fn, *nfn;
|
||||
struct ast_channel *trans = (struct ast_channel *)filename2;
|
||||
struct ast_channel *chan = (struct ast_channel *)filename2;
|
||||
|
||||
/* Start with negative response */
|
||||
if (action == ACTION_EXISTS)
|
||||
|
@ -280,18 +266,18 @@ static int ast_filehelper(char *filename, char *filename2, char *fmt, int action
|
|||
ast_log(LOG_WARNING, "Out of memory\n");
|
||||
break;
|
||||
case ACTION_OPEN:
|
||||
if ((ret < 0) && ((trans->format & f->format) /* == trans->format */)) {
|
||||
if ((ret < 0) && ((chan->writeformat & f->format))) {
|
||||
ret = open(fn, O_RDONLY);
|
||||
if (ret >= 0) {
|
||||
s = f->open(ret);
|
||||
if (s) {
|
||||
s->fmt = f;
|
||||
s->trans = NULL;
|
||||
trans->stream = s;
|
||||
if (f->apply(trans, s)) {
|
||||
chan->stream = s;
|
||||
if (f->apply(chan, s)) {
|
||||
f->close(s);
|
||||
trans->stream = NULL;
|
||||
ast_log(LOG_WARNING, "Unable to apply stream to channel %s\n", trans->name);
|
||||
chan->stream = NULL;
|
||||
ast_log(LOG_WARNING, "Unable to apply stream to channel %s\n", chan->name);
|
||||
close(ret);
|
||||
ret = 0;
|
||||
}
|
||||
|
@ -372,10 +358,10 @@ int ast_streamfile(struct ast_channel *chan, char *filename, char *preflang)
|
|||
|
||||
*/
|
||||
int fd = -1;
|
||||
struct ast_channel *trans;
|
||||
int fmts = -1;
|
||||
char filename2[256];
|
||||
char lang2[MAX_LANGUAGE];
|
||||
int res;
|
||||
ast_stopstream(chan);
|
||||
if (preflang && strlen(preflang)) {
|
||||
snprintf(filename2, sizeof(filename2), "%s-%s", filename, preflang);
|
||||
|
@ -394,24 +380,11 @@ int ast_streamfile(struct ast_channel *chan, char *filename, char *preflang)
|
|||
ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
|
||||
return -1;
|
||||
}
|
||||
if (fmts & chan->format) {
|
||||
/* No translation necessary -- we have a file in a format our channel can
|
||||
handle */
|
||||
trans = chan;
|
||||
} else {
|
||||
/* Find the best */
|
||||
fmts = ast_translator_best_choice(chan->format, fmts);
|
||||
if (fmts < 1) {
|
||||
ast_log(LOG_WARNING, "Unable to find a translator method\n");
|
||||
return -1;
|
||||
}
|
||||
trans = ast_translator_create(chan, fmts, AST_DIRECTION_OUT);
|
||||
if (!trans) {
|
||||
ast_log(LOG_WARNING, "Unable to create translator\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
fd = ast_filehelper(filename2, (char *)trans, NULL, ACTION_OPEN);
|
||||
chan->oldwriteformat = chan->writeformat;
|
||||
/* Set the channel to a format we can work with */
|
||||
res = ast_set_write_format(chan, fmts);
|
||||
|
||||
fd = ast_filehelper(filename2, (char *)chan, NULL, ACTION_OPEN);
|
||||
if (fd >= 0) {
|
||||
#if 1
|
||||
if (option_verbose > 2)
|
||||
|
@ -419,9 +392,7 @@ int ast_streamfile(struct ast_channel *chan, char *filename, char *preflang)
|
|||
#endif
|
||||
return 0;
|
||||
}
|
||||
ast_log(LOG_WARNING, "Unable to open %s (format %d): %s\n", filename, chan->format, strerror(errno));
|
||||
if (chan != trans)
|
||||
ast_translator_destroy(trans);
|
||||
ast_log(LOG_WARNING, "Unable to open %s (format %d): %s\n", filename, chan->nativeformats, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -473,12 +444,10 @@ char ast_waitstream(struct ast_channel *c, char *breakon)
|
|||
{
|
||||
int res;
|
||||
struct ast_frame *fr;
|
||||
if (c->trans)
|
||||
c=c->trans;
|
||||
while(c->stream) {
|
||||
res = ast_sched_wait(c->sched);
|
||||
if (res < 0) {
|
||||
/* Okay, stop :) */
|
||||
ast_closestream(c->stream);
|
||||
return 0;
|
||||
}
|
||||
res = ast_waitfor(c, res);
|
||||
|
|
|
@ -36,27 +36,37 @@ extern "C" {
|
|||
struct ast_channel {
|
||||
char name[AST_CHANNEL_NAME]; /* ASCII Description of channel name */
|
||||
char language[MAX_LANGUAGE]; /* Language requested */
|
||||
char *type; /* Type of channel */
|
||||
int fd; /* File descriptor for channel -- all must have
|
||||
a file descriptor! */
|
||||
|
||||
int blocking; /* Whether or not we're blocking */
|
||||
pthread_t blocker; /* If anyone is blocking, this is them */
|
||||
pthread_mutex_t lock; /* Lock, can be used to lock a channel for some operations */
|
||||
char *blockproc; /* Procedure causing blocking */
|
||||
|
||||
char *appl; /* Current application */
|
||||
char *data; /* Data passed to current application */
|
||||
int blocking; /* Whether or not we're blocking */
|
||||
|
||||
int exception; /* Has an exception been detected */
|
||||
struct sched_context *sched; /* Schedule context */
|
||||
|
||||
int streamid; /* For streaming playback, the schedule ID */
|
||||
struct ast_filestream *stream; /* Stream itself. */
|
||||
struct ast_channel *trans; /* Translator if present */
|
||||
struct ast_channel *master; /* Master channel, if this is a translator */
|
||||
int fd; /* File descriptor for channel -- all must have
|
||||
a file descriptor! */
|
||||
char *type; /* Type of channel */
|
||||
int oldwriteformat; /* Original writer format */
|
||||
|
||||
int state; /* State of line */
|
||||
int rings; /* Number of rings so far */
|
||||
int stack; /* Current level of application */
|
||||
int format; /* Kinds of data this channel can
|
||||
|
||||
int nativeformats; /* Kinds of data this channel can
|
||||
natively handle */
|
||||
int readformat; /* Requested read format */
|
||||
int writeformat; /* Requested write format */
|
||||
|
||||
char *dnid; /* Malloc'd Dialed Number Identifier */
|
||||
char *callerid; /* Malloc'd Caller ID */
|
||||
|
||||
char context[AST_MAX_EXTENSION]; /* Current extension context */
|
||||
char exten[AST_MAX_EXTENSION]; /* Current extension number */
|
||||
int priority; /* Current extension priority */
|
||||
|
@ -125,7 +135,7 @@ int ast_waitfor(struct ast_channel *chan, int ms);
|
|||
struct ast_channel *ast_waitfor_n(struct ast_channel **chan, int n, int *ms);
|
||||
|
||||
/* This version works on fd's only. Be careful with it. */
|
||||
int ast_waitfor_n_fd(int *fds, int n, int *ms);
|
||||
int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception);
|
||||
|
||||
/* Read a frame. Returns a frame, or NULL on error. If it returns NULL, you
|
||||
best just stop reading frames and assume the channel has been
|
||||
|
@ -135,6 +145,12 @@ struct ast_frame *ast_read(struct ast_channel *chan);
|
|||
/* Write a frame to a channel */
|
||||
int ast_write(struct ast_channel *chan, struct ast_frame *frame);
|
||||
|
||||
/* Set read format for channelto whichever component of "format" is best. */
|
||||
int ast_set_read_format(struct ast_channel *chan, int format);
|
||||
|
||||
/* Set write format for channel to whichever compoent of "format" is best. */
|
||||
int ast_set_write_format(struct ast_channel *chan, int format);
|
||||
|
||||
/* Write text to a display on a channel */
|
||||
int ast_sendtext(struct ast_channel *chan, char *text);
|
||||
|
||||
|
@ -148,10 +164,32 @@ char ast_waitfordigit(struct ast_channel *c, int ms);
|
|||
digits "timeout" (-1 for none), terminated by anything in "enders". Give them rtimeout
|
||||
for the first digit */
|
||||
int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders);
|
||||
|
||||
#define AST_BRIDGE_DTMF_CHANNEL_0 (1 << 0) /* Report DTMF on channel 0 */
|
||||
#define AST_BRIDGE_DTMF_CHANNEL_1 (1 << 1) /* Report DTMF on channel 1 */
|
||||
#define AST_BRIDGE_REC_CHANNEL_0 (1 << 2) /* Return all voice frames on channel 0 */
|
||||
#define AST_BRIDGE_REC_CHANNEL_1 (1 << 3) /* Return all voice frames on channel 1 */
|
||||
#define AST_BRIDGE_IGNORE_SIGS (1 << 4) /* Ignore all signal frames except NULL */
|
||||
|
||||
|
||||
/* Set two channels to compatible formats -- call before ast_channel_bridge in general . Returns 0 on success
|
||||
and -1 if it could not be done */
|
||||
int ast_channel_make_compatible(struct ast_channel *c0, struct ast_channel *c1);
|
||||
|
||||
/* Bridge two channels (c0 and c1) together. If an important frame occurs, we return that frame in
|
||||
*rf (remember, it could be NULL) and which channel (0 or 1) in rc */
|
||||
int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);
|
||||
|
||||
#ifdef DO_CRASH
|
||||
#define CRASH do { *((int *)0) = 0; } while(0)
|
||||
#else
|
||||
#define CRASH do { } while(0)
|
||||
#endif
|
||||
|
||||
#define CHECK_BLOCKING(c) { \
|
||||
if ((c)->blocking) {\
|
||||
ast_log(LOG_WARNING, "Blocking '%s', already blocked by thread %ld in procedure %s\n", (c)->name, (c)->blocker, (c)->blockproc); \
|
||||
/* *((int *)0)=0; */ \
|
||||
ast_log(LOG_WARNING, "Thread %ld Blocking '%s', already blocked by thread %ld in procedure %s\n", pthread_self(), (c)->name, (c)->blocker, (c)->blockproc); \
|
||||
CRASH; \
|
||||
} else { \
|
||||
(c)->blocker = pthread_self(); \
|
||||
(c)->blockproc = __PRETTY_FUNCTION__; \
|
||||
|
|
|
@ -24,6 +24,14 @@ extern "C" {
|
|||
struct ast_channel_pvt {
|
||||
/* Private data used by channel backend */
|
||||
void *pvt;
|
||||
/* Write translation path */
|
||||
struct ast_trans_pvt *writetrans;
|
||||
/* Read translation path */
|
||||
struct ast_trans_pvt *readtrans;
|
||||
/* Raw read format */
|
||||
int rawreadformat;
|
||||
/* Raw write format */
|
||||
int rawwriteformat;
|
||||
/* Send a literal DTMF digit */
|
||||
int (*send_digit)(struct ast_channel *chan, char digit);
|
||||
/* Call a given phone number (address, etc), but don't
|
||||
|
@ -39,6 +47,10 @@ struct ast_channel_pvt {
|
|||
int (*write)(struct ast_channel *chan, struct ast_frame *frame);
|
||||
/* Display or transmit text */
|
||||
int (*send_text)(struct ast_channel *chan, char *text);
|
||||
/* Handle an exception, reading a frame */
|
||||
struct ast_frame * (*exception)(struct ast_channel *chan);
|
||||
/* Bridge two channels of the same type together */
|
||||
int (*bridge)(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc);
|
||||
};
|
||||
|
||||
/* Create a channel structure */
|
||||
|
|
|
@ -29,7 +29,7 @@ struct ast_translator {
|
|||
char name[80];
|
||||
int srcfmt;
|
||||
int dstfmt;
|
||||
struct ast_translator_pvt *(*new)();
|
||||
struct ast_translator_pvt *(*new)(void);
|
||||
int (*framein)(struct ast_translator_pvt *pvt, struct ast_frame *in);
|
||||
struct ast_frame * (*frameout)(struct ast_translator_pvt *pvt);
|
||||
void (*destroy)(struct ast_translator_pvt *pvt);
|
||||
|
@ -44,29 +44,22 @@ struct ast_translator {
|
|||
|
||||
struct ast_trans_pvt;
|
||||
|
||||
/* Create a pseudo channel which translates from a real channel into our
|
||||
desired format. When a translator is installed, you should not use the
|
||||
sub channel until you have stopped the translator. For all other
|
||||
actions, use the real channel. Generally, translators should be created
|
||||
when needed and immediately destroyed when no longer needed. */
|
||||
|
||||
/* Directions */
|
||||
#define AST_DIRECTION_OUT 1
|
||||
#define AST_DIRECTION_IN 2
|
||||
#define AST_DIRECTION_BOTH 3
|
||||
|
||||
extern struct ast_channel *ast_translator_create(struct ast_channel *real, int format, int direction);
|
||||
extern void ast_translator_destroy(struct ast_channel *tran);
|
||||
/* Register a Codec translator */
|
||||
extern int ast_register_translator(struct ast_translator *t);
|
||||
/* Unregister same */
|
||||
extern int ast_unregister_translator(struct ast_translator *t);
|
||||
/* Given a list of sources, and a designed destination format, which should
|
||||
I choose? */
|
||||
extern int ast_translator_best_choice(int dst, int srcs);
|
||||
extern struct ast_trans_pvt *ast_translator_build_path(int source, int dest);
|
||||
I choose? Returns 0 on success, -1 if no path could be found. Modifies
|
||||
dests and srcs in place */
|
||||
extern int ast_translator_best_choice(int *dsts, int *srcs);
|
||||
|
||||
/* Build a path (possibly NULL) from source to dest */
|
||||
extern struct ast_trans_pvt *ast_translator_build_path(int dest, int source);
|
||||
extern void ast_translator_free_path(struct ast_trans_pvt *tr);
|
||||
extern struct ast_frame_chain *ast_translate(struct ast_trans_pvt *tr, struct ast_frame *f);
|
||||
|
||||
/* Apply an input frame into the translator and receive zero or one output frames. Consume
|
||||
determines whether the original frame should be freed */
|
||||
extern struct ast_frame *ast_translate(struct ast_trans_pvt *tr, struct ast_frame *f, int consume);
|
||||
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
|
|
Reference in New Issue