[svn-commits] oej: branch oej/pinequeue-1.8 r363092 - in /team/oej/pinequeue-1.8: apps/ con...

SVN commits to the Digium repositories svn-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 svn-commits mailing list