Various moh fixes (bug #3291)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@4724 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.2-netsec
Mark Spencer 21 years ago
parent 89fb8c1037
commit 03458dc73a

@ -79,7 +79,6 @@ static int respawn_time = 20;
struct moh_files_state { struct moh_files_state {
struct mohclass *class; struct mohclass *class;
struct ast_filestream *stream;
int origwfmt; int origwfmt;
int samples; int samples;
int sample_queue; int sample_queue;
@ -87,18 +86,19 @@ struct moh_files_state {
unsigned char save_pos; unsigned char save_pos;
}; };
#define MOH_QUIET (1 << 0)
#define MOH_SINGLE (1 << 1)
#define MOH_CUSTOM (1 << 2)
#define MOH_RANDOMIZE (1 << 3)
struct mohclass { struct mohclass {
char class[80]; char class[80];
char dir[256]; char dir[256];
char miscargs[256]; char miscargs[256];
char filearray[MAX_MOHFILES][MAX_MOHFILE_LEN]; char filearray[MAX_MOHFILES][MAX_MOHFILE_LEN];
unsigned int flags;
int total_files; int total_files;
int destroyme;
int pid; /* PID of mpg123 */ int pid; /* PID of mpg123 */
int quiet;
int single;
int custom;
int randomize;
time_t start; time_t start;
pthread_t thread; pthread_t thread;
struct mohdata *members; struct mohdata *members;
@ -154,7 +154,7 @@ static int ast_moh_files_next(struct ast_channel *chan) {
state->pos++; state->pos++;
} }
if (state->class->randomize) { if (ast_test_flag(state->class, MOH_RANDOMIZE)) {
srand(time(NULL)+getpid()+strlen(chan->name)-state->class->total_files); srand(time(NULL)+getpid()+strlen(chan->name)-state->class->total_files);
state->pos = rand(); state->pos = rand();
} }
@ -175,19 +175,18 @@ static int ast_moh_files_next(struct ast_channel *chan) {
if (option_verbose > 2) if (option_verbose > 2)
ast_log(LOG_NOTICE, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]); ast_log(LOG_NOTICE, "%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);
return state->pos; return 0;
} }
static struct ast_frame *moh_files_readframe(struct ast_channel *chan) { static struct ast_frame *moh_files_readframe(struct ast_channel *chan) {
struct ast_frame *f = NULL; struct ast_frame *f = NULL;
if (!chan->stream || !(f = ast_readframe(chan->stream))) { if (!(chan->stream && (f = ast_readframe(chan->stream)))) {
if (ast_moh_files_next(chan) > -1) if (!ast_moh_files_next(chan))
f = ast_readframe(chan->stream); f = ast_readframe(chan->stream);
} }
@ -224,13 +223,12 @@ static void *moh_files_alloc(struct ast_channel *chan, void *params)
struct mohclass *class = params; struct mohclass *class = params;
int allocated = 0; int allocated = 0;
if ((!chan->music_state) && ((state = malloc(sizeof(struct moh_files_state))))) { if (!chan->music_state && (state = malloc(sizeof(struct moh_files_state)))) {
chan->music_state = state; chan->music_state = state;
allocated = 1; allocated = 1;
} else } else
state = chan->music_state; state = chan->music_state;
if (state) { if (state) {
if (allocated || state->class != class) { if (allocated || state->class != class) {
/* initialize */ /* initialize */
@ -246,10 +244,8 @@ 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", (char *)params, chan->name); ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->class, chan->name);
} }
} }
return chan->music_state; return chan->music_state;
@ -281,7 +277,7 @@ static int spawn_mp3(struct mohclass *class)
return -1; return -1;
} }
if (!class->custom) { if (!ast_test_flag(class, MOH_CUSTOM)) {
argv[argc++] = "mpg123"; argv[argc++] = "mpg123";
argv[argc++] = "-q"; argv[argc++] = "-q";
argv[argc++] = "-s"; argv[argc++] = "-s";
@ -289,14 +285,14 @@ static int spawn_mp3(struct mohclass *class)
argv[argc++] = "-r"; argv[argc++] = "-r";
argv[argc++] = "8000"; argv[argc++] = "8000";
if (!class->single) { if (!ast_test_flag(class, MOH_SINGLE)) {
argv[argc++] = "-b"; argv[argc++] = "-b";
argv[argc++] = "2048"; argv[argc++] = "2048";
} }
argv[argc++] = "-f"; argv[argc++] = "-f";
if (class->quiet) if (ast_test_flag(class, MOH_QUIET))
argv[argc++] = "4096"; argv[argc++] = "4096";
else else
argv[argc++] = "8192"; argv[argc++] = "8192";
@ -334,10 +330,10 @@ static int spawn_mp3(struct mohclass *class)
} else { } else {
while ((de = readdir(dir)) && (files < MAX_MP3S)) { while ((de = readdir(dir)) && (files < MAX_MP3S)) {
if ((strlen(de->d_name) > 3) && if ((strlen(de->d_name) > 3) &&
((class->custom && ((ast_test_flag(class, MOH_CUSTOM) &&
(!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") ||
!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) ||
|| !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) { !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
strncpy(fns[files], de->d_name, sizeof(fns[files]) - 1); strncpy(fns[files], de->d_name, sizeof(fns[files]) - 1);
argv[argc++] = fns[files]; argv[argc++] = fns[files];
files++; files++;
@ -389,7 +385,7 @@ static int spawn_mp3(struct mohclass *class)
} }
/* Child */ /* Child */
chdir(class->dir); chdir(class->dir);
if(class->custom) { if (ast_test_flag(class, MOH_CUSTOM)) {
execv(argv[0], argv); execv(argv[0], argv);
} else { } else {
/* Default install is /usr/local/bin */ /* Default install is /usr/local/bin */
@ -525,7 +521,7 @@ static int moh1_exec(struct ast_channel *chan, void *data)
return -1; return -1;
} }
if (ast_moh_start(chan, NULL)) { if (ast_moh_start(chan, NULL)) {
ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi((char *)data), chan->name); ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name);
return -1; return -1;
} }
res = ast_safe_sleep(chan, atoi(data) * 1000); res = ast_safe_sleep(chan, atoi(data) * 1000);
@ -616,13 +612,8 @@ static void *moh_alloc(struct ast_channel *chan, void *params)
struct mohdata *res; struct mohdata *res;
struct mohclass *class; struct mohclass *class;
class = params; class = params;
if (class)
res = mohalloc(class); res = mohalloc(class);
else {
if (strcasecmp(params, "default"))
ast_log(LOG_WARNING, "No class: %s\n", (char *)params);
res = NULL;
}
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, AST_FORMAT_SLINEAR)) {
@ -631,7 +622,7 @@ static void *moh_alloc(struct ast_channel *chan, void *params)
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", (char *)params, chan->name); ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->class, chan->name);
} }
return res; return res;
} }
@ -642,11 +633,13 @@ static int moh_generate(struct ast_channel *chan, void *data, int len, int sampl
struct mohdata *moh = data; struct mohdata *moh = data;
short buf[1280 + AST_FRIENDLY_OFFSET / 2]; short buf[1280 + AST_FRIENDLY_OFFSET / 2];
int res; int res;
if (!moh->parent->pid) if (!moh->parent->pid)
return -1; return -1;
len = samples * 2; len = samples * 2;
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), (int)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;
} }
res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len); res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
@ -655,7 +648,9 @@ static int moh_generate(struct ast_channel *chan, void *data, int len, int sampl
ast_log(LOG_WARNING, "Read only %d of %d bytes: %s\n", res, len, strerror(errno)); ast_log(LOG_WARNING, "Read only %d of %d bytes: %s\n", res, len, strerror(errno));
} }
#endif #endif
if (res > 0) { if (res <= 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 = AST_FORMAT_SLINEAR;
@ -668,7 +663,6 @@ static int moh_generate(struct ast_channel *chan, void *data, int len, int sampl
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;
} }
@ -759,7 +753,7 @@ static int moh_register(char *classname, char *mode, char *param, char *miscargs
if (miscargs) { if (miscargs) {
strncpy(moh->miscargs, miscargs, sizeof(moh->miscargs) - 1); strncpy(moh->miscargs, miscargs, sizeof(moh->miscargs) - 1);
if (strchr(miscargs,'r')) if (strchr(miscargs,'r'))
moh->randomize=1; ast_set_flag(moh, MOH_RANDOMIZE);
} }
if (!strcasecmp(mode, "files")) { if (!strcasecmp(mode, "files")) {
if (param) if (param)
@ -774,11 +768,11 @@ static int moh_register(char *classname, char *mode, char *param, char *miscargs
strncpy(moh->dir, param, sizeof(moh->dir) - 1); strncpy(moh->dir, param, sizeof(moh->dir) - 1);
if (!strcasecmp(mode, "custom")) if (!strcasecmp(mode, "custom"))
moh->custom = 1; ast_set_flag(moh, MOH_CUSTOM);
else if (!strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3nb")) else if (!strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3nb"))
moh->single = 1; ast_set_flag(moh, MOH_SINGLE);
else if (!strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb")) else if (!strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb"))
moh->quiet = 1; ast_set_flag(moh, MOH_QUIET);
moh->srcfd = -1; moh->srcfd = -1;
#ifdef ZAPATA_MOH #ifdef ZAPATA_MOH
@ -865,19 +859,20 @@ static int load_moh_classes(void)
char *data; char *data;
char *args; char *args;
int x = 0; int x = 0;
cfg = ast_load("musiconhold.conf"); cfg = ast_load("musiconhold.conf");
if (cfg) {
if (!cfg)
return 0;
var = ast_variable_browse(cfg, "classes"); var = ast_variable_browse(cfg, "classes");
while (var) { while (var) {
data = strchr(var->value, ':'); data = strchr(var->value, ':');
if (data) { if (data) {
*data = '\0'; *data++ = '\0';
data++;
args = strchr(data, ','); args = strchr(data, ',');
if (args) { if (args)
*args = '\0'; *args++ = '\0';
args++;
}
if (!(get_mohbyname(var->name))) { if (!(get_mohbyname(var->name))) {
moh_register(var->name, var->value, data, args); moh_register(var->name, var->value, data, args);
x++; x++;
@ -889,10 +884,8 @@ static int load_moh_classes(void)
while (var) { while (var) {
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';
args++;
}
moh_register(var->name, "files", var->value, args); moh_register(var->name, "files", var->value, args);
x++; x++;
} }
@ -900,7 +893,6 @@ static int load_moh_classes(void)
} }
ast_destroy(cfg); ast_destroy(cfg);
}
return x; return x;
} }
@ -909,6 +901,7 @@ static void ast_moh_destroy(void)
struct mohclass *moh,*tmp; struct mohclass *moh,*tmp;
char buff[8192]; char buff[8192];
int bytes, tbytes=0, stime = 0, pid = 0; int bytes, tbytes=0, stime = 0, pid = 0;
if (option_verbose > 1) if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n"); ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
ast_mutex_lock(&moh_lock); ast_mutex_lock(&moh_lock);
@ -917,11 +910,11 @@ static void ast_moh_destroy(void)
while (moh) { while (moh) {
if (moh->pid) { if (moh->pid) {
ast_log(LOG_DEBUG, "killing %d!\n", moh->pid); ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
stime = time(NULL); stime = time(NULL) + 5;
pid = moh->pid; pid = moh->pid;
moh->pid = 0; moh->pid = 0;
kill(pid, SIGKILL); kill(pid, SIGKILL);
while ((bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime + 5) { while ((bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime) {
tbytes = tbytes + bytes; tbytes = tbytes + bytes;
} }
ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes); ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
@ -935,9 +928,9 @@ static void ast_moh_destroy(void)
ast_mutex_unlock(&moh_lock); ast_mutex_unlock(&moh_lock);
} }
static void moh_on_off(int on) { static void moh_on_off(int on) {
struct ast_channel *chan = ast_channel_walk_locked(NULL); struct ast_channel *chan = ast_channel_walk_locked(NULL);
while (chan) { while (chan) {
if (ast_test_flag(chan, AST_FLAG_MOH)) { if (ast_test_flag(chan, AST_FLAG_MOH)) {
if (on) if (on)
@ -952,7 +945,8 @@ static void moh_on_off(int on) {
static int moh_cli(int fd, int argc, char *argv[]) static int moh_cli(int fd, int argc, char *argv[])
{ {
int x = 0; int x;
moh_on_off(0); moh_on_off(0);
ast_moh_destroy(); ast_moh_destroy();
x = load_moh_classes(); x = load_moh_classes();
@ -984,8 +978,9 @@ static struct ast_cli_entry cli_moh = { { "moh", "reload"}, moh_cli, "Music On
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 int init_classes(void) { static void init_classes(void) {
struct mohclass *moh; struct mohclass *moh;
load_moh_classes(); load_moh_classes();
moh = mohclasses; moh = mohclasses;
while (moh) { while (moh) {
@ -993,12 +988,12 @@ static int init_classes(void) {
moh_scan_files(moh); moh_scan_files(moh);
moh = moh->next; moh = moh->next;
} }
return 0;
} }
int load_module(void) int load_module(void)
{ {
int res; int res;
ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup); ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
res = ast_register_application(app0, moh0_exec, synopsis0, descrip0); res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
ast_register_atexit(ast_moh_destroy); ast_register_atexit(ast_moh_destroy);
@ -1009,14 +1004,17 @@ int load_module(void)
if (!res) if (!res)
res = ast_register_application(app2, moh2_exec, synopsis2, descrip2); res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
return init_classes(); init_classes();
return 0;
} }
int reload(void) int reload(void)
{ {
return init_classes(); init_classes();
}
return 0;
}
int unload_module(void) int unload_module(void)
{ {

Loading…
Cancel
Save