mirror of
https://github.com/asterisk/asterisk.git
synced 2025-10-10 14:51:09 +00:00
Merge anthm's native MOH patch (bug #2639) he promises me he'll rid it of ast_flag_moh...
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@4552 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
19
channel.c
19
channel.c
@@ -613,6 +613,10 @@ void ast_channel_free(struct ast_channel *chan)
|
||||
chan->monitor->stop( chan, 0 );
|
||||
}
|
||||
|
||||
/* If there is native format music-on-hold state, free it */
|
||||
if(chan->music_state)
|
||||
ast_moh_cleanup(chan);
|
||||
|
||||
/* Free translatosr */
|
||||
if (chan->pvt->readtrans)
|
||||
ast_translator_free_path(chan->pvt->readtrans);
|
||||
@@ -2960,22 +2964,26 @@ unsigned int ast_get_group(char *s)
|
||||
return group;
|
||||
}
|
||||
|
||||
|
||||
static int (*ast_moh_start_ptr)(struct ast_channel *, char *) = NULL;
|
||||
static void (*ast_moh_stop_ptr)(struct ast_channel *) = NULL;
|
||||
static void (*ast_moh_cleanup_ptr)(struct ast_channel *) = NULL;
|
||||
|
||||
|
||||
void ast_install_music_functions(int (*start_ptr)(struct ast_channel *, char *),
|
||||
void (*stop_ptr)(struct ast_channel *))
|
||||
void (*stop_ptr)(struct ast_channel *),
|
||||
void (*cleanup_ptr)(struct ast_channel *)
|
||||
)
|
||||
{
|
||||
ast_moh_start_ptr = start_ptr;
|
||||
ast_moh_stop_ptr = stop_ptr;
|
||||
ast_moh_cleanup_ptr = cleanup_ptr;
|
||||
}
|
||||
|
||||
void ast_uninstall_music_functions(void)
|
||||
{
|
||||
ast_moh_start_ptr = NULL;
|
||||
ast_moh_stop_ptr = NULL;
|
||||
ast_moh_cleanup_ptr = NULL;
|
||||
}
|
||||
|
||||
/*! Turn on/off music on hold on a given channel */
|
||||
@@ -2996,3 +3004,10 @@ void ast_moh_stop(struct ast_channel *chan)
|
||||
if(ast_moh_stop_ptr)
|
||||
ast_moh_stop_ptr(chan);
|
||||
}
|
||||
|
||||
void ast_moh_cleanup(struct ast_channel *chan)
|
||||
{
|
||||
if(ast_moh_cleanup_ptr)
|
||||
ast_moh_cleanup_ptr(chan);
|
||||
}
|
||||
|
||||
|
17
file.c
17
file.c
@@ -431,8 +431,12 @@ static int ast_filehelper(const char *filename, const char *filename2, const cha
|
||||
res = ret ? ret : -1;
|
||||
return res;
|
||||
}
|
||||
|
||||
struct ast_filestream *ast_openstream(struct ast_channel *chan, const char *filename, const char *preflang)
|
||||
{
|
||||
return ast_openstream_full(chan, filename, preflang, 0);
|
||||
}
|
||||
|
||||
struct ast_filestream *ast_openstream_full(struct ast_channel *chan, const char *filename, const char *preflang, int asis)
|
||||
{
|
||||
/* This is a fairly complex routine. Essentially we should do
|
||||
the following:
|
||||
@@ -452,10 +456,13 @@ struct ast_filestream *ast_openstream(struct ast_channel *chan, const char *file
|
||||
char filename3[256]="";
|
||||
char *endpart;
|
||||
int res;
|
||||
ast_stopstream(chan);
|
||||
/* do this first, otherwise we detect the wrong writeformat */
|
||||
if (chan->generator)
|
||||
ast_deactivate_generator(chan);
|
||||
|
||||
if (!asis) {
|
||||
/* do this first, otherwise we detect the wrong writeformat */
|
||||
ast_stopstream(chan);
|
||||
if (chan->generator)
|
||||
ast_deactivate_generator(chan);
|
||||
}
|
||||
if (preflang && !ast_strlen_zero(preflang)) {
|
||||
strncpy(filename3, filename, sizeof(filename3) - 1);
|
||||
endpart = strrchr(filename3, '/');
|
||||
|
@@ -88,7 +88,8 @@ struct ast_channel {
|
||||
|
||||
/*! Default music class */
|
||||
char musicclass[MAX_LANGUAGE];
|
||||
|
||||
/*! Music State*/
|
||||
void *music_state;
|
||||
/*! Current generator data if there is any */
|
||||
void *generatordata;
|
||||
/*! Current active data generator */
|
||||
@@ -230,6 +231,7 @@ struct ast_channel {
|
||||
#define AST_FLAG_BLOCKING (1 << 3) /* if we are blocking */
|
||||
#define AST_FLAG_ZOMBIE (1 << 4) /* if we are a zombie */
|
||||
#define AST_FLAG_EXCEPTION (1 << 5) /* if there is a pending exception */
|
||||
#define AST_FLAG_MOH (1 << 6) /* XXX anthm promises me this will disappear XXX listening to moh */
|
||||
|
||||
struct ast_bridge_config {
|
||||
int play_to_caller;
|
||||
|
@@ -198,6 +198,15 @@ int ast_closestream(struct ast_filestream *f);
|
||||
*/
|
||||
struct ast_filestream *ast_openstream(struct ast_channel *chan, const char *filename, const char *preflang);
|
||||
|
||||
//! Opens stream for use in seeking, playing
|
||||
/*!
|
||||
* \param chan channel to work with
|
||||
* \param filename to use
|
||||
* \param preflang prefered language to use
|
||||
* \param asis if set, don't clear generators
|
||||
* Returns a ast_filestream pointer if it opens the file, NULL on error
|
||||
*/
|
||||
struct ast_filestream *ast_openstream_full(struct ast_channel *chan, const char *filename, const char *preflang, int asis);
|
||||
//! Opens stream for use in seeking, playing
|
||||
/*!
|
||||
* \param chan channel to work with
|
||||
|
@@ -25,8 +25,11 @@ extern int ast_moh_start(struct ast_channel *chan, char *mclass);
|
||||
extern void ast_moh_stop(struct ast_channel *chan);
|
||||
|
||||
extern void ast_install_music_functions(int (*start_ptr)(struct ast_channel *, char *),
|
||||
void (*stop_ptr)(struct ast_channel *));
|
||||
void (*stop_ptr)(struct ast_channel *),
|
||||
void (*cleanup_ptr)(struct ast_channel *));
|
||||
|
||||
extern void ast_uninstall_music_functions(void);
|
||||
void ast_moh_cleanup(struct ast_channel *chan);
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
}
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <../astconf.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <asterisk/translate.h>
|
||||
@@ -25,6 +26,7 @@
|
||||
#include <asterisk/config.h>
|
||||
#include <asterisk/utils.h>
|
||||
#include <stdlib.h>
|
||||
#include <asterisk/cli.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
@@ -45,6 +47,8 @@
|
||||
#endif
|
||||
#include <unistd.h>
|
||||
#include <sys/ioctl.h>
|
||||
#define MAX_MOHFILES 512
|
||||
#define MAX_MOHFILE_LEN 128
|
||||
|
||||
static char *app0 = "MusicOnHold";
|
||||
static char *app1 = "WaitMusicOnHold";
|
||||
@@ -73,15 +77,28 @@ static char *descrip2 = "SetMusicOnHold(class): "
|
||||
|
||||
static int respawn_time = 20;
|
||||
|
||||
struct moh_files_state {
|
||||
struct mohclass *class;
|
||||
struct ast_filestream *stream;
|
||||
int origwfmt;
|
||||
int samples;
|
||||
int sample_queue;
|
||||
unsigned char pos;
|
||||
unsigned char save_pos;
|
||||
};
|
||||
|
||||
struct mohclass {
|
||||
char class[80];
|
||||
char dir[256];
|
||||
char miscargs[256];
|
||||
char filearray[MAX_MOHFILES][MAX_MOHFILE_LEN];
|
||||
int total_files;
|
||||
int destroyme;
|
||||
int pid; /* PID of mpg123 */
|
||||
int quiet;
|
||||
int single;
|
||||
int custom;
|
||||
int randomize;
|
||||
time_t start;
|
||||
pthread_t thread;
|
||||
struct mohdata *members;
|
||||
@@ -101,17 +118,154 @@ struct mohdata {
|
||||
|
||||
static struct mohclass *mohclasses;
|
||||
|
||||
|
||||
AST_MUTEX_DEFINE_STATIC(moh_lock);
|
||||
|
||||
#define LOCAL_MPG_123 "/usr/local/bin/mpg123"
|
||||
#define MPG_123 "/usr/bin/mpg123"
|
||||
#define MAX_MP3S 256
|
||||
|
||||
static void moh_files_release(struct ast_channel *chan, void *data)
|
||||
{
|
||||
struct moh_files_state *state = chan->music_state;
|
||||
|
||||
if (chan && state) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
|
||||
|
||||
if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
|
||||
ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt);
|
||||
}
|
||||
state->save_pos = state->pos + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int ast_moh_files_next(struct ast_channel *chan) {
|
||||
struct moh_files_state *state = chan->music_state;
|
||||
|
||||
if(state->save_pos) {
|
||||
state->pos = state->save_pos - 1;
|
||||
state->save_pos = 0;
|
||||
} else {
|
||||
state->samples = 0;
|
||||
if (chan->stream) {
|
||||
ast_closestream(chan->stream);
|
||||
chan->stream = NULL;
|
||||
state->pos++;
|
||||
}
|
||||
|
||||
if (state->class->randomize) {
|
||||
srand(time(NULL)+getpid()+strlen(chan->name)-state->class->total_files);
|
||||
state->pos = rand();
|
||||
}
|
||||
}
|
||||
|
||||
state->pos = state->pos % state->class->total_files;
|
||||
|
||||
if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
|
||||
ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
|
||||
return -1;
|
||||
}
|
||||
if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
|
||||
ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
|
||||
state->pos++;
|
||||
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 (state->samples)
|
||||
ast_seekstream(chan->stream, state->samples, SEEK_SET);
|
||||
|
||||
return state->pos;
|
||||
}
|
||||
|
||||
|
||||
static struct ast_frame *moh_files_readframe(struct ast_channel *chan) {
|
||||
struct ast_frame *f = NULL;
|
||||
|
||||
if (!chan->stream || !(f = ast_readframe(chan->stream))) {
|
||||
if (ast_moh_files_next(chan) > -1)
|
||||
f = ast_readframe(chan->stream);
|
||||
}
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static int moh_files_generator(struct ast_channel *chan, void *data, int len, int samples)
|
||||
{
|
||||
struct moh_files_state *state = chan->music_state;
|
||||
struct ast_frame *f = NULL;
|
||||
int res = 0;
|
||||
state->sample_queue += samples;
|
||||
|
||||
while(state->sample_queue > 0) {
|
||||
if ((f = moh_files_readframe(chan))) {
|
||||
state->samples += f->samples;
|
||||
res = ast_write(chan, f);
|
||||
ast_frfree(f);
|
||||
if(res < 0) {
|
||||
ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
state->sample_queue -= f->samples;
|
||||
} else
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static void *moh_files_alloc(struct ast_channel *chan, void *params)
|
||||
{
|
||||
struct moh_files_state *state;
|
||||
struct mohclass *class = params;
|
||||
int allocated = 0;
|
||||
|
||||
if ((!chan->music_state) && ((state = malloc(sizeof(struct moh_files_state))))) {
|
||||
chan->music_state = state;
|
||||
allocated = 1;
|
||||
} else
|
||||
state = chan->music_state;
|
||||
|
||||
|
||||
if(state) {
|
||||
if (allocated || state->class != class) {
|
||||
/* initialize */
|
||||
memset(state, 0, sizeof(struct moh_files_state));
|
||||
state->class = class;
|
||||
}
|
||||
|
||||
state->origwfmt = chan->writeformat;
|
||||
|
||||
if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
|
||||
ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
|
||||
free(chan->music_state);
|
||||
chan->music_state = NULL;
|
||||
} else {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", (char *)params, chan->name);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return chan->music_state;
|
||||
}
|
||||
|
||||
static struct ast_generator moh_file_stream =
|
||||
{
|
||||
alloc: moh_files_alloc,
|
||||
release: moh_files_release,
|
||||
generate: moh_files_generator,
|
||||
};
|
||||
|
||||
static int spawn_mp3(struct mohclass *class)
|
||||
{
|
||||
int fds[2];
|
||||
int files;
|
||||
int files=0;
|
||||
char fns[MAX_MP3S][80];
|
||||
char *argv[MAX_MP3S + 50];
|
||||
char xargs[256];
|
||||
@@ -119,11 +273,13 @@ static int spawn_mp3(struct mohclass *class)
|
||||
int argc = 0;
|
||||
DIR *dir;
|
||||
struct dirent *de;
|
||||
|
||||
|
||||
dir = opendir(class->dir);
|
||||
if (!dir && !strstr(class->dir,"http://") && !strstr(class->dir,"HTTP://")) {
|
||||
ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!class->custom) {
|
||||
argv[argc++] = "mpg123";
|
||||
@@ -137,14 +293,14 @@ static int spawn_mp3(struct mohclass *class)
|
||||
argv[argc++] = "-b";
|
||||
argv[argc++] = "2048";
|
||||
}
|
||||
|
||||
|
||||
argv[argc++] = "-f";
|
||||
|
||||
|
||||
if (class->quiet)
|
||||
argv[argc++] = "4096";
|
||||
else
|
||||
argv[argc++] = "8192";
|
||||
|
||||
|
||||
/* Look for extra arguments and add them to the list */
|
||||
strncpy(xargs, class->miscargs, sizeof(xargs) - 1);
|
||||
argptr = xargs;
|
||||
@@ -156,7 +312,7 @@ static int spawn_mp3(struct mohclass *class)
|
||||
argptr++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
} else {
|
||||
/* Format arguments for argv vector */
|
||||
strncpy(xargs, class->miscargs, sizeof(xargs) - 1);
|
||||
argptr = xargs;
|
||||
@@ -171,16 +327,17 @@ static int spawn_mp3(struct mohclass *class)
|
||||
}
|
||||
|
||||
files = 0;
|
||||
if (strstr(class->dir,"http://") || strstr(class->dir,"HTTP://"))
|
||||
{
|
||||
if (strstr(class->dir,"http://") || strstr(class->dir,"HTTP://")) {
|
||||
strncpy(fns[files], class->dir, sizeof(fns[files]) - 1);
|
||||
argv[argc++] = fns[files];
|
||||
files++;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
while((de = readdir(dir)) && (files < MAX_MP3S)) {
|
||||
if ((strlen(de->d_name) > 3) && !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3")) {
|
||||
if ((strlen(de->d_name) > 3) &&
|
||||
((class->custom &&
|
||||
(!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, ".mp3"))) {
|
||||
strncpy(fns[files], de->d_name, sizeof(fns[files]) - 1);
|
||||
argv[argc++] = fns[files];
|
||||
files++;
|
||||
@@ -189,6 +346,7 @@ static int spawn_mp3(struct mohclass *class)
|
||||
}
|
||||
argv[argc] = NULL;
|
||||
closedir(dir);
|
||||
|
||||
if (pipe(fds)) {
|
||||
ast_log(LOG_WARNING, "Pipe failed\n");
|
||||
return -1;
|
||||
@@ -229,18 +387,19 @@ static int spawn_mp3(struct mohclass *class)
|
||||
close(x);
|
||||
}
|
||||
}
|
||||
/* Child */
|
||||
chdir(class->dir);
|
||||
if(class->custom) {
|
||||
/* Child */
|
||||
|
||||
if(class->custom) {
|
||||
chdir(class->dir);
|
||||
execv(argv[0], argv);
|
||||
} else {
|
||||
/* Default install is /usr/local/bin */
|
||||
execv(LOCAL_MPG_123, argv);
|
||||
/* Many places have it in /usr/bin */
|
||||
execv(MPG_123, argv);
|
||||
/* Check PATH as a last-ditch effort */
|
||||
execvp("mpg123", argv);
|
||||
}
|
||||
} else {
|
||||
/* Default install is /usr/local/bin */
|
||||
execv(LOCAL_MPG_123, argv);
|
||||
/* Many places have it in /usr/bin */
|
||||
execv(MPG_123, argv);
|
||||
/* Check PATH as a last-ditch effort */
|
||||
execvp("mpg123", argv);
|
||||
}
|
||||
ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
|
||||
close(fds[1]);
|
||||
exit(1);
|
||||
@@ -456,8 +615,7 @@ static void *moh_alloc(struct ast_channel *chan, void *params)
|
||||
{
|
||||
struct mohdata *res;
|
||||
struct mohclass *class;
|
||||
ast_mutex_lock(&moh_lock);
|
||||
class = get_mohbyname(params);
|
||||
class = params;
|
||||
if (class)
|
||||
res = mohalloc(class);
|
||||
else {
|
||||
@@ -465,7 +623,6 @@ static void *moh_alloc(struct ast_channel *chan, void *params)
|
||||
ast_log(LOG_WARNING, "No class: %s\n", (char *)params);
|
||||
res = NULL;
|
||||
}
|
||||
ast_mutex_unlock(&moh_lock);
|
||||
if (res) {
|
||||
res->origwfmt = chan->writeformat;
|
||||
if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
|
||||
@@ -473,10 +630,6 @@ static void *moh_alloc(struct ast_channel *chan, void *params)
|
||||
moh_release(NULL, res);
|
||||
res = NULL;
|
||||
}
|
||||
#if 0
|
||||
/* Allow writes to interrupt */
|
||||
chan->writeinterrupt = 1;
|
||||
#endif
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", (char *)params, chan->name);
|
||||
}
|
||||
@@ -489,7 +642,8 @@ static int moh_generate(struct ast_channel *chan, void *data, int len, int sampl
|
||||
struct mohdata *moh = data;
|
||||
short buf[1280 + AST_FRIENDLY_OFFSET / 2];
|
||||
int res;
|
||||
|
||||
if(!moh->parent->pid)
|
||||
return - 1;
|
||||
len = samples * 2;
|
||||
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);
|
||||
@@ -525,6 +679,58 @@ static struct ast_generator mohgen =
|
||||
generate: moh_generate,
|
||||
};
|
||||
|
||||
static int moh_scan_files(struct mohclass *class) {
|
||||
|
||||
DIR *files_DIR;
|
||||
struct dirent *files_dirent;
|
||||
char path[512];
|
||||
char filepath[MAX_MOHFILE_LEN];
|
||||
char *scan;
|
||||
struct stat statbuf;
|
||||
int dirnamelen;
|
||||
int i;
|
||||
|
||||
files_DIR = opendir(class->dir);
|
||||
if (!files_DIR) {
|
||||
ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist", class->dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
class->total_files = 0;
|
||||
dirnamelen = strlen(class->dir) + 2;
|
||||
getcwd(path, 512);
|
||||
chdir(class->dir);
|
||||
memset(class->filearray, 0, MAX_MOHFILES*MAX_MOHFILE_LEN);
|
||||
|
||||
while ((files_dirent = readdir(files_DIR))) {
|
||||
if ((strlen(files_dirent->d_name) < 4) || ((strlen(files_dirent->d_name) + dirnamelen) >= MAX_MOHFILE_LEN))
|
||||
continue;
|
||||
|
||||
snprintf(filepath, MAX_MOHFILE_LEN, "%s/%s", class->dir, files_dirent->d_name);
|
||||
|
||||
if (stat(filepath, &statbuf))
|
||||
continue;
|
||||
|
||||
if (!S_ISREG(statbuf.st_mode))
|
||||
continue;
|
||||
|
||||
if ((scan = strrchr(filepath, '.')))
|
||||
*scan = '\0';
|
||||
|
||||
/* if the file is present in multiple formats, ensure we only put it into the list once */
|
||||
for (i = 0; i < class->total_files; i++)
|
||||
if (!strcmp(filepath, class->filearray[i]))
|
||||
break;
|
||||
|
||||
if (i == class->total_files)
|
||||
strcpy(class->filearray[class->total_files++], filepath);
|
||||
}
|
||||
|
||||
closedir(files_DIR);
|
||||
chdir(path);
|
||||
return class->total_files;
|
||||
}
|
||||
|
||||
static int moh_register(char *classname, char *mode, char *param, char *miscargs)
|
||||
{
|
||||
struct mohclass *moh;
|
||||
@@ -545,16 +751,30 @@ static int moh_register(char *classname, char *mode, char *param, char *miscargs
|
||||
time(&moh->start);
|
||||
moh->start -= respawn_time;
|
||||
strncpy(moh->class, classname, sizeof(moh->class) - 1);
|
||||
if (miscargs)
|
||||
if (miscargs) {
|
||||
strncpy(moh->miscargs, miscargs, sizeof(moh->miscargs) - 1);
|
||||
if (!strcasecmp(mode, "mp3") || !strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb") || !strcasecmp(mode, "httpmp3") || !strcasecmp(mode, "custom")) {
|
||||
if (strchr(miscargs,'r'))
|
||||
moh->randomize=1;
|
||||
}
|
||||
if (!strcasecmp(mode, "files")) {
|
||||
if (param)
|
||||
strncpy(moh->dir, param, sizeof(moh->dir) - 1);
|
||||
if (!moh_scan_files(moh)) {
|
||||
free(moh);
|
||||
return -1;
|
||||
}
|
||||
} else if (!strcasecmp(mode, "mp3") || !strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb") || !strcasecmp(mode, "httpmp3") || !strcasecmp(mode, "custom")) {
|
||||
|
||||
if (param)
|
||||
strncpy(moh->dir, param, sizeof(moh->dir) - 1);
|
||||
|
||||
if (!strcasecmp(mode, "custom"))
|
||||
moh->custom = 1;
|
||||
if (!strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3nb"))
|
||||
else if (!strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3nb"))
|
||||
moh->single = 1;
|
||||
if (!strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb"))
|
||||
else if (!strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb"))
|
||||
moh->quiet = 1;
|
||||
strncpy(moh->dir, param, sizeof(moh->dir) - 1);
|
||||
|
||||
moh->srcfd = -1;
|
||||
#ifdef ZAPATA_MOH
|
||||
/* It's an MP3 Moh -- Open /dev/zap/pseudo for timing... Is
|
||||
@@ -588,26 +808,58 @@ static int moh_register(char *classname, char *mode, char *param, char *miscargs
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void local_ast_moh_cleanup(struct ast_channel *chan)
|
||||
{
|
||||
if(chan->music_state) {
|
||||
free(chan->music_state);
|
||||
chan->music_state = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static int local_ast_moh_start(struct ast_channel *chan, char *class)
|
||||
{
|
||||
struct mohclass *mohclass;
|
||||
|
||||
if (!class || ast_strlen_zero(class))
|
||||
class = chan->musicclass;
|
||||
if (!class || ast_strlen_zero(class))
|
||||
class = "default";
|
||||
return ast_activate_generator(chan, &mohgen, class);
|
||||
ast_mutex_lock(&moh_lock);
|
||||
mohclass = get_mohbyname(class);
|
||||
ast_mutex_unlock(&moh_lock);
|
||||
|
||||
if (!mohclass) {
|
||||
ast_log(LOG_WARNING, "No class: %s\n", (char *)class);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ast_set_flag(chan, AST_FLAG_MOH);
|
||||
if (mohclass->total_files) {
|
||||
return ast_activate_generator(chan, &moh_file_stream, mohclass);
|
||||
} else
|
||||
return ast_activate_generator(chan, &mohgen, mohclass);
|
||||
}
|
||||
|
||||
static void local_ast_moh_stop(struct ast_channel *chan)
|
||||
{
|
||||
ast_clear_flag(chan, AST_FLAG_MOH);
|
||||
ast_deactivate_generator(chan);
|
||||
|
||||
if(chan->music_state) {
|
||||
if(chan->stream) {
|
||||
ast_closestream(chan->stream);
|
||||
chan->stream = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void load_moh_classes(void)
|
||||
static int load_moh_classes(void)
|
||||
{
|
||||
struct ast_config *cfg;
|
||||
struct ast_variable *var;
|
||||
char *data;
|
||||
char *args;
|
||||
int x = 0;
|
||||
cfg = ast_load("musiconhold.conf");
|
||||
if (cfg) {
|
||||
var = ast_variable_browse(cfg, "classes");
|
||||
@@ -621,54 +873,121 @@ static void load_moh_classes(void)
|
||||
*args = '\0';
|
||||
args++;
|
||||
}
|
||||
moh_register(var->name, var->value, data,args);
|
||||
if(!(get_mohbyname(var->name))) {
|
||||
moh_register(var->name, var->value, data, args);
|
||||
x++;
|
||||
}
|
||||
}
|
||||
var = var->next;
|
||||
}
|
||||
var = ast_variable_browse(cfg, "moh_files");
|
||||
while(var) {
|
||||
if(!(get_mohbyname(var->name))) {
|
||||
args = strchr(var->value, ',');
|
||||
if (args) {
|
||||
*args = '\0';
|
||||
args++;
|
||||
}
|
||||
moh_register(var->name, "files", var->value, args);
|
||||
x++;
|
||||
}
|
||||
var = var->next;
|
||||
}
|
||||
|
||||
ast_destroy(cfg);
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
static void ast_moh_destroy(void)
|
||||
{
|
||||
struct mohclass *moh;
|
||||
struct mohclass *moh,*tmp;
|
||||
char buff[8192];
|
||||
int bytes, tbytes=0, stime = 0;
|
||||
int bytes, tbytes=0, stime = 0, pid = 0;
|
||||
if (option_verbose > 1)
|
||||
ast_verbose(VERBOSE_PREFIX_2 "Destroying any remaining musiconhold processes\n");
|
||||
ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
|
||||
ast_mutex_lock(&moh_lock);
|
||||
moh = mohclasses;
|
||||
|
||||
while(moh) {
|
||||
if (moh->pid) {
|
||||
ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
|
||||
stime = time(NULL);
|
||||
kill(moh->pid, SIGKILL);
|
||||
pid = moh->pid;
|
||||
moh->pid = 0;
|
||||
kill(pid, SIGKILL);
|
||||
while ((bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime + 5) {
|
||||
tbytes = tbytes + bytes;
|
||||
}
|
||||
ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", moh->pid, tbytes);
|
||||
ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
|
||||
close(moh->srcfd);
|
||||
moh->pid = 0;
|
||||
}
|
||||
tmp = moh;
|
||||
moh = moh->next;
|
||||
free(tmp);
|
||||
}
|
||||
mohclasses = NULL;
|
||||
ast_mutex_unlock(&moh_lock);
|
||||
}
|
||||
|
||||
|
||||
static void moh_on_off(int on) {
|
||||
struct ast_channel *chan = ast_channel_walk_locked(NULL);
|
||||
while(chan) {
|
||||
if(ast_test_flag(chan, AST_FLAG_MOH)) {
|
||||
if(on)
|
||||
local_ast_moh_start(chan,NULL);
|
||||
else
|
||||
ast_deactivate_generator(chan);
|
||||
}
|
||||
ast_mutex_unlock(&chan->lock);
|
||||
chan = ast_channel_walk_locked(chan);
|
||||
}
|
||||
}
|
||||
|
||||
static int moh_cli(int fd, int argc, char *argv[])
|
||||
{
|
||||
int x = 0;
|
||||
moh_on_off(0);
|
||||
ast_moh_destroy();
|
||||
x = load_moh_classes();
|
||||
moh_on_off(1);
|
||||
ast_cli(fd,"\n%d class%s reloaded.\n",x,x == 1 ? "" : "es");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct ast_cli_entry cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL};
|
||||
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
int res;
|
||||
load_moh_classes();
|
||||
ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop);
|
||||
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);
|
||||
ast_register_atexit(ast_moh_destroy);
|
||||
ast_cli_register(&cli_moh);
|
||||
if (!res)
|
||||
res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
|
||||
if (!res)
|
||||
res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int reload(void)
|
||||
{
|
||||
struct mohclass *moh = mohclasses;
|
||||
load_moh_classes();
|
||||
while(moh) {
|
||||
if (moh->total_files)
|
||||
moh_scan_files(moh);
|
||||
moh = moh->next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
return -1;
|
||||
|
Reference in New Issue
Block a user