Routines implementing music on hold. More...
#include "asterisk.h"
#include <ctype.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/ioctl.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
#include "asterisk/stringfields.h"
#include "asterisk/linkedlists.h"
#include "asterisk/manager.h"
#include "asterisk/paths.h"
#include "asterisk/astobj2.h"
Go to the source code of this file.
Data Structures | |
struct | moh_files_state |
struct | mohclass |
struct | mohdata |
Defines | |
#define | DONT_UNREF 0 |
#define | get_mohbyname(a, b, c) _get_mohbyname(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__) |
#define | HANDLE_REF 1 |
#define | INITIAL_NUM_FILES 8 |
#define | LOCAL_MPG_123 "/usr/local/bin/mpg123" |
#define | MAX_MP3S 256 |
#define | MOH_CACHERTCLASSES (1 << 5) |
#define | moh_class_malloc() _moh_class_malloc(__FILE__,__LINE__,__PRETTY_FUNCTION__) |
#define | MOH_CUSTOM (1 << 2) |
#define | MOH_MS_INTERVAL 100 |
#define | MOH_NOTDELETED (1 << 30) |
#define | MOH_QUIET (1 << 0) |
#define | MOH_RANDOMIZE (1 << 3) |
#define | moh_register(a, b, c) _moh_register(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__) |
#define | MOH_SINGLE (1 << 1) |
#define | MOH_SORTALPHA (1 << 4) |
#define | mohclass_ref(class, string) (ao2_t_ref((class), +1, (string)), class) |
#define | mohclass_unref(class, string) (ao2_t_ref((class), -1, (string)), (struct mohclass *) NULL) |
#define | MPG_123 "/usr/bin/mpg123" |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static struct mohclass * | _get_mohbyname (const char *name, int warn, int flags, const char *file, int lineno, const char *funcname) |
static struct mohclass * | _moh_class_malloc (const char *file, int line, const char *funcname) |
static int | _moh_register (struct mohclass *moh, int reload, int unref, const char *file, int line, const char *funcname) |
static void | ast_moh_destroy (void) |
static int | ast_moh_files_next (struct ast_channel *chan) |
static struct mohclass * | get_mohbydigit (char digit) |
static char * | handle_cli_moh_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_cli_moh_show_classes (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static char * | handle_cli_moh_show_files (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) |
static int | init_app_class (struct mohclass *class) |
static int | init_files_class (struct mohclass *class) |
static int | load_module (void) |
static int | load_moh_classes (int reload) |
static void | local_ast_moh_cleanup (struct ast_channel *chan) |
static int | local_ast_moh_start (struct ast_channel *chan, const char *mclass, const char *interpclass) |
static void | local_ast_moh_stop (struct ast_channel *chan) |
static int | moh_add_file (struct mohclass *class, const char *filepath) |
static void * | moh_alloc (struct ast_channel *chan, void *params) |
static int | moh_class_cmp (void *obj, void *arg, int flags) |
static void | moh_class_destructor (void *obj) |
static int | moh_class_hash (const void *obj, const int flags) |
static int | moh_class_inuse (void *obj, void *arg, int flags) |
static int | moh_class_mark (void *obj, void *arg, int flags) |
static int | moh_classes_delete_marked (void *obj, void *arg, int flags) |
static int | moh_diff (struct mohclass *old, struct mohclass *new) |
static int | moh_digit_match (void *obj, void *arg, int flags) |
static void * | moh_files_alloc (struct ast_channel *chan, void *params) |
static int | moh_files_generator (struct ast_channel *chan, void *data, int len, int samples) |
static struct ast_frame * | moh_files_readframe (struct ast_channel *chan) |
static void | moh_files_release (struct ast_channel *chan, void *data) |
static int | moh_generate (struct ast_channel *chan, void *data, int len, int samples) |
static void | moh_handle_digit (struct ast_channel *chan, char digit) |
static void | moh_release (struct ast_channel *chan, void *data) |
static void | moh_rescan_files (void) |
static int | moh_scan_files (struct mohclass *class) |
static int | moh_sort_compare (const void *i1, const void *i2) |
static struct mohdata * | mohalloc (struct mohclass *cl) |
static void * | monmp3thread (void *data) |
static int | play_moh_exec (struct ast_channel *chan, void *data) |
static int | reload (void) |
static int | set_moh_exec (struct ast_channel *chan, void *data) |
static int | spawn_mp3 (struct mohclass *class) |
static int | start_moh_exec (struct ast_channel *chan, void *data) |
static int | stop_moh_exec (struct ast_channel *chan, void *data) |
static int | unload_module (void) |
static int | wait_moh_exec (struct ast_channel *chan, void *data) |
Variables | |
static struct ast_module_info __MODULE_INFO_SECTION | __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Music On Hold Resource" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } |
static struct ast_module_info * | ast_module_info = &__mod_info |
static struct ast_cli_entry | cli_moh [] |
static struct ast_flags | global_flags [1] = {{0}} |
static struct ast_generator | moh_file_stream |
static struct ao2_container * | mohclasses |
static struct ast_generator | mohgen |
static char * | play_moh = "MusicOnHold" |
static char * | play_moh_desc = "Returns 0 when done, -1 on hangup.\n" |
static char * | play_moh_syn = "Play Music On Hold indefinitely" |
static int | respawn_time = 20 |
static char * | set_moh = "SetMusicOnHold" |
static char * | set_moh_desc = " !!! DEPRECATED. USe Set(CHANNEL(musicclass)=...) instead !!!\n" |
static char * | set_moh_syn = "Set default Music On Hold class" |
static char * | start_moh = "StartMusicOnHold" |
static char * | start_moh_desc = "music source for the channel will be used. Always returns 0.\n" |
static char * | start_moh_syn = "Play Music On Hold" |
static char * | stop_moh = "StopMusicOnHold" |
static char * | stop_moh_desc = "Stops playing music on hold.\n" |
static char * | stop_moh_syn = "Stop Playing Music On Hold" |
static char * | wait_moh = "WaitMusicOnHold" |
static char * | wait_moh_desc = " !!! DEPRECATED. Use MusicOnHold instead !!!\n" |
static char * | wait_moh_syn = "Wait, playing Music On Hold" |
Routines implementing music on hold.
Definition in file res_musiconhold.c.
#define DONT_UNREF 0 |
Definition at line 77 of file res_musiconhold.c.
Referenced by local_ast_moh_start().
#define get_mohbyname | ( | a, | |
b, | |||
c | |||
) | _get_mohbyname(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__) |
Definition at line 795 of file res_musiconhold.c.
Referenced by local_ast_moh_start().
#define HANDLE_REF 1 |
Definition at line 76 of file res_musiconhold.c.
Referenced by load_moh_classes().
#define INITIAL_NUM_FILES 8 |
Definition at line 75 of file res_musiconhold.c.
Referenced by moh_add_file().
#define LOCAL_MPG_123 "/usr/local/bin/mpg123" |
Definition at line 194 of file res_musiconhold.c.
Referenced by spawn_mp3().
#define MAX_MP3S 256 |
Definition at line 196 of file res_musiconhold.c.
Referenced by spawn_mp3().
#define MOH_CACHERTCLASSES (1 << 5) |
Should we use a separate instance of MOH for each user or not
Definition at line 147 of file res_musiconhold.c.
Referenced by load_moh_classes(), and local_ast_moh_start().
#define moh_class_malloc | ( | ) | _moh_class_malloc(__FILE__,__LINE__,__PRETTY_FUNCTION__) |
Definition at line 1240 of file res_musiconhold.c.
Referenced by load_moh_classes(), and local_ast_moh_start().
#define MOH_CUSTOM (1 << 2) |
Definition at line 143 of file res_musiconhold.c.
Referenced by handle_cli_moh_show_classes(), init_app_class(), local_ast_moh_start(), and spawn_mp3().
#define MOH_MS_INTERVAL 100 |
Referenced by monmp3thread().
#define MOH_NOTDELETED (1 << 30) |
Find only records that aren't deleted?
Definition at line 150 of file res_musiconhold.c.
Referenced by _moh_register(), and moh_class_cmp().
#define MOH_QUIET (1 << 0) |
Definition at line 141 of file res_musiconhold.c.
Referenced by init_app_class(), local_ast_moh_start(), and spawn_mp3().
#define MOH_RANDOMIZE (1 << 3) |
Definition at line 144 of file res_musiconhold.c.
Referenced by ast_moh_files_next(), init_files_class(), load_moh_classes(), local_ast_moh_start(), and moh_files_alloc().
#define moh_register | ( | a, | |
b, | |||
c | |||
) | _moh_register(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__) |
Definition at line 1170 of file res_musiconhold.c.
Referenced by load_moh_classes(), and local_ast_moh_start().
#define MOH_SINGLE (1 << 1) |
Definition at line 142 of file res_musiconhold.c.
Referenced by init_app_class(), local_ast_moh_start(), and spawn_mp3().
#define MOH_SORTALPHA (1 << 4) |
Definition at line 145 of file res_musiconhold.c.
Referenced by load_moh_classes(), local_ast_moh_start(), and moh_scan_files().
#define mohclass_ref | ( | class, | |
string | |||
) | (ao2_t_ref((class), +1, (string)), class) |
Definition at line 200 of file res_musiconhold.c.
Referenced by moh_alloc(), moh_files_alloc(), and mohalloc().
#define mohclass_unref | ( | class, | |
string | |||
) | (ao2_t_ref((class), -1, (string)), (struct mohclass *) NULL) |
Definition at line 203 of file res_musiconhold.c.
Referenced by _moh_register(), handle_cli_moh_show_classes(), handle_cli_moh_show_files(), load_moh_classes(), local_ast_moh_cleanup(), local_ast_moh_start(), moh_files_release(), moh_handle_digit(), moh_release(), and unload_module().
#define MPG_123 "/usr/bin/mpg123" |
Definition at line 195 of file res_musiconhold.c.
Referenced by spawn_mp3().
static void __reg_module | ( | void | ) | [static] |
Definition at line 1914 of file res_musiconhold.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1914 of file res_musiconhold.c.
static struct mohclass* _get_mohbyname | ( | const char * | name, |
int | warn, | ||
int | flags, | ||
const char * | file, | ||
int | lineno, | ||
const char * | funcname | ||
) | [static, read] |
Definition at line 797 of file res_musiconhold.c.
References _ao2_find(), _ao2_find_debug(), ast_copy_string(), ast_log(), mohclass::flags, LOG_DEBUG, moh, and mohclass::name.
Referenced by _moh_register().
{ struct mohclass *moh = NULL; struct mohclass tmp_class = { .flags = 0, }; ast_copy_string(tmp_class.name, name, sizeof(tmp_class.name)); #ifdef REF_DEBUG moh = _ao2_find_debug(mohclasses, &tmp_class, flags, "get_mohbyname", (char *) file, lineno, funcname); #else moh = _ao2_find(mohclasses, &tmp_class, flags); #endif if (!moh && warn) { ast_log(LOG_DEBUG, "Music on Hold class '%s' not found in memory\n", name); } return moh; }
static struct mohclass* _moh_class_malloc | ( | const char * | file, |
int | line, | ||
const char * | funcname | ||
) | [static, read] |
Definition at line 1242 of file res_musiconhold.c.
References __AST_DEBUG_MALLOC, _ao2_alloc_debug(), ao2_alloc, AST_FORMAT_SLINEAR, mohclass::format, and moh_class_destructor().
{ struct mohclass *class; if ((class = #ifdef REF_DEBUG _ao2_alloc_debug(sizeof(*class), moh_class_destructor, "Allocating new moh class", file, line, funcname, 1) #elif defined(__AST_DEBUG_MALLOC) _ao2_alloc_debug(sizeof(*class), moh_class_destructor, "Allocating new moh class", file, line, funcname, 0) #else ao2_alloc(sizeof(*class), moh_class_destructor) #endif )) { class->format = AST_FORMAT_SLINEAR; class->srcfd = -1; class->pseudofd = -1; } return class; }
static int _moh_register | ( | struct mohclass * | moh, |
int | reload, | ||
int | unref, | ||
const char * | file, | ||
int | line, | ||
const char * | funcname | ||
) | [static] |
Definition at line 1171 of file res_musiconhold.c.
References _get_mohbyname(), ao2_t_link, ast_log(), init_app_class(), init_files_class(), LOG_WARNING, mohclass::mode, moh_diff(), MOH_NOTDELETED, mohclass_unref, mohclass::name, respawn_time, and mohclass::start.
{ struct mohclass *mohclass = NULL; if ((mohclass = _get_mohbyname(moh->name, 0, MOH_NOTDELETED, file, line, funcname)) && !moh_diff(mohclass, moh)) { ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name); mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name"); if (unref) { moh = mohclass_unref(moh, "unreffing potential new moh class (it is a duplicate)"); } return -1; } else if (mohclass) { /* Found a class, but it's different from the one being registered */ mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name"); } time(&moh->start); moh->start -= respawn_time; if (!strcasecmp(moh->mode, "files")) { if (init_files_class(moh)) { if (unref) { moh = mohclass_unref(moh, "unreffing potential new moh class (init_files_class failed)"); } return -1; } } 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 (init_app_class(moh)) { if (unref) { moh = mohclass_unref(moh, "unreffing potential new moh class (init_app_class_failed)"); } return -1; } } else { ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode); if (unref) { moh = mohclass_unref(moh, "unreffing potential new moh class (unknown mode)"); } return -1; } ao2_t_link(mohclasses, moh, "Adding class to container"); if (unref) { moh = mohclass_unref(moh, "Unreffing new moh class because we just added it to the container"); } return 0; }
static void ast_moh_destroy | ( | void | ) | [static] |
Definition at line 1707 of file res_musiconhold.c.
References ao2_t_callback, ast_verb, OBJ_MULTIPLE, OBJ_NODATA, and OBJ_UNLINK.
Referenced by load_module(), and unload_module().
{ ast_verb(2, "Destroying musiconhold processes\n"); ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "Destroy callback"); }
static int ast_moh_files_next | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 256 of file res_musiconhold.c.
References ast_closestream(), ast_debug, ast_fileexists(), ast_log(), ast_openstream_full(), ast_random(), ast_seekstream(), ast_test_flag, moh_files_state::class, errno, mohclass::filearray, ast_channel::language, LOG_WARNING, MOH_RANDOMIZE, ast_channel::music_state, ast_channel::name, mohclass::name, moh_files_state::pos, moh_files_state::samples, moh_files_state::save_pos, moh_files_state::save_pos_filename, ast_channel::stream, and mohclass::total_files.
Referenced by moh_files_readframe().
{ struct moh_files_state *state = chan->music_state; int tries; /* Discontinue a stream if it is running already */ if (chan->stream) { ast_closestream(chan->stream); chan->stream = NULL; } if (!state->class->total_files) { ast_log(LOG_WARNING, "No files available for class '%s'\n", state->class->name); return -1; } if (state->pos == 0 && state->save_pos_filename == NULL) { /* First time so lets play the file. */ state->save_pos = -1; } else if (state->save_pos >= 0 && state->save_pos < state->class->total_files && state->class->filearray[state->save_pos] == state->save_pos_filename) { /* If a specific file has been saved confirm it still exists and that it is still valid */ state->pos = state->save_pos; state->save_pos = -1; } else if (ast_test_flag(state->class, MOH_RANDOMIZE)) { /* Get a random file and ensure we can open it */ for (tries = 0; tries < 20; tries++) { state->pos = ast_random() % state->class->total_files; if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0) { break; } } state->save_pos = -1; state->samples = 0; } else { /* This is easy, just increment our position and make sure we don't exceed the total file count */ state->pos++; state->pos %= state->class->total_files; state->save_pos = -1; state->samples = 0; } for (tries = 0; tries < state->class->total_files; ++tries) { if (ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) { break; } ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno)); state->pos++; state->pos %= state->class->total_files; } if (tries == state->class->total_files) { return -1; } /* Record the pointer to the filename for position resuming later */ state->save_pos_filename = state->class->filearray[state->pos]; ast_debug(1, "%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 0; }
static struct mohclass* get_mohbydigit | ( | char | digit | ) | [static, read] |
Definition at line 417 of file res_musiconhold.c.
References ao2_t_callback, and moh_digit_match().
Referenced by moh_handle_digit().
{ return ao2_t_callback(mohclasses, 0, moh_digit_match, &digit, "digit callback"); }
static char* handle_cli_moh_reload | ( | struct ast_cli_entry * | e, |
int | cmd, | ||
struct ast_cli_args * | a | ||
) | [static] |
Definition at line 1713 of file res_musiconhold.c.
References ast_cli_args::argc, ast_cli_entry::args, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, reload, and ast_cli_entry::usage.
{ switch (cmd) { case CLI_INIT: e->command = "moh reload"; e->usage = "Usage: moh reload\n" " Reloads the MusicOnHold module.\n" " Alias for 'module reload res_musiconhold.so'\n"; return NULL; case CLI_GENERATE: return NULL; } if (a->argc != e->args) return CLI_SHOWUSAGE; reload(); return CLI_SUCCESS; }
static char* handle_cli_moh_show_classes | ( | struct ast_cli_entry * | e, |
int | cmd, | ||
struct ast_cli_args * | a | ||
) | [static] |
Definition at line 1773 of file res_musiconhold.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_t_iterator_next, ast_cli_args::argc, ast_cli_entry::args, ast_cli(), ast_getformatname(), ast_test_flag, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, MOH_CUSTOM, mohclass_unref, S_OR, and ast_cli_entry::usage.
{ struct mohclass *class; struct ao2_iterator i; switch (cmd) { case CLI_INIT: e->command = "moh show classes"; e->usage = "Usage: moh show classes\n" " Lists all MusicOnHold classes.\n"; return NULL; case CLI_GENERATE: return NULL; } if (a->argc != e->args) return CLI_SHOWUSAGE; i = ao2_iterator_init(mohclasses, 0); for (; (class = ao2_t_iterator_next(&i, "Show classes iterator")); mohclass_unref(class, "Unref iterator in moh show classes")) { ast_cli(a->fd, "Class: %s\n", class->name); ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>")); ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>")); if (ast_test_flag(class, MOH_CUSTOM)) { ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>")); } if (strcasecmp(class->mode, "files")) { ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(class->format)); } } ao2_iterator_destroy(&i); return CLI_SUCCESS; }
static char* handle_cli_moh_show_files | ( | struct ast_cli_entry * | e, |
int | cmd, | ||
struct ast_cli_args * | a | ||
) | [static] |
Definition at line 1735 of file res_musiconhold.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_t_iterator_next, ast_cli_args::argc, ast_cli_entry::args, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, mohclass_unref, and ast_cli_entry::usage.
{ struct mohclass *class; struct ao2_iterator i; switch (cmd) { case CLI_INIT: e->command = "moh show files"; e->usage = "Usage: moh show files\n" " Lists all loaded file-based MusicOnHold classes and their\n" " files.\n"; return NULL; case CLI_GENERATE: return NULL; } if (a->argc != e->args) return CLI_SHOWUSAGE; i = ao2_iterator_init(mohclasses, 0); for (; (class = ao2_t_iterator_next(&i, "Show files iterator")); mohclass_unref(class, "Unref iterator in moh show files")) { int x; if (!class->total_files) { continue; } ast_cli(a->fd, "Class: %s\n", class->name); for (x = 0; x < class->total_files; x++) { ast_cli(a->fd, "\tFile: %s\n", class->filearray[x]); } } ao2_iterator_destroy(&i); return CLI_SUCCESS; }
static int init_app_class | ( | struct mohclass * | class | ) | [static] |
Definition at line 1124 of file res_musiconhold.c.
References ast_log(), ast_pthread_create_background, ast_set_flag, LOG_WARNING, MOH_CUSTOM, MOH_QUIET, MOH_SINGLE, and monmp3thread().
Referenced by _moh_register().
{ #ifdef HAVE_DAHDI int x; #endif if (!strcasecmp(class->mode, "custom")) { ast_set_flag(class, MOH_CUSTOM); } else if (!strcasecmp(class->mode, "mp3nb")) { ast_set_flag(class, MOH_SINGLE); } else if (!strcasecmp(class->mode, "quietmp3nb")) { ast_set_flag(class, MOH_SINGLE | MOH_QUIET); } else if (!strcasecmp(class->mode, "quietmp3")) { ast_set_flag(class, MOH_QUIET); } class->srcfd = -1; class->pseudofd = -1; #ifdef HAVE_DAHDI /* Open /dev/zap/pseudo for timing... Is there a better, yet reliable way to do this? */ class->pseudofd = open("/dev/dahdi/pseudo", O_RDONLY); if (class->pseudofd < 0) { ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n"); } else { x = 320; ioctl(class->pseudofd, DAHDI_SET_BLOCKSIZE, &x); } #endif if (ast_pthread_create_background(&class->thread, NULL, monmp3thread, class)) { ast_log(LOG_WARNING, "Unable to create moh thread...\n"); if (class->pseudofd > -1) { close(class->pseudofd); class->pseudofd = -1; } return -1; } return 0; }
static int init_files_class | ( | struct mohclass * | class | ) | [static] |
Definition at line 1063 of file res_musiconhold.c.
References ast_set_flag, ast_verbose(), MOH_RANDOMIZE, moh_scan_files(), option_verbose, and VERBOSE_PREFIX_3.
Referenced by _moh_register().
{ int res; res = moh_scan_files(class); if (res < 0) { return -1; } if (!res) { if (option_verbose > 2) { ast_verbose(VERBOSE_PREFIX_3 "Files not found in %s for moh class:%s\n", class->dir, class->name); } return -1; } #if 0 /* XXX This isn't correct. Args is an application for custom mode. XXX */ if (strchr(class->args, 'r')) { ast_set_flag(class, MOH_RANDOMIZE); } #endif return 0; }
static int load_module | ( | void | ) | [static] |
Definition at line 1831 of file res_musiconhold.c.
References ao2_t_container_alloc, ARRAY_LEN, ast_check_realtime(), ast_cli_register_multiple(), ast_install_music_functions(), ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_moh_destroy(), ast_register_application, ast_register_atexit(), load_moh_classes(), local_ast_moh_cleanup(), local_ast_moh_start(), local_ast_moh_stop(), LOG_WARNING, moh_class_cmp(), moh_class_hash(), play_moh_exec(), set_moh_exec(), start_moh_exec(), stop_moh_exec(), and wait_moh_exec().
{ int res; if (!(mohclasses = ao2_t_container_alloc(53, moh_class_hash, moh_class_cmp, "Moh class container"))) { return AST_MODULE_LOAD_DECLINE; } if (!load_moh_classes(0) && ast_check_realtime("musiconhold") == 0) { /* No music classes configured, so skip it */ ast_log(LOG_WARNING, "No music on hold classes configured, " "disabling music on hold.\n"); } else { ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup); } res = ast_register_application(play_moh, play_moh_exec, play_moh_syn, play_moh_desc); ast_register_atexit(ast_moh_destroy); ast_cli_register_multiple(cli_moh, ARRAY_LEN(cli_moh)); if (!res) res = ast_register_application(wait_moh, wait_moh_exec, wait_moh_syn, wait_moh_desc); if (!res) res = ast_register_application(set_moh, set_moh_exec, set_moh_syn, set_moh_desc); if (!res) res = ast_register_application(start_moh, start_moh_exec, start_moh_syn, start_moh_desc); if (!res) res = ast_register_application(stop_moh, stop_moh_exec, stop_moh_syn, stop_moh_desc); return AST_MODULE_LOAD_SUCCESS; }
static int load_moh_classes | ( | int | reload | ) | [static] |
Definition at line 1598 of file res_musiconhold.c.
References ao2_t_callback, ast_category_browse(), ast_check_realtime(), ast_clear_flag, ast_config_destroy(), ast_config_load, ast_copy_string(), AST_FLAGS_ALL, AST_FORMAT_SLINEAR, ast_getformatbyname(), ast_log(), ast_set2_flag, ast_set_flag, ast_strlen_zero(), ast_true(), ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, HANDLE_REF, LOG_WARNING, MOH_CACHERTCLASSES, moh_class_malloc, moh_class_mark(), moh_classes_delete_marked(), MOH_RANDOMIZE, moh_register, moh_rescan_files(), MOH_SORTALPHA, mohclass_unref, ast_variable::name, ast_variable::next, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, ast_variable::value, and var.
Referenced by load_module().
{ struct ast_config *cfg; struct ast_variable *var; struct mohclass *class; char *cat; int numclasses = 0; struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; cfg = ast_config_load("musiconhold.conf", config_flags); if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) { if (ast_check_realtime("musiconhold") && reload) { ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes"); ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, moh_classes_delete_marked, NULL, "Purge marked classes"); } if (cfg == CONFIG_STATUS_FILEUNCHANGED) { moh_rescan_files(); } return 0; } if (reload) { ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes"); } ast_clear_flag(global_flags, AST_FLAGS_ALL); cat = ast_category_browse(cfg, NULL); for (; cat; cat = ast_category_browse(cfg, cat)) { /* Setup common options from [general] section */ if (!strcasecmp(cat, "general")) { for (var = ast_variable_browse(cfg, cat); var; var = var->next) { if (!strcasecmp(var->name, "cachertclasses")) { ast_set2_flag(global_flags, ast_true(var->value), MOH_CACHERTCLASSES); } else { ast_log(LOG_WARNING, "Unknown option '%s' in [general] section of musiconhold.conf\n", var->name); } } } /* These names were deprecated in 1.4 and should not be used until after the next major release. */ if (!strcasecmp(cat, "classes") || !strcasecmp(cat, "moh_files") || !strcasecmp(cat, "general")) { continue; } if (!(class = moh_class_malloc())) { break; } ast_copy_string(class->name, cat, sizeof(class->name)); for (var = ast_variable_browse(cfg, cat); var; var = var->next) { if (!strcasecmp(var->name, "mode")) ast_copy_string(class->mode, var->value, sizeof(class->mode)); 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, "digit") && (isdigit(*var->value) || strchr("*#", *var->value))) class->digit = *var->value; else if (!strcasecmp(var->name, "random")) ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE); else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "random")) ast_set_flag(class, MOH_RANDOMIZE); else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) ast_set_flag(class, MOH_SORTALPHA); 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; } } } 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); class = mohclass_unref(class, "unreffing potential mohclass (no directory)"); continue; } } if (ast_strlen_zero(class->mode)) { ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name); class = mohclass_unref(class, "unreffing potential mohclass (no mode)"); 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); class = mohclass_unref(class, "unreffing potential mohclass (no app for custom mode)"); continue; } /* Don't leak a class when it's already registered */ if (!moh_register(class, reload, HANDLE_REF)) { numclasses++; } } ast_config_destroy(cfg); ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, moh_classes_delete_marked, NULL, "Purge marked classes"); return numclasses; }
static void local_ast_moh_cleanup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1223 of file res_musiconhold.c.
References ast_free, ast_module_unref(), moh_files_state::class, mohclass_unref, ast_channel::music_state, and ast_module_info::self.
Referenced by load_module().
{ struct moh_files_state *state = chan->music_state; if (state) { if (state->class) { state->class = mohclass_unref(state->class, "Channel MOH state destruction"); } ast_free(chan->music_state); chan->music_state = NULL; /* Only held a module reference if we had a music state */ ast_module_unref(ast_module_info->self); } }
static int local_ast_moh_start | ( | struct ast_channel * | chan, |
const char * | mclass, | ||
const char * | interpclass | ||
) | [static] |
Definition at line 1263 of file res_musiconhold.c.
References mohclass::args, ast_activate_generator(), ast_check_realtime(), ast_copy_string(), AST_FLAG_MOH, AST_FORMAT_SLINEAR, ast_getformatbyname(), ast_load_realtime(), ast_log(), ast_pthread_create_background, ast_set2_flag, ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_true(), ast_variables_destroy(), moh_files_state::class, mohclass::digit, mohclass::dir, DONT_UNREF, EVENT_FLAG_CALL, mohclass::format, get_mohbyname, LOG_NOTICE, LOG_WARNING, manager_event, mohclass::mode, MOH_CACHERTCLASSES, moh_class_malloc, MOH_CUSTOM, MOH_QUIET, MOH_RANDOMIZE, moh_register, moh_scan_files(), MOH_SINGLE, MOH_SORTALPHA, mohclass_unref, monmp3thread(), ast_channel::music_state, ast_channel::musicclass, ast_channel::name, mohclass::name, ast_variable::name, ast_variable::next, mohclass::pseudofd, mohclass::realtime, respawn_time, SENTINEL, mohclass::srcfd, mohclass::start, mohclass::thread, mohclass::total_files, ast_channel::uniqueid, ast_variable::value, and var.
Referenced by load_module().
{ struct mohclass *mohclass = NULL; struct moh_files_state *state = chan->music_state; struct ast_variable *var = NULL; int res; int realtime_possible = ast_check_realtime("musiconhold"); /* The following is the order of preference for which class to use: * 1) The channels explicitly set musicclass, which should *only* be * set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan. * 2) The mclass argument. If a channel is calling ast_moh_start() as the * result of receiving a HOLD control frame, this should be the * payload that came with the frame. * 3) The interpclass argument. This would be from the mohinterpret * option from channel drivers. This is the same as the old musicclass * option. * 4) The default class. */ if (!ast_strlen_zero(chan->musicclass)) { mohclass = get_mohbyname(chan->musicclass, 1, 0); if (!mohclass && realtime_possible) { var = ast_load_realtime("musiconhold", "name", chan->musicclass, SENTINEL); } } if (!mohclass && !var && !ast_strlen_zero(mclass)) { mohclass = get_mohbyname(mclass, 1, 0); if (!mohclass && realtime_possible) { var = ast_load_realtime("musiconhold", "name", mclass, SENTINEL); } } if (!mohclass && !var && !ast_strlen_zero(interpclass)) { mohclass = get_mohbyname(interpclass, 1, 0); if (!mohclass && realtime_possible) { var = ast_load_realtime("musiconhold", "name", interpclass, SENTINEL); } } if (!mohclass && !var) { mohclass = get_mohbyname("default", 1, 0); if (!mohclass && realtime_possible) { var = ast_load_realtime("musiconhold", "name", "default", SENTINEL); } } /* If no moh class found in memory, then check RT. Note that the logic used * above guarantees that if var is non-NULL, then mohclass must be NULL. */ if (var) { struct ast_variable *tmp = NULL; if ((mohclass = moh_class_malloc())) { mohclass->realtime = 1; for (tmp = var; tmp; tmp = tmp->next) { if (!strcasecmp(tmp->name, "name")) ast_copy_string(mohclass->name, tmp->value, sizeof(mohclass->name)); else if (!strcasecmp(tmp->name, "mode")) ast_copy_string(mohclass->mode, tmp->value, sizeof(mohclass->mode)); else if (!strcasecmp(tmp->name, "directory")) ast_copy_string(mohclass->dir, tmp->value, sizeof(mohclass->dir)); else if (!strcasecmp(tmp->name, "application")) ast_copy_string(mohclass->args, tmp->value, sizeof(mohclass->args)); else if (!strcasecmp(tmp->name, "digit") && (isdigit(*tmp->value) || strchr("*#", *tmp->value))) mohclass->digit = *tmp->value; else if (!strcasecmp(tmp->name, "random")) ast_set2_flag(mohclass, ast_true(tmp->value), MOH_RANDOMIZE); else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "random")) ast_set_flag(mohclass, MOH_RANDOMIZE); else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "alpha")) ast_set_flag(mohclass, MOH_SORTALPHA); else if (!strcasecmp(tmp->name, "format")) { mohclass->format = ast_getformatbyname(tmp->value); if (!mohclass->format) { ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", tmp->value); mohclass->format = AST_FORMAT_SLINEAR; } } } ast_variables_destroy(var); if (ast_strlen_zero(mohclass->dir)) { if (!strcasecmp(mohclass->mode, "custom")) { strcpy(mohclass->dir, "nodir"); } else { ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", mohclass->name); mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no directory specified)"); return -1; } } if (ast_strlen_zero(mohclass->mode)) { ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", mohclass->name); mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no mode specified)"); return -1; } if (ast_strlen_zero(mohclass->args) && !strcasecmp(mohclass->mode, "custom")) { ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", mohclass->name); mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no app specified for custom mode"); return -1; } if (ast_test_flag(global_flags, MOH_CACHERTCLASSES)) { /* CACHERTCLASSES enabled, let's add this class to default tree */ if (state && state->class) { /* Class already exist for this channel */ ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name); if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) { /* we found RT class with the same name, seems like we should continue playing existing one */ /* XXX This code is impossible to reach */ mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has a class)"); mohclass = state->class; } } /* We don't want moh_register to unref the mohclass because we do it at the end of this function as well. * If we allowed moh_register to unref the mohclass,too, then the count would be off by one. The result would * be that the destructor would be called when the generator on the channel is deactivated. The container then * has a pointer to a freed mohclass, so any operations involving the mohclass container would result in reading * invalid memory. */ if (moh_register(mohclass, 0, DONT_UNREF) == -1) { mohclass = mohclass_unref(mohclass, "unreffing mohclass failed to register"); return -1; } } else { /* We don't register RT moh class, so let's init it manualy */ time(&mohclass->start); mohclass->start -= respawn_time; if (!strcasecmp(mohclass->mode, "files")) { if (!moh_scan_files(mohclass)) { mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)"); return -1; } if (strchr(mohclass->args, 'r')) ast_set_flag(mohclass, MOH_RANDOMIZE); } else if (!strcasecmp(mohclass->mode, "mp3") || !strcasecmp(mohclass->mode, "mp3nb") || !strcasecmp(mohclass->mode, "quietmp3") || !strcasecmp(mohclass->mode, "quietmp3nb") || !strcasecmp(mohclass->mode, "httpmp3") || !strcasecmp(mohclass->mode, "custom")) { if (!strcasecmp(mohclass->mode, "custom")) ast_set_flag(mohclass, MOH_CUSTOM); else if (!strcasecmp(mohclass->mode, "mp3nb")) ast_set_flag(mohclass, MOH_SINGLE); else if (!strcasecmp(mohclass->mode, "quietmp3nb")) ast_set_flag(mohclass, MOH_SINGLE | MOH_QUIET); else if (!strcasecmp(mohclass->mode, "quietmp3")) ast_set_flag(mohclass, MOH_QUIET); mohclass->srcfd = -1; #ifdef HAVE_DAHDI /* Open /dev/dahdi/pseudo for timing... Is there a better, yet reliable way to do this? */ mohclass->pseudofd = open("/dev/dahdi/pseudo", O_RDONLY); if (mohclass->pseudofd < 0) { ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n"); } else { int x = 320; ioctl(mohclass->pseudofd, DAHDI_SET_BLOCKSIZE, &x); } #else mohclass->pseudofd = -1; #endif /* Let's check if this channel already had a moh class before */ if (state && state->class) { /* Class already exist for this channel */ ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name); if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) { /* we found RT class with the same name, seems like we should continue playing existing one */ mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has one)"); mohclass = state->class; } } else { if (ast_pthread_create_background(&mohclass->thread, NULL, monmp3thread, mohclass)) { ast_log(LOG_WARNING, "Unable to create moh...\n"); if (mohclass->pseudofd > -1) { close(mohclass->pseudofd); mohclass->pseudofd = -1; } mohclass = mohclass_unref(mohclass, "Unreffing potential mohclass (failed to create background thread)"); return -1; } } } else { ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mohclass->mode); mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (unknown mode)"); return -1; } } } else { ast_variables_destroy(var); } } if (!mohclass) { return -1; } manager_event(EVENT_FLAG_CALL, "MusicOnHold", "State: Start\r\n" "Channel: %s\r\n" "UniqueID: %s\r\n", chan->name, chan->uniqueid); ast_set_flag(chan, AST_FLAG_MOH); if (mohclass->total_files) { res = ast_activate_generator(chan, &moh_file_stream, mohclass); } else { res = ast_activate_generator(chan, &mohgen, mohclass); } mohclass = mohclass_unref(mohclass, "unreffing local reference to mohclass in local_ast_moh_start"); return res; }
static void local_ast_moh_stop | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1476 of file res_musiconhold.c.
References ast_channel_lock, ast_channel_unlock, ast_clear_flag, ast_closestream(), ast_deactivate_generator(), AST_FLAG_MOH, EVENT_FLAG_CALL, manager_event, ast_channel::music_state, ast_channel::name, ast_channel::stream, and ast_channel::uniqueid.
Referenced by load_module().
{ ast_clear_flag(chan, AST_FLAG_MOH); ast_deactivate_generator(chan); ast_channel_lock(chan); if (chan->music_state) { if (chan->stream) { ast_closestream(chan->stream); chan->stream = NULL; } } manager_event(EVENT_FLAG_CALL, "MusicOnHold", "State: Stop\r\n" "Channel: %s\r\n" "UniqueID: %s\r\n", chan->name, chan->uniqueid); ast_channel_unlock(chan); }
static int moh_add_file | ( | struct mohclass * | class, |
const char * | filepath | ||
) | [static] |
Definition at line 946 of file res_musiconhold.c.
References ast_calloc, ast_realloc, ast_strdup, and INITIAL_NUM_FILES.
Referenced by moh_scan_files().
{ if (!class->allowed_files) { if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray)))) return -1; class->allowed_files = INITIAL_NUM_FILES; } else if (class->total_files == class->allowed_files) { if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) { class->allowed_files = 0; class->total_files = 0; return -1; } class->allowed_files *= 2; } if (!(class->filearray[class->total_files] = ast_strdup(filepath))) return -1; class->total_files++; return 0; }
static void* moh_alloc | ( | struct ast_channel * | chan, |
void * | params | ||
) | [static] |
Definition at line 881 of file res_musiconhold.c.
References ast_calloc, ast_codec2str(), ast_log(), ast_module_ref(), ast_set_write_format(), ast_verb, moh_files_state::class, mohclass::format, LOG_WARNING, moh_release(), mohalloc(), mohclass_ref, ast_channel::music_state, mohclass::name, ast_channel::name, mohdata::origwfmt, ast_module_info::self, and ast_channel::writeformat.
{ struct mohdata *res; struct mohclass *class = params; struct moh_files_state *state; /* Initiating music_state for current channel. Channel should know name of moh class */ if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) { chan->music_state = state; state->class = mohclass_ref(class, "Copying reference into state container"); ast_module_ref(ast_module_info->self); } else state = chan->music_state; if (state && state->class != class) { memset(state, 0, sizeof(*state)); state->class = class; } if ((res = mohalloc(class))) { res->origwfmt = chan->writeformat; if (ast_set_write_format(chan, class->format)) { ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format)); moh_release(NULL, res); res = NULL; } ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name); } return res; }
static int moh_class_cmp | ( | void * | obj, |
void * | arg, | ||
int | flags | ||
) | [static] |
Definition at line 1822 of file res_musiconhold.c.
References CMP_MATCH, CMP_STOP, and MOH_NOTDELETED.
Referenced by load_module().
{ struct mohclass *class = obj, *class2 = arg; return strcasecmp(class->name, class2->name) ? 0 : (flags & MOH_NOTDELETED) && (class->delete || class2->delete) ? 0 : CMP_MATCH | CMP_STOP; }
static void moh_class_destructor | ( | void * | obj | ) | [static] |
Definition at line 1497 of file res_musiconhold.c.
References ast_debug, AST_LIST_REMOVE_HEAD, ast_log(), AST_PTHREADT_NULL, ast_wait_for_input(), buff, errno, free, LOG_DEBUG, LOG_WARNING, and mohclass::pid.
Referenced by _moh_class_malloc().
{ struct mohclass *class = obj; struct mohdata *member; pthread_t tid = 0; ast_debug(1, "Destroying MOH class '%s'\n", class->name); /* Kill the thread first, so it cannot restart the child process while the * class is being destroyed */ if (class->thread != AST_PTHREADT_NULL && class->thread != 0) { tid = class->thread; class->thread = AST_PTHREADT_NULL; pthread_cancel(tid); /* We'll collect the exit status later, after we ensure all the readers * are dead. */ } if (class->pid > 1) { char buff[8192]; int bytes, tbytes = 0, stime = 0, pid = 0; ast_log(LOG_DEBUG, "killing %d!\n", class->pid); stime = time(NULL) + 2; pid = class->pid; class->pid = 0; /* Back when this was just mpg123, SIGKILL was fine. Now we need * to give the process a reason and time enough to kill off its * children. */ do { if (killpg(pid, SIGHUP) < 0) { ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno)); } usleep(100000); if (killpg(pid, SIGTERM) < 0) { if (errno == ESRCH) { break; } ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno)); } usleep(100000); if (killpg(pid, SIGKILL) < 0) { if (errno == ESRCH) { break; } ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno)); } } while (0); while ((ast_wait_for_input(class->srcfd, 100) > 0) && (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) { tbytes = tbytes + bytes; } ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes); close(class->srcfd); } while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) { free(member); } if (class->pseudofd > -1) { close(class->pseudofd); class->pseudofd = -1; } if (class->filearray) { int i; for (i = 0; i < class->total_files; i++) { free(class->filearray[i]); } free(class->filearray); class->filearray = NULL; } /* Finally, collect the exit status of the monitor thread */ if (tid > 0) { pthread_join(tid, NULL); } }
static int moh_class_hash | ( | const void * | obj, |
const int | flags | ||
) | [static] |
Definition at line 1815 of file res_musiconhold.c.
References ast_str_case_hash().
Referenced by load_module().
{ const struct mohclass *class = obj; return ast_str_case_hash(class->name); }
static int moh_class_inuse | ( | void * | obj, |
void * | arg, | ||
int | flags | ||
) | [static] |
Definition at line 1872 of file res_musiconhold.c.
References AST_LIST_EMPTY, CMP_MATCH, and CMP_STOP.
Referenced by unload_module().
{ struct mohclass *class = obj; return AST_LIST_EMPTY(&class->members) ? 0 : CMP_MATCH | CMP_STOP; }
static int moh_class_mark | ( | void * | obj, |
void * | arg, | ||
int | flags | ||
) | [static] |
Definition at line 1582 of file res_musiconhold.c.
References mohclass::delete.
Referenced by load_moh_classes().
static int moh_classes_delete_marked | ( | void * | obj, |
void * | arg, | ||
int | flags | ||
) | [static] |
Definition at line 1591 of file res_musiconhold.c.
References CMP_MATCH, and mohclass::delete.
Referenced by load_moh_classes().
Definition at line 1105 of file res_musiconhold.c.
References mohclass::args, mohclass::dir, mohclass::flags, and mohclass::mode.
Referenced by _moh_register().
static int moh_digit_match | ( | void * | obj, |
void * | arg, | ||
int | flags | ||
) | [static] |
Definition at line 408 of file res_musiconhold.c.
References CMP_MATCH, CMP_STOP, and mohclass::digit.
Referenced by get_mohbydigit().
static void* moh_files_alloc | ( | struct ast_channel * | chan, |
void * | params | ||
) | [static] |
Definition at line 369 of file res_musiconhold.c.
References ast_calloc, ast_copy_string(), ast_module_ref(), ast_random(), ast_test_flag, ast_verb, moh_files_state::class, MOH_RANDOMIZE, mohclass_ref, ast_channel::music_state, ast_channel::name, moh_files_state::name, moh_files_state::origwfmt, moh_files_state::pos, moh_files_state::save_total, ast_module_info::self, and ast_channel::writeformat.
{ struct moh_files_state *state; struct mohclass *class = params; if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) { chan->music_state = state; ast_module_ref(ast_module_info->self); } else { state = chan->music_state; } if (!state) { return NULL; } /* LOGIC: Comparing an unrefcounted pointer is a really bad idea, because * malloc may allocate a different class to the same memory block. This * might only happen when two reloads are generated in a short period of * time, but it's still important to protect against. * PROG: Compare the quick operation first, to save CPU. */ if (state->save_total != class->total_files || strcmp(state->name, class->name) != 0) { memset(state, 0, sizeof(*state)); if (ast_test_flag(class, MOH_RANDOMIZE) && class->total_files) { state->pos = ast_random() % class->total_files; } } state->class = mohclass_ref(class, "Reffing music class for channel"); state->origwfmt = chan->writeformat; /* For comparison on restart of MOH (see above) */ ast_copy_string(state->name, class->name, sizeof(state->name)); state->save_total = class->total_files; ast_verb(3, "Started music on hold, class '%s', on %s\n", class->name, chan->name); return chan->music_state; }
static int moh_files_generator | ( | struct ast_channel * | chan, |
void * | data, | ||
int | len, | ||
int | samples | ||
) | [static] |
Definition at line 335 of file res_musiconhold.c.
References ast_channel_lock, ast_channel_unlock, ast_frfree, ast_log(), ast_write(), errno, f, LOG_WARNING, moh_files_readframe(), ast_channel::music_state, ast_channel::name, moh_files_state::sample_queue, moh_files_state::samples, and ast_frame::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) { ast_channel_lock(chan); if ((f = moh_files_readframe(chan))) { /* We need to be sure that we unlock * the channel prior to calling * ast_write. Otherwise, the recursive locking * that occurs can cause deadlocks when using * indirect channels, like local channels */ ast_channel_unlock(chan); state->samples += f->samples; state->sample_queue -= 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; } } else { ast_channel_unlock(chan); return -1; } } return res; }
static struct ast_frame* moh_files_readframe | ( | struct ast_channel * | chan | ) | [static, read] |
Definition at line 323 of file res_musiconhold.c.
References ast_moh_files_next(), ast_readframe(), f, and ast_channel::stream.
Referenced by moh_files_generator().
{ struct ast_frame *f = NULL; if (!(chan->stream && (f = ast_readframe(chan->stream)))) { if (!ast_moh_files_next(chan)) f = ast_readframe(chan->stream); } return f; }
static void moh_files_release | ( | struct ast_channel * | chan, |
void * | data | ||
) | [static] |
Definition at line 228 of file res_musiconhold.c.
References ast_closestream(), ast_log(), ast_set_write_format(), ast_verbose(), moh_files_state::class, LOG_WARNING, mohclass_unref, ast_channel::music_state, ast_channel::name, option_verbose, moh_files_state::origwfmt, moh_files_state::pos, moh_files_state::save_pos, ast_channel::stream, and VERBOSE_PREFIX_3.
{ struct moh_files_state *state; if (!chan || !chan->music_state) { return; } state = chan->music_state; if (chan->stream) { ast_closestream(chan->stream); chan->stream = NULL; } 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; state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator"); }
static int moh_generate | ( | struct ast_channel * | chan, |
void * | data, | ||
int | len, | ||
int | samples | ||
) | [static] |
Definition at line 911 of file res_musiconhold.c.
References ast_codec_get_len(), ast_codec_get_samples(), AST_FRIENDLY_OFFSET, ast_log(), ast_write(), buf, ast_frame::data, ast_frame::datalen, errno, mohdata::f, mohclass::format, LOG_WARNING, moh, ast_channel::name, mohdata::parent, mohdata::pipe, ast_frame::ptr, and ast_frame::samples.
{ struct mohdata *moh = data; short buf[1280 + AST_FRIENDLY_OFFSET / 2]; int res; len = ast_codec_get_len(moh->parent->format, samples); if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) { ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name); len = sizeof(buf) - AST_FRIENDLY_OFFSET; } res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len); if (res <= 0) return 0; moh->f.datalen = res; moh->f.data.ptr = buf + AST_FRIENDLY_OFFSET / 2; moh->f.samples = ast_codec_get_samples(&moh->f); if (ast_write(chan, &moh->f) < 0) { ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); return -1; } return 0; }
static void moh_handle_digit | ( | struct ast_channel * | chan, |
char | digit | ||
) | [static] |
Definition at line 422 of file res_musiconhold.c.
References ast_moh_start(), ast_moh_stop(), ast_strdupa, ast_string_field_set, get_mohbydigit(), mohclass_unref, and musicclass.
{ struct mohclass *class; const char *classname = NULL; if ((class = get_mohbydigit(digit))) { classname = ast_strdupa(class->name); class = mohclass_unref(class, "Unreffing ao2_find from finding by digit"); ast_string_field_set(chan,musicclass,classname); ast_moh_stop(chan); ast_moh_start(chan, classname, NULL); } }
static void moh_release | ( | struct ast_channel * | chan, |
void * | data | ||
) | [static] |
Definition at line 852 of file res_musiconhold.c.
References ao2_lock(), ao2_unlock(), ast_free, ast_getformatname(), AST_LIST_REMOVE, ast_log(), ast_set_write_format(), ast_verb, LOG_WARNING, mohclass::members, moh, mohclass_unref, ast_channel::name, mohdata::origwfmt, mohdata::parent, and mohdata::pipe.
Referenced by moh_alloc().
{ struct mohdata *moh = data; struct mohclass *class = moh->parent; int oldwfmt; ao2_lock(class); AST_LIST_REMOVE(&moh->parent->members, moh, list); ao2_unlock(class); close(moh->pipe[0]); close(moh->pipe[1]); oldwfmt = moh->origwfmt; moh->parent = class = mohclass_unref(class, "unreffing moh->parent upon deactivation of generator"); ast_free(moh); if (chan) { if (oldwfmt && ast_set_write_format(chan, oldwfmt)) { ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt)); } ast_verb(3, "Stopped music on hold on %s\n", chan->name); } }
static void moh_rescan_files | ( | void | ) | [static] |
Definition at line 1091 of file res_musiconhold.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, and moh_scan_files().
Referenced by load_moh_classes().
{ struct ao2_iterator i; struct mohclass *c; i = ao2_iterator_init(mohclasses, 0); while ((c = ao2_iterator_next(&i))) { moh_scan_files(c); ao2_ref(c, -1); } ao2_iterator_destroy(&i); }
static int moh_scan_files | ( | struct mohclass * | class | ) | [static] |
Definition at line 979 of file res_musiconhold.c.
References ast_config_AST_DATA_DIR, ast_copy_string(), ast_debug, ast_free, ast_log(), ast_test_flag, errno, ext, LOG_WARNING, moh_add_file(), moh_sort_compare(), and MOH_SORTALPHA.
Referenced by init_files_class(), local_ast_moh_start(), and moh_rescan_files().
{ DIR *files_DIR; struct dirent *files_dirent; char dir_path[PATH_MAX]; char path[PATH_MAX]; char filepath[PATH_MAX]; char *ext; struct stat statbuf; int dirnamelen; int i; if (class->dir[0] != '/') { ast_copy_string(dir_path, ast_config_AST_DATA_DIR, sizeof(dir_path)); strncat(dir_path, "/", sizeof(dir_path) - 1); strncat(dir_path, class->dir, sizeof(dir_path) - 1); } else { ast_copy_string(dir_path, class->dir, sizeof(dir_path)); } ast_debug(4, "Scanning '%s' for files for class '%s'\n", dir_path, class->name); files_DIR = opendir(dir_path); if (!files_DIR) { ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", dir_path); return -1; } for (i = 0; i < class->total_files; i++) ast_free(class->filearray[i]); class->total_files = 0; dirnamelen = strlen(dir_path) + 2; if (!getcwd(path, sizeof(path))) { ast_log(LOG_WARNING, "getcwd() failed: %s\n", strerror(errno)); return -1; } if (chdir(dir_path) < 0) { ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); return -1; } while ((files_dirent = readdir(files_DIR))) { /* The file name must be at least long enough to have the file type extension */ if ((strlen(files_dirent->d_name) < 4)) continue; /* Skip files that starts with a dot */ if (files_dirent->d_name[0] == '.') continue; /* Skip files without extensions... they are not audio */ if (!strchr(files_dirent->d_name, '.')) continue; snprintf(filepath, sizeof(filepath), "%s/%s", dir_path, files_dirent->d_name); if (stat(filepath, &statbuf)) continue; if (!S_ISREG(statbuf.st_mode)) continue; if ((ext = strrchr(filepath, '.'))) *ext = '\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) { if (moh_add_file(class, filepath)) break; } } closedir(files_DIR); if (chdir(path) < 0) { ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); return -1; } if (ast_test_flag(class, MOH_SORTALPHA)) qsort(&class->filearray[0], class->total_files, sizeof(char *), moh_sort_compare); return class->total_files; }
static int moh_sort_compare | ( | const void * | i1, |
const void * | i2 | ||
) | [static] |
Definition at line 969 of file res_musiconhold.c.
Referenced by moh_scan_files().
{ char *s1, *s2; s1 = ((char **)i1)[0]; s2 = ((char **)i2)[0]; return strcasecmp(s1, s2); }
Definition at line 819 of file res_musiconhold.c.
References ao2_lock(), ao2_unlock(), ast_calloc, AST_FRAME_VOICE, ast_free, AST_FRIENDLY_OFFSET, AST_LIST_INSERT_HEAD, ast_log(), errno, mohdata::f, mohclass::flags, mohclass::format, ast_frame::frametype, LOG_WARNING, mohclass::members, moh, mohclass_ref, ast_frame::offset, mohdata::parent, mohdata::pipe, and ast_frame::subclass.
Referenced by moh_alloc().
{ struct mohdata *moh; long flags; if (!(moh = ast_calloc(1, sizeof(*moh)))) return NULL; if (pipe(moh->pipe)) { ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno)); ast_free(moh); return NULL; } /* Make entirely non-blocking */ flags = fcntl(moh->pipe[0], F_GETFL); fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK); flags = fcntl(moh->pipe[1], F_GETFL); fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK); moh->f.frametype = AST_FRAME_VOICE; moh->f.subclass = cl->format; moh->f.offset = AST_FRIENDLY_OFFSET; moh->parent = mohclass_ref(cl, "Reffing music class for mohdata parent"); ao2_lock(cl); AST_LIST_INSERT_HEAD(&cl->members, moh, list); ao2_unlock(cl); return moh; }
static void* monmp3thread | ( | void * | data | ) | [static] |
Definition at line 585 of file res_musiconhold.c.
References ao2_lock(), ao2_unlock(), ast_codec_get_len(), ast_debug, AST_LIST_EMPTY, AST_LIST_TRAVERSE, ast_log(), ast_samp2tv(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), buf, errno, len(), LOG_NOTICE, LOG_WARNING, moh, MOH_MS_INTERVAL, mohdata::pipe, and spawn_mp3().
Referenced by init_app_class(), and local_ast_moh_start().
{ #define MOH_MS_INTERVAL 100 struct mohclass *class = data; struct mohdata *moh; char buf[8192]; short sbuf[8192]; int res, res2; int len; struct timeval deadline, tv_tmp; deadline.tv_sec = 0; deadline.tv_usec = 0; for(;/* ever */;) { pthread_testcancel(); /* Spawn mp3 player if it's not there */ if (class->srcfd < 0) { if ((class->srcfd = spawn_mp3(class)) < 0) { ast_log(LOG_WARNING, "Unable to spawn mp3player\n"); /* Try again later */ sleep(500); pthread_testcancel(); } } if (class->pseudofd > -1) { #ifdef SOLARIS thr_yield(); #endif /* Pause some amount of time */ res = read(class->pseudofd, buf, sizeof(buf)); pthread_testcancel(); } else { long delta; /* Reliable sleep */ tv_tmp = ast_tvnow(); if (ast_tvzero(deadline)) deadline = tv_tmp; delta = ast_tvdiff_ms(tv_tmp, deadline); if (delta < MOH_MS_INTERVAL) { /* too early */ deadline = ast_tvadd(deadline, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */ usleep(1000 * (MOH_MS_INTERVAL - delta)); pthread_testcancel(); } else { ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n"); deadline = tv_tmp; } res = 8 * MOH_MS_INTERVAL; /* 8 samples per millisecond */ } if ((strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir")) && AST_LIST_EMPTY(&class->members)) continue; /* Read mp3 audio */ len = ast_codec_get_len(class->format, res); if ((res2 = read(class->srcfd, sbuf, len)) != len) { if (!res2) { close(class->srcfd); class->srcfd = -1; pthread_testcancel(); if (class->pid > 1) { do { if (killpg(class->pid, SIGHUP) < 0) { if (errno == ESRCH) { break; } ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno)); } usleep(100000); if (killpg(class->pid, SIGTERM) < 0) { if (errno == ESRCH) { break; } ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno)); } usleep(100000); if (killpg(class->pid, SIGKILL) < 0) { if (errno == ESRCH) { break; } ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno)); } } while (0); class->pid = 0; } } else { ast_debug(1, "Read %d bytes of audio while expecting %d\n", res2, len); } continue; } pthread_testcancel(); ao2_lock(class); AST_LIST_TRAVERSE(&class->members, moh, list) { /* Write data */ if ((res = write(moh->pipe[1], sbuf, res2)) != res2) { ast_debug(1, "Only wrote %d of %d bytes to pipe\n", res, res2); } } ao2_unlock(class); } return NULL; }
static int play_moh_exec | ( | struct ast_channel * | chan, |
void * | data | ||
) | [static] |
Definition at line 689 of file res_musiconhold.c.
References mohclass::args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_moh_start(), ast_moh_stop(), ast_safe_sleep(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, ast_channel::name, parse(), and S_OR.
Referenced by load_module().
{ char *parse; char *class; int timeout = -1; int res; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(class); AST_APP_ARG(duration); ); parse = ast_strdupa(data); AST_STANDARD_APP_ARGS(args, parse); if (!ast_strlen_zero(args.duration)) { if (sscanf(args.duration, "%30d", &timeout) == 1) { timeout *= 1000; } else { ast_log(LOG_WARNING, "Invalid MusicOnHold duration '%s'. Will wait indefinitely.\n", args.duration); } } class = S_OR(args.class, NULL); if (ast_moh_start(chan, class, NULL)) { ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, chan->name); return 0; } if (timeout > 0) res = ast_safe_sleep(chan, timeout); else { while (!(res = ast_safe_sleep(chan, 10000))); } ast_moh_stop(chan); return res; }
static int reload | ( | void | ) | [static] |
static int set_moh_exec | ( | struct ast_channel * | chan, |
void * | data | ||
) | [static] |
Definition at line 752 of file res_musiconhold.c.
References ast_log(), ast_string_field_set, ast_strlen_zero(), LOG_WARNING, and musicclass.
Referenced by load_module().
{ static int deprecation_warning = 0; if (!deprecation_warning) { deprecation_warning = 1; ast_log(LOG_WARNING, "SetMusicOnHold application is deprecated and will be removed. Use Set(CHANNEL(musicclass)=...) instead\n"); } if (ast_strlen_zero(data)) { ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n"); return -1; } ast_string_field_set(chan, musicclass, data); return 0; }
static int spawn_mp3 | ( | struct mohclass * | class | ) | [static] |
Definition at line 444 of file res_musiconhold.c.
References ast_close_fds_above_n(), ast_copy_string(), ast_log(), ast_opt_high_priority, ast_safe_fork(), ast_set_priority(), ast_strlen_zero(), ast_test_flag, mohclass::dir, errno, LOCAL_MPG_123, LOG_WARNING, MAX_MP3S, MOH_CUSTOM, MOH_QUIET, MOH_SINGLE, MPG_123, and strsep().
Referenced by monmp3thread().
{ int fds[2]; int files = 0; char fns[MAX_MP3S][80]; char *argv[MAX_MP3S + 50]; char xargs[256]; char *argptr; int argc = 0; DIR *dir = NULL; struct dirent *de; if (!strcasecmp(class->dir, "nodir")) { files = 1; } else { dir = opendir(class->dir); if (!dir && strncasecmp(class->dir, "http://", 7)) { ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir); return -1; } } if (!ast_test_flag(class, MOH_CUSTOM)) { argv[argc++] = "mpg123"; argv[argc++] = "-q"; argv[argc++] = "-s"; argv[argc++] = "--mono"; argv[argc++] = "-r"; argv[argc++] = "8000"; if (!ast_test_flag(class, MOH_SINGLE)) { argv[argc++] = "-b"; argv[argc++] = "2048"; } argv[argc++] = "-f"; if (ast_test_flag(class, MOH_QUIET)) argv[argc++] = "4096"; else argv[argc++] = "8192"; /* Look for extra arguments and add them to the list */ ast_copy_string(xargs, class->args, sizeof(xargs)); argptr = xargs; while (!ast_strlen_zero(argptr)) { argv[argc++] = argptr; strsep(&argptr, ","); } } else { /* Format arguments for argv vector */ ast_copy_string(xargs, class->args, sizeof(xargs)); argptr = xargs; while (!ast_strlen_zero(argptr)) { argv[argc++] = argptr; strsep(&argptr, " "); } } if (!strncasecmp(class->dir, "http://", 7)) { ast_copy_string(fns[files], class->dir, sizeof(fns[files])); argv[argc++] = fns[files]; files++; } else if (dir) { while ((de = readdir(dir)) && (files < MAX_MP3S)) { if ((strlen(de->d_name) > 3) && ((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, ".sln"))) || !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) { ast_copy_string(fns[files], de->d_name, sizeof(fns[files])); argv[argc++] = fns[files]; files++; } } } argv[argc] = NULL; if (dir) { closedir(dir); } if (pipe(fds)) { ast_log(LOG_WARNING, "Pipe failed\n"); return -1; } if (!files) { ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir); close(fds[0]); close(fds[1]); return -1; } if (!strncasecmp(class->dir, "http://", 7) && time(NULL) - class->start < respawn_time) { sleep(respawn_time - (time(NULL) - class->start)); } time(&class->start); class->pid = ast_safe_fork(0); if (class->pid < 0) { close(fds[0]); close(fds[1]); ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno)); return -1; } if (!class->pid) { if (ast_opt_high_priority) ast_set_priority(0); close(fds[0]); /* Stdout goes to pipe */ dup2(fds[1], STDOUT_FILENO); /* Close everything else */ ast_close_fds_above_n(STDERR_FILENO); /* Child */ if (strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir") && chdir(class->dir) < 0) { ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); _exit(1); } setpgid(0, getpid()); if (ast_test_flag(class, MOH_CUSTOM)) { 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); } /* Can't use logger, since log FDs are closed */ fprintf(stderr, "MOH: exec failed: %s\n", strerror(errno)); close(fds[1]); _exit(1); } else { /* Parent */ close(fds[1]); } return fds[0]; }
static int start_moh_exec | ( | struct ast_channel * | chan, |
void * | data | ||
) | [static] |
Definition at line 769 of file res_musiconhold.c.
References mohclass::args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_moh_start(), AST_STANDARD_APP_ARGS, ast_strdupa, LOG_WARNING, ast_channel::name, parse(), and S_OR.
Referenced by load_module().
{ char *parse; char *class; AST_DECLARE_APP_ARGS(args, AST_APP_ARG(class); ); parse = ast_strdupa(data); AST_STANDARD_APP_ARGS(args, parse); class = S_OR(args.class, NULL); if (ast_moh_start(chan, class, NULL)) ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, chan->name); return 0; }
static int stop_moh_exec | ( | struct ast_channel * | chan, |
void * | data | ||
) | [static] |
Definition at line 788 of file res_musiconhold.c.
References ast_moh_stop().
Referenced by load_module().
{ ast_moh_stop(chan); return 0; }
static int unload_module | ( | void | ) | [static] |
Definition at line 1879 of file res_musiconhold.c.
References ao2_t_callback, ARRAY_LEN, ast_cli_unregister_multiple(), ast_log(), ast_moh_destroy(), ast_uninstall_music_functions(), ast_unregister_application(), ast_unregister_atexit(), LOG_WARNING, moh_class_inuse(), and mohclass_unref.
{ int res = 0; struct mohclass *class = NULL; /* XXX This check shouldn't be required if module ref counting was being used * properly ... */ if ((class = ao2_t_callback(mohclasses, 0, moh_class_inuse, NULL, "Module unload callback"))) { class = mohclass_unref(class, "unref of class from module unload callback"); res = -1; } if (res < 0) { ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n"); return res; } ast_uninstall_music_functions(); ast_moh_destroy(); res = ast_unregister_application(play_moh); res |= ast_unregister_application(wait_moh); res |= ast_unregister_application(set_moh); res |= ast_unregister_application(start_moh); res |= ast_unregister_application(stop_moh); ast_cli_unregister_multiple(cli_moh, ARRAY_LEN(cli_moh)); ast_unregister_atexit(ast_moh_destroy); return res; }
static int wait_moh_exec | ( | struct ast_channel * | chan, |
void * | data | ||
) | [static] |
Definition at line 729 of file res_musiconhold.c.
References ast_log(), ast_moh_start(), ast_moh_stop(), ast_safe_sleep(), LOG_WARNING, and ast_channel::name.
Referenced by load_module().
{ static int deprecation_warning = 0; int res; if (!deprecation_warning) { deprecation_warning = 1; ast_log(LOG_WARNING, "WaitMusicOnHold application is deprecated and will be removed. Use MusicOnHold with duration parameter instead\n"); } if (!data || !atoi(data)) { ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n"); return -1; } if (ast_moh_start(chan, NULL, NULL)) { ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name); return 0; } res = ast_safe_sleep(chan, atoi(data) * 1000); ast_moh_stop(chan); return res; }
struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Music On Hold Resource" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 1914 of file res_musiconhold.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1914 of file res_musiconhold.c.
struct ast_cli_entry cli_moh[] [static] |
{ AST_CLI_DEFINE(handle_cli_moh_reload, "Reload MusicOnHold"), AST_CLI_DEFINE(handle_cli_moh_show_classes, "List MusicOnHold classes"), AST_CLI_DEFINE(handle_cli_moh_show_files, "List MusicOnHold file-based classes") }
Definition at line 1809 of file res_musiconhold.c.
struct ast_flags global_flags[1] = {{0}} [static] |
global MOH_ flags
Definition at line 152 of file res_musiconhold.c.
struct ast_generator moh_file_stream [static] |
Definition at line 436 of file res_musiconhold.c.
struct ao2_container* mohclasses [static] |
Definition at line 192 of file res_musiconhold.c.
struct ast_generator mohgen [static] |
Definition at line 939 of file res_musiconhold.c.
char* play_moh = "MusicOnHold" [static] |
Definition at line 79 of file res_musiconhold.c.
char* play_moh_desc = "Returns 0 when done, -1 on hangup.\n" [static] |
Definition at line 91 of file res_musiconhold.c.
char* play_moh_syn = "Play Music On Hold indefinitely" [static] |
Definition at line 85 of file res_musiconhold.c.
int respawn_time = 20 [static] |
Definition at line 127 of file res_musiconhold.c.
Referenced by _moh_register(), and local_ast_moh_start().
char* set_moh = "SetMusicOnHold" [static] |
Definition at line 81 of file res_musiconhold.c.
char* set_moh_desc = " !!! DEPRECATED. USe Set(CHANNEL(musicclass)=...) instead !!!\n" [static] |
Definition at line 109 of file res_musiconhold.c.
char* set_moh_syn = "Set default Music On Hold class" [static] |
Definition at line 87 of file res_musiconhold.c.
char* start_moh = "StartMusicOnHold" [static] |
Definition at line 82 of file res_musiconhold.c.
char* start_moh_desc = "music source for the channel will be used. Always returns 0.\n" [static] |
Definition at line 119 of file res_musiconhold.c.
char* start_moh_syn = "Play Music On Hold" [static] |
Definition at line 88 of file res_musiconhold.c.
char* stop_moh = "StopMusicOnHold" [static] |
Definition at line 83 of file res_musiconhold.c.
char* stop_moh_desc = "Stops playing music on hold.\n" [static] |
Definition at line 124 of file res_musiconhold.c.
char* stop_moh_syn = "Stop Playing Music On Hold" [static] |
Definition at line 89 of file res_musiconhold.c.
char* wait_moh = "WaitMusicOnHold" [static] |
Definition at line 80 of file res_musiconhold.c.
char* wait_moh_desc = " !!! DEPRECATED. Use MusicOnHold instead !!!\n" [static] |
Definition at line 99 of file res_musiconhold.c.
char* wait_moh_syn = "Wait, playing Music On Hold" [static] |
Definition at line 86 of file res_musiconhold.c.