aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-09-05 20:53:41 +0000
committerrussell <russell@f38db490-d61c-443f-a65b-d21fe96a405b>2007-09-05 20:53:41 +0000
commit348b34d836c65a46bdd097e3a3cf84d315cd74dd (patch)
tree21079dca25ed1c23c36170ebb92db4b70f3eba9b
parent32be69e04efba6789deebe6204853932deef69db (diff)
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: http://svn.digium.com/svn/asterisk/branches/1.4@81599 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r--include/asterisk/channel.h3
-rw-r--r--include/asterisk/file.h1
-rw-r--r--main/file.c126
-rw-r--r--main/say.c6
-rw-r--r--res/res_features.c6
5 files changed, 109 insertions, 33 deletions
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 063d325ef..7035b5746 100644
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -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 */
diff --git a/include/asterisk/file.h b/include/asterisk/file.h
index 029bcf25d..936735c4a 100644
--- a/include/asterisk/file.h
+++ b/include/asterisk/file.h
@@ -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; */
diff --git a/main/file.c b/main/file.c
index 6bb0551a3..443cb24d4 100644
--- a/main/file.c
+++ b/main/file.c
@@ -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 1;
+ 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 1;
+
+ 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)
@@ -1006,10 +1062,22 @@ 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)
diff --git a/main/say.c b/main/say.c
index 7ab1931ed..e0282f84f 100644
--- a/main/say.c
+++ b/main/say.c
@@ -258,9 +258,9 @@ static int say_digit_str_full(struct ast_channel *chan, const char *str, const c
res = ast_streamfile(chan, fn, lang);
if (!res) {
if ((audiofd > -1) && (ctrlfd > -1))
- res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
- else
- res = ast_waitstream(chan, ints);
+ res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
+ else
+ res = ast_waitstream(chan, ints);
}
ast_stopstream(chan);
}
diff --git a/res/res_features.c b/res/res_features.c
index 498e52f85..dd037ab64 100644
--- a/res/res_features.c
+++ b/res/res_features.c
@@ -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);