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