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:
Kevin P. Fleming
2005-08-22 19:29:29 +00:00
parent 69f9c479e7
commit ff971379f4
7 changed files with 341 additions and 69 deletions

View File

@@ -137,3 +137,9 @@ AGI:
behavior has been fixed. If you do not want your script to terminate 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 at the end of AGI being called (e.g. on a hangup) then set SIGHUP to
be ignored within your application. 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.

View File

@@ -1,16 +1,30 @@
; ;
; Music on hold class definitions ; Music on Hold -- Sample Configuration
; ;
[classes]
default => quietmp3:/var/lib/asterisk/mohmp3 [default]
;loud => mp3:/var/lib/asterisk/mohmp3 mode=quietmp3
;random => quietmp3:/var/lib/asterisk/mohmp3,-z directory=/var/lib/asterisk/mohmp3
;unbuffered => mp3nb:/var/lib/asterisk/mohmp3
;quietunbuf => quietmp3nb:/var/lib/asterisk/mohmp3 ; valid mode options:
; Note that the custom mode cannot handle escaped parameters (specifically embedded spaces) ; quietmp3 -- default
;manual => custom:/var/lib/asterisk/mohmp3,/usr/bin/mpg123 -q -r 8000 -f 8192 -b 2048 --mono -s ; mp3 -- loud
; For a custom app, reading from a directory may not be necessary ; mp3nb -- unbuffered
;manual => custom:nodir,/bin/my-dirless-app myarg ; 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 ; 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 ; this, res_musiconhold will skip the files it is not able to
; understand when it loads. ; understand when it loads.
; ;
[moh_files]
;native => /var/lib/asterisk/moh-native ;[native]
;native-random => /var/lib/asterisk/moh-native,r ;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
View File

@@ -1168,7 +1168,6 @@ static int speex_samples(unsigned char *data, int len)
return cnt; return cnt;
} }
int ast_codec_get_samples(struct ast_frame *f) int ast_codec_get_samples(struct ast_frame *f)
{ {
int samples=0; int samples=0;
@@ -1210,3 +1209,35 @@ int ast_codec_get_samples(struct ast_frame *f)
return samples; 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;
}

View File

@@ -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 */ /* Returns the number of samples contained in the frame */
extern int ast_codec_get_samples(struct ast_frame *f); 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 */ /* Gets duration in ms of interpolation frame for a format */
static inline int ast_codec_interp_len(int format) static inline int ast_codec_interp_len(int format)
{ {

View File

@@ -108,12 +108,14 @@ struct moh_files_state {
#define MOH_RANDOMIZE (1 << 3) #define MOH_RANDOMIZE (1 << 3)
struct mohclass { struct mohclass {
char class[80]; char name[MAX_MUSICCLASS];
char dir[256]; char dir[256];
char miscargs[256]; char args[256];
char mode[80];
char filearray[MAX_MOHFILES][MAX_MOHFILE_LEN]; char filearray[MAX_MOHFILES][MAX_MOHFILE_LEN];
unsigned int flags; unsigned int flags;
int total_files; int total_files;
int format;
int pid; /* PID of mpg123 */ int pid; /* PID of mpg123 */
time_t start; time_t start;
pthread_t thread; pthread_t thread;
@@ -212,8 +214,8 @@ static int ast_moh_files_next(struct ast_channel *chan)
return -1; return -1;
} }
if (option_verbose > 2) if (option_debug)
ast_log(LOG_NOTICE, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]); ast_log(LOG_DEBUG, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]);
if (state->samples) if (state->samples)
ast_seekstream(chan->stream, state->samples, SEEK_SET); 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; chan->music_state = NULL;
} else { } else {
if (option_verbose > 2) 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"; argv[argc++] = "8192";
/* Look for extra arguments and add them to the list */ /* 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; argptr = xargs;
while (argptr && !ast_strlen_zero(argptr)) { while (argptr && !ast_strlen_zero(argptr)) {
argv[argc++] = argptr; argv[argc++] = argptr;
@@ -355,7 +357,7 @@ static int spawn_mp3(struct mohclass *class)
} }
} else { } else {
/* Format arguments for argv vector */ /* Format arguments for argv vector */
strncpy(xargs, class->miscargs, sizeof(xargs) - 1); strncpy(xargs, class->args, sizeof(xargs) - 1);
argptr = xargs; argptr = xargs;
while (argptr && !ast_strlen_zero(argptr)) { while (argptr && !ast_strlen_zero(argptr)) {
argv[argc++] = argptr; argv[argc++] = argptr;
@@ -460,6 +462,7 @@ static void *monmp3thread(void *data)
char buf[8192]; char buf[8192];
short sbuf[8192]; short sbuf[8192];
int res, res2; int res, res2;
int len;
struct timeval tv, tv_tmp; struct timeval tv, tv_tmp;
tv.tv_sec = 0; tv.tv_sec = 0;
@@ -495,7 +498,9 @@ static void *monmp3thread(void *data)
if (!class->members) if (!class->members)
continue; continue;
/* Read mp3 audio */ /* 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) { if (!res2) {
close(class->srcfd); close(class->srcfd);
class->srcfd = -1; class->srcfd = -1;
@@ -504,7 +509,7 @@ static void *monmp3thread(void *data)
class->pid = 0; class->pid = 0;
} }
} else } 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; continue;
} }
ast_mutex_lock(&moh_lock); ast_mutex_lock(&moh_lock);
@@ -581,7 +586,7 @@ static struct mohclass *get_mohbyname(char *name)
struct mohclass *moh; struct mohclass *moh;
moh = mohclasses; moh = mohclasses;
while (moh) { while (moh) {
if (!strcasecmp(name, moh->class)) if (!strcasecmp(name, moh->name))
return moh; return moh;
moh = moh->next; 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) static void *moh_alloc(struct ast_channel *chan, void *params)
{ {
struct mohdata *res; struct mohdata *res;
struct mohclass *class; struct mohclass *class = params;
class = params;
res = mohalloc(class); res = mohalloc(class);
if (res) { if (res) {
res->origwfmt = chan->writeformat; res->origwfmt = chan->writeformat;
if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) { if (ast_set_write_format(chan, class->format)) {
ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format\n", chan->name); ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format));
moh_release(NULL, res); moh_release(NULL, res);
res = NULL; res = NULL;
} }
if (option_verbose > 2) 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; return res;
} }
@@ -674,7 +678,8 @@ static int moh_generate(struct ast_channel *chan, void *data, int len, int sampl
if (!moh->parent->pid) if (!moh->parent->pid)
return -1; return -1;
len = samples * 2; len = ast_codec_get_len(moh->parent->format, samples);
if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) { 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); 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; 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; return 0;
memset(&f, 0, sizeof(f)); memset(&f, 0, sizeof(f));
f.frametype = AST_FRAME_VOICE; f.frametype = AST_FRAME_VOICE;
f.subclass = AST_FORMAT_SLINEAR; f.subclass = moh->parent->format;
f.mallocd = 0; f.mallocd = 0;
f.datalen = res; f.datalen = res;
f.samples = res / 2;
f.data = buf + AST_FRIENDLY_OFFSET / 2; f.data = buf + AST_FRIENDLY_OFFSET / 2;
f.offset = AST_FRIENDLY_OFFSET; f.offset = AST_FRIENDLY_OFFSET;
f.samples = ast_codec_get_samples(&f);
if (ast_write(chan, &f) < 0) { if (ast_write(chan, &f) < 0) {
ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
return -1; return -1;
} }
return 0; return 0;
} }
@@ -763,53 +771,42 @@ static int moh_scan_files(struct mohclass *class) {
return class->total_files; 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 #ifdef ZAPATA_MOH
int x; int x;
#endif #endif
ast_mutex_lock(&moh_lock); ast_mutex_lock(&moh_lock);
moh = get_mohbyname(classname); if (get_mohbyname(moh->name)) {
ast_mutex_unlock(&moh_lock); ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
if (moh) { free(moh);
ast_log(LOG_WARNING, "Music on Hold '%s' already exists\n", classname); ast_mutex_unlock(&moh_lock);
return -1; return -1;
} }
moh = malloc(sizeof(struct mohclass)); ast_mutex_unlock(&moh_lock);
if (!moh)
return -1;
memset(moh, 0, sizeof(struct mohclass));
time(&moh->start); time(&moh->start);
moh->start -= respawn_time; moh->start -= respawn_time;
strncpy(moh->class, classname, sizeof(moh->class) - 1);
if (miscargs) { if (!strcasecmp(moh->mode, "files")) {
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 (!moh_scan_files(moh)) { if (!moh_scan_files(moh)) {
ast_moh_free_class(&moh); ast_moh_free_class(&moh);
return -1; 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) if (!strcasecmp(moh->mode, "custom"))
strncpy(moh->dir, param, sizeof(moh->dir) - 1);
if (!strcasecmp(mode, "custom"))
ast_set_flag(moh, MOH_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); 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); ast_set_flag(moh, MOH_QUIET);
moh->srcfd = -1; moh->srcfd = -1;
#ifdef ZAPATA_MOH #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? */ there a better, yet reliable way to do this? */
moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY); moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
if (moh->pseudofd < 0) { if (moh->pseudofd < 0) {
@@ -829,7 +826,7 @@ static int moh_register(char *classname, char *mode, char *param, char *miscargs
return -1; return -1;
} }
} else { } 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); ast_moh_free_class(&moh);
return -1; 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) static int load_moh_classes(void)
{ {
struct ast_config *cfg; struct ast_config *cfg;
struct ast_variable *var; struct ast_variable *var;
struct mohclass *class;
char *data; char *data;
char *args; char *args;
int x = 0; char *cat;
int numclasses = 0;
static int dep_warning = 0;
cfg = ast_config_load("musiconhold.conf"); cfg = ast_config_load("musiconhold.conf");
if (!cfg) if (!cfg)
return 0; 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"); var = ast_variable_browse(cfg, "classes");
while (var) { 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, ':'); data = strchr(var->value, ':');
if (data) { if (data) {
*data++ = '\0'; *data++ = '\0';
@@ -907,26 +983,55 @@ static int load_moh_classes(void)
if (args) if (args)
*args++ = '\0'; *args++ = '\0';
if (!(get_mohbyname(var->name))) { if (!(get_mohbyname(var->name))) {
moh_register(var->name, var->value, data, args); class = moh_class_malloc();
x++; 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 = var->next;
} }
var = ast_variable_browse(cfg, "moh_files"); var = ast_variable_browse(cfg, "moh_files");
while (var) { 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))) { if (!(get_mohbyname(var->name))) {
args = strchr(var->value, ','); args = strchr(var->value, ',');
if (args) if (args)
*args++ = '\0'; *args++ = '\0';
moh_register(var->name, "files", var->value, args); class = moh_class_malloc();
x++; 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; var = var->next;
} }
ast_config_destroy(cfg); ast_config_destroy(cfg);
return x;
return numclasses;
} }
static void ast_moh_destroy(void) 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) if (!class->total_files)
continue; 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++) for (i = 0; i < class->total_files; i++)
ast_cli(fd, "\tFile: %s\n", class->filearray[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; 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 = { { "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 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) static void init_classes(void)
@@ -1033,6 +1157,7 @@ int load_module(void)
ast_register_atexit(ast_moh_destroy); ast_register_atexit(ast_moh_destroy);
ast_cli_register(&cli_moh); ast_cli_register(&cli_moh);
ast_cli_register(&cli_moh_files_show); ast_cli_register(&cli_moh_files_show);
ast_cli_register(&cli_moh_classes_show);
if (!res) if (!res)
res = ast_register_application(app1, moh1_exec, synopsis1, descrip1); res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
if (!res) if (!res)

View File

@@ -21,7 +21,7 @@ ifeq ($(findstring BSD,${OSARCH}),BSD)
CFLAGS+=-I$(CROSS_COMPILE_TARGET)/usr/local/include -L$(CROSS_COMPILE_TARGET)/usr/local/lib CFLAGS+=-I$(CROSS_COMPILE_TARGET)/usr/local/include -L$(CROSS_COMPILE_TARGET)/usr/local/lib
endif 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/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) 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 smsq: smsq.o
$(CC) $(CFLAGS) -o smsq ${SOL} smsq.o -lpopt $(CC) $(CFLAGS) -o smsq ${SOL} smsq.o -lpopt
streamplayer: streamplayer.o
$(CC) $(CFLAGS) -o streamplayer ${SOL} streamplayer.o
ifneq ($(wildcard .depend),) ifneq ($(wildcard .depend),)
include .depend include .depend
endif endif

84
utils/streamplayer.c Executable file
View 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);
}