mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-04 11:58:52 +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
|
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.
|
||||||
|
@@ -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
33
frame.c
@@ -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;
|
||||||
|
}
|
||||||
|
@@ -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)
|
||||||
{
|
{
|
||||||
|
@@ -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)
|
||||||
|
@@ -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
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