[asterisk-commits] oej: branch oej/pinetestedition-1.8 r383028 - in /team/oej/pinetestedition-1....

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Wed Mar 13 10:45:51 CDT 2013


Author: oej
Date: Wed Mar 13 10:45:46 2013
New Revision: 383028

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=383028
Log:
A soup of patches to give testers a good preview of what's coming to an Asterisk near them.

Added:
    team/oej/pinetestedition-1.8/patches/
    team/oej/pinetestedition-1.8/patches/README.darjeeling   (with props)
    team/oej/pinetestedition-1.8/patches/README.oolong-path-support   (with props)
    team/oej/pinetestedition-1.8/patches/README.pinequeue   (with props)
    team/oej/pinetestedition-1.8/patches/README.rana-dtmf-rtp-duration   (with props)
    team/oej/pinetestedition-1.8/patches/README.roibos-cng.txt   (with props)
    team/oej/pinetestedition-1.8/patches/oolong-path-support-1.8.diff   (with props)
    team/oej/pinetestedition-1.8/patches/pinequeue-1.8.diff   (with props)
    team/oej/pinetestedition-1.8/patches/rana-dtmf-duration-1.8.diff   (with props)
    team/oej/pinetestedition-1.8/patches/roibos-cng-support-1.8.diff   (with props)
    team/oej/pinetestedition-1.8/patches/set-tone-zone-sip.diff   (with props)
    team/oej/pinetestedition-1.8/res/res_noise.c   (with props)
Modified:
    team/oej/pinetestedition-1.8/apps/app_queue.c
    team/oej/pinetestedition-1.8/apps/app_senddtmf.c
    team/oej/pinetestedition-1.8/channels/chan_iax2.c
    team/oej/pinetestedition-1.8/channels/chan_local.c
    team/oej/pinetestedition-1.8/channels/chan_mgcp.c
    team/oej/pinetestedition-1.8/channels/chan_sip.c
    team/oej/pinetestedition-1.8/channels/sip/include/sip.h
    team/oej/pinetestedition-1.8/configs/queues.conf.sample
    team/oej/pinetestedition-1.8/configs/sip.conf.sample
    team/oej/pinetestedition-1.8/funcs/func_frame_trace.c
    team/oej/pinetestedition-1.8/include/asterisk/channel.h
    team/oej/pinetestedition-1.8/include/asterisk/file.h
    team/oej/pinetestedition-1.8/include/asterisk/frame.h
    team/oej/pinetestedition-1.8/include/asterisk/indications.h
    team/oej/pinetestedition-1.8/include/asterisk/rtp_engine.h
    team/oej/pinetestedition-1.8/main/asterisk.dynamics
    team/oej/pinetestedition-1.8/main/channel.c
    team/oej/pinetestedition-1.8/main/features.c
    team/oej/pinetestedition-1.8/main/file.c
    team/oej/pinetestedition-1.8/main/frame.c
    team/oej/pinetestedition-1.8/main/rtp_engine.c
    team/oej/pinetestedition-1.8/main/say.c
    team/oej/pinetestedition-1.8/res/res_rtp_asterisk.c

Modified: team/oej/pinetestedition-1.8/apps/app_queue.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinetestedition-1.8/apps/app_queue.c?view=diff&rev=383028&r1=383027&r2=383028
==============================================================================
--- team/oej/pinetestedition-1.8/apps/app_queue.c (original)
+++ team/oej/pinetestedition-1.8/apps/app_queue.c Wed Mar 13 10:45:46 2013
@@ -881,7 +881,6 @@
 	{ QUEUE_AUTOPAUSE_ALL,"all" },
 };
 
-
 static struct ast_taskprocessor *devicestate_tps;
 
 #define DEFAULT_RETRY		5
@@ -927,6 +926,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;
@@ -1190,6 +1192,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 */
@@ -2627,28 +2630,7 @@
 	return res;
 }
 
-static int play_file(struct ast_channel *chan, const char *filename)
-{
-	int res;
-
-	if (ast_strlen_zero(filename)) {
-		return 0;
-	}
-
-	if (!ast_fileexists(filename, NULL, chan->language)) {
-		return 0;
-	}
-
-	ast_stopstream(chan);
-
-	res = ast_streamfile(chan, filename, chan->language);
-	if (!res)
-		res = ast_waitstream(chan, AST_DIGIT_ANY);
-
-	ast_stopstream(chan);
-
-	return res;
-}
+void destroy_streamfile_info(struct ast_queue_streamfile_info *playdata);
 
 /*!
  * \brief Check for valid exit from queue via goto
@@ -2681,7 +2663,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;
 	}
@@ -2704,11 +2686,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 ||
@@ -2720,7 +2703,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
@@ -2728,7 +2711,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 */
@@ -2736,7 +2719,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 */
@@ -2745,11 +2728,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;
 			}
@@ -2770,10 +2753,10 @@
 
 	/* If the hold time is >1 min, if it's enabled, and if it's not
 	   supposed to be only once and we have already said it, say it */
-    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);
+	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,ringing,NULL);
 		if (res)
 			goto playout;
 
@@ -2783,11 +2766,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;
 			}
@@ -2797,7 +2780,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;
 		}
@@ -2811,11 +2794,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 */
@@ -2823,13 +2806,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;
 }
 
@@ -3480,12 +3468,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) {
@@ -3496,18 +3478,11 @@
 	}
 	
 	/* 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 = 0;
-
-	/* Resume Music on Hold if the caller is going to stay in the queue */
-	if (!res) {
-		if (ringing)
-			ast_indicate(qe->chan, AST_CONTROL_RINGING);
-		else
-			ast_moh_start(qe->chan, qe->moh, NULL);
-	}
+	res = play_file(qe->chan, ast_str_buffer(qe->parent->sound_periodicannounce[qe->last_periodic_announce_sound]), ringing, qe->moh);
+
+	/* we no longer check for valid_exit(), as we simply
+	   start the playback and let the autoservice thread
+	   keep it going */
 
 	/* update last_periodic_announce_time */
 	if (qe->parent->relativeperiodicannounce)
@@ -3646,10 +3621,15 @@
 #endif
 
 	while ((*to = ast_remaining_ms(start_time_tv, orig)) && !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;
@@ -4196,6 +4176,10 @@
 	/* This is the holding pen for callers 2 through maxlen */
 	for (;;) {
 
+		if (background_prompts) {
+			play_file(qe->chan, NULL, 0, qe->moh);
+		}
+
 		if (is_our_turn(qe))
 			break;
 
@@ -4217,9 +4201,9 @@
 		}
 
 		/* Make a position announcement, if enabled */
-		if (qe->parent->announcefrequency &&
-			(res = say_position(qe,ringing)))
+		if (qe->parent->announcefrequency && (res = say_position(qe,ringing))) {
 			break;
+		}
 
 		/* If we have timed out, break out */
 		if (qe->expire && (time(NULL) >= qe->expire)) {
@@ -4446,6 +4430,7 @@
 	.chan_fixup = queue_transfer_fixup,
 	.destroy = queue_transfer_destroy,
 };
+
 
 /*! \brief Log an attended transfer when a queue caller channel is masqueraded
  *
@@ -4903,39 +4888,41 @@
 			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 (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) {
+				if (play_file(peer, announce, ringing, qe->moh) < 0) {
+					ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", announce, peer->name);
 				}
-				if (!res2 && announce) {
-					if (play_file(peer, announce) < 0) {
-						ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", announce, peer->name);
+			}
+			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);
+						if (play_file(peer, qe->parent->sound_minutes, ringing, qe->moh) < 0) {
+							ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minutes, peer->name);
+						}
 					}
-				}
-				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);
-							if (play_file(peer, qe->parent->sound_minutes) < 0) {
-								ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_minutes, peer->name);
-							}
-						}
-						if (holdtimesecs > 1) {
-							ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, peer->language, NULL);
-							if (play_file(peer, qe->parent->sound_seconds) < 0) {
-								ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_seconds, peer->name);
-							}
+					if (holdtimesecs > 1) {
+						ast_say_number(peer, holdtimesecs, AST_DIGIT_ANY, peer->language, NULL);
+						if (play_file(peer, qe->parent->sound_seconds, ringing, qe->moh) < 0) {
+							ast_log(LOG_ERROR, "play_file failed for '%s' on %s\n", qe->parent->sound_seconds, peer->name);
 						}
 					}
 				}
 				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);
@@ -4964,10 +4951,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);
@@ -4985,7 +4973,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);
 		}
 
@@ -5152,7 +5140,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;
 			}
 			
@@ -5373,8 +5361,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;
 
@@ -6064,6 +6053,326 @@
 	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 */
+}
+
+/*! \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;
+		}
+
+		if (!ast_fileexists(filename, NULL, chan->language)) {
+			return 0;
+		}
+
+		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 */
+	
+	ast_channel_lock(chan);
+	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", chan->name);
+		ast_channel_unlock(chan);
+		return 1; /* Why continue, if I can't access the datastore & list? */
+	}
+	ast_channel_unlock(chan);
+	if (option_debug && !ast_strlen_zero(filename)) {
+		ast_debug(2, "---- Aqsi now playing: %s\n", aqsi->now_playing ? "true" : "false");
+	}
+	
+	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));
+				ast_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 ? aqsi->qe->moh : NULL, NULL);
+					}
+				}
+				return 0;
+			}
+		} 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 0;
+		}
+	}
+
+	/* If the filename doesn't exist, do not queue it up */
+	if (!ast_strlen_zero(filename)) {
+		if (!ast_fileexists(filename, NULL, chan->language)) {
+			ast_log(LOG_ERROR, "Filename %s does not exist, not queued for playing out on chan %s\n", filename, chan->name);
+			return 0;
+		}
+	}
+
+	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);
+		if (!fn || ! fn->filename) {
+			ast_log(LOG_ERROR, "Error allocating memory.\n");
+			AST_LIST_UNLOCK(&aqsi->flist);
+			return 1;
+		} 
+		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");
+			AST_LIST_UNLOCK(&aqsi->flist);
+			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 
@@ -6087,6 +6396,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 = ast_calloc(1, sizeof(struct ast_queue_streamfile_info));
+
 	/* whether to exit Queue application after the timeout hits */
 	int tries = 0;
 	int noption = 0;
@@ -6209,6 +6521,24 @@
 		S_OR(args.url, ""),
 		S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, ""),
 		qe.opos);
+
+	/* Add the background music datastore for this channel */
+	if (background_prompts) {
+		datastore = ast_datastore_alloc(ast_sound_ending(), NULL);
+		if (datastore && aqsi) {
+			/* If memory allocation worked out */
+			aqsi->qe = &qe;
+			aqsi->chan = chan;
+			aqsi->ringing = ringing;
+			aqsi->now_playing = 0;
+			ast_copy_string(aqsi->moh, qe.moh, sizeof(aqsi->moh));
+			AST_LIST_HEAD_INIT(&aqsi->flist);
+			datastore->data = aqsi;
+	
+			ast_channel_datastore_add(chan, datastore);
+		}
+	}
+
 	copy_rules(&qe, args.rule);
 	qe.pr = AST_LIST_FIRST(&qe.qe_rules);
 check_turns:
@@ -6242,6 +6572,9 @@
 			break;
 		}
 
+		if (background_prompts) {
+			play_file(qe.chan, NULL, ringing, qe.moh);	
+		}
 		if (makeannouncement) {
 			/* Make a position announcement, if enabled */
 			if (qe.parent->announcefrequency)
@@ -6324,6 +6657,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) {
@@ -6340,17 +6679,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);
@@ -6816,6 +7144,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")))
 		shared_lastcall = ast_true(general_val);

Modified: team/oej/pinetestedition-1.8/apps/app_senddtmf.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinetestedition-1.8/apps/app_senddtmf.c?view=diff&rev=383028&r1=383027&r2=383028
==============================================================================
--- team/oej/pinetestedition-1.8/apps/app_senddtmf.c (original)
+++ team/oej/pinetestedition-1.8/apps/app_senddtmf.c Wed Mar 13 10:45:46 2013
@@ -79,6 +79,9 @@
 			<parameter name="Digit" required="true">
 				<para>The DTMF digit to play.</para>
 			</parameter>
+			<parameter name="Duration" required="false">
+				<para>The duration in ms for the digit to play.</para>
+			</parameter>
 		</syntax>
 		<description>
 			<para>Plays a dtmf digit on the specified channel.</para>
@@ -145,7 +148,9 @@
 {
 	const char *channel = astman_get_header(m, "Channel");
 	const char *digit = astman_get_header(m, "Digit");
+	const char *duration = astman_get_header(m, "Duration");
 	struct ast_channel *chan;
+	int dtmfduration = 0;
 
 	if (!(chan = ast_channel_get_by_name(channel))) {
 		astman_send_error(s, m, "Channel not found");
@@ -157,8 +162,11 @@
 		chan = ast_channel_unref(chan);
 		return 0;
 	}
+	if (!ast_strlen_zero(duration)) {
+		dtmfduration = atoi(duration);
+	}
 
-	ast_senddigit(chan, *digit, 0);
+	ast_senddigit(chan, *digit, dtmfduration);
 
 	chan = ast_channel_unref(chan);
 

Modified: team/oej/pinetestedition-1.8/channels/chan_iax2.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinetestedition-1.8/channels/chan_iax2.c?view=diff&rev=383028&r1=383027&r2=383028
==============================================================================
--- team/oej/pinetestedition-1.8/channels/chan_iax2.c (original)
+++ team/oej/pinetestedition-1.8/channels/chan_iax2.c Wed Mar 13 10:45:46 2013
@@ -1170,6 +1170,7 @@
 static int iax2_call(struct ast_channel *c, char *dest, int timeout);
 static int iax2_devicestate(void *data);
 static int iax2_digit_begin(struct ast_channel *c, char digit);
+static int iax2_digit_continue(struct ast_channel *c, char digit, unsigned int duration);
 static int iax2_digit_end(struct ast_channel *c, char digit, unsigned int duration);
 static int iax2_do_register(struct iax2_registry *reg);
 static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newchan);
@@ -1221,6 +1222,7 @@
 	.requester = iax2_request,
 	.devicestate = iax2_devicestate,
 	.send_digit_begin = iax2_digit_begin,
+	.send_digit_continue = iax2_digit_continue,
 	.send_digit_end = iax2_digit_end,
 	.send_text = iax2_sendtext,
 	.send_image = iax2_sendimage,
@@ -4293,8 +4295,15 @@
 	return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_DTMF_BEGIN, digit, 0, NULL, 0, -1);
 }
 
+static int iax2_digit_continue(struct ast_channel *c, char digit, unsigned int duration)
+{
+	/* We propably should find a way to send duration here. */
+	return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_DTMF_CONTINUE, digit, 0, NULL, 0, -1);
+}
+
 static int iax2_digit_end(struct ast_channel *c, char digit, unsigned int duration)
 {
+	/* We propably should find a way to send duration here. */
 	return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_DTMF_END, digit, 0, NULL, 0, -1);
 }
 

Modified: team/oej/pinetestedition-1.8/channels/chan_local.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinetestedition-1.8/channels/chan_local.c?view=diff&rev=383028&r1=383027&r2=383028
==============================================================================
--- team/oej/pinetestedition-1.8/channels/chan_local.c (original)
+++ team/oej/pinetestedition-1.8/channels/chan_local.c Wed Mar 13 10:45:46 2013
@@ -96,6 +96,7 @@
 
 static struct ast_channel *local_request(const char *type, format_t format, const struct ast_channel *requestor, void *data, int *cause);
 static int local_digit_begin(struct ast_channel *ast, char digit);
+static int local_digit_continue(struct ast_channel *ast, char digit, unsigned int duration);
 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int local_call(struct ast_channel *ast, char *dest, int timeout);
 static int local_hangup(struct ast_channel *ast);
@@ -118,6 +119,7 @@
 	.capabilities = -1,
 	.requester = local_request,
 	.send_digit_begin = local_digit_begin,
+	.send_digit_continue = local_digit_continue,
 	.send_digit_end = local_digit_end,
 	.call = local_call,
 	.hangup = local_hangup,
@@ -804,6 +806,29 @@
 	return res;
 }
 
+static int local_digit_continue(struct ast_channel *ast, char digit, unsigned int duration)
+{
+	struct local_pvt *p = ast->tech_pvt;
+	int res = -1;
+	struct ast_frame f = { AST_FRAME_DTMF_CONTINUE, };
+	int isoutbound;
+
+	if (!p) {
+		return -1;
+	}
+
+	ao2_ref(p, 1); /* ref for local_queue_frame */
+	ao2_lock(p);
+	isoutbound = IS_OUTBOUND(ast, p);
+	f.subclass.integer = digit;
+	f.len = duration;
+	res = local_queue_frame(p, isoutbound, &f, ast, 0);
+	ao2_unlock(p);
+	ao2_ref(p, -1);
+
+	return res;
+}
+
 static int local_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
 {
 	struct local_pvt *p = ast->tech_pvt;

Modified: team/oej/pinetestedition-1.8/channels/chan_mgcp.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinetestedition-1.8/channels/chan_mgcp.c?view=diff&rev=383028&r1=383027&r2=383028
==============================================================================
--- team/oej/pinetestedition-1.8/channels/chan_mgcp.c (original)
+++ team/oej/pinetestedition-1.8/channels/chan_mgcp.c Wed Mar 13 10:45:46 2013
@@ -450,6 +450,7 @@
 static int mgcp_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen);
 static int mgcp_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 static int mgcp_senddigit_begin(struct ast_channel *ast, char digit);
+static int mgcp_senddigit_continue(struct ast_channel *ast, char digit, unsigned int duration);
 static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int mgcp_devicestate(void *data);
 static void add_header_offhook(struct mgcp_subchannel *sub, struct mgcp_request *resp, char *tone);
@@ -475,6 +476,7 @@
 	.indicate = mgcp_indicate,
 	.fixup = mgcp_fixup,
 	.send_digit_begin = mgcp_senddigit_begin,
+	.send_digit_continue = mgcp_senddigit_continue,
 	.send_digit_end = mgcp_senddigit_end,
 	.bridge = ast_rtp_instance_bridge,
 	.func_channel_read = acf_channel_read,
@@ -1317,6 +1319,21 @@
 	return res;
 }
 
+static int mgcp_senddigit_continue(struct ast_channel *ast, char digit, unsigned int duration)
+{
+	struct mgcp_subchannel *sub = ast->tech_pvt;
+	struct mgcp_endpoint *p = sub->parent;
+
+	ast_mutex_lock(&sub->lock);
+
+	if (p->dtmfmode & MGCP_DTMF_RFC2833) {
+		ast_debug(4, "DTMF continue using RFC2833\n");
+		ast_rtp_instance_dtmf_continue(sub->rtp, digit, duration);
+	}
+	ast_mutex_unlock(&sub->lock);
+
+	return 0;
+}
 static int mgcp_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration)
 {
 	struct mgcp_subchannel *sub = ast->tech_pvt;

Modified: team/oej/pinetestedition-1.8/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/pinetestedition-1.8/channels/chan_sip.c?view=diff&rev=383028&r1=383027&r2=383028
==============================================================================
--- team/oej/pinetestedition-1.8/channels/chan_sip.c (original)
+++ team/oej/pinetestedition-1.8/channels/chan_sip.c Wed Mar 13 10:45:46 2013
@@ -264,6 +264,7 @@
 #include "asterisk/cel.h"
 #include "asterisk/data.h"
 #include "asterisk/aoc.h"
+#include "asterisk/indications.h"
 #include "sip/include/sip.h"
 #include "sip/include/globals.h"
 #include "sip/include/config_parser.h"
@@ -691,6 +692,7 @@
 static char default_engine[256];                   /*!< Default RTP engine */
 static int default_maxcallbitrate;                 /*!< Maximum bitrate for call */
 static struct ast_codec_pref default_prefs;        /*!< Default codec prefs */
+static char default_zone[MAX_TONEZONE_COUNTRY];        /*!< Default tone zone for channels created from the SIP driver */
 static unsigned int default_transports;            /*!< Default Transports (enum sip_transport) that are acceptable */
 static unsigned int default_primary_transport;     /*!< Default primary Transport (enum sip_transport) for outbound connections to devices */
 /*@}*/
@@ -1224,6 +1226,7 @@
 static int sip_transfer(struct ast_channel *ast, const char *dest);
 static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
 static int sip_senddigit_begin(struct ast_channel *ast, char digit);
+static int sip_senddigit_continue(struct ast_channel *ast, char digit, unsigned int duration);
 static int sip_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);
 static int sip_setoption(struct ast_channel *chan, int option, void *data, int datalen);
 static int sip_queryoption(struct ast_channel *chan, int option, void *data, int *datalen);
@@ -1281,6 +1284,8 @@
 static void free_old_route(struct sip_route *route);
 static void list_route(struct sip_route *route);
 static void build_route(struct sip_pvt *p, struct sip_request *req, int backwards, int resp);
+static void build_path(struct sip_pvt *p, struct sip_peer *peer, struct sip_request *req, char *pathbuf);
+static void copy_route(struct sip_route **d, struct sip_route *s);
 static enum check_auth_result register_verify(struct sip_pvt *p, struct ast_sockaddr *addr,
 					      struct sip_request *req, const char *uri);
 static struct sip_pvt *get_sip_pvt_byid_locked(const char *callid, const char *totag, const char *fromtag);
@@ -1446,7 +1451,7 @@
 static void set_socket_transport(struct sip_socket *socket, int transport);
 
 /* Realtime device support */
-static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *username, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms);
+static void realtime_update_peer(const char *peername, struct ast_sockaddr *addr, const char *username, const char *fullcontact, const char *useragent, int expirey, unsigned short deprecated_username, int lastms, const char *path);
 static void update_peer(struct sip_peer *p, int expire);
 static struct ast_variable *get_insecure_variable_from_config(struct ast_config *config);
 static const char *get_name_from_variable(const struct ast_variable *var);
@@ -1528,6 +1533,7 @@
 static int add_rpid(struct sip_request *req, struct sip_pvt *p);
 static int add_vidupdate(struct sip_request *req);
 static void add_route(struct sip_request *req, struct sip_route *route);
+static void make_route_list(struct sip_route *route, char *r, int rem);
 static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field);
 static int copy_all_header(struct sip_request *req, const struct sip_request *orig, const char *field);
 static int copy_via_headers(struct sip_pvt *p, struct sip_request *req, const struct sip_request *orig, const char *field);
@@ -1614,6 +1620,7 @@
 	.transfer = sip_transfer,		/* called with chan locked */
 	.fixup = sip_fixup,			/* called with chan locked */
 	.send_digit_begin = sip_senddigit_begin,	/* called with chan unlocked */
+	.send_digit_continue = sip_senddigit_continue,	/* called with chan unlocked */
 	.send_digit_end = sip_senddigit_end,
 	.bridge = ast_rtp_instance_bridge,			/* XXX chan unlocked ? */
 	.early_bridge = ast_rtp_instance_early_bridge,
@@ -4757,6 +4764,10 @@
 		 * implied else case here
 		 */
 		break;
+	case AST_OPTION_CNG_SUPPORT:
+		/* Check if the current dialog has agreed on Comfort Noise support */
+		res = (p->noncodeccapability & AST_RTP_CN);
+		break;
 	default:
 		break;
 	}
@@ -4858,7 +4869,7 @@
 	that name and store that in the "regserver" field in the sippeers
 	table to facilitate multi-server setups.
 */

[... 9423 lines stripped ...]



More information about the asterisk-commits mailing list