Index: res/res_musiconhold.c
===================================================================
RCS file: /usr/cvsroot/asterisk/res/res_musiconhold.c,v
retrieving revision 1.52
diff -u -r1.52 res_musiconhold.c
--- res/res_musiconhold.c	25 Jan 2005 06:10:20 -0000	1.52
+++ res/res_musiconhold.c	12 Feb 2005 17:01:11 -0000
@@ -77,6 +77,14 @@
 
 static int respawn_time = 20;
 
+struct moh_relay_state {
+	struct mohclass *class;
+	struct ast_channel *chan;
+	int origwfmt;
+	int done;
+};
+
+
 struct moh_files_state {
 	struct mohclass *class;
 	int origwfmt;
@@ -89,7 +97,9 @@
 #define MOH_QUIET		(1 << 0)
 #define MOH_SINGLE		(1 << 1)
 #define MOH_CUSTOM		(1 << 2)
-#define MOH_RANDOMIZE		(1 << 3)
+#define MOH_RANDOMIZE	(1 << 3)
+#define MOH_FILES		(1 << 4)
+#define MOH_RELAY		(1 << 5)
 
 struct mohclass {
 	char class[80];
@@ -124,6 +134,115 @@
 #define MPG_123 "/usr/bin/mpg123"
 #define MAX_MP3S 256
 
+
+static void *moh_relay_alloc(struct ast_channel *chan, void *params) {
+	struct mohclass *class = params;
+	struct ast_channel *newchan;
+	char *proto;
+	char *data;
+	int format = 0, fail = 0, outstate = 0;
+	struct moh_relay_state *state;
+
+	if (!(proto = ast_strdupa(class->dir)))
+		return NULL;
+	
+	if ((data = strchr(proto, '/'))) {
+		*data = '\0';
+		data++;
+	} else {
+		return NULL;
+	}
+	if(!ast_strlen_zero(class->miscargs))
+		format = ast_getformatbyname(class->miscargs);
+	if(!format)
+		format = AST_FORMAT_SLINEAR;
+	
+	if((newchan = ast_request(proto, format, data, &outstate))) {
+		ast_call(newchan, data, 0);
+		if (ast_set_write_format(newchan, AST_FORMAT_SLINEAR) < 0) {
+			ast_log(LOG_WARNING, "Unable to set '%s' to write linear mode\n", newchan->name);
+			fail++;
+		}
+
+		if (ast_set_read_format(newchan, AST_FORMAT_SLINEAR) < 0) {
+			ast_log(LOG_WARNING, "Unable to set '%s' to read linear mode\n", newchan->name);
+			fail++;
+		}
+
+		if(fail) {
+			if(newchan)
+				ast_hangup(newchan);
+		} else {
+			if (!chan->music_state && (state = malloc(sizeof(struct moh_relay_state)))) {
+				memset(state, 0, sizeof(struct moh_relay_state));
+				state->class = class;
+				state->origwfmt = chan->writeformat;
+				
+				if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
+					ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
+					free(chan->music_state);
+					chan->music_state = NULL;
+					ast_hangup(newchan);
+					return NULL;
+				} else {
+					if (option_verbose > 2)
+						ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->class, chan->name);
+				}
+				
+				state->chan = newchan;
+				chan->music_state = state;
+				return chan->music_state;
+				
+			} else 
+				return NULL;
+
+		}
+	}
+
+	return params;
+}
+static void moh_relay_release(struct ast_channel *chan, void *data)
+{
+
+	struct moh_relay_state *state = chan->music_state;
+	
+	if (chan && state) {
+		if (option_verbose > 2)
+			ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
+
+		if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
+			ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt);
+		}
+		state->done = 1;
+		ast_hangup(state->chan);
+		free(state);
+		chan->music_state = NULL;
+	}
+}
+
+static int moh_relay_generator(struct ast_channel *chan, void *data, int len, int samples)
+{
+	struct ast_frame *f = NULL;
+	struct moh_relay_state *state = chan->music_state;
+	int res = -1;
+
+	if(state && !state->done) {
+		/* i'd like to ast_waitfor here but it causes a deadlock
+		   so i'll live with harmeless read warnings on iax till the 
+		   day we clean up chan lists to not be so lame
+		 */
+		if((f = ast_read(state->chan))) {
+			if(f->frametype == AST_FRAME_VOICE) {
+				ast_write(chan, f);
+			} 
+			ast_frfree(f);
+			res = 0;
+		} 
+	}
+
+	return res;
+}
+
 static void moh_files_release(struct ast_channel *chan, void *data)
 {
 	struct moh_files_state *state = chan->music_state;
@@ -267,6 +386,13 @@
 	generate: moh_files_generator,
 };
 
+static struct ast_generator moh_relay_gen = 
+{
+	alloc: moh_relay_alloc,
+	release: moh_relay_release,
+	generate: moh_relay_generator,
+};
+
 static int spawn_mp3(struct mohclass *class)
 {
 	int fds[2];
@@ -761,12 +887,18 @@
 			ast_set_flag(moh, MOH_RANDOMIZE);
 	}
 	if (!strcasecmp(mode, "files")) {
+		ast_set_flag(moh, MOH_FILES);
 		if (param)
 			strncpy(moh->dir, param, sizeof(moh->dir) - 1);
 		if (!moh_scan_files(moh)) {
 			free(moh);
 			return -1;
 		}
+	} else if (!strcasecmp(mode, "relay")) {
+		ast_set_flag(moh, MOH_RELAY);
+		if (param)
+            strncpy(moh->dir, param, sizeof(moh->dir) - 1);
+
 	} else if (!strcasecmp(mode, "mp3") || !strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb") || !strcasecmp(mode, "httpmp3") || !strcasecmp(mode, "custom")) {
 
 		if (param)
@@ -838,8 +970,10 @@
 	}
 
 	ast_set_flag(chan, AST_FLAG_MOH);
-	if (mohclass->total_files) {
+	if (ast_test_flag(mohclass, MOH_FILES) && mohclass->total_files) {
 		return ast_activate_generator(chan, &moh_file_stream, mohclass);
+	} else if(ast_test_flag(mohclass, MOH_RELAY)) {
+		return ast_activate_generator(chan, &moh_relay_gen, mohclass);
 	} else
 		return ast_activate_generator(chan, &mohgen, mohclass);
 }
@@ -892,6 +1026,18 @@
 			if (args)
 				*args++ = '\0';
 			moh_register(var->name, "files", var->value, args);
+			x++;
+		}
+		var = var->next;
+	}
+
+	var = ast_variable_browse(cfg, "moh_relay");
+	while (var) {
+		if (!(get_mohbyname(var->name))) {
+			args = strchr(var->value, ',');
+			if (args)
+				*args++ = '\0';
+			moh_register(var->name, "relay", var->value, args);
 			x++;
 		}
 		var = var->next;
