[svn-commits] oej: branch oej/pinequeue-trunk r363098 - in /team/oej/pinequeue-trunk: apps/...

SVN commits to the Digium repositories svn-commits at lists.digium.com
Mon Apr 23 08:02:40 CDT 2012


Author: oej
Date: Mon Apr 23 08:02:37 2012
New Revision: 363098

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=363098
Log:
Look ma, it compiles

Modified:
    team/oej/pinequeue-trunk/apps/app_queue.c
    team/oej/pinequeue-trunk/configs/queues.conf.sample
    team/oej/pinequeue-trunk/include/asterisk/channel.h
    team/oej/pinequeue-trunk/include/asterisk/file.h
    team/oej/pinequeue-trunk/main/asterisk.dynamics
    team/oej/pinequeue-trunk/main/channel.c
    team/oej/pinequeue-trunk/main/features.c
    team/oej/pinequeue-trunk/main/file.c
    team/oej/pinequeue-trunk/main/say.c

Modified: team/oej/pinequeue-trunk/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinequeue-trunk/apps/app_queue.c?view=diff&rev=363098&r1=363097&r2=363098
==============================================================================
--- team/oej/pinequeue-trunk/apps/app_queue.c (original)
+++ team/oej/pinequeue-trunk/apps/app_queue.c Mon Apr 23 08:02:37 2012
@@ -968,7 +968,6 @@
 	{ QUEUE_AUTOPAUSE_ALL,"all" },
 };
 
-
 static struct ast_taskprocessor *devicestate_tps;
 
 #define DEFAULT_RETRY		5
@@ -1016,6 +1015,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;
@@ -1288,6 +1290,7 @@
 static void update_realtime_members(struct call_queue *q);
 static struct member *interface_exists(struct call_queue *q, const char *interface);
 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);
 
@@ -2696,6 +2699,8 @@
 	return res;
 }
 
+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;
@@ -2717,7 +2722,7 @@
 	ast_stopstream(chan);
 
 	return res;
-}
+} */
 
 /*!
  * \brief Check for valid exit from queue via goto
@@ -2750,7 +2755,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;
 	}
@@ -2773,11 +2778,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 ||
@@ -2789,7 +2795,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
@@ -2797,7 +2803,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, ast_channel_language(qe->chan), NULL); /* Needs gender */
@@ -2805,7 +2811,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, ast_channel_language(qe->chan), NULL); /* Needs gender */
@@ -2814,11 +2820,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;
 			}
@@ -2842,7 +2848,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;
 
@@ -2852,11 +2858,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;
 			}
@@ -2866,7 +2872,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;
 		}
@@ -2880,11 +2886,11 @@
 			ast_channel_name(qe->chan), 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  && !valid_exit(qe, res)) /* in other words, ignore any play_file problems... */
 		res = 0;
 
 	/* Set our last_pos indicators */
@@ -2892,13 +2898,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;
 }
 
@@ -3492,12 +3503,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) {
@@ -3508,10 +3513,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) {
@@ -3673,10 +3682,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;
@@ -4003,6 +4017,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) {
@@ -4391,6 +4408,7 @@
 	.chan_fixup = queue_transfer_fixup,
 	.destroy = queue_transfer_destroy,
 };
+
 
 /*! \brief Log an attended transfer when a queue caller channel is masqueraded
  *
@@ -4849,29 +4867,36 @@
 			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, ast_channel_language(peer), NULL);
-							play_file(peer, qe->parent->sound_minutes);
-						}
-						if (holdtimesecs > 1) {
-							ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, ast_channel_language(peer), 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) {
+	//int ast_say_number(struct ast_channel *chan, int num,
+	//const char *ints, const char *lang, const char *options);
+						ast_say_number(peer, holdtime, AST_DIGIT_ANY, ast_channel_language(peer), NULL);
+						play_file(peer, qe->parent->sound_minutes, ringing, qe->moh);
+					}
+					if (holdtimesecs > 1) {
+						ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, ast_channel_language(peer), NULL);
+						play_file(peer, qe->parent->sound_seconds, ringing, qe->moh);
 					}
 				}
 			}
@@ -4904,10 +4929,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 (ast_channel_cdr(qe->chan)) {
 			ast_cdr_setdestchan(ast_channel_cdr(qe->chan), ast_channel_name(peer));
@@ -4926,7 +4952,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);
 		}
 
@@ -5100,7 +5126,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", ast_channel_name(qe->chan));
 				res = -1;
 			}
 			
@@ -5343,8 +5369,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;
 
@@ -6105,6 +6132,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", ast_channel_name(chan));
+	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';
+	ast_channel_stream_set(state->chan, 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", ast_channel_name(state->chan));
+	} 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", ast_channel_name(state->chan));
+		return f;
+	}
+
+	if (!state->stream) {
+		if (!(state->stream = ast_openstream_full(state->chan, state->filename, ast_channel_language(state->chan), 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, ast_channel_name(chan));
+
+	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, ast_channel_language(chan));
+		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, ast_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 ast_sound_ending datastore! on chan %s\n", ast_channel_name(chan));
+		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(ast_channel_flags(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, ast_channel_name(chan));
+		
+		/* 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", ast_channel_name(chan));
+			ast_indicate(chan,-1);
+		} else {
+			ast_debug(3, "Stopping MOH on chan %s\n", ast_channel_name(chan));
+			ast_moh_stop(chan);
+		}
+			
+		ast_debug(3, "Stopping Streaming on chan %s\n", ast_channel_name(chan));
+		ast_stopstream(chan);
+		
+		ast_debug(3, "Autoservice stop on chan %s\n", ast_channel_name(chan));
+		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, ast_channel_name(chan));
+			/* 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 
@@ -6128,6 +6459,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;
@@ -6256,6 +6590,20 @@
 		S_OR(args.url, ""),
 		S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, ""),
 		qe.opos);
+  /* Begin old Olle patch */
+	datastore = ast_datastore_alloc(ast_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:
@@ -6289,6 +6637,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)
@@ -6371,6 +6722,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) {
@@ -6387,17 +6744,6 @@
 			ast_queue_log(args.queuename, ast_channel_uniqueid(chan), "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);
@@ -6972,6 +7318,10 @@
 	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"))) {

Modified: team/oej/pinequeue-trunk/configs/queues.conf.sample
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinequeue-trunk/configs/queues.conf.sample?view=diff&rev=363098&r1=363097&r2=363098
==============================================================================
--- team/oej/pinequeue-trunk/configs/queues.conf.sample (original)
+++ team/oej/pinequeue-trunk/configs/queues.conf.sample Mon Apr 23 08:02:37 2012
@@ -77,6 +77,14 @@
 ; set appropriately.
 ;
 ;check_state_unknown = 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-trunk/include/asterisk/channel.h
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinequeue-trunk/include/asterisk/channel.h?view=diff&rev=363098&r1=363097&r2=363098
==============================================================================
--- team/oej/pinequeue-trunk/include/asterisk/channel.h (original)
+++ team/oej/pinequeue-trunk/include/asterisk/channel.h Mon Apr 23 08:02:37 2012
@@ -3513,6 +3513,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-trunk/include/asterisk/file.h
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinequeue-trunk/include/asterisk/file.h?view=diff&rev=363098&r1=363097&r2=363098
==============================================================================
--- team/oej/pinequeue-trunk/include/asterisk/file.h (original)
+++ team/oej/pinequeue-trunk/include/asterisk/file.h Mon Apr 23 08:02:37 2012
@@ -39,6 +39,8 @@
 
 struct ast_filestream;
 struct ast_format;
+
+const struct ast_datastore_info *ast_sound_ending(void);
 
 /*! The maximum number of formats we expect to see in a format string */
 #define AST_MAX_FORMATS 10
@@ -338,6 +340,7 @@
  */
 char *ast_format_str_reduce(char *fmts);
 
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif

Modified: team/oej/pinequeue-trunk/main/asterisk.dynamics
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinequeue-trunk/main/asterisk.dynamics?view=diff&rev=363098&r1=363097&r2=363098
==============================================================================
--- team/oej/pinequeue-trunk/main/asterisk.dynamics (original)
+++ team/oej/pinequeue-trunk/main/asterisk.dynamics Mon Apr 23 08:02:37 2012
@@ -1,4 +1,5 @@
 {
+	*ast_sound_*;
 	*ast_adsi_*;
 	*ast_agi_*;
 	*ast_pktccops_*;

Modified: team/oej/pinequeue-trunk/main/channel.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinequeue-trunk/main/channel.c?view=diff&rev=363098&r1=363097&r2=363098
==============================================================================
--- team/oej/pinequeue-trunk/main/channel.c (original)
+++ team/oej/pinequeue-trunk/main/channel.c Mon Apr 23 08:02:37 2012
@@ -2880,6 +2880,7 @@
 		ast_channel_generator(chan)->write_format_change(chan, ast_channel_generatordata(chan));
 	}
 	ast_channel_unlock(chan);
+	ast_debug(3, "ast_deactivate_generator() done on chan %s\n", ast_channel_name(chan));
 }
 
 static int generator_force(const void *data)
@@ -4050,6 +4051,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-trunk/main/features.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinequeue-trunk/main/features.c?view=diff&rev=363098&r1=363097&r2=363098
==============================================================================
--- team/oej/pinequeue-trunk/main/features.c (original)
+++ team/oej/pinequeue-trunk/main/features.c Mon Apr 23 08:02:37 2012
@@ -1567,10 +1567,13 @@
 	ast_debug(4, "AMI ParkedCall Channel: %s\n", ast_channel_name(chan));
 	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-trunk/main/file.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinequeue-trunk/main/file.c?view=diff&rev=363098&r1=363097&r2=363098
==============================================================================
--- team/oej/pinequeue-trunk/main/file.c (original)
+++ team/oej/pinequeue-trunk/main/file.c Mon Apr 23 08:02:37 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"
@@ -771,6 +772,18 @@
 	return NULL;
 }
 
+static const struct ast_datastore_info ast_sound_ending_obj = { /* 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 = "ast_sound_ending"
+};
+
+const struct ast_datastore_info *ast_sound_ending()
+{
+	return &ast_sound_ending_obj;
+}
+
+
 static struct ast_frame *read_frame(struct ast_filestream *s, int *whennext)
 {
 	struct ast_frame *fr, *new_fr;
@@ -829,6 +842,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;
 		}
 

Modified: team/oej/pinequeue-trunk/main/say.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinequeue-trunk/main/say.c?view=diff&rev=363098&r1=363097&r2=363098
==============================================================================
--- team/oej/pinequeue-trunk/main/say.c (original)
+++ team/oej/pinequeue-trunk/main/say.c Mon Apr 23 08:02:37 2012
@@ -50,11 +50,13 @@
 #include "asterisk/lock.h"
 #include "asterisk/localtime.h"
 #include "asterisk/utils.h"
+#include "asterisk/musiconhold.h"
 #include "asterisk/app.h"
 #include "asterisk/test.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)
@@ -124,14 +126,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++;
 	}
@@ -204,14 +199,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++;
 	}
@@ -254,14 +242,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++;
 	}
@@ -422,12 +403,89 @@
 
 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);
+}
+
+/*! wait_file_full: 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;
+
+	/* 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, ast_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, ast_channel_name(chan));
+				
+				/* 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, ast_channel_language(aqsi->chan)); /* 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, ast_channel_language(aqsi->chan));
+				}
+				
+				
+				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
@@ -563,13 +621,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;
@@ -686,14 +738,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;
@@ -795,13 +840,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;
@@ -925,19 +964,10 @@
 			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);
+				if (strlen(fna) != 0 ) {
+					res = wait_file_full(chan, ints, fn, language, audiofd, ctrlfd);
 				}
 				ast_stopstream(chan);
 				strcpy(fna, "");
@@ -1011,13 +1041,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;
@@ -1116,14 +1140,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);
 		}
 
 	}
@@ -1208,13 +1225,7 @@
 			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);
 		}
 	}
 	return res;
@@ -1379,14 +1390,7 @@
 		}
 		tmpnum = 0;
 		if (!res) {
-			if (!ast_streamfile(chan, fn, language)) {
-				if ((audiofd > -1) && (ctrlfd > -1)) {

[... 1053 lines stripped ...]



More information about the svn-commits mailing list