diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index 11fb1df38d3ca44282dcbfd82bb2f63151a2237c..57b7552c6fd7491557247c87db153a3e2c8da0a5 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -546,6 +546,9 @@ enum { /*! Flag to show channels that this call is hangup due to the fact that the call was indeed anwered, but in another channel */ AST_FLAG_ANSWERED_ELSEWHERE = (1 << 15), + /*! This flag indicates that on a masquerade, an active stream should not + * be carried over */ + AST_FLAG_MASQ_NOSTREAM = (1 << 16), }; /*! \brief ast_bridge_config flags */ diff --git a/include/asterisk/file.h b/include/asterisk/file.h index 22a887c66f2cd1a5e35cb9a07cc6b8917622d8d0..f94fa71c4b63e4da75ed2fc9bd80635fe3eeb7a5 100644 --- a/include/asterisk/file.h +++ b/include/asterisk/file.h @@ -133,6 +133,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 dda1b3d634fa58d66c05668dae11b4c4939bad41..d64e9cd946a1ca744e38e6cdf48f06012164fc0f 100644 --- a/main/file.c +++ b/main/file.c @@ -603,39 +603,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); + 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_readvideo_callback(void *data) +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_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) { @@ -644,15 +673,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) @@ -663,11 +708,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) @@ -737,6 +785,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); ast_free(f); return 0; @@ -788,16 +838,19 @@ int ast_streamfile(struct ast_channel *chan, const char *filename, const char *p ast_debug(1, "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); ast_verb(3, "<%s> Playing '%s.%s' (language '%s')\n", chan->name, filename, ast_getformatname(chan->writeformat), 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; @@ -980,6 +1033,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) @@ -989,10 +1045,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; @@ -1087,7 +1155,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 9ed4817ff968e4e2646a7ccff03511c10f48fcfa..9f77d34668849d48ab0ba0f620bce0f19413438d 100644 --- a/main/say.c +++ b/main/say.c @@ -260,9 +260,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 f8ff92446e8f27cd8a4f81b4f2a0c274cd57026d..a9c252b7e681d62627a66249dbef9ca56cdd56c0 100644 --- a/res/res_features.c +++ b/res/res_features.c @@ -491,8 +491,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, ast_strdup(pu->parkingexten), ast_free, registrar)) notify_metermaids(pu->parkingexten, parking_con, AST_DEVICE_INUSE);