[asterisk-commits] oej: branch oej/pinequeue-1.8 r363092 - in /team/oej/pinequeue-1.8: apps/ con...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Mon Apr 23 03:38:49 CDT 2012
Author: oej
Date: Mon Apr 23 03:38:45 2012
New Revision: 363092
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=363092
Log:
Forwardporting patch
Modified:
team/oej/pinequeue-1.8/apps/app_queue.c
team/oej/pinequeue-1.8/configs/queues.conf.sample
team/oej/pinequeue-1.8/include/asterisk/channel.h
team/oej/pinequeue-1.8/main/channel.c
team/oej/pinequeue-1.8/main/features.c
team/oej/pinequeue-1.8/main/file.c
team/oej/pinequeue-1.8/main/say.c
Modified: team/oej/pinequeue-1.8/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinequeue-1.8/apps/app_queue.c?view=diff&rev=363092&r1=363091&r2=363092
==============================================================================
--- team/oej/pinequeue-1.8/apps/app_queue.c (original)
+++ team/oej/pinequeue-1.8/apps/app_queue.c Mon Apr 23 03:38:45 2012
@@ -930,6 +930,9 @@
/*! \brief queues.conf [general] option */
static int shared_lastcall = 1;
+/*! \brief Play prompts without interrupts (foreground) */
+static int background_prompts = 0;
+
/*! \brief Subscription to device state change events */
static struct ast_event_sub *device_state_sub;
@@ -1187,6 +1190,7 @@
static void update_realtime_members(struct call_queue *q);
static int set_member_paused(const char *queuename, const char *interface, const char *reason, int paused);
+static int play_file(struct ast_channel *chan, const char *filename, int ringing, char *moh);
static void queue_transfer_fixup(void *data, struct ast_channel *old_chan, struct ast_channel *new_chan);
/*! \brief sets the QUEUESTATUS channel variable */
@@ -2523,6 +2527,9 @@
return res;
}
+extern const struct ast_datastore_info queue_ds_sound_ending;
+void destroy_streamfile_info(struct ast_queue_streamfile_info *playdata);
+/* Uncommented by Old Olle patch
static int play_file(struct ast_channel *chan, const char *filename)
{
int res;
@@ -2544,7 +2551,7 @@
ast_stopstream(chan);
return res;
-}
+} */
/*!
* \brief Check for valid exit from queue via goto
@@ -2577,7 +2584,7 @@
/* We have an exact match */
if (!ast_goto_if_exists(qe->chan, qe->context, qe->digits, 1)) {
- qe->valid_digits = 1;
+ qe->valid_digits = 1; /* there it is, the only indication */
/* Return 1 on a successful goto */
return 1;
}
@@ -2600,11 +2607,12 @@
if ((qe->last_pos_said == qe->pos) && ((now - qe->last_pos) < qe->parent->announcefrequency))
return 0;
- if (ringing) {
- ast_indicate(qe->chan,-1);
- } else {
- ast_moh_stop(qe->chan);
- }
+ /* Commented out by old Olle patch */
+ /* if (ringing) { */
+ /* ast_indicate(qe->chan,-1); */
+ /* } else { */
+ /* ast_moh_stop(qe->chan); */
+ /* } */
if (qe->parent->announceposition == ANNOUNCEPOSITION_YES ||
qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN ||
@@ -2616,7 +2624,7 @@
if (announceposition == 1) {
/* Say we're next, if we are */
if (qe->pos == 1) {
- res = play_file(qe->chan, qe->parent->sound_next);
+ res = play_file(qe->chan, qe->parent->sound_next, ringing, NULL);
if (res)
goto playout;
else
@@ -2624,7 +2632,7 @@
} else {
if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
/* More than Case*/
- res = play_file(qe->chan, qe->parent->queue_quantity1);
+ res = play_file(qe->chan, qe->parent->queue_quantity1, ringing, NULL);
if (res)
goto playout;
res = ast_say_number(qe->chan, qe->parent->announcepositionlimit, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
@@ -2632,7 +2640,7 @@
goto playout;
} else {
/* Normal Case */
- res = play_file(qe->chan, qe->parent->sound_thereare);
+ res = play_file(qe->chan, qe->parent->sound_thereare, ringing, NULL);
if (res)
goto playout;
res = ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, NULL); /* Needs gender */
@@ -2641,11 +2649,11 @@
}
if (qe->parent->announceposition == ANNOUNCEPOSITION_MORE_THAN && qe->pos > qe->parent->announcepositionlimit){
/* More than Case*/
- res = play_file(qe->chan, qe->parent->queue_quantity2);
+ res = play_file(qe->chan, qe->parent->queue_quantity2, ringing, NULL);
if (res)
goto playout;
} else {
- res = play_file(qe->chan, qe->parent->sound_calls);
+ res = play_file(qe->chan, qe->parent->sound_calls, ringing, NULL);
if (res)
goto playout;
}
@@ -2669,7 +2677,7 @@
if ((avgholdmins+avgholdsecs) > 0 && qe->parent->announceholdtime &&
((qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE && !qe->last_pos) ||
!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE))) {
- res = play_file(qe->chan, qe->parent->sound_holdtime);
+ res = play_file(qe->chan, qe->parent->sound_holdtime,ringing,NULL);
if (res)
goto playout;
@@ -2679,11 +2687,11 @@
goto playout;
if (avgholdmins == 1) {
- res = play_file(qe->chan, qe->parent->sound_minute);
+ res = play_file(qe->chan, qe->parent->sound_minute, ringing, NULL);
if (res)
goto playout;
} else {
- res = play_file(qe->chan, qe->parent->sound_minutes);
+ res = play_file(qe->chan, qe->parent->sound_minutes, ringing, NULL);
if (res)
goto playout;
}
@@ -2693,7 +2701,7 @@
if (res)
goto playout;
- res = play_file(qe->chan, qe->parent->sound_seconds);
+ res = play_file(qe->chan, qe->parent->sound_seconds, ringing, NULL);
if (res)
goto playout;
}
@@ -2707,11 +2715,11 @@
qe->chan->name, qe->parent->name, qe->pos);
}
if (say_thanks) {
- res = play_file(qe->chan, qe->parent->sound_thanks);
+ res = play_file(qe->chan, qe->parent->sound_thanks, ringing, NULL);
}
playout:
- if ((res > 0 && !valid_exit(qe, res)))
+ if (res > 0) /* in other words, ignore any play_file problems... */
res = 0;
/* Set our last_pos indicators */
@@ -2719,13 +2727,18 @@
qe->last_pos_said = qe->pos;
/* Don't restart music on hold if we're about to exit the caller from the queue */
- if (!res) {
+ /* Next section commented out by old Olle patch */
+ /* if (!res) {
if (ringing) {
ast_indicate(qe->chan, AST_CONTROL_RINGING);
} else {
ast_moh_start(qe->chan, qe->moh, NULL);
}
- }
+ } */
+ /* it used to be, that we'd fire up the MOH/Indication at this point;
+ now, play_file handles those details; it no longer waits for any
+ user input... so no questions about valid_exit().
+ */
return res;
}
@@ -3293,12 +3306,6 @@
if ((now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency)
return 0;
- /* Stop the music on hold so we can play our own file */
- if (ringing)
- ast_indicate(qe->chan,-1);
- else
- ast_moh_stop(qe->chan);
-
ast_verb(3, "Playing periodic announcement\n");
if (qe->parent->randomperiodicannounce && qe->parent->numperiodicannounce) {
@@ -3309,10 +3316,14 @@
}
/* play the announcement */
- res = play_file(qe->chan, ast_str_buffer(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]));
-
- if (res > 0 && !valid_exit(qe, res))
+ res = play_file(qe->chan, ast_str_buffer(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]),ringing, qe->moh);
+
+ /* if (res > 0 && !valid_exit(qe, res))
res = 0;
+ */
+ /* we no longer check for valid_exit(), as we simply
+ start the playback and let the autoservice thread
+ keep it going */
/* Resume Music on Hold if the caller is going to stay in the queue */
if (!res) {
@@ -3460,10 +3471,15 @@
#endif
while (*to && !peer) {
+
int numlines, retry, pos = 1;
struct ast_channel *watchers[AST_MAX_WATCHERS];
watchers[0] = in;
start = NULL;
+
+ if (background_prompts) {
+ play_file(qe->chan, NULL, 0, qe->moh);
+ }
for (retry = 0; retry < 2; retry++) {
numlines = 0;
@@ -3784,6 +3800,9 @@
}
}
}
+ if (background_prompts) {
+ play_file(qe->chan, NULL, 0, qe->moh);
+ }
/* If we received an event from the caller, deal with it. */
if (winner == in) {
@@ -4172,6 +4191,7 @@
.chan_fixup = queue_transfer_fixup,
.destroy = queue_transfer_destroy,
};
+
/*! \brief Log an attended transfer when a queue caller channel is masqueraded
*
@@ -4625,33 +4645,39 @@
int res2;
res2 = ast_autoservice_start(qe->chan);
- if (!res2) {
- if (qe->parent->memberdelay) {
- ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
- res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
- }
- if (!res2 && announce) {
- play_file(peer, announce);
- }
- if (!res2 && qe->parent->reportholdtime) {
- if (!play_file(peer, qe->parent->sound_reporthold)) {
- int holdtime, holdtimesecs;
-
- time(&now);
- holdtime = abs((now - qe->start) / 60);
- holdtimesecs = abs((now - qe->start) % 60);
- if (holdtime > 0) {
- ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
- play_file(peer, qe->parent->sound_minutes);
- }
- if (holdtimesecs > 1) {
- ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, peer->language, NULL);
- play_file(peer, qe->parent->sound_seconds);
- }
+ /* instead of starting autoservice and jacking this thread to push sound to the
+ peer channel, let's set up a background player to the peer channel and
+ get on with life in this thread. */
+
+ if (qe->parent->memberdelay) {
+ ast_log(LOG_NOTICE, "Delaying member connect for %d seconds\n", qe->parent->memberdelay);
+ res2 |= ast_safe_sleep(peer, qe->parent->memberdelay * 1000);
+ }
+ if (!res2 && announce) {
+ play_file(peer, announce, ringing, qe->moh);;
+ }
+ if (!res2 && qe->parent->reportholdtime) {
+ int res3;
+ res3 = play_file(peer, qe->parent->sound_reporthold, ringing, qe->moh);
+ if (!res3) {
+ int holdtime, holdtimesecs;
+
+ time(&now);
+ holdtime = abs((now - qe->start) / 60);
+ holdtimesecs = abs((now - qe->start) % 60);
+ if (holdtime > 0) {
+ ast_say_number(peer, holdtime, AST_DIGIT_ANY, peer->language, NULL);
+ play_file(peer, qe->parent->sound_minutes, ringing, qe->moh);
+ }
+ if (holdtimesecs > 1) {
+ ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, peer->language, NULL);
+ play_file(peer, qe->parent->sound_seconds, ringing, qe->moh);
}
}
}
res2 |= ast_autoservice_stop(qe->chan);
+
+
if (ast_check_hangup(peer)) {
/* Agent must have hung up */
ast_log(LOG_WARNING, "Agent on %s hungup on the customer.\n", peer->name);
@@ -4680,10 +4706,11 @@
}
}
/* Stop music on hold */
- if (ringing)
+ if (ringing) {
ast_indicate(qe->chan,-1);
- else
+ } else {
ast_moh_stop(qe->chan);
+ }
/* If appropriate, log that we have a destination channel */
if (qe->chan->cdr)
ast_cdr_setdestchan(qe->chan->cdr, peer->name);
@@ -4701,7 +4728,7 @@
/* Play announcement to the caller telling it's his turn if defined */
if (!ast_strlen_zero(qe->parent->sound_callerannounce)) {
- if (play_file(qe->chan, qe->parent->sound_callerannounce))
+ if (play_file(qe->chan, qe->parent->sound_callerannounce,ringing,qe->moh))
ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", qe->parent->sound_callerannounce);
}
@@ -4868,7 +4895,7 @@
res = ast_autoservice_start(qe->chan);
if (res) {
- ast_log(LOG_ERROR, "Unable to start autoservice on calling channel\n");
+ ast_log(LOG_ERROR, "Unable to start autoservice on calling channel %s\n", qe->chan->name);
res = -1;
}
@@ -5091,8 +5118,9 @@
{
/* Don't need to hold the lock while we setup the outgoing calls */
int retrywait = qe->parent->retry * 1000;
-
- int res = ast_waitfordigit(qe->chan, retrywait);
+ int res;
+
+ res = ast_waitfordigit(qe->chan, retrywait);
if (res > 0 && !valid_exit(qe, res))
res = 0;
@@ -5777,6 +5805,310 @@
AST_LIST_UNLOCK(&rule_lists);
}
+/*! \brief Data structure for \ref play_file() channel frame generator */
+struct gen_state {
+ struct ast_channel *chan;
+ struct ast_filestream *stream;
+ int sample_queue;
+ char filename[512];
+ struct ast_queue_streamfile_info *aqsi;
+};
+
+
+/*! \brief Allocate generator data structures if needed
+
+We don't really do anything here since we get the needed data as params.
+*/
+static void *gen_alloc(struct ast_channel *chan, void *params)
+{
+ struct gen_state *state = params;
+
+ ast_debug(3, "--- Allocating generator for %s\n", chan->name);
+ return state;
+}
+
+/*! \brief Close file stream used by generator */
+static void gen_closestream(struct gen_state *state)
+{
+ if (!state->stream) {
+ ast_debug(3, "--- No active stream to close.\n");
+ return;
+ }
+
+ ast_closestream(state->stream);
+ state->filename[0] = '\0';
+ state->chan->stream = NULL;
+ state->stream = NULL;
+ state->aqsi->now_playing = 0; /* Important flag to indicate we are no longer playing on this channel */
+ //ast_log(LOG_DEBUG, "--- Restarting MOH --\n");
+ //if (state->aqsi->ringing) {
+ //ast_indicate(state->chan, AST_CONTROL_RINGING);
+ //} else if (state->aqsi->moh) {
+ //ast_moh_start(state->chan, state->aqsi->moh, NULL);
+ //}
+}
+
+/*! \brief Release generator on channel */
+static void gen_release(struct ast_channel *chan, void *data)
+{
+ struct gen_state *state = data;
+ ast_debug(3, "--- releasing stream \n");
+ if (!data) {
+ ast_debug(3, "--- No state??? \n");
+ return;
+ }
+ gen_closestream(state);
+ ast_free(state);
+}
+
+
+/*! \brief Read frames from file stream and return them to the generator \ref gen_generate() */
+static struct ast_frame *gen_readframe(struct gen_state *state)
+{
+ struct ast_frame *f = NULL;
+ if (state && state->chan) {
+ ast_debug(3, "... Generating frames for %s\n", state->chan->name);
+ } else {
+ ast_log(LOG_ERROR, "... no channel to generate frames for!\n");
+ return f;
+ }
+ if (ast_strlen_zero(state->filename)) {
+ ast_log(LOG_ERROR, ".... no file to read from?? Generator for %s\n", state->chan->name);
+ return f;
+ }
+
+ if (!state->stream) {
+ if (!(state->stream = ast_openstream_full(state->chan, state->filename, state->chan->language, 1))) {
+ ast_log(LOG_WARNING, "File '%s' could not be opened: %s\n", state->filename, strerror(errno));
+ return f;
+ }
+
+ }
+ f = ast_readframe(state->stream);
+
+ return f;
+}
+
+/*! \brief The actual generator that reads frames and sends them to the channel
+ While letting the queue app do it's thing.
+ */
+static int gen_generate(struct ast_channel *chan, void *data, int len, int samples)
+{
+ struct gen_state *state = data;
+ struct ast_frame *f = NULL;
+ int res = 0;
+
+ ast_debug(2, "***** Generating good old prompts for your benefit. Did I hear a thank you?\n");
+
+ if (!state) {
+ ast_log(LOG_ERROR, "---- Do not have a current state data structure\n");
+ return -1;
+ }
+ if (!state->chan) {
+ ast_log(LOG_ERROR, "... no channel to generate frames for!\n");
+ return -1;
+ }
+
+ state->sample_queue += samples;
+ ast_debug(3, "--------->>>>> Generating %d samples - sample queue now %d channel %s\n", samples, state->sample_queue, chan->name);
+
+ while (state->sample_queue > 0) {
+ if (!(f = gen_readframe(state))) {
+ ast_debug(3, "---- :-( Could not get more frames\n");
+ return -1;
+ }
+
+ res = ast_write(chan, f);
+ state->sample_queue -= f->samples;
+ ast_frfree(f);
+ if (res < 0) {
+ ast_log(LOG_WARNING, "Failed to write frame: %s\n", strerror(errno));
+ return -1;
+ }
+ }
+
+ return res;
+}
+
+/*! \brief Generator initialization structure for play_file */
+static struct ast_generator play_file_gen =
+{
+ alloc: gen_alloc, /*! \ref gen_alloc() */
+ release: gen_release, /*! \ref gen_release() */
+ generate: gen_generate, /*! \ref gen_generate() */
+};
+
+/*! \brief Play queue updates in the background, being able to interrupt if an
+ agent becomes available.
+
+ To enable playing of a string of files, one after the other, and not have to wait
+ around for each one to finish before playing the next, instead we put them into
+ a list, which we insert at the tail.
+
+ Make sure to get things rolling with a plain play_file(), then use this
+ to queue up the others in sequence
+
+ When called without a filename, we check if we have a list of files in the
+ playlist. If so we start playing again.
+*/
+static int play_file(struct ast_channel *chan, const char *filename, int ringing, char *moh)
+{
+ int res = 0;
+ struct ast_datastore *datastore;
+ struct ast_queue_streamfile_info *aqsi = NULL;
+ struct gen_state *generatordata;
+ struct ast_queue_streamfile_name *sfn = NULL;
+ char playfilename[512];
+
+
+ if (!background_prompts) {
+ if (ast_strlen_zero(filename)) {
+ return 0;
+ }
+ /* Play prompts like before, with no interruption */
+ ast_stopstream(chan);
+ res = ast_streamfile(chan, filename, chan->language);
+ if (!res) {
+ res = ast_waitstream(chan, AST_DIGIT_ANY);
+ }
+ ast_stopstream(chan);
+ if (ringing) {
+ ast_indicate(chan, AST_CONTROL_RINGING);
+ } else {
+ ast_moh_start(chan, moh, NULL);
+ }
+
+ return res;
+ }
+
+ /* look up the datastore and the play_finished struct, and set appropriate values */
+ if ((datastore = ast_channel_datastore_find(chan, &queue_ds_sound_ending, NULL))) {
+ aqsi = datastore->data;
+ if (aqsi) { /* copy this stuff into place */
+ aqsi->ringing = ringing;
+ if (moh) {
+ strcpy(aqsi->moh, moh);
+ }
+ }
+ } else {
+ ast_log(LOG_ERROR, "Can't find the queue_ds_sound_ending datastore! on chan %s\n", chan->name);
+ return 1; /* Why continue, if I can't access the datastore & list? */
+ }
+ ast_debug(2, "---- Aqsi now playing: %d\n", aqsi->now_playing);
+
+ if (aqsi->now_playing == 0) {
+ playfilename[0] = '\0';
+ if (ast_strlen_zero(filename)) {
+ /* take the first one if we have a playlist */
+ if (!AST_LIST_EMPTY(&aqsi->flist)) {
+ sfn = AST_LIST_REMOVE_HEAD(&aqsi->flist, list);
+ ast_copy_string(playfilename, sfn->filename, sizeof(playfilename));
+ ringing = aqsi->ringing;
+ moh = aqsi->moh;
+ free(sfn);
+ ast_debug(3, "--- No filename and not playing - selecting next file in playlist - %s\n", playfilename);
+ }
+ if (ast_strlen_zero(playfilename)) {
+ ast_debug(3, "--- empty queue... No filename and not currently playing\n");
+ if (ringing) {
+ ast_indicate(chan, AST_CONTROL_RINGING);
+ } else {
+ if (!ast_test_flag(chan, AST_FLAG_MOH)) {
+ ast_moh_start(chan, aqsi->qe->moh, NULL);
+ }
+ }
+ return -1;
+ }
+ } else {
+ ast_copy_string(playfilename, filename, sizeof(playfilename));
+ }
+ } else {
+ if (ast_strlen_zero(filename)) {
+ ast_debug(3, "--- just checking... No filename and currently playing\n");
+ return -1;
+ }
+ }
+
+ AST_LIST_LOCK(&aqsi->flist);
+
+ if (aqsi->now_playing) {
+ struct ast_queue_streamfile_name *fn = ast_calloc(1, sizeof(*fn));
+ fn->filename = ast_strdup(filename);
+ ast_debug(3, " queued sound file %s for playing on chan %s\n", filename, chan->name);
+
+ /* link the struct into the current ast_queue_streamfile_info struct */
+ AST_LIST_INSERT_TAIL(&aqsi->flist, fn, list);
+ /* in this case, nothing else to do, just insert the new file at the end of the list */
+ } else {
+ /* Start playing */
+
+ /* Stop the music on hold so we can play our own file */
+ if (ringing) {
+ ast_debug(3, "Stopping Indication on %s\n", chan->name);
+ ast_indicate(chan,-1);
+ } else {
+ ast_debug(3, "Stopping MOH on chan %s\n", chan->name);
+ ast_moh_stop(chan);
+ }
+
+ ast_debug(3, "Stopping Streaming on chan %s\n", chan->name);
+ ast_stopstream(chan);
+
+ ast_debug(3, "Autoservice stop on chan %s\n", chan->name);
+ ast_autoservice_stop(chan);
+
+ /* Create generator to start playing audio without waiting */
+ generatordata = ast_calloc(1, sizeof(struct gen_state));
+ if (!generatordata) {
+ ast_log(LOG_ERROR, "Can't allocate generator input\n");
+ return 1;
+ }
+ ast_copy_string(generatordata->filename, playfilename, sizeof(generatordata->filename));
+ generatordata->chan = chan;
+ generatordata->aqsi = aqsi;
+
+
+
+ /* Starting new generator on channel. */
+ if (ast_activate_generator(chan, &play_file_gen, generatordata)) {
+ ast_log(LOG_ERROR, "Not playing requested prompt %s. Generator failed on %s.\n", playfilename, chan->name);
+ /* oops, the current file has problems */
+ /* restore the moh */
+ if (ringing) {
+ ast_indicate(chan, AST_CONTROL_RINGING);
+ } else {
+ ast_moh_start(chan, aqsi->qe->moh, NULL);
+ }
+ AST_LIST_UNLOCK(&aqsi->flist);
+ return 1;
+ } else {
+ ast_debug(3, "--- Generator Starting to play file %s \n", playfilename);
+ }
+ aqsi->now_playing = 1; /* We have begun playback */
+ }
+
+ AST_LIST_UNLOCK(&aqsi->flist);
+ ast_waitfor(chan, 1);
+
+ return 0; /* non-zero most likely means the file doesn't exist */
+}
+
+/*! \brief This routine propably will only need to be called at module unload time */
+void destroy_streamfile_info(struct ast_queue_streamfile_info *playdata)
+{
+ struct ast_queue_streamfile_name *fn;
+ AST_LIST_LOCK(&playdata->flist);
+ while (!AST_LIST_EMPTY(&playdata->flist)) {
+ fn = AST_LIST_REMOVE_HEAD(&playdata->flist, list);
+ ast_free(fn->filename);
+
+ ast_free(fn);
+ }
+ AST_LIST_UNLOCK(&playdata->flist);
+ AST_LIST_HEAD_DESTROY(&playdata->flist);
+ ast_free(playdata);
+}
+
/*!\brief The starting point for all queue calls
*
* The process involved here is to
@@ -5800,6 +6132,9 @@
int qcontinue = 0;
int max_penalty, min_penalty;
enum queue_result reason = QUEUE_UNKNOWN;
+ struct ast_datastore *datastore = NULL;
+ struct ast_queue_streamfile_info *aqsi = calloc(1,sizeof(struct ast_queue_streamfile_info));
+
/* whether to exit Queue application after the timeout hits */
int tries = 0;
int noption = 0;
@@ -5920,6 +6255,20 @@
S_OR(args.url, ""),
S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""),
qe.opos);
+ /* Begin old Olle patch */
+ datastore = ast_channel_datastore_alloc(&queue_ds_sound_ending, NULL);
+
+ aqsi->qe = &qe;
+ aqsi->chan = chan;
+ aqsi->ringing = ringing;
+ aqsi->now_playing = 0;
+ strcpy(aqsi->moh, qe.moh);
+ AST_LIST_HEAD_INIT(&aqsi->flist);
+ datastore->data = aqsi;
+
+ ast_channel_datastore_add(chan, datastore);
+ /* End old Olle patch */
+
copy_rules(&qe, args.rule);
qe.pr = AST_LIST_FIRST(&qe.qe_rules);
check_turns:
@@ -5953,6 +6302,9 @@
break;
}
+ if (background_prompts) {
+ play_file(qe.chan, NULL, ringing, qe.moh); /* OEJ - Trigger next prompt */
+ }
if (makeannouncement) {
/* Make a position announcement, if enabled */
if (qe.parent->announcefrequency)
@@ -6035,6 +6387,12 @@
}
stop:
+ /* remove the playdata datastore */
+ ast_channel_datastore_remove(chan, datastore);
+
+ /* get rid of the datastore for non-wait sound playing */
+ destroy_streamfile_info(aqsi);
+
if (res) {
if (res < 0) {
if (!qe.handled) {
@@ -6051,17 +6409,6 @@
ast_queue_log(args.queuename, chan->uniqueid, "NONE", "EXITWITHKEY",
"%s|%d", qe.digits, qe.pos);
}
- }
-
- /* Don't allow return code > 0 */
- if (res >= 0) {
- res = 0;
- if (ringing) {
- ast_indicate(chan, -1);
- } else {
- ast_moh_stop(chan);
- }
- ast_stopstream(chan);
}
set_queue_variables(qe.parent, qe.chan);
@@ -6526,6 +6873,9 @@
update_cdr = 0;
if ((general_val = ast_variable_retrieve(cfg, "general", "updatecdr")))
update_cdr = ast_true(general_val);
+ background_prompts = 0;
+ if ((general_val = ast_variable_retrieve(cfg, "general", "background_prompts")))
+ background_prompts = ast_true(general_val);
shared_lastcall = 0;
if ((general_val = ast_variable_retrieve(cfg, "general", "shared_lastcall")))
shared_lastcall = ast_true(general_val);
Modified: team/oej/pinequeue-1.8/configs/queues.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinequeue-1.8/configs/queues.conf.sample?view=diff&rev=363092&r1=363091&r2=363092
==============================================================================
--- team/oej/pinequeue-1.8/configs/queues.conf.sample (original)
+++ team/oej/pinequeue-1.8/configs/queues.conf.sample Mon Apr 23 03:38:45 2012
@@ -60,6 +60,14 @@
; The default value is yes.
;
;shared_lastcall=no
+;
+; Prompts played to the caller by default is played in the foreground,
+; which means that even if a queue member becomes available, the
+; prompt will be played fully. Enabling 'background_prompts' will
+; make sure that prompts are interruptible. If a queue member becomes
+; available, the prompt will be interrupted.
+;
+background_prompts=no
;
;[markq]
;
Modified: team/oej/pinequeue-1.8/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinequeue-1.8/include/asterisk/channel.h?view=diff&rev=363092&r1=363091&r2=363092
==============================================================================
--- team/oej/pinequeue-1.8/include/asterisk/channel.h (original)
+++ team/oej/pinequeue-1.8/include/asterisk/channel.h Mon Apr 23 03:38:45 2012
@@ -3498,6 +3498,28 @@
* \param size The size of the buffer to write to
*/
int ast_channel_get_cc_agent_type(struct ast_channel *chan, char *agent_type, size_t size);
+
+/*! \brief Asynchronous filestream playing playlist
+ Used (at least at first) in app_queue - in the ast_queue_streamfile_info channel datastore
+*/
+struct ast_queue_streamfile_name {
+ char *filename;
+ AST_LIST_ENTRY(ast_queue_streamfile_name) list;
+};
+
+/*! \brief Information data about background playing of prompts */
+struct ast_queue_streamfile_info {
+ void (*digitHandler)(void *data, char digit); /* a func ptr to the handler that will do what needs doing when the streaming of a soundfile is finished */
+ struct queue_ent *qe;
+ AST_LIST_HEAD(,ast_queue_streamfile_name) flist; /* a list of other sound files that need to be played in sequence */
+ struct ast_channel *chan;
+ int ringing;
+ char moh[80];
+ int now_playing;
+ int valid_exit; /* if valid_exit() in app_queue is true */
+};
+
+
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif
Modified: team/oej/pinequeue-1.8/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinequeue-1.8/main/channel.c?view=diff&rev=363092&r1=363091&r2=363092
==============================================================================
--- team/oej/pinequeue-1.8/main/channel.c (original)
+++ team/oej/pinequeue-1.8/main/channel.c Mon Apr 23 03:38:45 2012
@@ -3034,10 +3034,12 @@
void ast_deactivate_generator(struct ast_channel *chan)
{
+ ast_debug(3, "ast_deactivate_generator() called on chan %s\n", chan->name);
ast_channel_lock(chan);
if (chan->generatordata) {
if (chan->generator && chan->generator->release)
chan->generator->release(chan, chan->generatordata);
+ ast_debug(3,"removing the generator stuff on chan %s\n", chan->name);
chan->generatordata = NULL;
chan->generator = NULL;
ast_channel_set_fd(chan, AST_GENERATOR_FD, -1);
@@ -3045,6 +3047,7 @@
ast_settimeout(chan, 0, NULL, NULL);
}
ast_channel_unlock(chan);
+ ast_debug(3, "ast_deactivate_generator() done on chan %s\n", chan->name);
}
static int generator_force(const void *data)
@@ -3062,15 +3065,18 @@
generate = chan->generator->generate;
ast_channel_unlock(chan);
- if (!tmp || !generate)
+ ast_debug(3, "GENERATOR_FORCE: generate() CALLED res=%d on chan %s\n", res, chan->name);
+ if (!tmp || !generate) {
+ ast_log(LOG_ERROR, "Can't find generator data or generator function \n");
return 0;
+ }
res = generate(chan, tmp, 0, ast_format_rate(chan->writeformat & AST_FORMAT_AUDIO_MASK) / 50);
chan->generatordata = tmp;
if (res) {
- ast_debug(1, "Auto-deactivating generator\n");
+ ast_debug(1, "Auto-deactivating generator on chan %s\n", chan->name);
ast_deactivate_generator(chan);
}
@@ -3088,6 +3094,7 @@
chan->generatordata = NULL;
}
if (gen->alloc && !(chan->generatordata = gen->alloc(chan, params))) {
+ ast_debug(3,"Generator Data is -1\n");
res = -1;
}
if (!res) {
@@ -3626,6 +3633,7 @@
static void ast_read_generator_actions(struct ast_channel *chan, struct ast_frame *f)
{
+ ast_debug(3, "----- Jost poking around. Have a happy life. \n");
if (chan->generator && chan->generator->generate && chan->generatordata && !ast_internal_timing_enabled(chan)) {
void *tmp = chan->generatordata;
int (*generate)(struct ast_channel *chan, void *tmp, int datalen, int samples) = chan->generator->generate;
@@ -4227,6 +4235,7 @@
/* Run generator sitting on the line if timing device not available
* and synchronous generation of outgoing frames is necessary */
+ ast_debug(3, ">>>>>>>>> just another silly message. We are generating, man! \n");
ast_read_generator_actions(chan, f);
}
break;
Modified: team/oej/pinequeue-1.8/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinequeue-1.8/main/features.c?view=diff&rev=363092&r1=363091&r2=363092
==============================================================================
--- team/oej/pinequeue-1.8/main/features.c (original)
+++ team/oej/pinequeue-1.8/main/features.c Mon Apr 23 03:38:45 2012
@@ -1513,10 +1513,13 @@
ast_debug(4, "AMI ParkedCall Channel: %s\n", chan->name);
ast_debug(4, "AMI ParkedCall From: %s\n", event_from);
+/* OEJ */
+#ifdef HAVE_ADSI
if (peer && adsipark && ast_adsi_available(peer)) {
adsi_announce_park(peer, pu->parkingexten); /* Only supports parking numbers */
ast_adsi_unload_session(peer);
}
+#endif
snprintf(app_data, sizeof(app_data), "%s,%s", pu->parkingexten,
pu->parkinglot->name);
Modified: team/oej/pinequeue-1.8/main/file.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinequeue-1.8/main/file.c?view=diff&rev=363092&r1=363091&r2=363092
==============================================================================
--- team/oej/pinequeue-1.8/main/file.c (original)
+++ team/oej/pinequeue-1.8/main/file.c Mon Apr 23 03:38:45 2012
@@ -44,6 +44,7 @@
#include "asterisk/app.h"
#include "asterisk/pbx.h"
#include "asterisk/linkedlists.h"
+#include "asterisk/channel.h"
#include "asterisk/module.h"
#include "asterisk/astobj2.h"
#include "asterisk/test.h"
@@ -708,6 +709,12 @@
return NULL;
}
+const struct ast_datastore_info queue_ds_sound_ending = { /* this is here because it is referenced here
+ and the only other place it is used is in app_queue,
+ which is not always loaded. */
+ .type = "queue_sound_ending"
+};
+
static struct ast_frame *read_frame(struct ast_filestream *s, int *whennext)
{
struct ast_frame *fr, *new_fr;
@@ -756,6 +763,7 @@
struct ast_frame *fr;
if (s->orig_chan_name && strcasecmp(s->owner->name, s->orig_chan_name)) {
+ ast_log(LOG_DEBUG, "--- Giving up here\n");
goto return_failure;
}
@@ -766,6 +774,7 @@
ast_log(LOG_WARNING, "Failed to write frame\n");
ast_frfree(fr);
}
+ ast_log(LOG_DEBUG, "--- Giving up here now\n");
goto return_failure;
}
@@ -792,6 +801,10 @@
return FSREAD_SUCCESS_SCHED;
return_failure:
+ if (option_debug > 1) {
+ ast_log(LOG_DEBUG, "DEBUG: return_failure called. Giving up. !\n");
+ }
+
s->owner->streamid = -1;
ast_settimeout(s->owner, 0, NULL, NULL);
return FSREAD_FAILURE;
Modified: team/oej/pinequeue-1.8/main/say.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinequeue-1.8/main/say.c?view=diff&rev=363092&r1=363091&r2=363092
==============================================================================
--- team/oej/pinequeue-1.8/main/say.c (original)
+++ team/oej/pinequeue-1.8/main/say.c Mon Apr 23 03:38:45 2012
@@ -50,11 +50,12 @@
#include "asterisk/lock.h"
#include "asterisk/localtime.h"
#include "asterisk/utils.h"
+#include "asterisk/musiconhold.h"
#include "asterisk/app.h"
/* Forward declaration */
static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang);
-
+static int wait_file_full(struct ast_channel *chan, const char *ints, const char *file, const char *lang, int audiofd, int ctrlfd);
static int say_character_str_full(struct ast_channel *chan, const char *str, const char *ints, const char *lang, int audiofd, int ctrlfd)
{
@@ -123,14 +124,7 @@
}
if ((fn && ast_fileexists(fn, NULL, lang) > 0) ||
(snprintf(asciibuf + 13, sizeof(asciibuf) - 13, "%d", str[num]) > 0 && ast_fileexists(asciibuf, NULL, lang) > 0 && (fn = asciibuf))) {
- 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);
- }
- ast_stopstream(chan);
+ res = wait_file_full(chan, ints, fn, lang, audiofd, ctrlfd);
}
num++;
}
@@ -203,14 +197,7 @@
fn = fnbuf;
}
if (fn && ast_fileexists(fn, NULL, lang) > 0) {
- 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);
- }
- ast_stopstream(chan);
+ res = wait_file_full(chan, ints, fn, lang, audiofd, ctrlfd);
}
num++;
}
@@ -253,14 +240,7 @@
break;
}
if (fn && ast_fileexists(fn, NULL, lang) > 0) {
- 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);
- }
- ast_stopstream(chan);
+ res = wait_file_full(chan, ints, fn, lang, audiofd, ctrlfd);
}
num++;
}
@@ -419,14 +399,90 @@
static int ast_say_datetime_from_now_ka(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
static int ast_say_datetime_from_now_he(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
-static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang)
+static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang)
+{
+ return wait_file_full(chan, ints, file, lang, -1, -1);
+}
+
+/* this routine to provide wait_file capability for those with audiofd, ctrlfd */
+
+static int wait_file_full(struct ast_channel *chan, const char *ints, const char *file, const char *lang, int audiofd, int ctrlfd)
{
int res;
- if ((res = ast_streamfile(chan, file, lang)))
- ast_log(LOG_WARNING, "Unable to play message %s\n", file);
- if (!res)
- res = ast_waitstream(chan, ints);
- return res;
+ struct ast_datastore *datastore;
+ extern const struct ast_datastore_info queue_ds_sound_ending; /* defined in file.c */
+
+ /* if a datastore is present, we are in the queue app (perhaps others in time)
+ and don't want to wait around for the sounds to finish playing */
+
+ if ((datastore = ast_channel_datastore_find(chan, &queue_ds_sound_ending, NULL))) { /* app_queue wants to schedule this instead of play & wait */
+ struct ast_queue_streamfile_info *aqsi = datastore->data;
+ if (aqsi) {
+ AST_LIST_LOCK(&aqsi->flist);
+ if (aqsi->now_playing) {
+ struct ast_queue_streamfile_name *fn = ast_calloc(1, sizeof(*fn));
+
+ fn->filename = ast_strdup(file);
+ ast_debug(3, "----> Adding file %s to playlist for %s\n", file, chan->name);
+
+ /* link the struct into the current ast_queue_streamfile_info struct */
+ AST_LIST_INSERT_TAIL(&aqsi->flist, fn, list);
+ } else {
+ /* if not playing, then start playing this file */
+ if (aqsi->ringing) {
+ ast_indicate(aqsi->chan,-1);
+ } else {
+ ast_moh_stop(aqsi->chan);
+ }
+
+ ast_stopstream(aqsi->chan);
+
+ ast_autoservice_stop(aqsi->chan);
+
+ ast_debug(3, "Starting to stream %s\n", file);
+ res = ast_streamfile(aqsi->chan, file, aqsi->chan->language); /* begin the streaming */
+
+ while (res && !AST_LIST_EMPTY(&aqsi->flist)) {
+ /* really, how could this even be possible?
+ just in case.... */
+ struct ast_queue_streamfile_name *fn;
+
+ fn = AST_LIST_REMOVE_HEAD(&aqsi->flist, list);
+
+ ast_debug(3,"Start streaming file %s\n", fn->filename);
+ res = ast_streamfile(aqsi->chan, fn->filename, aqsi->chan->language);
+ }
+
+
+ if (res) {
+ /* oops, the current file has problems */
+ /* restore the moh */
+ if (aqsi->ringing) {
+ ast_indicate(aqsi->chan, AST_CONTROL_RINGING);
+ } else {
+ ast_moh_start(aqsi->chan, aqsi->moh, NULL);
+ }
+ AST_LIST_UNLOCK(&aqsi->flist);
+ return 1;
+ }
+ aqsi->now_playing = 1; /* We have begun playback */
+ ast_autoservice_start(aqsi->chan); /* this will let the sound file play in a different thread */
+ }
+ AST_LIST_UNLOCK(&aqsi->flist);
+ return 0;
+ }
+
+ } else {
+ /* otherwise, exactly business as usual */
+ if ((res = ast_streamfile(chan, file, lang)))
+ ast_log(LOG_WARNING, "Unable to play message %s\n", file);
+ if ((audiofd > -1) && (ctrlfd > -1))
+ res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
+ else
+ res = ast_waitstream(chan, ints);
+ return res;
+ }
+ return 0;
}
/*! \brief ast_say_number_full: call language-specific functions */
@@ -561,13 +617,7 @@
}
}
if (!res) {
- if (!ast_streamfile(chan, fn, language)) {
- if ((audiofd > -1) && (ctrlfd > -1))
- res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
- else
- res = ast_waitstream(chan, ints);
- }
- ast_stopstream(chan);
+ res = wait_file_full(chan, ints, fn, language, audiofd, ctrlfd);
}
}
return res;
@@ -683,14 +733,7 @@
num -= left * (exp10_int(length-1));
}
if (!res) {
- if (!ast_streamfile(chan, fn, language)) {
- if ((audiofd > -1) && (ctrlfd > -1)) {
- res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
- } else {
- res = ast_waitstream(chan, ints);
- }
- }
- ast_stopstream(chan);
+ res = wait_file_full(chan, ints, fn, language, audiofd, ctrlfd);
}
}
return res;
@@ -792,13 +835,7 @@
}
}
if (!res) {
- if (!ast_streamfile(chan, fn, language)) {
- if ((audiofd > -1) && (ctrlfd > -1))
- res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
- else
- res = ast_waitstream(chan, ints);
- }
- ast_stopstream(chan);
+ res = wait_file_full(chan, ints, fn, language, audiofd, ctrlfd);
}
}
return res;
@@ -921,21 +958,11 @@
res = -1;
}
if (!res) {
- if (!ast_streamfile(chan, fn, language)) {
- if ((audiofd > -1) && (ctrlfd > -1))
- res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
- else
- res = ast_waitstream(chan, ints);
- }
- ast_stopstream(chan);
+ res = wait_file_full(chan, ints, fn, language, audiofd, ctrlfd);
if (!res) {
- if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) {
- if ((audiofd > -1) && (ctrlfd > -1))
- res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
- else
- res = ast_waitstream(chan, ints);
- }
- ast_stopstream(chan);
+ if (strlen(fna)) {
+ res = wait_file_full(chan, ints, fn, language, audiofd, ctrlfd);
+ }
strcpy(fna, "");
}
}
@@ -1007,13 +1034,7 @@
}
if (!res) {
- if (!ast_streamfile(chan, fn, language)) {
- if ((audiofd > -1) && (ctrlfd > -1))
- res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
- else
- res = ast_waitstream(chan, ints);
- }
- ast_stopstream(chan);
+ res = wait_file_full(chan, ints, fn, language, audiofd, ctrlfd);
}
}
return res;
@@ -1111,14 +1132,7 @@
}
if (!res) {
- if (!ast_streamfile(chan, fn, language)) {
- if ((audiofd > -1) && (ctrlfd > -1))
- res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
- else
- res = ast_waitstream(chan, ints);
- }
- ast_stopstream(chan);
-
[... 1230 lines stripped ...]
More information about the asterisk-commits
mailing list