From 5a7a8666a120096bd6429dc5c123244ee095ac2b Mon Sep 17 00:00:00 2001 From: Mark Spencer Date: Sun, 31 Jul 2005 22:07:58 +0000 Subject: [PATCH] Add periodic announcement (bug #4677 with mods) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6248 65c4cc65-6c06-0410-ace0-fbb531ad65f3 --- apps/app_queue.c | 97 ++++++++++++++++++++++++++--- configs/queues.conf.sample | 6 ++ sounds.txt | 2 + sounds/queue-periodic-announce.gsm | Bin 0 -> 12474 bytes 4 files changed, 97 insertions(+), 8 deletions(-) create mode 100755 sounds/queue-periodic-announce.gsm diff --git a/apps/app_queue.c b/apps/app_queue.c index fa4b8ffae6..f8f7a7461f 100755 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -238,6 +238,7 @@ struct queue_ent { int pos; /* Where we are in the queue */ int prio; /* Our priority */ int last_pos_said; /* Last position we told the user */ + time_t last_periodic_announce_time; /* The last time we played a periodic anouncement */ time_t last_pos; /* Last time we told the user their position */ int opos; /* Where we started in the queue */ int handled; /* Whether our call was handled */ @@ -284,6 +285,7 @@ struct ast_call_queue { unsigned int maskmemberstatus:1; unsigned int realtime:1; int announcefrequency; /* How often to announce their position */ + int periodicannouncefrequency; /* How often to play periodic announcement */ int roundingseconds; /* How many seconds do we round to? */ int holdtime; /* Current avg holdtime, based on recursive boxcar filter */ int callscompleted; /* Number of queue calls completed */ @@ -300,6 +302,7 @@ struct ast_call_queue { char sound_seconds[80]; /* Sound file: "seconds." (def. queue-seconds) */ char sound_thanks[80]; /* Sound file: "Thank you for your patience." (def. queue-thankyou) */ char sound_reporthold[80]; /* Sound file: "Hold time" (def. queue-reporthold) */ + char sound_periodicannounce[80];/* Sound file: Custom announce, no default */ int count; /* How many entries */ int maxlen; /* Max number of entries */ @@ -526,6 +529,7 @@ static void init_queue(struct ast_call_queue *q) q->announce[0] = '\0'; q->context[0] = '\0'; q->monfmt[0] = '\0'; + q->periodicannouncefrequency = 0; ast_copy_string(q->sound_next, "queue-youarenext", sizeof(q->sound_next)); ast_copy_string(q->sound_thereare, "queue-thereare", sizeof(q->sound_thereare)); ast_copy_string(q->sound_calls, "queue-callswaiting", sizeof(q->sound_calls)); @@ -535,6 +539,7 @@ static void init_queue(struct ast_call_queue *q) ast_copy_string(q->sound_thanks, "queue-thankyou", sizeof(q->sound_thanks)); ast_copy_string(q->sound_lessthan, "queue-less-than", sizeof(q->sound_lessthan)); ast_copy_string(q->sound_reporthold, "queue-reporthold", sizeof(q->sound_reporthold)); + ast_copy_string(q->sound_periodicannounce, "queue-periodic-announce", sizeof(q->sound_periodicannounce)); } static void clear_queue(struct ast_call_queue *q) @@ -608,6 +613,10 @@ static void queue_set_param(struct ast_call_queue *q, const char *param, const c q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS; else q->announceholdtime = 0; + } else if (!strcasecmp(param, "periodic-announce")) { + ast_copy_string(q->sound_periodicannounce, val, sizeof(q->sound_periodicannounce)); + } else if (!strcasecmp(param, "periodic-announce-frequency")) { + q->periodicannouncefrequency = atoi(val); } else if (!strcasecmp(param, "retry")) { q->retry = atoi(val); if (q->retry < 0) @@ -1108,13 +1117,6 @@ static int say_position(struct queue_ent *qe) return res; } -static void record_abandoned(struct queue_ent *qe) -{ - ast_mutex_lock(&qe->parent->lock); - qe->parent->callsabandoned++; - ast_mutex_unlock(&qe->parent->lock); -} - static void recalc_holdtime(struct queue_ent *qe) { int oldvalue, newvalue; @@ -1467,6 +1469,71 @@ static int store_next(struct queue_ent *qe, struct localuser *outgoing) return 0; } +static int background_file(struct queue_ent *qe, struct ast_channel *chan, char *filename) +{ + int res; + + ast_stopstream(chan); + res = ast_streamfile(chan, filename, chan->language); + + if (!res) { + /* Wait for a keypress */ + res = ast_waitstream(chan, AST_DIGIT_ANY); + if (res <= 0 || !valid_exit(qe, res)) + res = 0; + + /* Stop playback */ + ast_stopstream(chan); + } else { + res = 0; + } + + /*if (res) { + ast_log(LOG_WARNING, "ast_streamfile failed on %s \n", chan->name); + res = 0; + }*/ + + return res; +} + +static int say_periodic_announcement(struct queue_ent *qe) +{ + int res = 0; + time_t now; + + /* Get the current time */ + time(&now); + + /* Check to see if it is time to announce */ + if ( (now - qe->last_periodic_announce_time) < qe->parent->periodicannouncefrequency ) + return -1; + + /* Stop the music on hold so we can play our own file */ + ast_moh_stop(qe->chan); + + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "Playing periodic announcement\n"); + + /* play the announcement */ + res = background_file(qe, qe->chan, qe->parent->sound_periodicannounce); + + /* Resume Music on Hold */ + ast_moh_start(qe->chan, qe->moh); + + /* update last_periodic_announce_time */ + qe->last_periodic_announce_time = now; + + return(res); +} + +static void record_abandoned(struct queue_ent *qe) +{ + ast_mutex_lock(&qe->parent->lock); + qe->parent->callsabandoned++; + ast_mutex_unlock(&qe->parent->lock); +} + + #define AST_MAX_WATCHERS 256 #define BUILD_WATCHERS do { \ @@ -1780,8 +1847,12 @@ static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *r if (res) break; + /* Make a periodic announcement, if enabled */ + if (qe->parent->periodicannouncefrequency && !ringing) + res = say_periodic_announcement(qe); + /* Wait a second before checking again */ - res = ast_waitfordigit(qe->chan, RECHECK * 1000); + if (!res) res = ast_waitfordigit(qe->chan, RECHECK * 1000); if (res) break; } @@ -2744,6 +2815,7 @@ static int queue_exec(struct ast_channel *chan, void *data) qe.prio = (int)prio; qe.last_pos_said = 0; qe.last_pos = 0; + qe.last_periodic_announce_time = time(NULL); if (!join_queue(queuename, &qe, &reason)) { ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "", chan->cid.cid_num ? chan->cid.cid_num : ""); @@ -2805,6 +2877,15 @@ check_turns: } makeannouncement = 1; + /* Make a periodic announcement, if enabled */ + if (qe.parent->periodicannouncefrequency && !ringing) + res = say_periodic_announcement(&qe); + + if (res && valid_exit(&qe, res)) { + ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHKEY", "%c|%d", res, qe.pos); + break; + } + /* Try calling all queue members for 'timeout' seconds */ res = try_calling(&qe, options, announceoverride, url, &go_on); if (res) { diff --git a/configs/queues.conf.sample b/configs/queues.conf.sample index 310d4cf750..68c980b6fc 100755 --- a/configs/queues.conf.sample +++ b/configs/queues.conf.sample @@ -80,6 +80,11 @@ persistentmembers = yes ; ;announce-frequency = 90 ; +; +; How often to make any periodic announcement (see periodic-announce) +; +;periodic-announce-frequency=60 +; ; Should we include estimated hold time in position announcements? ; Either yes, no, or only once. ; Hold time will be announced as the estimated time, @@ -105,6 +110,7 @@ persistentmembers = yes ;queue-thankyou = queue-thankyou ; ("Thank you for your patience.") ;queue-lessthan = queue-less-than ; ("less than") ;queue-reporthold = queue-reporthold ; ("Hold time") +;periodic-announce = queue-periodic-announce ; ("All reps busy / wait for next") ; ; Calls may be recorded using Asterisk's monitor resource ; This can be enabled from within the Queue application, starting recording diff --git a/sounds.txt b/sounds.txt index a0ece6017f..426c63c633 100755 --- a/sounds.txt +++ b/sounds.txt @@ -84,6 +84,8 @@ %pbx-transfer.gsm%Transfer. +%queue-periodic-announce.gsm%All of our represenatives are currently busy. Please stay on the line and your call will be answered by the next available representative. + %queue-callswaiting.gsm%Waiting to speak with a representative %queue-holdtime.gsm%The estimated hold time is currently diff --git a/sounds/queue-periodic-announce.gsm b/sounds/queue-periodic-announce.gsm new file mode 100755 index 0000000000000000000000000000000000000000..b06bedcb9d422a9bf80fda9bc5c749dfc0dfeecc GIT binary patch literal 12474 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 literal 0 HcmV?d00001