Fix an issue that can occur when you do an attended transfer to parking. If

you complete the transfer before the announcement of the parking spot finishes,
then the channel being parked will hear the remainder of the announcement.
These changes make it so that will not happen anymore.

Basically, res_features sets a flag on the channel is playing the announcement
to so that the file streaming core knows that it needs to watch out for a
channel masquerade, and if it occurs, to abort the announcement.

(closes BE-182)


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@81599 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.4
Russell Bryant 18 years ago
parent f0cf18cc75
commit aa3b7e22f5

@ -478,6 +478,9 @@ enum {
/*! This is set to tell the channel not to generate DTMF begin frames, and
* to instead only generate END frames. */
AST_FLAG_END_DTMF_ONLY = (1 << 14),
/*! This flag indicates that on a masquerade, an active stream should not
* be carried over */
AST_FLAG_MASQ_NOSTREAM = (1 << 15),
};
/*! \brief ast_bridge_config flags */

@ -129,6 +129,7 @@ struct ast_filestream {
int lastwriteformat;
int lasttimeout;
struct ast_channel *owner;
const char *orig_chan_name;
FILE *f;
struct ast_frame fr; /* frame produced by read, typically */
char *buf; /* buffer pointed to by ast_frame; */

@ -614,39 +614,68 @@ struct ast_frame *ast_readframe(struct ast_filestream *s)
return f;
}
static int ast_readaudio_callback(void *data)
enum fsread_res {
FSREAD_FAILURE,
FSREAD_SUCCESS_SCHED,
FSREAD_SUCCESS_NOSCHED,
};
static int ast_fsread_audio(void *data);
static enum fsread_res ast_readaudio_callback(struct ast_filestream *s)
{
struct ast_filestream *s = data;
int whennext = 0;
while(!whennext) {
struct ast_frame *fr = s->fmt->read(s, &whennext);
while (!whennext) {
struct ast_frame *fr;
if (s->orig_chan_name && strcasecmp(s->owner->name, s->orig_chan_name))
goto return_failure;
fr = s->fmt->read(s, &whennext);
if (!fr /* stream complete */ || ast_write(s->owner, fr) /* error writing */) {
if (fr)
ast_log(LOG_WARNING, "Failed to write frame\n");
s->owner->streamid = -1;
#ifdef HAVE_ZAPTEL
ast_settimeout(s->owner, 0, NULL, NULL);
#endif
return 0;
goto return_failure;
}
}
if (whennext != s->lasttimeout) {
#ifdef HAVE_ZAPTEL
if (s->owner->timingfd > -1)
ast_settimeout(s->owner, whennext, ast_readaudio_callback, s);
ast_settimeout(s->owner, whennext, ast_fsread_audio, s);
else
#endif
s->owner->streamid = ast_sched_add(s->owner->sched, whennext/8, ast_readaudio_callback, s);
s->owner->streamid = ast_sched_add(s->owner->sched, whennext/8, ast_fsread_audio, s);
s->lasttimeout = whennext;
return 0;
return FSREAD_SUCCESS_NOSCHED;
}
return FSREAD_SUCCESS_SCHED;
return_failure:
s->owner->streamid = -1;
#ifdef HAVE_ZAPTEL
ast_settimeout(s->owner, 0, NULL, NULL);
#endif
return FSREAD_FAILURE;
}
static int ast_fsread_audio(void *data)
{
struct ast_filestream *fs = data;
enum fsread_res res;
res = ast_readaudio_callback(fs);
if (res == FSREAD_SUCCESS_SCHED)
return 1;
return 0;
}
static int ast_readvideo_callback(void *data)
static int ast_fsread_video(void *data);
static enum fsread_res ast_readvideo_callback(struct ast_filestream *s)
{
struct ast_filestream *s = data;
int whennext = 0;
while (!whennext) {
@ -655,15 +684,31 @@ static int ast_readvideo_callback(void *data)
if (fr)
ast_log(LOG_WARNING, "Failed to write frame\n");
s->owner->vstreamid = -1;
return 0;
return FSREAD_FAILURE;
}
}
if (whennext != s->lasttimeout) {
s->owner->vstreamid = ast_sched_add(s->owner->sched, whennext/8, ast_readvideo_callback, s);
s->owner->vstreamid = ast_sched_add(s->owner->sched, whennext / 8,
ast_fsread_video, s);
s->lasttimeout = whennext;
return 0;
return FSREAD_SUCCESS_NOSCHED;
}
return FSREAD_SUCCESS_SCHED;
}
static int ast_fsread_video(void *data)
{
struct ast_filestream *fs = data;
enum fsread_res res;
res = ast_readvideo_callback(fs);
if (res == FSREAD_SUCCESS_SCHED)
return 1;
return 0;
}
int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
@ -674,11 +719,14 @@ int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
int ast_playstream(struct ast_filestream *s)
{
enum fsread_res res;
if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
ast_readaudio_callback(s);
res = ast_readaudio_callback(s);
else
ast_readvideo_callback(s);
return 0;
res = ast_readvideo_callback(s);
return (res == FSREAD_FAILURE) ? -1 : 0;
}
int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
@ -748,6 +796,8 @@ int ast_closestream(struct ast_filestream *f)
fclose(f->f);
if (f->vfs)
ast_closestream(f->vfs);
if (f->orig_chan_name)
free((void *) f->orig_chan_name);
ast_module_unref(f->fmt->module);
free(f);
return 0;
@ -798,17 +848,20 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p
if (vfs)
ast_log(LOG_DEBUG, "Ooh, found a video stream, too, format %s\n", ast_getformatname(vfs->fmt->format));
if (fs){
int res;
if (ast_test_flag(chan, AST_FLAG_MASQ_NOSTREAM))
fs->orig_chan_name = ast_strdup(chan->name);
if (ast_applystream(chan, fs))
return -1;
if (vfs && ast_applystream(chan, vfs))
return -1;
ast_playstream(fs);
if (vfs)
ast_playstream(vfs);
res = ast_playstream(fs);
if (!res && vfs)
res = ast_playstream(vfs);
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "<%s> Playing '%s' (language '%s')\n", chan->name, filename, preflang ? preflang : "default");
return 0;
return res;
}
ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname_multiple(fmt, sizeof(fmt), chan->nativeformats), strerror(errno));
return -1;
@ -997,6 +1050,9 @@ static int waitstream_core(struct ast_channel *c, const char *breakon,
const char *forward, const char *rewind, int skip_ms,
int audiofd, int cmdfd, const char *context)
{
const char *orig_chan_name = NULL;
int err = 0;
if (!breakon)
breakon = "";
if (!forward)
@ -1007,9 +1063,21 @@ static int waitstream_core(struct ast_channel *c, const char *breakon,
/* Switch the channel to end DTMF frame only. waitstream_core doesn't care about the start of DTMF. */
ast_set_flag(c, AST_FLAG_END_DTMF_ONLY);
if (ast_test_flag(c, AST_FLAG_MASQ_NOSTREAM))
orig_chan_name = ast_strdupa(c->name);
while (c->stream) {
int res;
int ms = ast_sched_wait(c->sched);
int ms;
if (orig_chan_name && strcasecmp(orig_chan_name, c->name)) {
ast_stopstream(c);
err = 1;
break;
}
ms = ast_sched_wait(c->sched);
if (ms < 0 && !c->timingfunc) {
ast_stopstream(c);
break;
@ -1104,7 +1172,7 @@ static int waitstream_core(struct ast_channel *c, const char *breakon,
ast_clear_flag(c, AST_FLAG_END_DTMF_ONLY);
return (c->_softhangup ? -1 : 0);
return (err || c->_softhangup) ? -1 : 0;
}
int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms)

@ -422,8 +422,12 @@ int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeou
if (!con) /* Still no context? Bad */
ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
/* Tell the peer channel the number of the parking space */
if (peer && pu->parkingnum != -1) /* Only say number if it's a number */
if (peer && pu->parkingnum != -1) { /* Only say number if it's a number */
/* Make sure we don't start saying digits to the channel being parked */
ast_set_flag(peer, AST_FLAG_MASQ_NOSTREAM);
ast_say_digits(peer, pu->parkingnum, "", peer->language);
ast_clear_flag(peer, AST_FLAG_MASQ_NOSTREAM);
}
if (con) {
if (!ast_add_extension2(con, 1, pu->parkingexten, 1, NULL, NULL, parkedcall, strdup(pu->parkingexten), ast_free, registrar))
notify_metermaids(pu->parkingexten, parking_con);

Loading…
Cancel
Save