#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 <dahdi/user.h>
#include <sys/capability.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/astobj2.h"
Go to the source code of this file.
Data Structures | |
struct | moh_files_state |
struct | mohclass |
struct | mohdata |
Defines | |
#define | INITIAL_NUM_FILES 8 |
#define | LOCAL_MPG_123 "/usr/local/bin/mpg123" |
#define | MAX_MP3S 256 |
#define | MOH_CACHERTCLASSES (1 << 5) |
#define | MOH_CUSTOM (1 << 2) |
#define | MOH_MS_INTERVAL 100 |
#define | MOH_QUIET (1 << 0) |
#define | MOH_RANDOMIZE (1 << 3) |
#define | MOH_SINGLE (1 << 1) |
#define | MOH_SORTALPHA (1 << 4) |
#define | mohclass_ref(class) (ao2_ref((class), +1), class) |
#define | mohclass_unref(class) (ao2_ref((class), -1), (struct mohclass *) NULL) |
#define | MPG_123 "/usr/bin/mpg123" |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static void | ast_moh_destroy (void) |
static int | ast_moh_files_next (struct ast_channel *chan) |
static struct mohclass * | get_mohbydigit (char digit) |
static struct mohclass * | get_mohbyname (const char *name, int warn) |
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 struct mohclass * | moh_class_malloc (void) |
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 int | moh_register (struct mohclass *moh, int reload, int unref) |
static void | moh_release (struct ast_channel *chan, void *data) |
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 | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Music On Hold Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, } |
static const 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 |
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 |
static char * | set_moh_syn = "Set default Music On Hold class" |
static char * | start_moh = "StartMusicOnHold" |
static char * | start_moh_desc |
static char * | start_moh_syn = "Play Music On Hold" |
static char * | stop_moh = "StopMusicOnHold" |
static char * | stop_moh_desc |
static char * | stop_moh_syn = "Stop Playing Music On Hold" |
static char * | wait_moh = "WaitMusicOnHold" |
static char * | wait_moh_desc |
static char * | wait_moh_syn = "Wait, playing Music On Hold" |
Definition in file res_musiconhold.c.
#define INITIAL_NUM_FILES 8 |
#define LOCAL_MPG_123 "/usr/local/bin/mpg123" |
Definition at line 185 of file res_musiconhold.c.
#define MAX_MP3S 256 |
#define MOH_CACHERTCLASSES (1 << 5) |
Should we use a separate instance of MOH for each user or not
Definition at line 141 of file res_musiconhold.c.
Referenced by load_moh_classes(), and local_ast_moh_start().
#define MOH_CUSTOM (1 << 2) |
Definition at line 137 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_QUIET (1 << 0) |
Definition at line 135 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 138 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_SINGLE (1 << 1) |
Definition at line 136 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 139 of file res_musiconhold.c.
Referenced by load_moh_classes(), and local_ast_moh_start().
#define mohclass_ref | ( | class | ) | (ao2_ref((class), +1), class) |
#define mohclass_unref | ( | class | ) | (ao2_ref((class), -1), (struct mohclass *) NULL) |
Definition at line 192 of file res_musiconhold.c.
Referenced by handle_cli_moh_show_classes(), handle_cli_moh_show_files(), local_ast_moh_start(), moh_files_release(), moh_handle_digit(), moh_register(), moh_release(), and unload_module().
#define MPG_123 "/usr/bin/mpg123" |
Definition at line 186 of file res_musiconhold.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 1741 of file res_musiconhold.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1741 of file res_musiconhold.c.
static void ast_moh_destroy | ( | void | ) | [static] |
Definition at line 1537 of file res_musiconhold.c.
References ao2_callback(), ast_verb, mohclasses, OBJ_MULTIPLE, OBJ_NODATA, and OBJ_UNLINK.
Referenced by load_module(), and unload_module().
01538 { 01539 ast_verb(2, "Destroying musiconhold processes\n"); 01540 ao2_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL); 01541 }
static int ast_moh_files_next | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 222 of file res_musiconhold.c.
References ast_closestream(), ast_fileexists(), ast_log(), ast_openstream_full(), ast_random(), ast_test_flag, chan, moh_files_state::class, errno, mohclass::filearray, ast_channel::language, LOG_WARNING, MOH_RANDOMIZE, ast_channel::music_state, 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().
00223 { 00224 struct moh_files_state *state = chan->music_state; 00225 int tries; 00226 00227 /* Discontinue a stream if it is running already */ 00228 if (chan->stream) { 00229 ast_closestream(chan->stream); 00230 chan->stream = NULL; 00231 } 00232 00233 if (!state->class->total_files) { 00234 ast_log(LOG_WARNING, "No files available for class '%s'\n", state->class->name); 00235 return -1; 00236 } 00237 00238 /* If a specific file has been saved confirm it still exists and that it is still valid */ 00239 if (state->save_pos >= 0 && state->save_pos < state->class->total_files && state->class->filearray[state->save_pos] == state->save_pos_filename) { 00240 state->pos = state->save_pos; 00241 state->save_pos = -1; 00242 } else if (ast_test_flag(state->class, MOH_RANDOMIZE)) { 00243 /* Get a random file and ensure we can open it */ 00244 for (tries = 0; tries < 20; tries++) { 00245 state->pos = ast_random() % state->class->total_files; 00246 if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0) 00247 break; 00248 } 00249 state->save_pos = -1; 00250 state->samples = 0; 00251 } else { 00252 /* This is easy, just increment our position and make sure we don't exceed the total file count */ 00253 state->pos++; 00254 state->pos %= state->class->total_files; 00255 state->save_pos = -1; 00256 state->samples = 0; 00257 } 00258 00259 if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) { 00260 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno)); 00261 state->pos++; 00262 state->pos %= state->class->total_files; 00263 return -1; 00264 } 00265 00266 /* Record the pointer to the filename for position resuming later */ 00267 state->save_pos_filename = state->class->filearray[state->pos]; 00268 00269 ast_debug(1, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]); 00270 00271 if (state->samples) 00272 ast_seekstream(chan->stream, state->samples, SEEK_SET); 00273 00274 return 0; 00275 }
static struct mohclass* get_mohbydigit | ( | char | digit | ) | [static] |
Definition at line 352 of file res_musiconhold.c.
References ao2_callback(), and moh_digit_match().
Referenced by moh_handle_digit().
00353 { 00354 return ao2_callback(mohclasses, 0, moh_digit_match, &digit); 00355 }
static struct mohclass* get_mohbyname | ( | const char * | name, | |
int | warn | |||
) | [static] |
Definition at line 742 of file res_musiconhold.c.
References ao2_find(), ast_copy_string(), ast_log(), mohclass::flags, LOG_DEBUG, moh, mohclasses, and mohclass::name.
Referenced by local_ast_moh_start(), and moh_register().
00743 { 00744 struct mohclass *moh = NULL; 00745 struct mohclass tmp_class = { 00746 .flags = 0, 00747 }; 00748 00749 ast_copy_string(tmp_class.name, name, sizeof(tmp_class.name)); 00750 00751 moh = ao2_find(mohclasses, &tmp_class, 0); 00752 00753 if (!moh && warn) { 00754 ast_log(LOG_DEBUG, "Music on Hold class '%s' not found in memory\n", name); 00755 } 00756 00757 return moh; 00758 }
static char* handle_cli_moh_reload | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 1543 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.
01544 { 01545 switch (cmd) { 01546 case CLI_INIT: 01547 e->command = "moh reload"; 01548 e->usage = 01549 "Usage: moh reload\n" 01550 " Reloads the MusicOnHold module.\n" 01551 " Alias for 'module reload res_musiconhold.so'\n"; 01552 return NULL; 01553 case CLI_GENERATE: 01554 return NULL; 01555 } 01556 01557 if (a->argc != e->args) 01558 return CLI_SHOWUSAGE; 01559 01560 reload(); 01561 01562 return CLI_SUCCESS; 01563 }
static char* handle_cli_moh_show_classes | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 1603 of file res_musiconhold.c.
References ao2_iterator_init(), ao2_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, mohclasses, S_OR, and ast_cli_entry::usage.
01604 { 01605 struct mohclass *class; 01606 struct ao2_iterator i; 01607 01608 switch (cmd) { 01609 case CLI_INIT: 01610 e->command = "moh show classes"; 01611 e->usage = 01612 "Usage: moh show classes\n" 01613 " Lists all MusicOnHold classes.\n"; 01614 return NULL; 01615 case CLI_GENERATE: 01616 return NULL; 01617 } 01618 01619 if (a->argc != e->args) 01620 return CLI_SHOWUSAGE; 01621 01622 i = ao2_iterator_init(mohclasses, 0); 01623 01624 for (; (class = ao2_iterator_next(&i)); mohclass_unref(class)) { 01625 ast_cli(a->fd, "Class: %s\n", class->name); 01626 ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>")); 01627 ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>")); 01628 if (ast_test_flag(class, MOH_CUSTOM)) { 01629 ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>")); 01630 } 01631 if (strcasecmp(class->mode, "files")) { 01632 ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(class->format)); 01633 } 01634 } 01635 01636 return CLI_SUCCESS; 01637 }
static char* handle_cli_moh_show_files | ( | struct ast_cli_entry * | e, | |
int | cmd, | |||
struct ast_cli_args * | a | |||
) | [static] |
Definition at line 1565 of file res_musiconhold.c.
References ao2_iterator_init(), ao2_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, mohclasses, and ast_cli_entry::usage.
01566 { 01567 struct mohclass *class; 01568 struct ao2_iterator i; 01569 01570 switch (cmd) { 01571 case CLI_INIT: 01572 e->command = "moh show files"; 01573 e->usage = 01574 "Usage: moh show files\n" 01575 " Lists all loaded file-based MusicOnHold classes and their\n" 01576 " files.\n"; 01577 return NULL; 01578 case CLI_GENERATE: 01579 return NULL; 01580 } 01581 01582 if (a->argc != e->args) 01583 return CLI_SHOWUSAGE; 01584 01585 i = ao2_iterator_init(mohclasses, 0); 01586 01587 for (; (class = ao2_iterator_next(&i)); mohclass_unref(class)) { 01588 int x; 01589 01590 if (!class->total_files) { 01591 continue; 01592 } 01593 01594 ast_cli(a->fd, "Class: %s\n", class->name); 01595 for (x = 0; x < class->total_files; x++) { 01596 ast_cli(a->fd, "\tFile: %s\n", class->filearray[x]); 01597 } 01598 } 01599 01600 return CLI_SUCCESS; 01601 }
static int init_app_class | ( | struct mohclass * | class | ) | [static] |
Definition at line 1039 of file res_musiconhold.c.
References ast_log(), ast_pthread_create_background, ast_set_flag, LOG_WARNING, mohclass::mode, MOH_CUSTOM, MOH_QUIET, MOH_SINGLE, monmp3thread(), mohclass::pseudofd, and mohclass::thread.
Referenced by moh_register().
01040 { 01041 #ifdef HAVE_DAHDI 01042 int x; 01043 #endif 01044 01045 if (!strcasecmp(class->mode, "custom")) { 01046 ast_set_flag(class, MOH_CUSTOM); 01047 } else if (!strcasecmp(class->mode, "mp3nb")) { 01048 ast_set_flag(class, MOH_SINGLE); 01049 } else if (!strcasecmp(class->mode, "quietmp3nb")) { 01050 ast_set_flag(class, MOH_SINGLE | MOH_QUIET); 01051 } else if (!strcasecmp(class->mode, "quietmp3")) { 01052 ast_set_flag(class, MOH_QUIET); 01053 } 01054 01055 class->srcfd = -1; 01056 class->pseudofd = -1; 01057 01058 #ifdef HAVE_DAHDI 01059 /* Open /dev/zap/pseudo for timing... Is 01060 there a better, yet reliable way to do this? */ 01061 class->pseudofd = open("/dev/dahdi/pseudo", O_RDONLY); 01062 if (class->pseudofd < 0) { 01063 ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n"); 01064 } else { 01065 x = 320; 01066 ioctl(class->pseudofd, DAHDI_SET_BLOCKSIZE, &x); 01067 } 01068 #endif 01069 01070 if (ast_pthread_create_background(&class->thread, NULL, monmp3thread, class)) { 01071 ast_log(LOG_WARNING, "Unable to create moh thread...\n"); 01072 if (class->pseudofd > -1) { 01073 close(class->pseudofd); 01074 class->pseudofd = -1; 01075 } 01076 return -1; 01077 } 01078 01079 return 0; 01080 }
static int init_files_class | ( | struct mohclass * | class | ) | [static] |
Definition at line 994 of file res_musiconhold.c.
References mohclass::args, ast_set_flag, ast_verbose(), mohclass::dir, MOH_RANDOMIZE, moh_scan_files(), mohclass::name, option_verbose, and VERBOSE_PREFIX_3.
Referenced by moh_register().
00995 { 00996 int res; 00997 00998 res = moh_scan_files(class); 00999 01000 if (res < 0) { 01001 return -1; 01002 } 01003 01004 if (!res) { 01005 if (option_verbose > 2) { 01006 ast_verbose(VERBOSE_PREFIX_3 "Files not found in %s for moh class:%s\n", 01007 class->dir, class->name); 01008 } 01009 return -1; 01010 } 01011 01012 if (strchr(class->args, 'r')) { 01013 ast_set_flag(class, MOH_RANDOMIZE); 01014 } 01015 01016 return 0; 01017 }
static int load_module | ( | void | ) | [static] |
Definition at line 1659 of file res_musiconhold.c.
References ao2_container_alloc(), 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(), cli_moh, load_moh_classes(), local_ast_moh_cleanup(), local_ast_moh_start(), local_ast_moh_stop(), LOG_WARNING, moh_class_cmp(), moh_class_hash(), mohclasses, play_moh_exec(), set_moh_exec(), start_moh_exec(), stop_moh_exec(), and wait_moh_exec().
01660 { 01661 int res; 01662 01663 if (!(mohclasses = ao2_container_alloc(53, moh_class_hash, moh_class_cmp))) { 01664 return AST_MODULE_LOAD_DECLINE; 01665 } 01666 01667 if (!load_moh_classes(0)) { /* No music classes configured, so skip it */ 01668 ast_log(LOG_WARNING, "No music on hold classes configured, " 01669 "disabling music on hold.\n"); 01670 } else { 01671 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, 01672 local_ast_moh_cleanup); 01673 } 01674 01675 res = ast_register_application(play_moh, play_moh_exec, play_moh_syn, play_moh_desc); 01676 ast_register_atexit(ast_moh_destroy); 01677 ast_cli_register_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry)); 01678 if (!res) 01679 res = ast_register_application(wait_moh, wait_moh_exec, wait_moh_syn, wait_moh_desc); 01680 if (!res) 01681 res = ast_register_application(set_moh, set_moh_exec, set_moh_syn, set_moh_desc); 01682 if (!res) 01683 res = ast_register_application(start_moh, start_moh_exec, start_moh_syn, start_moh_desc); 01684 if (!res) 01685 res = ast_register_application(stop_moh, stop_moh_exec, stop_moh_syn, stop_moh_desc); 01686 01687 return AST_MODULE_LOAD_SUCCESS; 01688 }
static int load_moh_classes | ( | int | reload | ) | [static] |
Definition at line 1436 of file res_musiconhold.c.
References ao2_callback(), ast_category_browse(), ast_clear_flag, ast_config_load, ast_copy_string(), AST_FLAGS_ALL, AST_FORMAT_SLINEAR, ast_getformatbyname(), ast_log(), ast_set2_flag, ast_set_flag, ast_true(), ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, global_flags, LOG_WARNING, MOH_CACHERTCLASSES, moh_class_malloc(), moh_class_mark(), MOH_RANDOMIZE, MOH_SORTALPHA, mohclasses, OBJ_NODATA, and var.
Referenced by load_module().
01437 { 01438 struct ast_config *cfg; 01439 struct ast_variable *var; 01440 struct mohclass *class; 01441 char *cat; 01442 int numclasses = 0; 01443 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 01444 01445 cfg = ast_config_load("musiconhold.conf", config_flags); 01446 01447 if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED) 01448 return 0; 01449 01450 if (reload) { 01451 ao2_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL); 01452 } 01453 01454 ast_clear_flag(global_flags, AST_FLAGS_ALL); 01455 01456 cat = ast_category_browse(cfg, NULL); 01457 for (; cat; cat = ast_category_browse(cfg, cat)) { 01458 /* Setup common options from [general] section */ 01459 if (!strcasecmp(cat, "general")) { 01460 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 01461 if (!strcasecmp(var->name, "cachertclasses")) { 01462 ast_set2_flag(global_flags, ast_true(var->value), MOH_CACHERTCLASSES); 01463 } else { 01464 ast_log(LOG_WARNING, "Unknown option '%s' in [general] section of musiconhold.conf\n", var->name); 01465 } 01466 } 01467 } 01468 /* These names were deprecated in 1.4 and should not be used until after the next major release. */ 01469 if (!strcasecmp(cat, "classes") || !strcasecmp(cat, "moh_files") || 01470 !strcasecmp(cat, "general")) { 01471 continue; 01472 } 01473 01474 if (!(class = moh_class_malloc())) { 01475 break; 01476 } 01477 01478 ast_copy_string(class->name, cat, sizeof(class->name)); 01479 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 01480 if (!strcasecmp(var->name, "mode")) 01481 ast_copy_string(class->mode, var->value, sizeof(class->mode)); 01482 else if (!strcasecmp(var->name, "directory")) 01483 ast_copy_string(class->dir, var->value, sizeof(class->dir)); 01484 else if (!strcasecmp(var->name, "application")) 01485 ast_copy_string(class->args, var->value, sizeof(class->args)); 01486 else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value))) 01487 class->digit = *var->value; 01488 else if (!strcasecmp(var->name, "random")) 01489 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE); 01490 else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "random")) 01491 ast_set_flag(class, MOH_RANDOMIZE); 01492 else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) 01493 ast_set_flag(class, MOH_SORTALPHA); 01494 else if (!strcasecmp(var->name, "format")) { 01495 class->format = ast_getformatbyname(var->value); 01496 if (!class->format) { 01497 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value); 01498 class->format = AST_FORMAT_SLINEAR; 01499 } 01500 } 01501 } 01502 01503 if (ast_strlen_zero(class->dir)) { 01504 if (!strcasecmp(class->mode, "custom")) { 01505 strcpy(class->dir, "nodir"); 01506 } else { 01507 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name); 01508 class = mohclass_unref(class); 01509 continue; 01510 } 01511 } 01512 if (ast_strlen_zero(class->mode)) { 01513 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name); 01514 class = mohclass_unref(class); 01515 continue; 01516 } 01517 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) { 01518 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name); 01519 class = mohclass_unref(class); 01520 continue; 01521 } 01522 01523 /* Don't leak a class when it's already registered */ 01524 if (!moh_register(class, reload, 1)) { 01525 numclasses++; 01526 } 01527 } 01528 01529 ast_config_destroy(cfg); 01530 01531 ao2_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, 01532 moh_classes_delete_marked, NULL); 01533 01534 return numclasses; 01535 }
static void local_ast_moh_cleanup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1131 of file res_musiconhold.c.
References ast_free, chan, and ast_channel::music_state.
Referenced by load_module().
01132 { 01133 struct moh_files_state *state = chan->music_state; 01134 01135 if (state) { 01136 ast_free(chan->music_state); 01137 chan->music_state = NULL; 01138 } 01139 }
static int local_ast_moh_start | ( | struct ast_channel * | chan, | |
const char * | mclass, | |||
const char * | interpclass | |||
) | [static] |
Definition at line 1154 of file res_musiconhold.c.
References mohclass::args, ast_check_realtime(), ast_copy_string(), 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(), chan, moh_files_state::class, mohclass::digit, mohclass::dir, mohclass::format, get_mohbyname(), global_flags, LOG_NOTICE, LOG_WARNING, 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, mohclass::name, mohclass::pseudofd, mohclass::realtime, mohclass::srcfd, mohclass::start, mohclass::thread, and var.
Referenced by load_module().
01155 { 01156 struct mohclass *mohclass = NULL; 01157 struct moh_files_state *state = chan->music_state; 01158 int res; 01159 01160 /* The following is the order of preference for which class to use: 01161 * 1) The channels explicitly set musicclass, which should *only* be 01162 * set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan. 01163 * 2) The mclass argument. If a channel is calling ast_moh_start() as the 01164 * result of receiving a HOLD control frame, this should be the 01165 * payload that came with the frame. 01166 * 3) The interpclass argument. This would be from the mohinterpret 01167 * option from channel drivers. This is the same as the old musicclass 01168 * option. 01169 * 4) The default class. 01170 */ 01171 if (!ast_strlen_zero(chan->musicclass)) { 01172 mohclass = get_mohbyname(chan->musicclass, 1); 01173 } 01174 if (!mohclass && !ast_strlen_zero(mclass)) { 01175 mohclass = get_mohbyname(mclass, 1); 01176 } 01177 if (!mohclass && !ast_strlen_zero(interpclass)) { 01178 mohclass = get_mohbyname(interpclass, 1); 01179 } 01180 01181 /* If no moh class found in memory, then check RT */ 01182 if (!mohclass && ast_check_realtime("musiconhold")) { 01183 struct ast_variable *var = NULL, *tmp = NULL; 01184 01185 if (!ast_strlen_zero(chan->musicclass)) { 01186 var = ast_load_realtime("musiconhold", "name", chan->musicclass, NULL); 01187 } 01188 if (!var && !ast_strlen_zero(mclass)) 01189 var = ast_load_realtime("musiconhold", "name", mclass, NULL); 01190 if (!var && !ast_strlen_zero(interpclass)) 01191 var = ast_load_realtime("musiconhold", "name", interpclass, NULL); 01192 if (!var) 01193 var = ast_load_realtime("musiconhold", "name", "default", NULL); 01194 if (var && (mohclass = moh_class_malloc())) { 01195 mohclass->realtime = 1; 01196 for (tmp = var; tmp; tmp = tmp->next) { 01197 if (!strcasecmp(tmp->name, "name")) 01198 ast_copy_string(mohclass->name, tmp->value, sizeof(mohclass->name)); 01199 else if (!strcasecmp(tmp->name, "mode")) 01200 ast_copy_string(mohclass->mode, tmp->value, sizeof(mohclass->mode)); 01201 else if (!strcasecmp(tmp->name, "directory")) 01202 ast_copy_string(mohclass->dir, tmp->value, sizeof(mohclass->dir)); 01203 else if (!strcasecmp(tmp->name, "application")) 01204 ast_copy_string(mohclass->args, tmp->value, sizeof(mohclass->args)); 01205 else if (!strcasecmp(tmp->name, "digit") && (isdigit(*tmp->value) || strchr("*#", *tmp->value))) 01206 mohclass->digit = *tmp->value; 01207 else if (!strcasecmp(tmp->name, "random")) 01208 ast_set2_flag(mohclass, ast_true(tmp->value), MOH_RANDOMIZE); 01209 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "random")) 01210 ast_set_flag(mohclass, MOH_RANDOMIZE); 01211 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "alpha")) 01212 ast_set_flag(mohclass, MOH_SORTALPHA); 01213 else if (!strcasecmp(tmp->name, "format")) { 01214 mohclass->format = ast_getformatbyname(tmp->value); 01215 if (!mohclass->format) { 01216 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", tmp->value); 01217 mohclass->format = AST_FORMAT_SLINEAR; 01218 } 01219 } 01220 } 01221 ast_variables_destroy(var); 01222 if (ast_strlen_zero(mohclass->dir)) { 01223 if (!strcasecmp(mohclass->mode, "custom")) { 01224 strcpy(mohclass->dir, "nodir"); 01225 } else { 01226 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", mohclass->name); 01227 mohclass = mohclass_unref(mohclass); 01228 return -1; 01229 } 01230 } 01231 if (ast_strlen_zero(mohclass->mode)) { 01232 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", mohclass->name); 01233 mohclass = mohclass_unref(mohclass); 01234 return -1; 01235 } 01236 if (ast_strlen_zero(mohclass->args) && !strcasecmp(mohclass->mode, "custom")) { 01237 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", mohclass->name); 01238 mohclass = mohclass_unref(mohclass); 01239 return -1; 01240 } 01241 01242 if (ast_test_flag(global_flags, MOH_CACHERTCLASSES)) { 01243 /* CACHERTCLASSES enabled, let's add this class to default tree */ 01244 if (state && state->class) { 01245 /* Class already exist for this channel */ 01246 ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name); 01247 if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) { 01248 /* we found RT class with the same name, seems like we should continue playing existing one */ 01249 mohclass = mohclass_unref(mohclass); 01250 mohclass = state->class; 01251 } 01252 } 01253 /* We don't want moh_register to unref the mohclass because we do it at the end of this function as well. 01254 * If we allowed moh_register to unref the mohclass,too, then the count would be off by one. The result would 01255 * be that the destructor would be called when the generator on the channel is deactivated. The container then 01256 * has a pointer to a freed mohclass, so any operations involving the mohclass container would result in reading 01257 * invalid memory. 01258 */ 01259 moh_register(mohclass, 0, 0); 01260 } else { 01261 /* We don't register RT moh class, so let's init it manualy */ 01262 01263 time(&mohclass->start); 01264 mohclass->start -= respawn_time; 01265 01266 if (!strcasecmp(mohclass->mode, "files")) { 01267 if (!moh_scan_files(mohclass)) { 01268 mohclass = mohclass_unref(mohclass); 01269 return -1; 01270 } 01271 if (strchr(mohclass->args, 'r')) 01272 ast_set_flag(mohclass, MOH_RANDOMIZE); 01273 } 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")) { 01274 01275 if (!strcasecmp(mohclass->mode, "custom")) 01276 ast_set_flag(mohclass, MOH_CUSTOM); 01277 else if (!strcasecmp(mohclass->mode, "mp3nb")) 01278 ast_set_flag(mohclass, MOH_SINGLE); 01279 else if (!strcasecmp(mohclass->mode, "quietmp3nb")) 01280 ast_set_flag(mohclass, MOH_SINGLE | MOH_QUIET); 01281 else if (!strcasecmp(mohclass->mode, "quietmp3")) 01282 ast_set_flag(mohclass, MOH_QUIET); 01283 01284 mohclass->srcfd = -1; 01285 #ifdef HAVE_DAHDI 01286 /* Open /dev/dahdi/pseudo for timing... Is 01287 there a better, yet reliable way to do this? */ 01288 mohclass->pseudofd = open("/dev/dahdi/pseudo", O_RDONLY); 01289 if (mohclass->pseudofd < 0) { 01290 ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n"); 01291 } else { 01292 int x = 320; 01293 ioctl(mohclass->pseudofd, DAHDI_SET_BLOCKSIZE, &x); 01294 } 01295 #else 01296 mohclass->pseudofd = -1; 01297 #endif 01298 /* Let's check if this channel already had a moh class before */ 01299 if (state && state->class) { 01300 /* Class already exist for this channel */ 01301 ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name); 01302 if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) { 01303 /* we found RT class with the same name, seems like we should continue playing existing one */ 01304 mohclass = mohclass_unref(mohclass); 01305 mohclass = state->class; 01306 } 01307 } else { 01308 if (ast_pthread_create_background(&mohclass->thread, NULL, monmp3thread, mohclass)) { 01309 ast_log(LOG_WARNING, "Unable to create moh...\n"); 01310 if (mohclass->pseudofd > -1) { 01311 close(mohclass->pseudofd); 01312 mohclass->pseudofd = -1; 01313 } 01314 mohclass = mohclass_unref(mohclass); 01315 return -1; 01316 } 01317 } 01318 } else { 01319 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mohclass->mode); 01320 mohclass = mohclass_unref(mohclass); 01321 return -1; 01322 } 01323 } 01324 } else if (var) { 01325 ast_variables_destroy(var); 01326 } 01327 } 01328 01329 if (!mohclass) { 01330 mohclass = get_mohbyname("default", 1); 01331 } 01332 01333 if (!mohclass) { 01334 return -1; 01335 } 01336 01337 ast_set_flag(chan, AST_FLAG_MOH); 01338 01339 if (mohclass->total_files) { 01340 res = ast_activate_generator(chan, &moh_file_stream, mohclass); 01341 } else { 01342 res = ast_activate_generator(chan, &mohgen, mohclass); 01343 } 01344 01345 mohclass = mohclass_unref(mohclass); 01346 01347 return res; 01348 }
static void local_ast_moh_stop | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1350 of file res_musiconhold.c.
References ast_clear_flag, ast_closestream(), ast_deactivate_generator(), AST_FLAG_MOH, chan, ast_channel::music_state, and ast_channel::stream.
Referenced by load_module().
01351 { 01352 struct moh_files_state *state = chan->music_state; 01353 ast_clear_flag(chan, AST_FLAG_MOH); 01354 ast_deactivate_generator(chan); 01355 01356 if (state) { 01357 if (chan->stream) { 01358 ast_closestream(chan->stream); 01359 chan->stream = NULL; 01360 } 01361 } 01362 }
static int moh_add_file | ( | struct mohclass * | class, | |
const char * | filepath | |||
) | [static] |
Definition at line 886 of file res_musiconhold.c.
References mohclass::allowed_files, ast_calloc, ast_realloc, ast_strdup, mohclass::filearray, INITIAL_NUM_FILES, and mohclass::total_files.
00887 { 00888 if (!class->allowed_files) { 00889 if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray)))) 00890 return -1; 00891 class->allowed_files = INITIAL_NUM_FILES; 00892 } else if (class->total_files == class->allowed_files) { 00893 if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) { 00894 class->allowed_files = 0; 00895 class->total_files = 0; 00896 return -1; 00897 } 00898 class->allowed_files *= 2; 00899 } 00900 00901 if (!(class->filearray[class->total_files] = ast_strdup(filepath))) 00902 return -1; 00903 00904 class->total_files++; 00905 00906 return 0; 00907 }
static void* moh_alloc | ( | struct ast_channel * | chan, | |
void * | params | |||
) | [static] |
Definition at line 822 of file res_musiconhold.c.
References ast_calloc, ast_codec2str(), ast_log(), ast_set_write_format(), ast_verb, chan, moh_files_state::class, mohclass::format, LOG_WARNING, moh_release(), mohalloc(), ast_channel::music_state, mohclass::name, ast_channel::name, mohdata::origwfmt, and ast_channel::writeformat.
00823 { 00824 struct mohdata *res; 00825 struct mohclass *class = params; 00826 struct moh_files_state *state; 00827 00828 /* Initiating music_state for current channel. Channel should know name of moh class */ 00829 if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) { 00830 chan->music_state = state; 00831 state->class = class; 00832 } else 00833 state = chan->music_state; 00834 if (state && state->class != class) { 00835 memset(state, 0, sizeof(*state)); 00836 state->class = class; 00837 } 00838 00839 if ((res = mohalloc(class))) { 00840 res->origwfmt = chan->writeformat; 00841 if (ast_set_write_format(chan, class->format)) { 00842 ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format)); 00843 moh_release(NULL, res); 00844 res = NULL; 00845 } 00846 ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name); 00847 } 00848 return res; 00849 }
static int moh_class_cmp | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1652 of file res_musiconhold.c.
References CMP_MATCH, and CMP_STOP.
Referenced by load_module().
01653 { 01654 struct mohclass *class = obj, *class2 = arg; 01655 01656 return strcasecmp(class->name, class2->name) ? 0 : CMP_MATCH | CMP_STOP; 01657 }
static void moh_class_destructor | ( | void * | obj | ) | [static] |
Definition at line 1364 of file res_musiconhold.c.
References ast_debug, AST_LIST_REMOVE_HEAD, ast_log(), AST_PTHREADT_NULL, ast_wait_for_input(), buff, free, and LOG_DEBUG.
Referenced by moh_class_malloc().
01365 { 01366 struct mohclass *class = obj; 01367 struct mohdata *member; 01368 01369 ast_debug(1, "Destroying MOH class '%s'\n", class->name); 01370 01371 if (class->pid > 1) { 01372 char buff[8192]; 01373 int bytes, tbytes = 0, stime = 0, pid = 0; 01374 01375 ast_log(LOG_DEBUG, "killing %d!\n", class->pid); 01376 01377 stime = time(NULL) + 2; 01378 pid = class->pid; 01379 class->pid = 0; 01380 01381 /* Back when this was just mpg123, SIGKILL was fine. Now we need 01382 * to give the process a reason and time enough to kill off its 01383 * children. */ 01384 killpg(pid, SIGHUP); 01385 usleep(100000); 01386 killpg(pid, SIGTERM); 01387 usleep(100000); 01388 killpg(pid, SIGKILL); 01389 01390 while ((ast_wait_for_input(class->srcfd, 100) > 0) && 01391 (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) { 01392 tbytes = tbytes + bytes; 01393 } 01394 01395 ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes); 01396 01397 close(class->srcfd); 01398 } 01399 01400 while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) { 01401 free(member); 01402 } 01403 01404 if (class->thread) { 01405 pthread_cancel(class->thread); 01406 pthread_join(class->thread, NULL); 01407 class->thread = AST_PTHREADT_NULL; 01408 } 01409 01410 if (class->filearray) { 01411 int i; 01412 for (i = 0; i < class->total_files; i++) { 01413 free(class->filearray[i]); 01414 } 01415 free(class->filearray); 01416 class->filearray = NULL; 01417 } 01418 }
static int moh_class_hash | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 1645 of file res_musiconhold.c.
References ast_str_case_hash().
Referenced by load_module().
01646 { 01647 const struct mohclass *class = obj; 01648 01649 return ast_str_case_hash(class->name); 01650 }
static int moh_class_inuse | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1700 of file res_musiconhold.c.
References AST_LIST_EMPTY, CMP_MATCH, and CMP_STOP.
Referenced by unload_module().
01701 { 01702 struct mohclass *class = obj; 01703 01704 return AST_LIST_EMPTY(&class->members) ? 0 : CMP_MATCH | CMP_STOP; 01705 }
static struct mohclass* moh_class_malloc | ( | void | ) | [static] |
Definition at line 1143 of file res_musiconhold.c.
References ao2_alloc(), AST_FORMAT_SLINEAR, mohclass::format, and moh_class_destructor().
Referenced by load_moh_classes(), and local_ast_moh_start().
01144 { 01145 struct mohclass *class; 01146 01147 if ((class = ao2_alloc(sizeof(*class), moh_class_destructor))) { 01148 class->format = AST_FORMAT_SLINEAR; 01149 } 01150 01151 return class; 01152 }
static int moh_class_mark | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1420 of file res_musiconhold.c.
Referenced by load_moh_classes().
01421 { 01422 struct mohclass *class = obj; 01423 01424 class->delete = 1; 01425 01426 return 0; 01427 }
static int moh_classes_delete_marked | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1429 of file res_musiconhold.c.
References CMP_MATCH.
01430 { 01431 struct mohclass *class = obj; 01432 01433 return class->delete ? CMP_MATCH : 0; 01434 }
Definition at line 1020 of file res_musiconhold.c.
References mohclass::args, mohclass::dir, mohclass::flags, and mohclass::mode.
Referenced by moh_register().
01021 { 01022 if (!old || !new) { 01023 return -1; 01024 } 01025 01026 if (strcmp(old->dir, new->dir)) { 01027 return -1; 01028 } else if (strcmp(old->mode, new->mode)) { 01029 return -1; 01030 } else if (strcmp(old->args, new->args)) { 01031 return -1; 01032 } else if (old->flags != new->flags) { 01033 return -1; 01034 } 01035 01036 return 0; 01037 }
static int moh_digit_match | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 343 of file res_musiconhold.c.
References CMP_MATCH, CMP_STOP, and mohclass::digit.
Referenced by get_mohbydigit().
00344 { 00345 char *digit = arg; 00346 struct mohclass *class = obj; 00347 00348 return (*digit == class->digit) ? CMP_MATCH | CMP_STOP : 0; 00349 }
static void* moh_files_alloc | ( | struct ast_channel * | chan, | |
void * | params | |||
) | [static] |
Definition at line 313 of file res_musiconhold.c.
References ast_calloc, ast_random(), ast_test_flag, ast_verb, chan, MOH_RANDOMIZE, mohclass_ref, ast_channel::music_state, ast_channel::name, and ast_channel::writeformat.
00314 { 00315 struct moh_files_state *state; 00316 struct mohclass *class = params; 00317 00318 if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) { 00319 chan->music_state = state; 00320 } else { 00321 state = chan->music_state; 00322 } 00323 00324 if (!state) { 00325 return NULL; 00326 } 00327 00328 if (state->class != class) { 00329 memset(state, 0, sizeof(*state)); 00330 if (ast_test_flag(class, MOH_RANDOMIZE) && class->total_files) { 00331 state->pos = ast_random() % class->total_files; 00332 } 00333 } 00334 00335 state->class = mohclass_ref(class); 00336 state->origwfmt = chan->writeformat; 00337 00338 ast_verb(3, "Started music on hold, class '%s', on %s\n", class->name, chan->name); 00339 00340 return chan->music_state; 00341 }
static int moh_files_generator | ( | struct ast_channel * | chan, | |
void * | data, | |||
int | len, | |||
int | samples | |||
) | [static] |
Definition at line 289 of file res_musiconhold.c.
References ast_frfree, ast_log(), ast_write(), chan, errno, f, LOG_WARNING, moh_files_readframe(), ast_channel::music_state, ast_channel::name, moh_files_state::sample_queue, and moh_files_state::samples.
00290 { 00291 struct moh_files_state *state = chan->music_state; 00292 struct ast_frame *f = NULL; 00293 int res = 0; 00294 00295 state->sample_queue += samples; 00296 00297 while (state->sample_queue > 0) { 00298 if ((f = moh_files_readframe(chan))) { 00299 state->samples += f->samples; 00300 state->sample_queue -= f->samples; 00301 res = ast_write(chan, f); 00302 ast_frfree(f); 00303 if (res < 0) { 00304 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); 00305 return -1; 00306 } 00307 } else 00308 return -1; 00309 } 00310 return res; 00311 }
static struct ast_frame* moh_files_readframe | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 277 of file res_musiconhold.c.
References ast_moh_files_next(), ast_readframe(), chan, f, and ast_channel::stream.
Referenced by moh_files_generator().
00278 { 00279 struct ast_frame *f = NULL; 00280 00281 if (!(chan->stream && (f = ast_readframe(chan->stream)))) { 00282 if (!ast_moh_files_next(chan)) 00283 f = ast_readframe(chan->stream); 00284 } 00285 00286 return f; 00287 }
static void moh_files_release | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 194 of file res_musiconhold.c.
References ast_closestream(), ast_log(), ast_set_write_format(), ast_verbose(), chan, 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.
00195 { 00196 struct moh_files_state *state; 00197 00198 if (!chan || !chan->music_state) { 00199 return; 00200 } 00201 00202 state = chan->music_state; 00203 00204 if (chan->stream) { 00205 ast_closestream(chan->stream); 00206 chan->stream = NULL; 00207 } 00208 00209 if (option_verbose > 2) { 00210 ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name); 00211 } 00212 00213 if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) { 00214 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt); 00215 } 00216 00217 state->save_pos = state->pos; 00218 00219 mohclass_unref(state->class); 00220 }
static int moh_generate | ( | struct ast_channel * | chan, | |
void * | data, | |||
int | len, | |||
int | samples | |||
) | [static] |
Definition at line 851 of file res_musiconhold.c.
References ast_codec_get_len(), ast_codec_get_samples(), AST_FRIENDLY_OFFSET, ast_log(), ast_write(), buf, chan, errno, LOG_WARNING, moh, and ast_channel::name.
00852 { 00853 struct mohdata *moh = data; 00854 short buf[1280 + AST_FRIENDLY_OFFSET / 2]; 00855 int res; 00856 00857 len = ast_codec_get_len(moh->parent->format, samples); 00858 00859 if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) { 00860 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name); 00861 len = sizeof(buf) - AST_FRIENDLY_OFFSET; 00862 } 00863 res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len); 00864 if (res <= 0) 00865 return 0; 00866 00867 moh->f.datalen = res; 00868 moh->f.data = buf + AST_FRIENDLY_OFFSET / 2; 00869 moh->f.samples = ast_codec_get_samples(&moh->f); 00870 00871 if (ast_write(chan, &moh->f) < 0) { 00872 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); 00873 return -1; 00874 } 00875 00876 return 0; 00877 }
static void moh_handle_digit | ( | struct ast_channel * | chan, | |
char | digit | |||
) | [static] |
Definition at line 357 of file res_musiconhold.c.
References ast_moh_start(), ast_moh_stop(), ast_strdupa, chan, get_mohbydigit(), and mohclass_unref.
00358 { 00359 struct mohclass *class; 00360 const char *classname = NULL; 00361 00362 if ((class = get_mohbydigit(digit))) { 00363 classname = ast_strdupa(class->name); 00364 class = mohclass_unref(class); 00365 } 00366 00367 if (!class) { 00368 return; 00369 } 00370 00371 ast_moh_stop(chan); 00372 ast_moh_start(chan, classname, NULL); 00373 }
static int moh_register | ( | struct mohclass * | moh, | |
int | reload, | |||
int | unref | |||
) | [static] |
Definition at line 1085 of file res_musiconhold.c.
References ao2_link(), ast_log(), mohclass::delete, get_mohbyname(), init_app_class(), init_files_class(), LOG_WARNING, moh, moh_diff(), mohclass_unref, and mohclasses.
Referenced by local_ast_moh_start().
01086 { 01087 struct mohclass *mohclass = NULL; 01088 01089 if ((mohclass = get_mohbyname(moh->name, 0)) && !moh_diff(mohclass, moh)) { 01090 if (!mohclass->delete) { 01091 ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name); 01092 mohclass = mohclass_unref(mohclass); 01093 if (unref) { 01094 moh = mohclass_unref(moh); 01095 } 01096 return -1; 01097 } 01098 mohclass = mohclass_unref(mohclass); 01099 } 01100 01101 time(&moh->start); 01102 moh->start -= respawn_time; 01103 01104 if (!strcasecmp(moh->mode, "files")) { 01105 if (init_files_class(moh)) { 01106 moh = mohclass_unref(moh); 01107 return -1; 01108 } 01109 } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || 01110 !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || 01111 !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) { 01112 if (init_app_class(moh)) { 01113 moh = mohclass_unref(moh); 01114 return -1; 01115 } 01116 } else { 01117 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode); 01118 moh = mohclass_unref(moh); 01119 return -1; 01120 } 01121 01122 ao2_link(mohclasses, moh); 01123 01124 if (unref) { 01125 moh = mohclass_unref(moh); 01126 } 01127 01128 return 0; 01129 }
static void moh_release | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 793 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, chan, LOG_WARNING, moh, mohclass_unref, and ast_channel::name.
Referenced by moh_alloc().
00794 { 00795 struct mohdata *moh = data; 00796 struct mohclass *class = moh->parent; 00797 int oldwfmt; 00798 00799 ao2_lock(class); 00800 AST_LIST_REMOVE(&moh->parent->members, moh, list); 00801 ao2_unlock(class); 00802 00803 close(moh->pipe[0]); 00804 close(moh->pipe[1]); 00805 00806 oldwfmt = moh->origwfmt; 00807 00808 moh->parent = class = mohclass_unref(class); 00809 00810 ast_free(moh); 00811 00812 if (chan) { 00813 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) { 00814 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", 00815 chan->name, ast_getformatname(oldwfmt)); 00816 } 00817 00818 ast_verb(3, "Stopped music on hold on %s\n", chan->name); 00819 } 00820 }
static int moh_scan_files | ( | struct mohclass * | class | ) | [static] |
Definition at line 919 of file res_musiconhold.c.
References ast_free, ast_log(), mohclass::dir, errno, ext, mohclass::filearray, LOG_WARNING, and mohclass::total_files.
Referenced by init_files_class(), and local_ast_moh_start().
00919 { 00920 00921 DIR *files_DIR; 00922 struct dirent *files_dirent; 00923 char path[PATH_MAX]; 00924 char filepath[PATH_MAX]; 00925 char *ext; 00926 struct stat statbuf; 00927 int dirnamelen; 00928 int i; 00929 00930 files_DIR = opendir(class->dir); 00931 if (!files_DIR) { 00932 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", class->dir); 00933 return -1; 00934 } 00935 00936 for (i = 0; i < class->total_files; i++) 00937 ast_free(class->filearray[i]); 00938 00939 class->total_files = 0; 00940 dirnamelen = strlen(class->dir) + 2; 00941 if (!getcwd(path, sizeof(path))) { 00942 ast_log(LOG_WARNING, "getcwd() failed: %s\n", strerror(errno)); 00943 return -1; 00944 } 00945 if (chdir(class->dir) < 0) { 00946 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 00947 return -1; 00948 } 00949 while ((files_dirent = readdir(files_DIR))) { 00950 /* The file name must be at least long enough to have the file type extension */ 00951 if ((strlen(files_dirent->d_name) < 4)) 00952 continue; 00953 00954 /* Skip files that starts with a dot */ 00955 if (files_dirent->d_name[0] == '.') 00956 continue; 00957 00958 /* Skip files without extensions... they are not audio */ 00959 if (!strchr(files_dirent->d_name, '.')) 00960 continue; 00961 00962 snprintf(filepath, sizeof(filepath), "%s/%s", class->dir, files_dirent->d_name); 00963 00964 if (stat(filepath, &statbuf)) 00965 continue; 00966 00967 if (!S_ISREG(statbuf.st_mode)) 00968 continue; 00969 00970 if ((ext = strrchr(filepath, '.'))) 00971 *ext = '\0'; 00972 00973 /* if the file is present in multiple formats, ensure we only put it into the list once */ 00974 for (i = 0; i < class->total_files; i++) 00975 if (!strcmp(filepath, class->filearray[i])) 00976 break; 00977 00978 if (i == class->total_files) { 00979 if (moh_add_file(class, filepath)) 00980 break; 00981 } 00982 } 00983 00984 closedir(files_DIR); 00985 if (chdir(path) < 0) { 00986 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 00987 return -1; 00988 } 00989 if (ast_test_flag(class, MOH_SORTALPHA)) 00990 qsort(&class->filearray[0], class->total_files, sizeof(char *), moh_sort_compare); 00991 return class->total_files; 00992 }
static int moh_sort_compare | ( | const void * | i1, | |
const void * | i2 | |||
) | [static] |
Definition at line 909 of file res_musiconhold.c.
00910 { 00911 char *s1, *s2; 00912 00913 s1 = ((char **)i1)[0]; 00914 s2 = ((char **)i2)[0]; 00915 00916 return strcasecmp(s1, s2); 00917 }
Definition at line 760 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, mohclass::format, LOG_WARNING, mohclass::members, moh, mohclass_ref, and mohdata::pipe.
Referenced by moh_alloc().
00761 { 00762 struct mohdata *moh; 00763 long flags; 00764 00765 if (!(moh = ast_calloc(1, sizeof(*moh)))) 00766 return NULL; 00767 00768 if (pipe(moh->pipe)) { 00769 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno)); 00770 ast_free(moh); 00771 return NULL; 00772 } 00773 00774 /* Make entirely non-blocking */ 00775 flags = fcntl(moh->pipe[0], F_GETFL); 00776 fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK); 00777 flags = fcntl(moh->pipe[1], F_GETFL); 00778 fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK); 00779 00780 moh->f.frametype = AST_FRAME_VOICE; 00781 moh->f.subclass = cl->format; 00782 moh->f.offset = AST_FRIENDLY_OFFSET; 00783 00784 moh->parent = mohclass_ref(cl); 00785 00786 ao2_lock(cl); 00787 AST_LIST_INSERT_HEAD(&cl->members, moh, list); 00788 ao2_unlock(cl); 00789 00790 return moh; 00791 }
static void* monmp3thread | ( | void * | data | ) | [static] |
Definition at line 549 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, len(), mohclass::list, LOG_NOTICE, LOG_WARNING, moh, MOH_MS_INTERVAL, and spawn_mp3().
Referenced by init_app_class(), and local_ast_moh_start().
00550 { 00551 #define MOH_MS_INTERVAL 100 00552 00553 struct mohclass *class = data; 00554 struct mohdata *moh; 00555 char buf[8192]; 00556 short sbuf[8192]; 00557 int res, res2; 00558 int len; 00559 struct timeval tv, tv_tmp; 00560 00561 tv.tv_sec = 0; 00562 tv.tv_usec = 0; 00563 for(;/* ever */;) { 00564 pthread_testcancel(); 00565 /* Spawn mp3 player if it's not there */ 00566 if (class->srcfd < 0) { 00567 if ((class->srcfd = spawn_mp3(class)) < 0) { 00568 ast_log(LOG_WARNING, "Unable to spawn mp3player\n"); 00569 /* Try again later */ 00570 sleep(500); 00571 pthread_testcancel(); 00572 } 00573 } 00574 if (class->pseudofd > -1) { 00575 #ifdef SOLARIS 00576 thr_yield(); 00577 #endif 00578 /* Pause some amount of time */ 00579 res = read(class->pseudofd, buf, sizeof(buf)); 00580 pthread_testcancel(); 00581 } else { 00582 long delta; 00583 /* Reliable sleep */ 00584 tv_tmp = ast_tvnow(); 00585 if (ast_tvzero(tv)) 00586 tv = tv_tmp; 00587 delta = ast_tvdiff_ms(tv_tmp, tv); 00588 if (delta < MOH_MS_INTERVAL) { /* too early */ 00589 tv = ast_tvadd(tv, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */ 00590 usleep(1000 * (MOH_MS_INTERVAL - delta)); 00591 pthread_testcancel(); 00592 } else { 00593 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n"); 00594 tv = tv_tmp; 00595 } 00596 res = 8 * MOH_MS_INTERVAL; /* 8 samples per millisecond */ 00597 } 00598 if ((strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir")) && AST_LIST_EMPTY(&class->members)) 00599 continue; 00600 /* Read mp3 audio */ 00601 len = ast_codec_get_len(class->format, res); 00602 00603 if ((res2 = read(class->srcfd, sbuf, len)) != len) { 00604 if (!res2) { 00605 close(class->srcfd); 00606 class->srcfd = -1; 00607 pthread_testcancel(); 00608 if (class->pid > 1) { 00609 killpg(class->pid, SIGHUP); 00610 usleep(100000); 00611 killpg(class->pid, SIGTERM); 00612 usleep(100000); 00613 killpg(class->pid, SIGKILL); 00614 class->pid = 0; 00615 } 00616 } else { 00617 ast_debug(1, "Read %d bytes of audio while expecting %d\n", res2, len); 00618 } 00619 continue; 00620 } 00621 00622 pthread_testcancel(); 00623 00624 ao2_lock(class); 00625 AST_LIST_TRAVERSE(&class->members, moh, list) { 00626 /* Write data */ 00627 if ((res = write(moh->pipe[1], sbuf, res2)) != res2) { 00628 ast_debug(1, "Only wrote %d of %d bytes to pipe\n", res, res2); 00629 } 00630 } 00631 ao2_unlock(class); 00632 } 00633 return NULL; 00634 }
static int play_moh_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 636 of file res_musiconhold.c.
References 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(), chan, LOG_WARNING, ast_channel::name, parse(), and S_OR.
Referenced by load_module().
00637 { 00638 char *parse; 00639 char *class; 00640 int timeout = -1; 00641 int res; 00642 AST_DECLARE_APP_ARGS(args, 00643 AST_APP_ARG(class); 00644 AST_APP_ARG(duration); 00645 ); 00646 00647 parse = ast_strdupa(data); 00648 00649 AST_STANDARD_APP_ARGS(args, parse); 00650 00651 if (!ast_strlen_zero(args.duration)) { 00652 if (sscanf(args.duration, "%d", &timeout) == 1) { 00653 timeout *= 1000; 00654 } else { 00655 ast_log(LOG_WARNING, "Invalid MusicOnHold duration '%s'. Will wait indefinitely.\n", args.duration); 00656 } 00657 } 00658 00659 class = S_OR(args.class, NULL); 00660 if (ast_moh_start(chan, class, NULL)) { 00661 ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, chan->name); 00662 return 0; 00663 } 00664 00665 if (timeout > 0) 00666 res = ast_safe_sleep(chan, timeout); 00667 else { 00668 while (!(res = ast_safe_sleep(chan, 10000))); 00669 } 00670 00671 ast_moh_stop(chan); 00672 00673 return res; 00674 }
static int reload | ( | void | ) | [static] |
static int set_moh_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 699 of file res_musiconhold.c.
References ast_log(), ast_string_field_set, ast_strlen_zero(), chan, LOG_WARNING, and musicclass.
Referenced by load_module().
00700 { 00701 static int deprecation_warning = 0; 00702 00703 if (!deprecation_warning) { 00704 deprecation_warning = 1; 00705 ast_log(LOG_WARNING, "SetMusicOnHold application is deprecated and will be removed. Use Set(CHANNEL(musicclass)=...) instead\n"); 00706 } 00707 00708 if (ast_strlen_zero(data)) { 00709 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n"); 00710 return -1; 00711 } 00712 ast_string_field_set(chan, musicclass, data); 00713 return 0; 00714 }
static int spawn_mp3 | ( | struct mohclass * | class | ) | [static] |
Definition at line 383 of file res_musiconhold.c.
References mohclass::args, ast_copy_string(), ast_log(), ast_opt_high_priority, 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, mohclass::pid, mohclass::start, and strsep().
Referenced by monmp3thread().
00384 { 00385 int fds[2]; 00386 int files = 0; 00387 char fns[MAX_MP3S][80]; 00388 char *argv[MAX_MP3S + 50]; 00389 char xargs[256]; 00390 char *argptr; 00391 int argc = 0; 00392 DIR *dir = NULL; 00393 struct dirent *de; 00394 sigset_t signal_set, old_set; 00395 00396 00397 if (!strcasecmp(class->dir, "nodir")) { 00398 files = 1; 00399 } else { 00400 dir = opendir(class->dir); 00401 if (!dir && strncasecmp(class->dir, "http://", 7)) { 00402 ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir); 00403 return -1; 00404 } 00405 } 00406 00407 if (!ast_test_flag(class, MOH_CUSTOM)) { 00408 argv[argc++] = "mpg123"; 00409 argv[argc++] = "-q"; 00410 argv[argc++] = "-s"; 00411 argv[argc++] = "--mono"; 00412 argv[argc++] = "-r"; 00413 argv[argc++] = "8000"; 00414 00415 if (!ast_test_flag(class, MOH_SINGLE)) { 00416 argv[argc++] = "-b"; 00417 argv[argc++] = "2048"; 00418 } 00419 00420 argv[argc++] = "-f"; 00421 00422 if (ast_test_flag(class, MOH_QUIET)) 00423 argv[argc++] = "4096"; 00424 else 00425 argv[argc++] = "8192"; 00426 00427 /* Look for extra arguments and add them to the list */ 00428 ast_copy_string(xargs, class->args, sizeof(xargs)); 00429 argptr = xargs; 00430 while (!ast_strlen_zero(argptr)) { 00431 argv[argc++] = argptr; 00432 strsep(&argptr, ","); 00433 } 00434 } else { 00435 /* Format arguments for argv vector */ 00436 ast_copy_string(xargs, class->args, sizeof(xargs)); 00437 argptr = xargs; 00438 while (!ast_strlen_zero(argptr)) { 00439 argv[argc++] = argptr; 00440 strsep(&argptr, " "); 00441 } 00442 } 00443 00444 if (!strncasecmp(class->dir, "http://", 7)) { 00445 ast_copy_string(fns[files], class->dir, sizeof(fns[files])); 00446 argv[argc++] = fns[files]; 00447 files++; 00448 } else if (dir) { 00449 while ((de = readdir(dir)) && (files < MAX_MP3S)) { 00450 if ((strlen(de->d_name) > 3) && 00451 ((ast_test_flag(class, MOH_CUSTOM) && 00452 (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 00453 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) || 00454 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) { 00455 ast_copy_string(fns[files], de->d_name, sizeof(fns[files])); 00456 argv[argc++] = fns[files]; 00457 files++; 00458 } 00459 } 00460 } 00461 argv[argc] = NULL; 00462 if (dir) { 00463 closedir(dir); 00464 } 00465 if (pipe(fds)) { 00466 ast_log(LOG_WARNING, "Pipe failed\n"); 00467 return -1; 00468 } 00469 if (!files) { 00470 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir); 00471 close(fds[0]); 00472 close(fds[1]); 00473 return -1; 00474 } 00475 if (!strncasecmp(class->dir, "http://", 7) && time(NULL) - class->start < respawn_time) { 00476 sleep(respawn_time - (time(NULL) - class->start)); 00477 } 00478 00479 /* Block signals during the fork() */ 00480 sigfillset(&signal_set); 00481 pthread_sigmask(SIG_BLOCK, &signal_set, &old_set); 00482 00483 time(&class->start); 00484 class->pid = fork(); 00485 if (class->pid < 0) { 00486 close(fds[0]); 00487 close(fds[1]); 00488 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno)); 00489 return -1; 00490 } 00491 if (!class->pid) { 00492 /* Child */ 00493 int x; 00494 #ifdef HAVE_CAP 00495 cap_t cap; 00496 #endif 00497 if (strcasecmp(class->dir, "nodir") && chdir(class->dir) < 0) { 00498 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 00499 _exit(1); 00500 } 00501 00502 if (ast_opt_high_priority) 00503 ast_set_priority(0); 00504 00505 /* Reset ignored signals back to default */ 00506 signal(SIGPIPE, SIG_DFL); 00507 pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL); 00508 00509 #ifdef HAVE_CAP 00510 cap = cap_from_text("cap_net_admin-eip"); 00511 00512 if (cap_set_proc(cap)) { 00513 ast_log(LOG_WARNING, "Unable to remove capabilities.\n"); 00514 } 00515 cap_free(cap); 00516 #endif 00517 close(fds[0]); 00518 /* Stdout goes to pipe */ 00519 dup2(fds[1], STDOUT_FILENO); 00520 /* Close unused file descriptors */ 00521 for (x=3;x<8192;x++) { 00522 if (-1 != fcntl(x, F_GETFL)) { 00523 close(x); 00524 } 00525 } 00526 setpgid(0, getpid()); 00527 00528 if (ast_test_flag(class, MOH_CUSTOM)) { 00529 execv(argv[0], argv); 00530 } else { 00531 /* Default install is /usr/local/bin */ 00532 execv(LOCAL_MPG_123, argv); 00533 /* Many places have it in /usr/bin */ 00534 execv(MPG_123, argv); 00535 /* Check PATH as a last-ditch effort */ 00536 execvp("mpg123", argv); 00537 } 00538 ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno)); 00539 close(fds[1]); 00540 _exit(1); 00541 } else { 00542 /* Parent */ 00543 pthread_sigmask(SIG_SETMASK, &old_set, NULL); 00544 close(fds[1]); 00545 } 00546 return fds[0]; 00547 }
static int start_moh_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 716 of file res_musiconhold.c.
References AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_moh_start(), AST_STANDARD_APP_ARGS, ast_strdupa, chan, LOG_WARNING, ast_channel::name, parse(), and S_OR.
Referenced by load_module().
00717 { 00718 char *parse; 00719 char *class; 00720 AST_DECLARE_APP_ARGS(args, 00721 AST_APP_ARG(class); 00722 ); 00723 00724 parse = ast_strdupa(data); 00725 00726 AST_STANDARD_APP_ARGS(args, parse); 00727 00728 class = S_OR(args.class, NULL); 00729 if (ast_moh_start(chan, class, NULL)) 00730 ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, chan->name); 00731 00732 return 0; 00733 }
static int stop_moh_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 735 of file res_musiconhold.c.
References ast_moh_stop(), and chan.
Referenced by load_module().
00736 { 00737 ast_moh_stop(chan); 00738 00739 return 0; 00740 }
static int unload_module | ( | void | ) | [static] |
Definition at line 1707 of file res_musiconhold.c.
References ao2_callback(), ast_cli_unregister_multiple(), ast_log(), ast_moh_destroy(), ast_uninstall_music_functions(), ast_unregister_application(), cli_moh, LOG_WARNING, moh_class_inuse(), mohclass_unref, and mohclasses.
01708 { 01709 int res = 0; 01710 struct mohclass *class = NULL; 01711 01712 /* XXX This check shouldn't be required if module ref counting was being used 01713 * properly ... */ 01714 if ((class = ao2_callback(mohclasses, 0, moh_class_inuse, NULL))) { 01715 class = mohclass_unref(class); 01716 res = -1; 01717 } 01718 01719 if (res < 0) { 01720 ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n"); 01721 return res; 01722 } 01723 01724 ast_uninstall_music_functions(); 01725 01726 ast_moh_destroy(); 01727 res = ast_unregister_application(play_moh); 01728 res |= ast_unregister_application(wait_moh); 01729 res |= ast_unregister_application(set_moh); 01730 res |= ast_unregister_application(start_moh); 01731 res |= ast_unregister_application(stop_moh); 01732 ast_cli_unregister_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry)); 01733 01734 return res; 01735 }
static int wait_moh_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 676 of file res_musiconhold.c.
References ast_log(), ast_moh_start(), ast_moh_stop(), ast_safe_sleep(), chan, LOG_WARNING, and ast_channel::name.
Referenced by load_module().
00677 { 00678 static int deprecation_warning = 0; 00679 int res; 00680 00681 if (!deprecation_warning) { 00682 deprecation_warning = 1; 00683 ast_log(LOG_WARNING, "WaitMusicOnHold application is deprecated and will be removed. Use MusicOnHold with duration parameter instead\n"); 00684 } 00685 00686 if (!data || !atoi(data)) { 00687 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n"); 00688 return -1; 00689 } 00690 if (ast_moh_start(chan, NULL, NULL)) { 00691 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name); 00692 return 0; 00693 } 00694 res = ast_safe_sleep(chan, atoi(data) * 1000); 00695 ast_moh_stop(chan); 00696 return res; 00697 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Music On Hold Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 1741 of file res_musiconhold.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1741 of file res_musiconhold.c.
struct ast_cli_entry cli_moh[] [static] |
Initial value:
{ { .handler = handle_cli_moh_reload , .summary = "Reload MusicOnHold" ,__VA_ARGS__ }, { .handler = handle_cli_moh_show_classes , .summary = "List MusicOnHold classes" ,__VA_ARGS__ }, { .handler = handle_cli_moh_show_files , .summary = "List MusicOnHold file-based classes" ,__VA_ARGS__ } }
Definition at line 1639 of file res_musiconhold.c.
Referenced by load_module(), and unload_module().
struct ast_flags global_flags[1] = {{0}} [static] |
global MOH_ flags
Definition at line 143 of file res_musiconhold.c.
struct ast_generator moh_file_stream [static] |
Definition at line 375 of file res_musiconhold.c.
struct ao2_container* mohclasses [static] |
Definition at line 183 of file res_musiconhold.c.
Referenced by ast_moh_destroy(), get_mohbyname(), handle_cli_moh_show_classes(), handle_cli_moh_show_files(), load_module(), load_moh_classes(), moh_register(), and unload_module().
struct ast_generator mohgen [static] |
Definition at line 879 of file res_musiconhold.c.
char* play_moh = "MusicOnHold" [static] |
Definition at line 75 of file res_musiconhold.c.
char* play_moh_desc [static] |
Definition at line 87 of file res_musiconhold.c.
char* play_moh_syn = "Play Music On Hold indefinitely" [static] |
Definition at line 81 of file res_musiconhold.c.
int respawn_time = 20 [static] |
Definition at line 123 of file res_musiconhold.c.
char* set_moh = "SetMusicOnHold" [static] |
Definition at line 77 of file res_musiconhold.c.
char* set_moh_desc [static] |
Definition at line 105 of file res_musiconhold.c.
char* set_moh_syn = "Set default Music On Hold class" [static] |
Definition at line 83 of file res_musiconhold.c.
char* start_moh = "StartMusicOnHold" [static] |
Definition at line 78 of file res_musiconhold.c.
char* start_moh_desc [static] |
Initial value:
" StartMusicOnHold(class):\n" "Starts playing music on hold, uses default music class for channel.\n" "Starts playing music specified by class. If omitted, the default\n" "music source for the channel will be used. Always returns 0.\n"
Definition at line 115 of file res_musiconhold.c.
char* start_moh_syn = "Play Music On Hold" [static] |
Definition at line 84 of file res_musiconhold.c.
char* stop_moh = "StopMusicOnHold" [static] |
Definition at line 79 of file res_musiconhold.c.
char* stop_moh_desc [static] |
Initial value:
" StopMusicOnHold(): " "Stops playing music on hold.\n"
Definition at line 120 of file res_musiconhold.c.
char* stop_moh_syn = "Stop Playing Music On Hold" [static] |
Definition at line 85 of file res_musiconhold.c.
char* wait_moh = "WaitMusicOnHold" [static] |
Definition at line 76 of file res_musiconhold.c.
char* wait_moh_desc [static] |
Definition at line 95 of file res_musiconhold.c.
char* wait_moh_syn = "Wait, playing Music On Hold" [static] |
Definition at line 82 of file res_musiconhold.c.