mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 10:47:18 +00:00 
			
		
		
		
	support new format for musiconhold.conf (issue #4908)
support non-SLINEAR moh streams (issue #4908) add external app to feed TCP stream into Asterisk for moh (issue #4908) git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@6353 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
		| @@ -137,3 +137,9 @@ AGI: | ||||
|   behavior has been fixed.  If you do not want your script to terminate  | ||||
|   at the end of AGI being called (e.g. on a hangup) then set SIGHUP to  | ||||
|   be ignored within your application. | ||||
|  | ||||
| Music On Hold: | ||||
|  | ||||
| * The preferred format for musiconhold.conf has changed; please see the | ||||
|   sample configuration file for the new format. The existing format | ||||
|   is still supported but will generate warnings when the module is loaded. | ||||
|   | ||||
| @@ -1,16 +1,30 @@ | ||||
| ; | ||||
| ; Music on hold class definitions | ||||
| ; Music on Hold -- Sample Configuration | ||||
| ; | ||||
| [classes] | ||||
| default => quietmp3:/var/lib/asterisk/mohmp3 | ||||
| ;loud => mp3:/var/lib/asterisk/mohmp3 | ||||
| ;random => quietmp3:/var/lib/asterisk/mohmp3,-z | ||||
| ;unbuffered => mp3nb:/var/lib/asterisk/mohmp3 | ||||
| ;quietunbuf => quietmp3nb:/var/lib/asterisk/mohmp3 | ||||
| ; Note that the custom mode cannot handle escaped parameters (specifically embedded spaces) | ||||
| ;manual => custom:/var/lib/asterisk/mohmp3,/usr/bin/mpg123 -q -r 8000 -f 8192 -b 2048 --mono -s | ||||
| ; For a custom app, reading from a directory may not be necessary | ||||
| ;manual => custom:nodir,/bin/my-dirless-app myarg | ||||
|  | ||||
| [default] | ||||
| mode=quietmp3 | ||||
| directory=/var/lib/asterisk/mohmp3 | ||||
|  | ||||
| ; valid mode options: | ||||
| ; quietmp3 	-- default | ||||
| ; mp3 		-- loud | ||||
| ; mp3nb		-- unbuffered | ||||
| ; quietmp3nb	-- quiet unbuffered | ||||
| ; custom	-- run a custom application  | ||||
| ; files		-- read files from a directory in any Asterisk supported format | ||||
|  | ||||
| ;[manual] | ||||
| ;mode=custom | ||||
| ; Note that with mode=custom, a directory is not required, such as when reading | ||||
| ; from a stream. | ||||
| ;directory=/var/lib/asterisk/mohmp3 | ||||
| ;application=/usr/bin/mpg123 -q -r 8000 -f 8192 -b 2048 --mono -s | ||||
|  | ||||
| ;[ulawstream] | ||||
| ;mode=custom | ||||
| ;application=/usr/bin/streamplayer 80.254.173.176 888 | ||||
| ;format=ulaw | ||||
|  | ||||
| ; | ||||
| ; File-based (native) music on hold | ||||
| @@ -31,6 +45,12 @@ default => quietmp3:/var/lib/asterisk/mohmp3 | ||||
| ; this, res_musiconhold will skip the files it is not able to | ||||
| ; understand when it loads. | ||||
| ; | ||||
| [moh_files] | ||||
| ;native => /var/lib/asterisk/moh-native | ||||
| ;native-random => /var/lib/asterisk/moh-native,r | ||||
|  | ||||
| ;[native] | ||||
| ;mode=files | ||||
| ;directory=/var/lib/asterisk/moh-native | ||||
| ; | ||||
| ;[native-random] | ||||
| ;mode=files | ||||
| ;directory=/var/lib/asterisk/moh-native | ||||
| ;random=yes 	; Play the files in a random order | ||||
|   | ||||
							
								
								
									
										33
									
								
								frame.c
									
									
									
									
									
								
							
							
						
						
									
										33
									
								
								frame.c
									
									
									
									
									
								
							| @@ -1168,7 +1168,6 @@ static int speex_samples(unsigned char *data, int len) | ||||
| 	return cnt; | ||||
| } | ||||
|  | ||||
|  | ||||
| int ast_codec_get_samples(struct ast_frame *f) | ||||
| { | ||||
| 	int samples=0; | ||||
| @@ -1210,3 +1209,35 @@ int ast_codec_get_samples(struct ast_frame *f) | ||||
| 	return samples; | ||||
| } | ||||
|  | ||||
| int ast_codec_get_len(int format, int samples) | ||||
| { | ||||
| 	int len = 0; | ||||
|  | ||||
| 	/* XXX Still need speex, g723, and lpc10 XXX */	 | ||||
| 	switch(format) { | ||||
| 	case AST_FORMAT_ILBC: | ||||
| 		len = (samples / 240) * 50; | ||||
| 		break; | ||||
| 	case AST_FORMAT_GSM: | ||||
| 		len = (samples / 160) * 33; | ||||
| 		break; | ||||
| 	case AST_FORMAT_G729A: | ||||
| 		len = samples / 8; | ||||
| 		break; | ||||
| 	case AST_FORMAT_SLINEAR: | ||||
| 		len = samples * 2; | ||||
| 		break; | ||||
| 	case AST_FORMAT_ULAW: | ||||
| 	case AST_FORMAT_ALAW: | ||||
| 		len = samples; | ||||
| 		break; | ||||
| 	case AST_FORMAT_ADPCM: | ||||
| 	case AST_FORMAT_G726: | ||||
| 		len = samples / 2; | ||||
| 		break; | ||||
| 	default: | ||||
| 		ast_log(LOG_WARNING, "Unable to calculate sample length for format %s\n", ast_getformatname(format)); | ||||
| 	} | ||||
|  | ||||
| 	return len; | ||||
| } | ||||
|   | ||||
| @@ -398,6 +398,9 @@ extern void ast_codec_pref_convert(struct ast_codec_pref *pref, char *buf, size_ | ||||
| /* Returns the number of samples contained in the frame */ | ||||
| extern int ast_codec_get_samples(struct ast_frame *f); | ||||
|  | ||||
| /* Returns the number of bytes for the number of samples of the given format */ | ||||
| extern int ast_codec_get_len(int format, int samples); | ||||
|  | ||||
| /* Gets duration in ms of interpolation frame for a format */ | ||||
| static inline int ast_codec_interp_len(int format)  | ||||
| {  | ||||
|   | ||||
| @@ -108,12 +108,14 @@ struct moh_files_state { | ||||
| #define MOH_RANDOMIZE		(1 << 3) | ||||
|  | ||||
| struct mohclass { | ||||
| 	char class[80]; | ||||
| 	char name[MAX_MUSICCLASS]; | ||||
| 	char dir[256]; | ||||
| 	char miscargs[256]; | ||||
| 	char args[256]; | ||||
| 	char mode[80]; | ||||
| 	char filearray[MAX_MOHFILES][MAX_MOHFILE_LEN]; | ||||
| 	unsigned int flags; | ||||
| 	int total_files; | ||||
| 	int format; | ||||
| 	int pid;		/* PID of mpg123 */ | ||||
| 	time_t start; | ||||
| 	pthread_t thread; | ||||
| @@ -212,8 +214,8 @@ static int ast_moh_files_next(struct ast_channel *chan) | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	if (option_verbose > 2) | ||||
| 		ast_log(LOG_NOTICE, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]); | ||||
| 	if (option_debug) | ||||
| 		ast_log(LOG_DEBUG, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]); | ||||
|  | ||||
| 	if (state->samples) | ||||
| 		ast_seekstream(chan->stream, state->samples, SEEK_SET); | ||||
| @@ -285,7 +287,7 @@ static void *moh_files_alloc(struct ast_channel *chan, void *params) | ||||
| 			chan->music_state = NULL; | ||||
| 		} else { | ||||
| 			if (option_verbose > 2) | ||||
| 				ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->class, chan->name); | ||||
| 				ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->name, chan->name); | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
| @@ -343,7 +345,7 @@ static int spawn_mp3(struct mohclass *class) | ||||
| 			argv[argc++] = "8192"; | ||||
| 		 | ||||
| 		/* Look for extra arguments and add them to the list */ | ||||
| 		strncpy(xargs, class->miscargs, sizeof(xargs) - 1); | ||||
| 		strncpy(xargs, class->args, sizeof(xargs) - 1); | ||||
| 		argptr = xargs; | ||||
| 		while (argptr && !ast_strlen_zero(argptr)) { | ||||
| 			argv[argc++] = argptr; | ||||
| @@ -355,7 +357,7 @@ static int spawn_mp3(struct mohclass *class) | ||||
| 		} | ||||
| 	} else  { | ||||
| 		/* Format arguments for argv vector */ | ||||
| 		strncpy(xargs, class->miscargs, sizeof(xargs) - 1); | ||||
| 		strncpy(xargs, class->args, sizeof(xargs) - 1); | ||||
| 		argptr = xargs; | ||||
| 		while (argptr && !ast_strlen_zero(argptr)) { | ||||
| 			argv[argc++] = argptr; | ||||
| @@ -460,6 +462,7 @@ static void *monmp3thread(void *data) | ||||
| 	char buf[8192]; | ||||
| 	short sbuf[8192]; | ||||
| 	int res, res2; | ||||
| 	int len; | ||||
| 	struct timeval tv, tv_tmp; | ||||
|  | ||||
| 	tv.tv_sec = 0; | ||||
| @@ -495,7 +498,9 @@ static void *monmp3thread(void *data) | ||||
| 		if (!class->members) | ||||
| 			continue; | ||||
| 		/* Read mp3 audio */ | ||||
| 		if ((res2 = read(class->srcfd, sbuf, res * 2)) != res * 2) { | ||||
| 		len = ast_codec_get_len(class->format, res); | ||||
| 		 | ||||
| 		if ((res2 = read(class->srcfd, sbuf, len)) != len) { | ||||
| 			if (!res2) { | ||||
| 				close(class->srcfd); | ||||
| 				class->srcfd = -1; | ||||
| @@ -504,7 +509,7 @@ static void *monmp3thread(void *data) | ||||
| 					class->pid = 0; | ||||
| 				} | ||||
| 			} else | ||||
| 				ast_log(LOG_DEBUG, "Read %d bytes of audio while expecting %d\n", res2, res * 2); | ||||
| 				ast_log(LOG_DEBUG, "Read %d bytes of audio while expecting %d\n", res2, len); | ||||
| 			continue; | ||||
| 		} | ||||
| 		ast_mutex_lock(&moh_lock); | ||||
| @@ -581,7 +586,7 @@ static struct mohclass *get_mohbyname(char *name) | ||||
| 	struct mohclass *moh; | ||||
| 	moh = mohclasses; | ||||
| 	while (moh) { | ||||
| 		if (!strcasecmp(name, moh->class)) | ||||
| 		if (!strcasecmp(name, moh->name)) | ||||
| 			return moh; | ||||
| 		moh = moh->next; | ||||
| 	} | ||||
| @@ -647,19 +652,18 @@ static void moh_release(struct ast_channel *chan, void *data) | ||||
| static void *moh_alloc(struct ast_channel *chan, void *params) | ||||
| { | ||||
| 	struct mohdata *res; | ||||
| 	struct mohclass *class; | ||||
| 	class = params; | ||||
| 	struct mohclass *class = params; | ||||
|  | ||||
| 	res = mohalloc(class); | ||||
| 	if (res) { | ||||
| 		res->origwfmt = chan->writeformat; | ||||
| 		if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) { | ||||
| 			ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format\n", chan->name); | ||||
| 		if (ast_set_write_format(chan, class->format)) { | ||||
| 			ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format)); | ||||
| 			moh_release(NULL, res); | ||||
| 			res = NULL; | ||||
| 		} | ||||
| 		if (option_verbose > 2) | ||||
| 			ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->class, chan->name); | ||||
| 			ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name); | ||||
| 	} | ||||
| 	return res; | ||||
| } | ||||
| @@ -674,7 +678,8 @@ static int moh_generate(struct ast_channel *chan, void *data, int len, int sampl | ||||
| 	if (!moh->parent->pid) | ||||
| 		return -1; | ||||
|  | ||||
| 	len = samples * 2; | ||||
| 	len = ast_codec_get_len(moh->parent->format, samples); | ||||
|  | ||||
| 	if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) { | ||||
| 		ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name); | ||||
| 		len = sizeof(buf) - AST_FRIENDLY_OFFSET; | ||||
| @@ -689,17 +694,20 @@ static int moh_generate(struct ast_channel *chan, void *data, int len, int sampl | ||||
| 		return 0; | ||||
|  | ||||
| 	memset(&f, 0, sizeof(f)); | ||||
| 	 | ||||
| 	f.frametype = AST_FRAME_VOICE; | ||||
| 	f.subclass = AST_FORMAT_SLINEAR; | ||||
| 	f.subclass = moh->parent->format; | ||||
| 	f.mallocd = 0; | ||||
| 	f.datalen = res; | ||||
| 	f.samples = res / 2; | ||||
| 	f.data = buf + AST_FRIENDLY_OFFSET / 2; | ||||
| 	f.offset = AST_FRIENDLY_OFFSET; | ||||
| 	f.samples = ast_codec_get_samples(&f); | ||||
|  | ||||
| 	if (ast_write(chan, &f) < 0) { | ||||
| 		ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @@ -763,53 +771,42 @@ static int moh_scan_files(struct mohclass *class) { | ||||
| 	return class->total_files; | ||||
| } | ||||
|  | ||||
| static int moh_register(char *classname, char *mode, char *param, char *miscargs) | ||||
| static int moh_register(struct mohclass *moh) | ||||
| { | ||||
| 	struct mohclass *moh; | ||||
| #ifdef ZAPATA_MOH | ||||
| 	int x; | ||||
| #endif | ||||
| 	ast_mutex_lock(&moh_lock); | ||||
| 	moh = get_mohbyname(classname); | ||||
| 	ast_mutex_unlock(&moh_lock); | ||||
| 	if (moh) { | ||||
| 		ast_log(LOG_WARNING, "Music on Hold '%s' already exists\n", classname); | ||||
| 	if (get_mohbyname(moh->name)) { | ||||
| 		ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name); | ||||
| 		free(moh);	 | ||||
| 		ast_mutex_unlock(&moh_lock); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	moh = malloc(sizeof(struct mohclass)); | ||||
| 	if (!moh) | ||||
| 		return -1; | ||||
| 	memset(moh, 0, sizeof(struct mohclass)); | ||||
| 	ast_mutex_unlock(&moh_lock); | ||||
|  | ||||
| 	time(&moh->start); | ||||
| 	moh->start -= respawn_time; | ||||
| 	strncpy(moh->class, classname, sizeof(moh->class) - 1); | ||||
| 	if (miscargs) { | ||||
| 		strncpy(moh->miscargs, miscargs, sizeof(moh->miscargs) - 1); | ||||
| 		if (strchr(miscargs,'r')) | ||||
| 			ast_set_flag(moh, MOH_RANDOMIZE); | ||||
| 	} | ||||
| 	if (!strcasecmp(mode, "files")) { | ||||
| 		if (param) | ||||
| 			strncpy(moh->dir, param, sizeof(moh->dir) - 1); | ||||
| 	 | ||||
| 	if (!strcasecmp(moh->mode, "files")) { | ||||
| 		if (!moh_scan_files(moh)) { | ||||
| 			ast_moh_free_class(&moh); | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} else if (!strcasecmp(mode, "mp3") || !strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb") || !strcasecmp(mode, "httpmp3") || !strcasecmp(mode, "custom")) { | ||||
| 		if (strchr(moh->args, 'r')) | ||||
| 			ast_set_flag(moh, MOH_RANDOMIZE); | ||||
| 	} else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) { | ||||
|  | ||||
| 		if (param) | ||||
| 			strncpy(moh->dir, param, sizeof(moh->dir) - 1); | ||||
|  | ||||
| 		if (!strcasecmp(mode, "custom")) | ||||
| 		if (!strcasecmp(moh->mode, "custom")) | ||||
| 			ast_set_flag(moh, MOH_CUSTOM); | ||||
| 		else if (!strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3nb")) | ||||
| 		else if (!strcasecmp(moh->mode, "mp3nb") || !strcasecmp(moh->mode, "quietmp3nb")) | ||||
| 			ast_set_flag(moh, MOH_SINGLE); | ||||
| 		else if (!strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb")) | ||||
| 		else if (!strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb")) | ||||
| 			ast_set_flag(moh, MOH_QUIET); | ||||
| 		 | ||||
| 		moh->srcfd = -1; | ||||
| #ifdef ZAPATA_MOH | ||||
| 		/* It's an MP3 Moh -- Open /dev/zap/pseudo for timing...  Is | ||||
| 		/* Open /dev/zap/pseudo for timing...  Is | ||||
| 		   there a better, yet reliable way to do this? */ | ||||
| 		moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY); | ||||
| 		if (moh->pseudofd < 0) { | ||||
| @@ -829,7 +826,7 @@ static int moh_register(char *classname, char *mode, char *param, char *miscargs | ||||
| 			return -1; | ||||
| 		} | ||||
| 	} else { | ||||
| 		ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mode); | ||||
| 		ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode); | ||||
| 		ast_moh_free_class(&moh); | ||||
| 		return -1; | ||||
| 	} | ||||
| @@ -885,21 +882,100 @@ static void local_ast_moh_stop(struct ast_channel *chan) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static struct mohclass *moh_class_malloc(void) | ||||
| { | ||||
| 	struct mohclass *class; | ||||
|  | ||||
| 	class = malloc(sizeof(struct mohclass)); | ||||
|  | ||||
| 	if (!class) | ||||
| 		return NULL; | ||||
|  | ||||
| 	memset(class, 0, sizeof(struct mohclass)); | ||||
|  | ||||
| 	class->format = AST_FORMAT_SLINEAR; | ||||
|  | ||||
| 	return class; | ||||
| } | ||||
|  | ||||
| static int load_moh_classes(void) | ||||
| { | ||||
| 	struct ast_config *cfg; | ||||
| 	struct ast_variable *var; | ||||
| 	struct mohclass *class;	 | ||||
| 	char *data; | ||||
| 	char *args; | ||||
| 	int x = 0; | ||||
| 	char *cat; | ||||
| 	int numclasses = 0; | ||||
| 	static int dep_warning = 0; | ||||
|  | ||||
| 	cfg = ast_config_load("musiconhold.conf"); | ||||
|  | ||||
| 	if (!cfg) | ||||
| 		return 0; | ||||
|  | ||||
| 	cat = ast_category_browse(cfg, NULL); | ||||
| 	for (; cat; cat = ast_category_browse(cfg, cat)) { | ||||
| 		if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) { | ||||
| 			class = moh_class_malloc(); | ||||
| 			if (!class) { | ||||
| 				ast_log(LOG_WARNING, "Out of memory!\n"); | ||||
| 				break; | ||||
| 			}				 | ||||
| 			ast_copy_string(class->name, cat, sizeof(class->name));	 | ||||
| 			var = ast_variable_browse(cfg, cat); | ||||
| 			while (var) { | ||||
| 				if (!strcasecmp(var->name, "mode")) | ||||
| 					ast_copy_string(class->mode, var->value, sizeof(class->name));  | ||||
| 				else if (!strcasecmp(var->name, "directory")) | ||||
| 					ast_copy_string(class->dir, var->value, sizeof(class->dir)); | ||||
| 				else if (!strcasecmp(var->name, "application")) | ||||
| 					ast_copy_string(class->args, var->value, sizeof(class->args)); | ||||
| 				else if (!strcasecmp(var->name, "random")) | ||||
| 					ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE); | ||||
| 				else if (!strcasecmp(var->name, "format")) { | ||||
| 					class->format = ast_getformatbyname(var->value); | ||||
| 					if (!class->format) { | ||||
| 						ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value); | ||||
| 						class->format = AST_FORMAT_SLINEAR; | ||||
| 					} | ||||
| 				} | ||||
| 					var = var->next; | ||||
| 			} | ||||
|  | ||||
| 			if (ast_strlen_zero(class->dir)) { | ||||
| 				if (!strcasecmp(class->mode, "custom")) { | ||||
| 					strcpy(class->dir, "nodir"); | ||||
| 				} else { | ||||
| 					ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name); | ||||
| 					free(class); | ||||
| 					continue; | ||||
| 				} | ||||
| 			} | ||||
| 			if (ast_strlen_zero(class->mode)) { | ||||
| 				ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name); | ||||
| 				free(class); | ||||
| 				continue; | ||||
| 			} | ||||
| 			if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) { | ||||
| 				ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name); | ||||
| 				free(class); | ||||
| 				continue; | ||||
| 			} | ||||
|  | ||||
| 			moh_register(class); | ||||
| 			numclasses++; | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	/* Deprecated Old-School Configuration */ | ||||
| 	var = ast_variable_browse(cfg, "classes"); | ||||
| 	while (var) { | ||||
| 		if (!dep_warning) { | ||||
| 			ast_log(LOG_WARNING, "The old musiconhold.conf syntax has been deprecated!  Please refer to the sample configuration for information on the new syntax.\n"); | ||||
| 			dep_warning = 1; | ||||
| 		} | ||||
| 		data = strchr(var->value, ':'); | ||||
| 		if (data) { | ||||
| 			*data++ = '\0'; | ||||
| @@ -907,26 +983,55 @@ static int load_moh_classes(void) | ||||
| 			if (args) | ||||
| 				*args++ = '\0'; | ||||
| 			if (!(get_mohbyname(var->name))) { | ||||
| 				moh_register(var->name, var->value, data, args); | ||||
| 				x++; | ||||
| 				class = moh_class_malloc(); | ||||
| 				if (!class) { | ||||
| 					ast_log(LOG_WARNING, "Out of memory!\n"); | ||||
| 					return numclasses; | ||||
| 				} | ||||
| 				 | ||||
| 				ast_copy_string(class->name, var->name, sizeof(class->name)); | ||||
| 				ast_copy_string(class->dir, data, sizeof(class->dir)); | ||||
| 				ast_copy_string(class->mode, var->value, sizeof(class->mode)); | ||||
| 				if (args) | ||||
| 					ast_copy_string(class->args, args, sizeof(class->args)); | ||||
| 				 | ||||
| 				moh_register(class); | ||||
| 				numclasses++; | ||||
| 			} | ||||
| 		} | ||||
| 		var = var->next; | ||||
| 	} | ||||
| 	var = ast_variable_browse(cfg, "moh_files"); | ||||
| 	while (var) { | ||||
| 		if (!dep_warning) { | ||||
| 			ast_log(LOG_WARNING, "The old musiconhold.conf syntax has been deprecated!  Please refer to the sample configuration for information on the new syntax.\n"); | ||||
| 			dep_warning = 1; | ||||
| 		} | ||||
| 		if (!(get_mohbyname(var->name))) { | ||||
| 			args = strchr(var->value, ','); | ||||
| 			if (args) | ||||
| 				*args++ = '\0'; | ||||
| 			moh_register(var->name, "files", var->value, args); | ||||
| 			x++; | ||||
| 			class = moh_class_malloc(); | ||||
| 			if (!class) { | ||||
| 				ast_log(LOG_WARNING, "Out of memory!\n"); | ||||
| 				return numclasses; | ||||
| 			} | ||||
| 			 | ||||
| 			ast_copy_string(class->name, var->name, sizeof(class->name)); | ||||
| 			ast_copy_string(class->dir, var->value, sizeof(class->dir)); | ||||
| 			strcpy(class->mode, "files"); | ||||
| 			if (args)	 | ||||
| 				ast_copy_string(class->args, args, sizeof(class->args)); | ||||
| 			 | ||||
| 			moh_register(class); | ||||
| 			numclasses++; | ||||
| 		} | ||||
| 		var = var->next; | ||||
| 	} | ||||
|  | ||||
| 	ast_config_destroy(cfg); | ||||
| 	return x; | ||||
|  | ||||
| 	return numclasses; | ||||
| } | ||||
|  | ||||
| static void ast_moh_destroy(void) | ||||
| @@ -998,7 +1103,7 @@ static int cli_files_show(int fd, int argc, char *argv[]) | ||||
| 		if (!class->total_files) | ||||
| 			continue; | ||||
|  | ||||
| 		ast_cli(fd, "Class: %s\n", class->class); | ||||
| 		ast_cli(fd, "Class: %s\n", class->name); | ||||
| 		for (i = 0; i < class->total_files; i++) | ||||
| 			ast_cli(fd, "\tFile: %s\n", class->filearray[i]); | ||||
| 	} | ||||
| @@ -1007,8 +1112,27 @@ static int cli_files_show(int fd, int argc, char *argv[]) | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int moh_classes_show(int fd, int argc, char *argv[]) | ||||
| { | ||||
| 	struct mohclass *class; | ||||
|  | ||||
| 	ast_mutex_lock(&moh_lock); | ||||
| 	for (class = mohclasses; class; class = class->next) { | ||||
| 		ast_cli(fd, "Class: %s\n", class->name); | ||||
| 		ast_cli(fd, "\tDirectory: %s\n", ast_strlen_zero(class->dir) ? "<none>" : class->dir); | ||||
| 		if (ast_test_flag(class, MOH_CUSTOM)) | ||||
| 			ast_cli(fd, "\tApplication: %s\n", ast_strlen_zero(class->args) ? "<none>" : class->args); | ||||
| 		ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format)); | ||||
| 	} | ||||
| 	ast_mutex_unlock(&moh_lock); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static struct ast_cli_entry  cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL}; | ||||
|  | ||||
| static struct ast_cli_entry  cli_moh_classes_show = { { "moh", "classes", "show"}, moh_classes_show, "List MOH classes", "Lists all MOH classes", NULL}; | ||||
|  | ||||
| static struct ast_cli_entry  cli_moh_files_show = { { "moh", "files", "show"}, cli_files_show, "List MOH file-based classes", "Lists all loaded file-based MOH classes and their files", NULL}; | ||||
|  | ||||
| static void init_classes(void)  | ||||
| @@ -1033,6 +1157,7 @@ int load_module(void) | ||||
| 	ast_register_atexit(ast_moh_destroy); | ||||
| 	ast_cli_register(&cli_moh); | ||||
| 	ast_cli_register(&cli_moh_files_show); | ||||
| 	ast_cli_register(&cli_moh_classes_show); | ||||
| 	if (!res) | ||||
| 		res = ast_register_application(app1, moh1_exec, synopsis1, descrip1); | ||||
| 	if (!res) | ||||
|   | ||||
| @@ -21,7 +21,7 @@ ifeq ($(findstring BSD,${OSARCH}),BSD) | ||||
| CFLAGS+=-I$(CROSS_COMPILE_TARGET)/usr/local/include -L$(CROSS_COMPILE_TARGET)/usr/local/lib | ||||
| endif | ||||
|  | ||||
| TARGET=stereorize | ||||
| TARGET=stereorize streamplayer | ||||
|  | ||||
| TARGET+=$(shell if [ -f $(CROSS_COMPILE_TARGET)/usr/include/popt.h ]; then echo "smsq"; else if [ -f $(CROSS_COMPILE_TARGET)/usr/local/include/popt.h ]; then echo "smsq"; fi ; fi) | ||||
| TARGET+=$(shell if [ -f $(CROSS_COMPILE_TARGET)/usr/include/newt.h ]; then echo "astman"; else if [ -f $(CROSS_COMPILE_TARGET)/usr/local/include/newt.h ]; then echo "astman"; fi ; fi) | ||||
| @@ -53,6 +53,9 @@ check_expr : check_expr.c ../ast_expr.a | ||||
| smsq: smsq.o | ||||
| 	$(CC) $(CFLAGS) -o smsq ${SOL} smsq.o -lpopt | ||||
|  | ||||
| streamplayer: streamplayer.o | ||||
| 	$(CC) $(CFLAGS) -o streamplayer ${SOL} streamplayer.o | ||||
|  | ||||
| ifneq ($(wildcard .depend),) | ||||
| include .depend | ||||
| endif | ||||
|   | ||||
							
								
								
									
										84
									
								
								utils/streamplayer.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										84
									
								
								utils/streamplayer.c
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| /* | ||||
| * streamplayer.c | ||||
| * | ||||
| * A utility for reading from a stream | ||||
| *  | ||||
| * Copyright (C) 2005, Digium, Inc. | ||||
| * | ||||
| * Russell Bryant <russell@digium.com> | ||||
| * | ||||
| * This program is free software, distributed under the terms of | ||||
| * the GNU General Public License | ||||
| */ | ||||
|  | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <netdb.h> | ||||
| #include <unistd.h> | ||||
| #include <sys/types.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/time.h> | ||||
|  | ||||
|  | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
| 	struct sockaddr_in sin; | ||||
| 	struct hostent *hp; | ||||
| 	int s; | ||||
| 	int res; | ||||
| 	char buf[2048]; | ||||
| 	fd_set wfds; | ||||
| 	struct timeval tv; | ||||
|  | ||||
| 	if (argc != 3) { | ||||
| 		fprintf(stderr, "Usage: ./streamplayer <ip> <port>\n"); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	hp = gethostbyname(argv[1]); | ||||
| 	if (!hp) { | ||||
| 		fprintf(stderr, "Unable to lookup IP for host '%s'\n", argv[1]); | ||||
| 		exit(1); | ||||
| 	} | ||||
|  | ||||
| 	memset(&sin, 0, sizeof(sin)); | ||||
| 	 | ||||
| 	sin.sin_family = AF_INET; | ||||
| 	sin.sin_port = htons(atoi(argv[2])); | ||||
| 	memcpy(&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr)); | ||||
| 	 | ||||
| 	s = socket(AF_INET, SOCK_STREAM, 0); | ||||
| 	 | ||||
| 	if (s < 0) { | ||||
| 		fprintf(stderr, "Unable to allocate socket!\n"); | ||||
| 		exit(1); | ||||
| 	}	 | ||||
|  | ||||
| 	res = connect(s, (struct sockaddr *)&sin, sizeof(sin)); | ||||
| 	 | ||||
| 	if (res) { | ||||
| 		fprintf(stderr, "Unable to connect to host!\n"); | ||||
| 		close(s); | ||||
| 		exit(1);	 | ||||
| 	} | ||||
|  | ||||
| 	while (1) { | ||||
| 		res = read(s, buf, sizeof(buf)); | ||||
|  | ||||
| 		if (res < 1) | ||||
| 			break;		 | ||||
| 	 | ||||
| 		memset(&tv, 0, sizeof(tv));		 | ||||
| 		FD_ZERO(&wfds); | ||||
| 		FD_SET(1, &wfds); | ||||
|  | ||||
| 		select(2, NULL, &wfds, NULL, &tv); | ||||
|  | ||||
| 		if (FD_ISSET(1, &wfds)) | ||||
| 			write(1, buf, res); | ||||
| 	} | ||||
|  | ||||
| 	close(s); | ||||
| 	exit(res); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user