#include "asterisk.h"
#include <ctype.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/ioctl.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
#include "asterisk/stringfields.h"
#include "asterisk/linkedlists.h"
#include "asterisk/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 = AST_BUILDOPT_SUM, .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(), local_ast_moh_start(), and moh_scan_files().
| #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(), 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 186 of file res_musiconhold.c.
| static void __reg_module | ( | void | ) | [static] |
Definition at line 1744 of file res_musiconhold.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 1744 of file res_musiconhold.c.
| static void ast_moh_destroy | ( | void | ) | [static] |
Definition at line 1540 of file res_musiconhold.c.
References ao2_callback(), ast_verb, OBJ_MULTIPLE, OBJ_NODATA, and OBJ_UNLINK.
Referenced by load_module(), and unload_module().
01541 { 01542 ast_verb(2, "Destroying musiconhold processes\n"); 01543 ao2_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL); 01544 }
| static int ast_moh_files_next | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 222 of file res_musiconhold.c.
References ast_closestream(), ast_debug, ast_fileexists(), ast_log(), ast_openstream_full(), ast_random(), ast_seekstream(), ast_test_flag, moh_files_state::class, errno, mohclass::filearray, ast_channel::language, LOG_WARNING, MOH_RANDOMIZE, ast_channel::music_state, ast_channel::name, mohclass::name, moh_files_state::pos, moh_files_state::samples, moh_files_state::save_pos, moh_files_state::save_pos_filename, ast_channel::stream, and mohclass::total_files.
Referenced by moh_files_readframe().
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, read] |
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, read] |
Definition at line 738 of file res_musiconhold.c.
References ao2_find(), ast_copy_string(), ast_log(), mohclass::flags, LOG_DEBUG, moh, and mohclass::name.
Referenced by local_ast_moh_start(), and moh_register().
00739 { 00740 struct mohclass *moh = NULL; 00741 struct mohclass tmp_class = { 00742 .flags = 0, 00743 }; 00744 00745 ast_copy_string(tmp_class.name, name, sizeof(tmp_class.name)); 00746 00747 moh = ao2_find(mohclasses, &tmp_class, 0); 00748 00749 if (!moh && warn) { 00750 ast_log(LOG_DEBUG, "Music on Hold class '%s' not found in memory\n", name); 00751 } 00752 00753 return moh; 00754 }
| static char* handle_cli_moh_reload | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1546 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.
01547 { 01548 switch (cmd) { 01549 case CLI_INIT: 01550 e->command = "moh reload"; 01551 e->usage = 01552 "Usage: moh reload\n" 01553 " Reloads the MusicOnHold module.\n" 01554 " Alias for 'module reload res_musiconhold.so'\n"; 01555 return NULL; 01556 case CLI_GENERATE: 01557 return NULL; 01558 } 01559 01560 if (a->argc != e->args) 01561 return CLI_SHOWUSAGE; 01562 01563 reload(); 01564 01565 return CLI_SUCCESS; 01566 }
| static char* handle_cli_moh_show_classes | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1606 of file res_musiconhold.c.
References ao2_iterator_destroy(), 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, S_OR, and ast_cli_entry::usage.
01607 { 01608 struct mohclass *class; 01609 struct ao2_iterator i; 01610 01611 switch (cmd) { 01612 case CLI_INIT: 01613 e->command = "moh show classes"; 01614 e->usage = 01615 "Usage: moh show classes\n" 01616 " Lists all MusicOnHold classes.\n"; 01617 return NULL; 01618 case CLI_GENERATE: 01619 return NULL; 01620 } 01621 01622 if (a->argc != e->args) 01623 return CLI_SHOWUSAGE; 01624 01625 i = ao2_iterator_init(mohclasses, 0); 01626 for (; (class = ao2_iterator_next(&i)); mohclass_unref(class)) { 01627 ast_cli(a->fd, "Class: %s\n", class->name); 01628 ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>")); 01629 ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>")); 01630 if (ast_test_flag(class, MOH_CUSTOM)) { 01631 ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>")); 01632 } 01633 if (strcasecmp(class->mode, "files")) { 01634 ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(class->format)); 01635 } 01636 } 01637 ao2_iterator_destroy(&i); 01638 01639 return CLI_SUCCESS; 01640 }
| static char* handle_cli_moh_show_files | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1568 of file res_musiconhold.c.
References ao2_iterator_destroy(), 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, and ast_cli_entry::usage.
01569 { 01570 struct mohclass *class; 01571 struct ao2_iterator i; 01572 01573 switch (cmd) { 01574 case CLI_INIT: 01575 e->command = "moh show files"; 01576 e->usage = 01577 "Usage: moh show files\n" 01578 " Lists all loaded file-based MusicOnHold classes and their\n" 01579 " files.\n"; 01580 return NULL; 01581 case CLI_GENERATE: 01582 return NULL; 01583 } 01584 01585 if (a->argc != e->args) 01586 return CLI_SHOWUSAGE; 01587 01588 i = ao2_iterator_init(mohclasses, 0); 01589 for (; (class = ao2_iterator_next(&i)); mohclass_unref(class)) { 01590 int x; 01591 01592 if (!class->total_files) { 01593 continue; 01594 } 01595 01596 ast_cli(a->fd, "Class: %s\n", class->name); 01597 for (x = 0; x < class->total_files; x++) { 01598 ast_cli(a->fd, "\tFile: %s\n", class->filearray[x]); 01599 } 01600 } 01601 ao2_iterator_destroy(&i); 01602 01603 return CLI_SUCCESS; 01604 }
| static int init_app_class | ( | struct mohclass * | class | ) | [static] |
Definition at line 1035 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().
01036 { 01037 #ifdef HAVE_DAHDI 01038 int x; 01039 #endif 01040 01041 if (!strcasecmp(class->mode, "custom")) { 01042 ast_set_flag(class, MOH_CUSTOM); 01043 } else if (!strcasecmp(class->mode, "mp3nb")) { 01044 ast_set_flag(class, MOH_SINGLE); 01045 } else if (!strcasecmp(class->mode, "quietmp3nb")) { 01046 ast_set_flag(class, MOH_SINGLE | MOH_QUIET); 01047 } else if (!strcasecmp(class->mode, "quietmp3")) { 01048 ast_set_flag(class, MOH_QUIET); 01049 } 01050 01051 class->srcfd = -1; 01052 class->pseudofd = -1; 01053 01054 #ifdef HAVE_DAHDI 01055 /* Open /dev/zap/pseudo for timing... Is 01056 there a better, yet reliable way to do this? */ 01057 class->pseudofd = open("/dev/dahdi/pseudo", O_RDONLY); 01058 if (class->pseudofd < 0) { 01059 ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n"); 01060 } else { 01061 x = 320; 01062 ioctl(class->pseudofd, DAHDI_SET_BLOCKSIZE, &x); 01063 } 01064 #endif 01065 01066 if (ast_pthread_create_background(&class->thread, NULL, monmp3thread, class)) { 01067 ast_log(LOG_WARNING, "Unable to create moh thread...\n"); 01068 if (class->pseudofd > -1) { 01069 close(class->pseudofd); 01070 class->pseudofd = -1; 01071 } 01072 return -1; 01073 } 01074 01075 return 0; 01076 }
| static int init_files_class | ( | struct mohclass * | class | ) | [static] |
Definition at line 990 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().
00991 { 00992 int res; 00993 00994 res = moh_scan_files(class); 00995 00996 if (res < 0) { 00997 return -1; 00998 } 00999 01000 if (!res) { 01001 if (option_verbose > 2) { 01002 ast_verbose(VERBOSE_PREFIX_3 "Files not found in %s for moh class:%s\n", 01003 class->dir, class->name); 01004 } 01005 return -1; 01006 } 01007 01008 if (strchr(class->args, 'r')) { 01009 ast_set_flag(class, MOH_RANDOMIZE); 01010 } 01011 01012 return 0; 01013 }
| static int load_module | ( | void | ) | [static] |
Definition at line 1662 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(), 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().
01663 { 01664 int res; 01665 01666 if (!(mohclasses = ao2_container_alloc(53, moh_class_hash, moh_class_cmp))) { 01667 return AST_MODULE_LOAD_DECLINE; 01668 } 01669 01670 if (!load_moh_classes(0)) { /* No music classes configured, so skip it */ 01671 ast_log(LOG_WARNING, "No music on hold classes configured, " 01672 "disabling music on hold.\n"); 01673 } else { 01674 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, 01675 local_ast_moh_cleanup); 01676 } 01677 01678 res = ast_register_application(play_moh, play_moh_exec, play_moh_syn, play_moh_desc); 01679 ast_register_atexit(ast_moh_destroy); 01680 ast_cli_register_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry)); 01681 if (!res) 01682 res = ast_register_application(wait_moh, wait_moh_exec, wait_moh_syn, wait_moh_desc); 01683 if (!res) 01684 res = ast_register_application(set_moh, set_moh_exec, set_moh_syn, set_moh_desc); 01685 if (!res) 01686 res = ast_register_application(start_moh, start_moh_exec, start_moh_syn, start_moh_desc); 01687 if (!res) 01688 res = ast_register_application(stop_moh, stop_moh_exec, stop_moh_syn, stop_moh_desc); 01689 01690 return AST_MODULE_LOAD_SUCCESS; 01691 }
| static int load_moh_classes | ( | int | reload | ) | [static] |
Definition at line 1439 of file res_musiconhold.c.
References ao2_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().
01440 { 01441 struct ast_config *cfg; 01442 struct ast_variable *var; 01443 struct mohclass *class; 01444 char *cat; 01445 int numclasses = 0; 01446 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 01447 01448 cfg = ast_config_load("musiconhold.conf", config_flags); 01449 01450 if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED) 01451 return 0; 01452 01453 if (reload) { 01454 ao2_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL); 01455 } 01456 01457 ast_clear_flag(global_flags, AST_FLAGS_ALL); 01458 01459 cat = ast_category_browse(cfg, NULL); 01460 for (; cat; cat = ast_category_browse(cfg, cat)) { 01461 /* Setup common options from [general] section */ 01462 if (!strcasecmp(cat, "general")) { 01463 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 01464 if (!strcasecmp(var->name, "cachertclasses")) { 01465 ast_set2_flag(global_flags, ast_true(var->value), MOH_CACHERTCLASSES); 01466 } else { 01467 ast_log(LOG_WARNING, "Unknown option '%s' in [general] section of musiconhold.conf\n", var->name); 01468 } 01469 } 01470 } 01471 /* These names were deprecated in 1.4 and should not be used until after the next major release. */ 01472 if (!strcasecmp(cat, "classes") || !strcasecmp(cat, "moh_files") || 01473 !strcasecmp(cat, "general")) { 01474 continue; 01475 } 01476 01477 if (!(class = moh_class_malloc())) { 01478 break; 01479 } 01480 01481 ast_copy_string(class->name, cat, sizeof(class->name)); 01482 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 01483 if (!strcasecmp(var->name, "mode")) 01484 ast_copy_string(class->mode, var->value, sizeof(class->mode)); 01485 else if (!strcasecmp(var->name, "directory")) 01486 ast_copy_string(class->dir, var->value, sizeof(class->dir)); 01487 else if (!strcasecmp(var->name, "application")) 01488 ast_copy_string(class->args, var->value, sizeof(class->args)); 01489 else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value))) 01490 class->digit = *var->value; 01491 else if (!strcasecmp(var->name, "random")) 01492 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE); 01493 else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "random")) 01494 ast_set_flag(class, MOH_RANDOMIZE); 01495 else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) 01496 ast_set_flag(class, MOH_SORTALPHA); 01497 else if (!strcasecmp(var->name, "format")) { 01498 class->format = ast_getformatbyname(var->value); 01499 if (!class->format) { 01500 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value); 01501 class->format = AST_FORMAT_SLINEAR; 01502 } 01503 } 01504 } 01505 01506 if (ast_strlen_zero(class->dir)) { 01507 if (!strcasecmp(class->mode, "custom")) { 01508 strcpy(class->dir, "nodir"); 01509 } else { 01510 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name); 01511 class = mohclass_unref(class); 01512 continue; 01513 } 01514 } 01515 if (ast_strlen_zero(class->mode)) { 01516 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name); 01517 class = mohclass_unref(class); 01518 continue; 01519 } 01520 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) { 01521 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name); 01522 class = mohclass_unref(class); 01523 continue; 01524 } 01525 01526 /* Don't leak a class when it's already registered */ 01527 if (!moh_register(class, reload, 1)) { 01528 numclasses++; 01529 } 01530 } 01531 01532 ast_config_destroy(cfg); 01533 01534 ao2_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, 01535 moh_classes_delete_marked, NULL); 01536 01537 return numclasses; 01538 }
| static void local_ast_moh_cleanup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1127 of file res_musiconhold.c.
References ast_free, and ast_channel::music_state.
Referenced by load_module().
01128 { 01129 struct moh_files_state *state = chan->music_state; 01130 01131 if (state) { 01132 ast_free(chan->music_state); 01133 chan->music_state = NULL; 01134 } 01135 }
| static int local_ast_moh_start | ( | struct ast_channel * | chan, | |
| const char * | mclass, | |||
| const char * | interpclass | |||
| ) | [static] |
Definition at line 1150 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, mohclass::format, get_mohbyname(), 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, ast_variable::name, ast_variable::next, mohclass::pseudofd, mohclass::realtime, mohclass::srcfd, mohclass::start, mohclass::thread, mohclass::total_files, ast_variable::value, and var.
Referenced by load_module().
01151 { 01152 struct mohclass *mohclass = NULL; 01153 struct moh_files_state *state = chan->music_state; 01154 struct ast_variable *var = NULL; 01155 int res; 01156 int realtime_possible = ast_check_realtime("musiconhold"); 01157 01158 /* The following is the order of preference for which class to use: 01159 * 1) The channels explicitly set musicclass, which should *only* be 01160 * set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan. 01161 * 2) The mclass argument. If a channel is calling ast_moh_start() as the 01162 * result of receiving a HOLD control frame, this should be the 01163 * payload that came with the frame. 01164 * 3) The interpclass argument. This would be from the mohinterpret 01165 * option from channel drivers. This is the same as the old musicclass 01166 * option. 01167 * 4) The default class. 01168 */ 01169 if (!ast_strlen_zero(chan->musicclass)) { 01170 mohclass = get_mohbyname(chan->musicclass, 1); 01171 if (!mohclass && realtime_possible) { 01172 var = ast_load_realtime("musiconhold", "name", chan->musicclass, NULL); 01173 } 01174 } 01175 if (!mohclass && !var && !ast_strlen_zero(mclass)) { 01176 mohclass = get_mohbyname(mclass, 1); 01177 if (!mohclass && realtime_possible) { 01178 var = ast_load_realtime("musiconhold", "name", mclass, NULL); 01179 } 01180 } 01181 if (!mohclass && !var && !ast_strlen_zero(interpclass)) { 01182 mohclass = get_mohbyname(interpclass, 1); 01183 if (!mohclass && realtime_possible) { 01184 var = ast_load_realtime("musiconhold", "name", interpclass, NULL); 01185 } 01186 } 01187 01188 if (!mohclass && !var) { 01189 mohclass = get_mohbyname("default", 1); 01190 if (!mohclass && realtime_possible) { 01191 var = ast_load_realtime("musiconhold", "name", "default", NULL); 01192 } 01193 } 01194 01195 /* If no moh class found in memory, then check RT. Note that the logic used 01196 * above guarantees that if var is non-NULL, then mohclass must be NULL. 01197 */ 01198 if (var) { 01199 struct ast_variable *tmp = NULL; 01200 01201 if ((mohclass = moh_class_malloc())) { 01202 mohclass->realtime = 1; 01203 for (tmp = var; tmp; tmp = tmp->next) { 01204 if (!strcasecmp(tmp->name, "name")) 01205 ast_copy_string(mohclass->name, tmp->value, sizeof(mohclass->name)); 01206 else if (!strcasecmp(tmp->name, "mode")) 01207 ast_copy_string(mohclass->mode, tmp->value, sizeof(mohclass->mode)); 01208 else if (!strcasecmp(tmp->name, "directory")) 01209 ast_copy_string(mohclass->dir, tmp->value, sizeof(mohclass->dir)); 01210 else if (!strcasecmp(tmp->name, "application")) 01211 ast_copy_string(mohclass->args, tmp->value, sizeof(mohclass->args)); 01212 else if (!strcasecmp(tmp->name, "digit") && (isdigit(*tmp->value) || strchr("*#", *tmp->value))) 01213 mohclass->digit = *tmp->value; 01214 else if (!strcasecmp(tmp->name, "random")) 01215 ast_set2_flag(mohclass, ast_true(tmp->value), MOH_RANDOMIZE); 01216 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "random")) 01217 ast_set_flag(mohclass, MOH_RANDOMIZE); 01218 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "alpha")) 01219 ast_set_flag(mohclass, MOH_SORTALPHA); 01220 else if (!strcasecmp(tmp->name, "format")) { 01221 mohclass->format = ast_getformatbyname(tmp->value); 01222 if (!mohclass->format) { 01223 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", tmp->value); 01224 mohclass->format = AST_FORMAT_SLINEAR; 01225 } 01226 } 01227 } 01228 ast_variables_destroy(var); 01229 if (ast_strlen_zero(mohclass->dir)) { 01230 if (!strcasecmp(mohclass->mode, "custom")) { 01231 strcpy(mohclass->dir, "nodir"); 01232 } else { 01233 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", mohclass->name); 01234 mohclass = mohclass_unref(mohclass); 01235 return -1; 01236 } 01237 } 01238 if (ast_strlen_zero(mohclass->mode)) { 01239 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", mohclass->name); 01240 mohclass = mohclass_unref(mohclass); 01241 return -1; 01242 } 01243 if (ast_strlen_zero(mohclass->args) && !strcasecmp(mohclass->mode, "custom")) { 01244 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", mohclass->name); 01245 mohclass = mohclass_unref(mohclass); 01246 return -1; 01247 } 01248 01249 if (ast_test_flag(global_flags, MOH_CACHERTCLASSES)) { 01250 /* CACHERTCLASSES enabled, let's add this class to default tree */ 01251 if (state && state->class) { 01252 /* Class already exist for this channel */ 01253 ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name); 01254 if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) { 01255 /* we found RT class with the same name, seems like we should continue playing existing one */ 01256 mohclass = mohclass_unref(mohclass); 01257 mohclass = state->class; 01258 } 01259 } 01260 /* We don't want moh_register to unref the mohclass because we do it at the end of this function as well. 01261 * If we allowed moh_register to unref the mohclass,too, then the count would be off by one. The result would 01262 * be that the destructor would be called when the generator on the channel is deactivated. The container then 01263 * has a pointer to a freed mohclass, so any operations involving the mohclass container would result in reading 01264 * invalid memory. 01265 */ 01266 moh_register(mohclass, 0, 0); 01267 } else { 01268 /* We don't register RT moh class, so let's init it manualy */ 01269 01270 time(&mohclass->start); 01271 mohclass->start -= respawn_time; 01272 01273 if (!strcasecmp(mohclass->mode, "files")) { 01274 if (!moh_scan_files(mohclass)) { 01275 mohclass = mohclass_unref(mohclass); 01276 return -1; 01277 } 01278 if (strchr(mohclass->args, 'r')) 01279 ast_set_flag(mohclass, MOH_RANDOMIZE); 01280 } 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")) { 01281 01282 if (!strcasecmp(mohclass->mode, "custom")) 01283 ast_set_flag(mohclass, MOH_CUSTOM); 01284 else if (!strcasecmp(mohclass->mode, "mp3nb")) 01285 ast_set_flag(mohclass, MOH_SINGLE); 01286 else if (!strcasecmp(mohclass->mode, "quietmp3nb")) 01287 ast_set_flag(mohclass, MOH_SINGLE | MOH_QUIET); 01288 else if (!strcasecmp(mohclass->mode, "quietmp3")) 01289 ast_set_flag(mohclass, MOH_QUIET); 01290 01291 mohclass->srcfd = -1; 01292 #ifdef HAVE_DAHDI 01293 /* Open /dev/dahdi/pseudo for timing... Is 01294 there a better, yet reliable way to do this? */ 01295 mohclass->pseudofd = open("/dev/dahdi/pseudo", O_RDONLY); 01296 if (mohclass->pseudofd < 0) { 01297 ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n"); 01298 } else { 01299 int x = 320; 01300 ioctl(mohclass->pseudofd, DAHDI_SET_BLOCKSIZE, &x); 01301 } 01302 #else 01303 mohclass->pseudofd = -1; 01304 #endif 01305 /* Let's check if this channel already had a moh class before */ 01306 if (state && state->class) { 01307 /* Class already exist for this channel */ 01308 ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name); 01309 if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) { 01310 /* we found RT class with the same name, seems like we should continue playing existing one */ 01311 mohclass = mohclass_unref(mohclass); 01312 mohclass = state->class; 01313 } 01314 } else { 01315 if (ast_pthread_create_background(&mohclass->thread, NULL, monmp3thread, mohclass)) { 01316 ast_log(LOG_WARNING, "Unable to create moh...\n"); 01317 if (mohclass->pseudofd > -1) { 01318 close(mohclass->pseudofd); 01319 mohclass->pseudofd = -1; 01320 } 01321 mohclass = mohclass_unref(mohclass); 01322 return -1; 01323 } 01324 } 01325 } else { 01326 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mohclass->mode); 01327 mohclass = mohclass_unref(mohclass); 01328 return -1; 01329 } 01330 } 01331 } else { 01332 ast_variables_destroy(var); 01333 } 01334 } 01335 01336 if (!mohclass) { 01337 return -1; 01338 } 01339 01340 ast_set_flag(chan, AST_FLAG_MOH); 01341 01342 if (mohclass->total_files) { 01343 res = ast_activate_generator(chan, &moh_file_stream, mohclass); 01344 } else { 01345 res = ast_activate_generator(chan, &mohgen, mohclass); 01346 } 01347 01348 mohclass = mohclass_unref(mohclass); 01349 01350 return res; 01351 }
| static void local_ast_moh_stop | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1353 of file res_musiconhold.c.
References ast_clear_flag, ast_closestream(), ast_deactivate_generator(), AST_FLAG_MOH, ast_channel::music_state, and ast_channel::stream.
Referenced by load_module().
01354 { 01355 struct moh_files_state *state = chan->music_state; 01356 ast_clear_flag(chan, AST_FLAG_MOH); 01357 ast_deactivate_generator(chan); 01358 01359 if (state) { 01360 if (chan->stream) { 01361 ast_closestream(chan->stream); 01362 chan->stream = NULL; 01363 } 01364 } 01365 }
| static int moh_add_file | ( | struct mohclass * | class, | |
| const char * | filepath | |||
| ) | [static] |
Definition at line 882 of file res_musiconhold.c.
References ast_calloc, ast_realloc, ast_strdup, and INITIAL_NUM_FILES.
Referenced by moh_scan_files().
00883 { 00884 if (!class->allowed_files) { 00885 if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray)))) 00886 return -1; 00887 class->allowed_files = INITIAL_NUM_FILES; 00888 } else if (class->total_files == class->allowed_files) { 00889 if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) { 00890 class->allowed_files = 0; 00891 class->total_files = 0; 00892 return -1; 00893 } 00894 class->allowed_files *= 2; 00895 } 00896 00897 if (!(class->filearray[class->total_files] = ast_strdup(filepath))) 00898 return -1; 00899 00900 class->total_files++; 00901 00902 return 0; 00903 }
| static void* moh_alloc | ( | struct ast_channel * | chan, | |
| void * | params | |||
| ) | [static] |
Definition at line 818 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, ast_channel::name, mohdata::origwfmt, and ast_channel::writeformat.
00819 { 00820 struct mohdata *res; 00821 struct mohclass *class = params; 00822 struct moh_files_state *state; 00823 00824 /* Initiating music_state for current channel. Channel should know name of moh class */ 00825 if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) { 00826 chan->music_state = state; 00827 state->class = class; 00828 } else 00829 state = chan->music_state; 00830 if (state && state->class != class) { 00831 memset(state, 0, sizeof(*state)); 00832 state->class = class; 00833 } 00834 00835 if ((res = mohalloc(class))) { 00836 res->origwfmt = chan->writeformat; 00837 if (ast_set_write_format(chan, class->format)) { 00838 ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format)); 00839 moh_release(NULL, res); 00840 res = NULL; 00841 } 00842 ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name); 00843 } 00844 return res; 00845 }
| static int moh_class_cmp | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1655 of file res_musiconhold.c.
References CMP_MATCH, and CMP_STOP.
Referenced by load_module().
01656 { 01657 struct mohclass *class = obj, *class2 = arg; 01658 01659 return strcasecmp(class->name, class2->name) ? 0 : CMP_MATCH | CMP_STOP; 01660 }
| static void moh_class_destructor | ( | void * | obj | ) | [static] |
Definition at line 1367 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().
01368 { 01369 struct mohclass *class = obj; 01370 struct mohdata *member; 01371 01372 ast_debug(1, "Destroying MOH class '%s'\n", class->name); 01373 01374 if (class->pid > 1) { 01375 char buff[8192]; 01376 int bytes, tbytes = 0, stime = 0, pid = 0; 01377 01378 ast_log(LOG_DEBUG, "killing %d!\n", class->pid); 01379 01380 stime = time(NULL) + 2; 01381 pid = class->pid; 01382 class->pid = 0; 01383 01384 /* Back when this was just mpg123, SIGKILL was fine. Now we need 01385 * to give the process a reason and time enough to kill off its 01386 * children. */ 01387 killpg(pid, SIGHUP); 01388 usleep(100000); 01389 killpg(pid, SIGTERM); 01390 usleep(100000); 01391 killpg(pid, SIGKILL); 01392 01393 while ((ast_wait_for_input(class->srcfd, 100) > 0) && 01394 (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) { 01395 tbytes = tbytes + bytes; 01396 } 01397 01398 ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes); 01399 01400 close(class->srcfd); 01401 } 01402 01403 while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) { 01404 free(member); 01405 } 01406 01407 if (class->thread) { 01408 pthread_cancel(class->thread); 01409 pthread_join(class->thread, NULL); 01410 class->thread = AST_PTHREADT_NULL; 01411 } 01412 01413 if (class->filearray) { 01414 int i; 01415 for (i = 0; i < class->total_files; i++) { 01416 free(class->filearray[i]); 01417 } 01418 free(class->filearray); 01419 class->filearray = NULL; 01420 } 01421 }
| static int moh_class_hash | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 1648 of file res_musiconhold.c.
References ast_str_case_hash().
Referenced by load_module().
01649 { 01650 const struct mohclass *class = obj; 01651 01652 return ast_str_case_hash(class->name); 01653 }
| static int moh_class_inuse | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1703 of file res_musiconhold.c.
References AST_LIST_EMPTY, CMP_MATCH, and CMP_STOP.
Referenced by unload_module().
01704 { 01705 struct mohclass *class = obj; 01706 01707 return AST_LIST_EMPTY(&class->members) ? 0 : CMP_MATCH | CMP_STOP; 01708 }
| static struct mohclass* moh_class_malloc | ( | void | ) | [static, read] |
Definition at line 1139 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().
01140 { 01141 struct mohclass *class; 01142 01143 if ((class = ao2_alloc(sizeof(*class), moh_class_destructor))) { 01144 class->format = AST_FORMAT_SLINEAR; 01145 } 01146 01147 return class; 01148 }
| static int moh_class_mark | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1423 of file res_musiconhold.c.
Referenced by load_moh_classes().
01424 { 01425 struct mohclass *class = obj; 01426 01427 class->delete = 1; 01428 01429 return 0; 01430 }
| static int moh_classes_delete_marked | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1432 of file res_musiconhold.c.
References CMP_MATCH.
Referenced by load_moh_classes().
01433 { 01434 struct mohclass *class = obj; 01435 01436 return class->delete ? CMP_MATCH : 0; 01437 }
Definition at line 1016 of file res_musiconhold.c.
References mohclass::args, mohclass::dir, mohclass::flags, and mohclass::mode.
Referenced by moh_register().
01017 { 01018 if (!old || !new) { 01019 return -1; 01020 } 01021 01022 if (strcmp(old->dir, new->dir)) { 01023 return -1; 01024 } else if (strcmp(old->mode, new->mode)) { 01025 return -1; 01026 } else if (strcmp(old->args, new->args)) { 01027 return -1; 01028 } else if (old->flags != new->flags) { 01029 return -1; 01030 } 01031 01032 return 0; 01033 }
| 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, moh_files_state::class, MOH_RANDOMIZE, mohclass_ref, ast_channel::music_state, ast_channel::name, moh_files_state::origwfmt, moh_files_state::pos, 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(), errno, f, LOG_WARNING, moh_files_readframe(), ast_channel::music_state, ast_channel::name, moh_files_state::sample_queue, ast_frame::samples, 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, read] |
Definition at line 277 of file res_musiconhold.c.
References ast_moh_files_next(), ast_readframe(), 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(), 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 847 of file res_musiconhold.c.
References ast_codec_get_len(), ast_codec_get_samples(), AST_FRIENDLY_OFFSET, ast_log(), ast_write(), buf, ast_frame::data, ast_frame::datalen, errno, mohdata::f, mohclass::format, LOG_WARNING, moh, ast_channel::name, mohdata::parent, mohdata::pipe, and ast_frame::samples.
00848 { 00849 struct mohdata *moh = data; 00850 short buf[1280 + AST_FRIENDLY_OFFSET / 2]; 00851 int res; 00852 00853 len = ast_codec_get_len(moh->parent->format, samples); 00854 00855 if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) { 00856 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name); 00857 len = sizeof(buf) - AST_FRIENDLY_OFFSET; 00858 } 00859 res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len); 00860 if (res <= 0) 00861 return 0; 00862 00863 moh->f.datalen = res; 00864 moh->f.data = buf + AST_FRIENDLY_OFFSET / 2; 00865 moh->f.samples = ast_codec_get_samples(&moh->f); 00866 00867 if (ast_write(chan, &moh->f) < 0) { 00868 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); 00869 return -1; 00870 } 00871 00872 return 0; 00873 }
| 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, ast_string_field_set, get_mohbydigit(), mohclass_unref, and musicclass.
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 ast_string_field_set(chan,musicclass,classname); 00366 ast_moh_stop(chan); 00367 ast_moh_start(chan, classname, NULL); 00368 } 00369 }
| static int moh_register | ( | struct mohclass * | moh, | |
| int | reload, | |||
| int | unref | |||
| ) | [static] |
Definition at line 1081 of file res_musiconhold.c.
References ao2_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().
01082 { 01083 struct mohclass *mohclass = NULL; 01084 01085 if ((mohclass = get_mohbyname(moh->name, 0)) && !moh_diff(mohclass, moh)) { 01086 if (!mohclass->delete) { 01087 ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name); 01088 mohclass = mohclass_unref(mohclass); 01089 if (unref) { 01090 moh = mohclass_unref(moh); 01091 } 01092 return -1; 01093 } 01094 mohclass = mohclass_unref(mohclass); 01095 } 01096 01097 time(&moh->start); 01098 moh->start -= respawn_time; 01099 01100 if (!strcasecmp(moh->mode, "files")) { 01101 if (init_files_class(moh)) { 01102 moh = mohclass_unref(moh); 01103 return -1; 01104 } 01105 } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || 01106 !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || 01107 !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) { 01108 if (init_app_class(moh)) { 01109 moh = mohclass_unref(moh); 01110 return -1; 01111 } 01112 } else { 01113 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode); 01114 moh = mohclass_unref(moh); 01115 return -1; 01116 } 01117 01118 ao2_link(mohclasses, moh); 01119 01120 if (unref) { 01121 moh = mohclass_unref(moh); 01122 } 01123 01124 return 0; 01125 }
| static void moh_release | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 789 of file res_musiconhold.c.
References ao2_lock(), ao2_unlock(), ast_free, ast_getformatname(), AST_LIST_REMOVE, ast_log(), ast_set_write_format(), ast_verb, LOG_WARNING, mohclass::members, moh, mohclass_unref, ast_channel::name, mohdata::origwfmt, mohdata::parent, and mohdata::pipe.
Referenced by moh_alloc().
00790 { 00791 struct mohdata *moh = data; 00792 struct mohclass *class = moh->parent; 00793 int oldwfmt; 00794 00795 ao2_lock(class); 00796 AST_LIST_REMOVE(&moh->parent->members, moh, list); 00797 ao2_unlock(class); 00798 00799 close(moh->pipe[0]); 00800 close(moh->pipe[1]); 00801 00802 oldwfmt = moh->origwfmt; 00803 00804 moh->parent = class = mohclass_unref(class); 00805 00806 ast_free(moh); 00807 00808 if (chan) { 00809 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) { 00810 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", 00811 chan->name, ast_getformatname(oldwfmt)); 00812 } 00813 00814 ast_verb(3, "Stopped music on hold on %s\n", chan->name); 00815 } 00816 }
| static int moh_scan_files | ( | struct mohclass * | class | ) | [static] |
Definition at line 915 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().
00915 { 00916 00917 DIR *files_DIR; 00918 struct dirent *files_dirent; 00919 char path[PATH_MAX]; 00920 char filepath[PATH_MAX]; 00921 char *ext; 00922 struct stat statbuf; 00923 int dirnamelen; 00924 int i; 00925 00926 files_DIR = opendir(class->dir); 00927 if (!files_DIR) { 00928 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", class->dir); 00929 return -1; 00930 } 00931 00932 for (i = 0; i < class->total_files; i++) 00933 ast_free(class->filearray[i]); 00934 00935 class->total_files = 0; 00936 dirnamelen = strlen(class->dir) + 2; 00937 if (!getcwd(path, sizeof(path))) { 00938 ast_log(LOG_WARNING, "getcwd() failed: %s\n", strerror(errno)); 00939 return -1; 00940 } 00941 if (chdir(class->dir) < 0) { 00942 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 00943 return -1; 00944 } 00945 while ((files_dirent = readdir(files_DIR))) { 00946 /* The file name must be at least long enough to have the file type extension */ 00947 if ((strlen(files_dirent->d_name) < 4)) 00948 continue; 00949 00950 /* Skip files that starts with a dot */ 00951 if (files_dirent->d_name[0] == '.') 00952 continue; 00953 00954 /* Skip files without extensions... they are not audio */ 00955 if (!strchr(files_dirent->d_name, '.')) 00956 continue; 00957 00958 snprintf(filepath, sizeof(filepath), "%s/%s", class->dir, files_dirent->d_name); 00959 00960 if (stat(filepath, &statbuf)) 00961 continue; 00962 00963 if (!S_ISREG(statbuf.st_mode)) 00964 continue; 00965 00966 if ((ext = strrchr(filepath, '.'))) 00967 *ext = '\0'; 00968 00969 /* if the file is present in multiple formats, ensure we only put it into the list once */ 00970 for (i = 0; i < class->total_files; i++) 00971 if (!strcmp(filepath, class->filearray[i])) 00972 break; 00973 00974 if (i == class->total_files) { 00975 if (moh_add_file(class, filepath)) 00976 break; 00977 } 00978 } 00979 00980 closedir(files_DIR); 00981 if (chdir(path) < 0) { 00982 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 00983 return -1; 00984 } 00985 if (ast_test_flag(class, MOH_SORTALPHA)) 00986 qsort(&class->filearray[0], class->total_files, sizeof(char *), moh_sort_compare); 00987 return class->total_files; 00988 }
| static int moh_sort_compare | ( | const void * | i1, | |
| const void * | i2 | |||
| ) | [static] |
Definition at line 905 of file res_musiconhold.c.
Referenced by moh_scan_files().
00906 { 00907 char *s1, *s2; 00908 00909 s1 = ((char **)i1)[0]; 00910 s2 = ((char **)i2)[0]; 00911 00912 return strcasecmp(s1, s2); 00913 }
Definition at line 756 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().
00757 { 00758 struct mohdata *moh; 00759 long flags; 00760 00761 if (!(moh = ast_calloc(1, sizeof(*moh)))) 00762 return NULL; 00763 00764 if (pipe(moh->pipe)) { 00765 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno)); 00766 ast_free(moh); 00767 return NULL; 00768 } 00769 00770 /* Make entirely non-blocking */ 00771 flags = fcntl(moh->pipe[0], F_GETFL); 00772 fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK); 00773 flags = fcntl(moh->pipe[1], F_GETFL); 00774 fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK); 00775 00776 moh->f.frametype = AST_FRAME_VOICE; 00777 moh->f.subclass = cl->format; 00778 moh->f.offset = AST_FRIENDLY_OFFSET; 00779 00780 moh->parent = mohclass_ref(cl); 00781 00782 ao2_lock(cl); 00783 AST_LIST_INSERT_HEAD(&cl->members, moh, list); 00784 ao2_unlock(cl); 00785 00786 return moh; 00787 }
| static void* monmp3thread | ( | void * | data | ) | [static] |
Definition at line 545 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().
00546 { 00547 #define MOH_MS_INTERVAL 100 00548 00549 struct mohclass *class = data; 00550 struct mohdata *moh; 00551 char buf[8192]; 00552 short sbuf[8192]; 00553 int res, res2; 00554 int len; 00555 struct timeval tv, tv_tmp; 00556 00557 tv.tv_sec = 0; 00558 tv.tv_usec = 0; 00559 for(;/* ever */;) { 00560 pthread_testcancel(); 00561 /* Spawn mp3 player if it's not there */ 00562 if (class->srcfd < 0) { 00563 if ((class->srcfd = spawn_mp3(class)) < 0) { 00564 ast_log(LOG_WARNING, "Unable to spawn mp3player\n"); 00565 /* Try again later */ 00566 sleep(500); 00567 pthread_testcancel(); 00568 } 00569 } 00570 if (class->pseudofd > -1) { 00571 #ifdef SOLARIS 00572 thr_yield(); 00573 #endif 00574 /* Pause some amount of time */ 00575 res = read(class->pseudofd, buf, sizeof(buf)); 00576 pthread_testcancel(); 00577 } else { 00578 long delta; 00579 /* Reliable sleep */ 00580 tv_tmp = ast_tvnow(); 00581 if (ast_tvzero(tv)) 00582 tv = tv_tmp; 00583 delta = ast_tvdiff_ms(tv_tmp, tv); 00584 if (delta < MOH_MS_INTERVAL) { /* too early */ 00585 tv = ast_tvadd(tv, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */ 00586 usleep(1000 * (MOH_MS_INTERVAL - delta)); 00587 pthread_testcancel(); 00588 } else { 00589 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n"); 00590 tv = tv_tmp; 00591 } 00592 res = 8 * MOH_MS_INTERVAL; /* 8 samples per millisecond */ 00593 } 00594 if ((strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir")) && AST_LIST_EMPTY(&class->members)) 00595 continue; 00596 /* Read mp3 audio */ 00597 len = ast_codec_get_len(class->format, res); 00598 00599 if ((res2 = read(class->srcfd, sbuf, len)) != len) { 00600 if (!res2) { 00601 close(class->srcfd); 00602 class->srcfd = -1; 00603 pthread_testcancel(); 00604 if (class->pid > 1) { 00605 killpg(class->pid, SIGHUP); 00606 usleep(100000); 00607 killpg(class->pid, SIGTERM); 00608 usleep(100000); 00609 killpg(class->pid, SIGKILL); 00610 class->pid = 0; 00611 } 00612 } else { 00613 ast_debug(1, "Read %d bytes of audio while expecting %d\n", res2, len); 00614 } 00615 continue; 00616 } 00617 00618 pthread_testcancel(); 00619 00620 ao2_lock(class); 00621 AST_LIST_TRAVERSE(&class->members, moh, list) { 00622 /* Write data */ 00623 if ((res = write(moh->pipe[1], sbuf, res2)) != res2) { 00624 ast_debug(1, "Only wrote %d of %d bytes to pipe\n", res, res2); 00625 } 00626 } 00627 ao2_unlock(class); 00628 } 00629 return NULL; 00630 }
| static int play_moh_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 632 of file res_musiconhold.c.
References mohclass::args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_moh_start(), ast_moh_stop(), ast_safe_sleep(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, ast_channel::name, parse(), and S_OR.
Referenced by load_module().
00633 { 00634 char *parse; 00635 char *class; 00636 int timeout = -1; 00637 int res; 00638 AST_DECLARE_APP_ARGS(args, 00639 AST_APP_ARG(class); 00640 AST_APP_ARG(duration); 00641 ); 00642 00643 parse = ast_strdupa(data); 00644 00645 AST_STANDARD_APP_ARGS(args, parse); 00646 00647 if (!ast_strlen_zero(args.duration)) { 00648 if (sscanf(args.duration, "%30d", &timeout) == 1) { 00649 timeout *= 1000; 00650 } else { 00651 ast_log(LOG_WARNING, "Invalid MusicOnHold duration '%s'. Will wait indefinitely.\n", args.duration); 00652 } 00653 } 00654 00655 class = S_OR(args.class, NULL); 00656 if (ast_moh_start(chan, class, NULL)) { 00657 ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, chan->name); 00658 return 0; 00659 } 00660 00661 if (timeout > 0) 00662 res = ast_safe_sleep(chan, timeout); 00663 else { 00664 while (!(res = ast_safe_sleep(chan, 10000))); 00665 } 00666 00667 ast_moh_stop(chan); 00668 00669 return res; 00670 }
| static int reload | ( | void | ) | [static] |
| static int set_moh_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 695 of file res_musiconhold.c.
References ast_log(), ast_string_field_set, ast_strlen_zero(), LOG_WARNING, and musicclass.
Referenced by load_module().
00696 { 00697 static int deprecation_warning = 0; 00698 00699 if (!deprecation_warning) { 00700 deprecation_warning = 1; 00701 ast_log(LOG_WARNING, "SetMusicOnHold application is deprecated and will be removed. Use Set(CHANNEL(musicclass)=...) instead\n"); 00702 } 00703 00704 if (ast_strlen_zero(data)) { 00705 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n"); 00706 return -1; 00707 } 00708 ast_string_field_set(chan, musicclass, data); 00709 return 0; 00710 }
| static int spawn_mp3 | ( | struct mohclass * | class | ) | [static] |
Definition at line 379 of file res_musiconhold.c.
References 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, and strsep().
Referenced by monmp3thread().
00380 { 00381 int fds[2]; 00382 int files = 0; 00383 char fns[MAX_MP3S][80]; 00384 char *argv[MAX_MP3S + 50]; 00385 char xargs[256]; 00386 char *argptr; 00387 int argc = 0; 00388 DIR *dir = NULL; 00389 struct dirent *de; 00390 sigset_t signal_set, old_set; 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 /* Block signals during the fork() */ 00476 sigfillset(&signal_set); 00477 pthread_sigmask(SIG_BLOCK, &signal_set, &old_set); 00478 00479 time(&class->start); 00480 class->pid = fork(); 00481 if (class->pid < 0) { 00482 close(fds[0]); 00483 close(fds[1]); 00484 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno)); 00485 return -1; 00486 } 00487 if (!class->pid) { 00488 /* Child */ 00489 int x; 00490 #ifdef HAVE_CAP 00491 cap_t cap; 00492 #endif 00493 if (strcasecmp(class->dir, "nodir") && chdir(class->dir) < 0) { 00494 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 00495 _exit(1); 00496 } 00497 00498 if (ast_opt_high_priority) 00499 ast_set_priority(0); 00500 00501 /* Reset ignored signals back to default */ 00502 signal(SIGPIPE, SIG_DFL); 00503 pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL); 00504 00505 #ifdef HAVE_CAP 00506 cap = cap_from_text("cap_net_admin-eip"); 00507 00508 if (cap_set_proc(cap)) { 00509 ast_log(LOG_WARNING, "Unable to remove capabilities.\n"); 00510 } 00511 cap_free(cap); 00512 #endif 00513 close(fds[0]); 00514 /* Stdout goes to pipe */ 00515 dup2(fds[1], STDOUT_FILENO); 00516 /* Close unused file descriptors */ 00517 for (x=3;x<8192;x++) { 00518 if (-1 != fcntl(x, F_GETFL)) { 00519 close(x); 00520 } 00521 } 00522 setpgid(0, getpid()); 00523 00524 if (ast_test_flag(class, MOH_CUSTOM)) { 00525 execv(argv[0], argv); 00526 } else { 00527 /* Default install is /usr/local/bin */ 00528 execv(LOCAL_MPG_123, argv); 00529 /* Many places have it in /usr/bin */ 00530 execv(MPG_123, argv); 00531 /* Check PATH as a last-ditch effort */ 00532 execvp("mpg123", argv); 00533 } 00534 ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno)); 00535 close(fds[1]); 00536 _exit(1); 00537 } else { 00538 /* Parent */ 00539 pthread_sigmask(SIG_SETMASK, &old_set, NULL); 00540 close(fds[1]); 00541 } 00542 return fds[0]; 00543 }
| static int start_moh_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 712 of file res_musiconhold.c.
References mohclass::args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_moh_start(), AST_STANDARD_APP_ARGS, ast_strdupa, LOG_WARNING, ast_channel::name, parse(), and S_OR.
Referenced by load_module().
00713 { 00714 char *parse; 00715 char *class; 00716 AST_DECLARE_APP_ARGS(args, 00717 AST_APP_ARG(class); 00718 ); 00719 00720 parse = ast_strdupa(data); 00721 00722 AST_STANDARD_APP_ARGS(args, parse); 00723 00724 class = S_OR(args.class, NULL); 00725 if (ast_moh_start(chan, class, NULL)) 00726 ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, chan->name); 00727 00728 return 0; 00729 }
| static int stop_moh_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 731 of file res_musiconhold.c.
References ast_moh_stop().
Referenced by load_module().
00732 { 00733 ast_moh_stop(chan); 00734 00735 return 0; 00736 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 1710 of file res_musiconhold.c.
References ao2_callback(), ast_cli_unregister_multiple(), ast_log(), ast_moh_destroy(), ast_uninstall_music_functions(), ast_unregister_application(), LOG_WARNING, moh_class_inuse(), and mohclass_unref.
01711 { 01712 int res = 0; 01713 struct mohclass *class = NULL; 01714 01715 /* XXX This check shouldn't be required if module ref counting was being used 01716 * properly ... */ 01717 if ((class = ao2_callback(mohclasses, 0, moh_class_inuse, NULL))) { 01718 class = mohclass_unref(class); 01719 res = -1; 01720 } 01721 01722 if (res < 0) { 01723 ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n"); 01724 return res; 01725 } 01726 01727 ast_uninstall_music_functions(); 01728 01729 ast_moh_destroy(); 01730 res = ast_unregister_application(play_moh); 01731 res |= ast_unregister_application(wait_moh); 01732 res |= ast_unregister_application(set_moh); 01733 res |= ast_unregister_application(start_moh); 01734 res |= ast_unregister_application(stop_moh); 01735 ast_cli_unregister_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry)); 01736 01737 return res; 01738 }
| static int wait_moh_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 672 of file res_musiconhold.c.
References ast_log(), ast_moh_start(), ast_moh_stop(), ast_safe_sleep(), LOG_WARNING, and ast_channel::name.
Referenced by load_module().
00673 { 00674 static int deprecation_warning = 0; 00675 int res; 00676 00677 if (!deprecation_warning) { 00678 deprecation_warning = 1; 00679 ast_log(LOG_WARNING, "WaitMusicOnHold application is deprecated and will be removed. Use MusicOnHold with duration parameter instead\n"); 00680 } 00681 00682 if (!data || !atoi(data)) { 00683 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n"); 00684 return -1; 00685 } 00686 if (ast_moh_start(chan, NULL, NULL)) { 00687 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name); 00688 return 0; 00689 } 00690 res = ast_safe_sleep(chan, atoi(data) * 1000); 00691 ast_moh_stop(chan); 00692 return res; 00693 }
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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 1744 of file res_musiconhold.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1744 of file res_musiconhold.c.
struct ast_cli_entry cli_moh[] [static] |
Initial value:
{
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 1642 of file res_musiconhold.c.
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 371 of file res_musiconhold.c.
struct ao2_container* mohclasses [static] |
Definition at line 183 of file res_musiconhold.c.
struct ast_generator mohgen [static] |
Definition at line 875 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.
1.5.6