#include "asterisk.h"
#include <ctype.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/ioctl.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
#include "asterisk/stringfields.h"
#include "asterisk/linkedlists.h"
#include "asterisk/manager.h"
#include "asterisk/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 = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ast_cli_entry | cli_moh [] |
| static struct ast_flags | global_flags [1] = {{0}} |
| static struct ast_generator | moh_file_stream |
| static struct ao2_container * | mohclasses |
| static struct ast_generator | mohgen |
| static char * | play_moh = "MusicOnHold" |
| static char * | play_moh_desc |
| 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 182 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 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) |
| #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 1730 of file res_musiconhold.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 1730 of file res_musiconhold.c.
| static void ast_moh_destroy | ( | void | ) | [static] |
Definition at line 1525 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().
01526 { 01527 ast_verb(2, "Destroying musiconhold processes\n"); 01528 ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "Destroy callback"); 01529 }
| 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, 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().
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 710 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().
00711 { 00712 struct mohclass *moh = NULL; 00713 struct mohclass tmp_class = { 00714 .flags = 0, 00715 }; 00716 00717 ast_copy_string(tmp_class.name, name, sizeof(tmp_class.name)); 00718 00719 moh = ao2_t_find(mohclasses, &tmp_class, 0, "Finding by name"); 00720 00721 if (!moh && warn) { 00722 ast_log(LOG_DEBUG, "Music on Hold class '%s' not found in memory\n", name); 00723 } 00724 00725 return moh; 00726 }
| static char* handle_cli_moh_reload | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1531 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.
01532 { 01533 switch (cmd) { 01534 case CLI_INIT: 01535 e->command = "moh reload"; 01536 e->usage = 01537 "Usage: moh reload\n" 01538 " Reloads the MusicOnHold module.\n" 01539 " Alias for 'module reload res_musiconhold.so'\n"; 01540 return NULL; 01541 case CLI_GENERATE: 01542 return NULL; 01543 } 01544 01545 if (a->argc != e->args) 01546 return CLI_SHOWUSAGE; 01547 01548 reload(); 01549 01550 return CLI_SUCCESS; 01551 }
| static char* handle_cli_moh_show_classes | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1591 of file res_musiconhold.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_t_iterator_next, ast_cli_args::argc, ast_cli_entry::args, ast_cli(), ast_getformatname(), ast_test_flag, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, MOH_CUSTOM, mohclass_unref, S_OR, and ast_cli_entry::usage.
01592 { 01593 struct mohclass *class; 01594 struct ao2_iterator i; 01595 01596 switch (cmd) { 01597 case CLI_INIT: 01598 e->command = "moh show classes"; 01599 e->usage = 01600 "Usage: moh show classes\n" 01601 " Lists all MusicOnHold classes.\n"; 01602 return NULL; 01603 case CLI_GENERATE: 01604 return NULL; 01605 } 01606 01607 if (a->argc != e->args) 01608 return CLI_SHOWUSAGE; 01609 01610 i = ao2_iterator_init(mohclasses, 0); 01611 for (; (class = ao2_t_iterator_next(&i, "Show classes iterator")); mohclass_unref(class, "Unref iterator in moh show classes")) { 01612 ast_cli(a->fd, "Class: %s\n", class->name); 01613 ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>")); 01614 ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>")); 01615 if (ast_test_flag(class, MOH_CUSTOM)) { 01616 ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>")); 01617 } 01618 if (strcasecmp(class->mode, "files")) { 01619 ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(class->format)); 01620 } 01621 } 01622 ao2_iterator_destroy(&i); 01623 01624 return CLI_SUCCESS; 01625 }
| static char* handle_cli_moh_show_files | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1553 of file res_musiconhold.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_t_iterator_next, ast_cli_args::argc, ast_cli_entry::args, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, mohclass_unref, and ast_cli_entry::usage.
01554 { 01555 struct mohclass *class; 01556 struct ao2_iterator i; 01557 01558 switch (cmd) { 01559 case CLI_INIT: 01560 e->command = "moh show files"; 01561 e->usage = 01562 "Usage: moh show files\n" 01563 " Lists all loaded file-based MusicOnHold classes and their\n" 01564 " files.\n"; 01565 return NULL; 01566 case CLI_GENERATE: 01567 return NULL; 01568 } 01569 01570 if (a->argc != e->args) 01571 return CLI_SHOWUSAGE; 01572 01573 i = ao2_iterator_init(mohclasses, 0); 01574 for (; (class = ao2_t_iterator_next(&i, "Show files iterator")); mohclass_unref(class, "Unref iterator in moh show files")) { 01575 int x; 01576 01577 if (!class->total_files) { 01578 continue; 01579 } 01580 01581 ast_cli(a->fd, "Class: %s\n", class->name); 01582 for (x = 0; x < class->total_files; x++) { 01583 ast_cli(a->fd, "\tFile: %s\n", class->filearray[x]); 01584 } 01585 } 01586 ao2_iterator_destroy(&i); 01587 01588 return CLI_SUCCESS; 01589 }
| static int init_app_class | ( | struct mohclass * | class | ) | [static] |
Definition at line 1007 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().
01008 { 01009 #ifdef HAVE_DAHDI 01010 int x; 01011 #endif 01012 01013 if (!strcasecmp(class->mode, "custom")) { 01014 ast_set_flag(class, MOH_CUSTOM); 01015 } else if (!strcasecmp(class->mode, "mp3nb")) { 01016 ast_set_flag(class, MOH_SINGLE); 01017 } else if (!strcasecmp(class->mode, "quietmp3nb")) { 01018 ast_set_flag(class, MOH_SINGLE | MOH_QUIET); 01019 } else if (!strcasecmp(class->mode, "quietmp3")) { 01020 ast_set_flag(class, MOH_QUIET); 01021 } 01022 01023 class->srcfd = -1; 01024 class->pseudofd = -1; 01025 01026 #ifdef HAVE_DAHDI 01027 /* Open /dev/zap/pseudo for timing... Is 01028 there a better, yet reliable way to do this? */ 01029 class->pseudofd = open("/dev/dahdi/pseudo", O_RDONLY); 01030 if (class->pseudofd < 0) { 01031 ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n"); 01032 } else { 01033 x = 320; 01034 ioctl(class->pseudofd, DAHDI_SET_BLOCKSIZE, &x); 01035 } 01036 #endif 01037 01038 if (ast_pthread_create_background(&class->thread, NULL, monmp3thread, class)) { 01039 ast_log(LOG_WARNING, "Unable to create moh thread...\n"); 01040 if (class->pseudofd > -1) { 01041 close(class->pseudofd); 01042 class->pseudofd = -1; 01043 } 01044 return -1; 01045 } 01046 01047 return 0; 01048 }
| static int init_files_class | ( | struct mohclass * | class | ) | [static] |
Definition at line 962 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().
00963 { 00964 int res; 00965 00966 res = moh_scan_files(class); 00967 00968 if (res < 0) { 00969 return -1; 00970 } 00971 00972 if (!res) { 00973 if (option_verbose > 2) { 00974 ast_verbose(VERBOSE_PREFIX_3 "Files not found in %s for moh class:%s\n", 00975 class->dir, class->name); 00976 } 00977 return -1; 00978 } 00979 00980 if (strchr(class->args, 'r')) { 00981 ast_set_flag(class, MOH_RANDOMIZE); 00982 } 00983 00984 return 0; 00985 }
| static int load_module | ( | void | ) | [static] |
Definition at line 1647 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().
01648 { 01649 int res; 01650 01651 if (!(mohclasses = ao2_t_container_alloc(53, moh_class_hash, moh_class_cmp, "Moh class container"))) { 01652 return AST_MODULE_LOAD_DECLINE; 01653 } 01654 01655 if (!load_moh_classes(0)) { /* No music classes configured, so skip it */ 01656 ast_log(LOG_WARNING, "No music on hold classes configured, " 01657 "disabling music on hold.\n"); 01658 } else { 01659 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, 01660 local_ast_moh_cleanup); 01661 } 01662 01663 res = ast_register_application(play_moh, play_moh_exec, play_moh_syn, play_moh_desc); 01664 ast_register_atexit(ast_moh_destroy); 01665 ast_cli_register_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry)); 01666 if (!res) 01667 res = ast_register_application(wait_moh, wait_moh_exec, wait_moh_syn, wait_moh_desc); 01668 if (!res) 01669 res = ast_register_application(set_moh, set_moh_exec, set_moh_syn, set_moh_desc); 01670 if (!res) 01671 res = ast_register_application(start_moh, start_moh_exec, start_moh_syn, start_moh_desc); 01672 if (!res) 01673 res = ast_register_application(stop_moh, stop_moh_exec, stop_moh_syn, stop_moh_desc); 01674 01675 return AST_MODULE_LOAD_SUCCESS; 01676 }
| static int load_moh_classes | ( | int | reload | ) | [static] |
Definition at line 1424 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().
01425 { 01426 struct ast_config *cfg; 01427 struct ast_variable *var; 01428 struct mohclass *class; 01429 char *cat; 01430 int numclasses = 0; 01431 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 01432 01433 cfg = ast_config_load("musiconhold.conf", config_flags); 01434 01435 if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED) 01436 return 0; 01437 01438 if (reload) { 01439 ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes"); 01440 } 01441 01442 ast_clear_flag(global_flags, AST_FLAGS_ALL); 01443 01444 cat = ast_category_browse(cfg, NULL); 01445 for (; cat; cat = ast_category_browse(cfg, cat)) { 01446 /* Setup common options from [general] section */ 01447 if (!strcasecmp(cat, "general")) { 01448 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 01449 if (!strcasecmp(var->name, "cachertclasses")) { 01450 ast_set2_flag(global_flags, ast_true(var->value), MOH_CACHERTCLASSES); 01451 } else { 01452 ast_log(LOG_WARNING, "Unknown option '%s' in [general] section of musiconhold.conf\n", var->name); 01453 } 01454 } 01455 } 01456 /* These names were deprecated in 1.4 and should not be used until after the next major release. */ 01457 if (!strcasecmp(cat, "classes") || !strcasecmp(cat, "moh_files") || 01458 !strcasecmp(cat, "general")) { 01459 continue; 01460 } 01461 01462 if (!(class = moh_class_malloc())) { 01463 break; 01464 } 01465 01466 ast_copy_string(class->name, cat, sizeof(class->name)); 01467 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 01468 if (!strcasecmp(var->name, "mode")) 01469 ast_copy_string(class->mode, var->value, sizeof(class->mode)); 01470 else if (!strcasecmp(var->name, "directory")) 01471 ast_copy_string(class->dir, var->value, sizeof(class->dir)); 01472 else if (!strcasecmp(var->name, "application")) 01473 ast_copy_string(class->args, var->value, sizeof(class->args)); 01474 else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value))) 01475 class->digit = *var->value; 01476 else if (!strcasecmp(var->name, "random")) 01477 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE); 01478 else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "random")) 01479 ast_set_flag(class, MOH_RANDOMIZE); 01480 else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) 01481 ast_set_flag(class, MOH_SORTALPHA); 01482 else if (!strcasecmp(var->name, "format")) { 01483 class->format = ast_getformatbyname(var->value); 01484 if (!class->format) { 01485 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value); 01486 class->format = AST_FORMAT_SLINEAR; 01487 } 01488 } 01489 } 01490 01491 if (ast_strlen_zero(class->dir)) { 01492 if (!strcasecmp(class->mode, "custom")) { 01493 strcpy(class->dir, "nodir"); 01494 } else { 01495 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name); 01496 class = mohclass_unref(class, "unreffing potential mohclass (no directory)"); 01497 continue; 01498 } 01499 } 01500 if (ast_strlen_zero(class->mode)) { 01501 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name); 01502 class = mohclass_unref(class, "unreffing potential mohclass (no mode)"); 01503 continue; 01504 } 01505 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) { 01506 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name); 01507 class = mohclass_unref(class, "unreffing potential mohclass (no app for custom mode)"); 01508 continue; 01509 } 01510 01511 /* Don't leak a class when it's already registered */ 01512 if (!moh_register(class, reload, 1)) { 01513 numclasses++; 01514 } 01515 } 01516 01517 ast_config_destroy(cfg); 01518 01519 ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, 01520 moh_classes_delete_marked, NULL, "Purge marked classes"); 01521 01522 return numclasses; 01523 }
| static void local_ast_moh_cleanup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1099 of file res_musiconhold.c.
References ast_free, and ast_channel::music_state.
Referenced by load_module().
01100 { 01101 struct moh_files_state *state = chan->music_state; 01102 01103 if (state) { 01104 ast_free(chan->music_state); 01105 chan->music_state = NULL; 01106 } 01107 }
| static int local_ast_moh_start | ( | struct ast_channel * | chan, | |
| const char * | mclass, | |||
| const char * | interpclass | |||
| ) | [static] |
Definition at line 1122 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, ast_channel::musicclass, ast_channel::name, mohclass::name, ast_variable::name, ast_variable::next, mohclass::pseudofd, mohclass::realtime, SENTINEL, mohclass::srcfd, mohclass::start, mohclass::thread, mohclass::total_files, ast_channel::uniqueid, ast_variable::value, and var.
Referenced by load_module().
01123 { 01124 struct mohclass *mohclass = NULL; 01125 struct moh_files_state *state = chan->music_state; 01126 struct ast_variable *var = NULL; 01127 int res; 01128 int realtime_possible = ast_check_realtime("musiconhold"); 01129 01130 /* The following is the order of preference for which class to use: 01131 * 1) The channels explicitly set musicclass, which should *only* be 01132 * set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan. 01133 * 2) The mclass argument. If a channel is calling ast_moh_start() as the 01134 * result of receiving a HOLD control frame, this should be the 01135 * payload that came with the frame. 01136 * 3) The interpclass argument. This would be from the mohinterpret 01137 * option from channel drivers. This is the same as the old musicclass 01138 * option. 01139 * 4) The default class. 01140 */ 01141 if (!ast_strlen_zero(chan->musicclass)) { 01142 mohclass = get_mohbyname(chan->musicclass, 1); 01143 if (!mohclass && realtime_possible) { 01144 var = ast_load_realtime("musiconhold", "name", chan->musicclass, SENTINEL); 01145 } 01146 } 01147 if (!mohclass && !var && !ast_strlen_zero(mclass)) { 01148 mohclass = get_mohbyname(mclass, 1); 01149 if (!mohclass && realtime_possible) { 01150 var = ast_load_realtime("musiconhold", "name", mclass, SENTINEL); 01151 } 01152 } 01153 if (!mohclass && !var && !ast_strlen_zero(interpclass)) { 01154 mohclass = get_mohbyname(interpclass, 1); 01155 if (!mohclass && realtime_possible) { 01156 var = ast_load_realtime("musiconhold", "name", interpclass, SENTINEL); 01157 } 01158 } 01159 01160 if (!mohclass && !var) { 01161 mohclass = get_mohbyname("default", 1); 01162 if (!mohclass && realtime_possible) { 01163 var = ast_load_realtime("musiconhold", "name", "default", SENTINEL); 01164 } 01165 } 01166 01167 /* If no moh class found in memory, then check RT. Note that the logic used 01168 * above guarantees that if var is non-NULL, then mohclass must be NULL. 01169 */ 01170 if (var) { 01171 struct ast_variable *tmp = NULL; 01172 01173 if ((mohclass = moh_class_malloc())) { 01174 mohclass->realtime = 1; 01175 for (tmp = var; tmp; tmp = tmp->next) { 01176 if (!strcasecmp(tmp->name, "name")) 01177 ast_copy_string(mohclass->name, tmp->value, sizeof(mohclass->name)); 01178 else if (!strcasecmp(tmp->name, "mode")) 01179 ast_copy_string(mohclass->mode, tmp->value, sizeof(mohclass->mode)); 01180 else if (!strcasecmp(tmp->name, "directory")) 01181 ast_copy_string(mohclass->dir, tmp->value, sizeof(mohclass->dir)); 01182 else if (!strcasecmp(tmp->name, "application")) 01183 ast_copy_string(mohclass->args, tmp->value, sizeof(mohclass->args)); 01184 else if (!strcasecmp(tmp->name, "digit") && (isdigit(*tmp->value) || strchr("*#", *tmp->value))) 01185 mohclass->digit = *tmp->value; 01186 else if (!strcasecmp(tmp->name, "random")) 01187 ast_set2_flag(mohclass, ast_true(tmp->value), MOH_RANDOMIZE); 01188 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "random")) 01189 ast_set_flag(mohclass, MOH_RANDOMIZE); 01190 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "alpha")) 01191 ast_set_flag(mohclass, MOH_SORTALPHA); 01192 else if (!strcasecmp(tmp->name, "format")) { 01193 mohclass->format = ast_getformatbyname(tmp->value); 01194 if (!mohclass->format) { 01195 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", tmp->value); 01196 mohclass->format = AST_FORMAT_SLINEAR; 01197 } 01198 } 01199 } 01200 ast_variables_destroy(var); 01201 if (ast_strlen_zero(mohclass->dir)) { 01202 if (!strcasecmp(mohclass->mode, "custom")) { 01203 strcpy(mohclass->dir, "nodir"); 01204 } else { 01205 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", mohclass->name); 01206 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no directory specified)"); 01207 return -1; 01208 } 01209 } 01210 if (ast_strlen_zero(mohclass->mode)) { 01211 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", mohclass->name); 01212 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no mode specified)"); 01213 return -1; 01214 } 01215 if (ast_strlen_zero(mohclass->args) && !strcasecmp(mohclass->mode, "custom")) { 01216 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", mohclass->name); 01217 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no app specified for custom mode"); 01218 return -1; 01219 } 01220 01221 if (ast_test_flag(global_flags, MOH_CACHERTCLASSES)) { 01222 /* CACHERTCLASSES enabled, let's add this class to default tree */ 01223 if (state && state->class) { 01224 /* Class already exist for this channel */ 01225 ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name); 01226 if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) { 01227 /* we found RT class with the same name, seems like we should continue playing existing one */ 01228 /* XXX This code is impossible to reach */ 01229 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has a class)"); 01230 mohclass = state->class; 01231 } 01232 } 01233 /* We don't want moh_register to unref the mohclass because we do it at the end of this function as well. 01234 * If we allowed moh_register to unref the mohclass,too, then the count would be off by one. The result would 01235 * be that the destructor would be called when the generator on the channel is deactivated. The container then 01236 * has a pointer to a freed mohclass, so any operations involving the mohclass container would result in reading 01237 * invalid memory. 01238 */ 01239 moh_register(mohclass, 0, 0); 01240 } else { 01241 /* We don't register RT moh class, so let's init it manualy */ 01242 01243 time(&mohclass->start); 01244 mohclass->start -= respawn_time; 01245 01246 if (!strcasecmp(mohclass->mode, "files")) { 01247 if (!moh_scan_files(mohclass)) { 01248 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)"); 01249 return -1; 01250 } 01251 if (strchr(mohclass->args, 'r')) 01252 ast_set_flag(mohclass, MOH_RANDOMIZE); 01253 } 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")) { 01254 01255 if (!strcasecmp(mohclass->mode, "custom")) 01256 ast_set_flag(mohclass, MOH_CUSTOM); 01257 else if (!strcasecmp(mohclass->mode, "mp3nb")) 01258 ast_set_flag(mohclass, MOH_SINGLE); 01259 else if (!strcasecmp(mohclass->mode, "quietmp3nb")) 01260 ast_set_flag(mohclass, MOH_SINGLE | MOH_QUIET); 01261 else if (!strcasecmp(mohclass->mode, "quietmp3")) 01262 ast_set_flag(mohclass, MOH_QUIET); 01263 01264 mohclass->srcfd = -1; 01265 #ifdef HAVE_DAHDI 01266 /* Open /dev/dahdi/pseudo for timing... Is 01267 there a better, yet reliable way to do this? */ 01268 mohclass->pseudofd = open("/dev/dahdi/pseudo", O_RDONLY); 01269 if (mohclass->pseudofd < 0) { 01270 ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n"); 01271 } else { 01272 int x = 320; 01273 ioctl(mohclass->pseudofd, DAHDI_SET_BLOCKSIZE, &x); 01274 } 01275 #else 01276 mohclass->pseudofd = -1; 01277 #endif 01278 /* Let's check if this channel already had a moh class before */ 01279 if (state && state->class) { 01280 /* Class already exist for this channel */ 01281 ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name); 01282 if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) { 01283 /* we found RT class with the same name, seems like we should continue playing existing one */ 01284 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has one)"); 01285 mohclass = state->class; 01286 } 01287 } else { 01288 if (ast_pthread_create_background(&mohclass->thread, NULL, monmp3thread, mohclass)) { 01289 ast_log(LOG_WARNING, "Unable to create moh...\n"); 01290 if (mohclass->pseudofd > -1) { 01291 close(mohclass->pseudofd); 01292 mohclass->pseudofd = -1; 01293 } 01294 mohclass = mohclass_unref(mohclass, "Unreffing potential mohclass (failed to create background thread)"); 01295 return -1; 01296 } 01297 } 01298 } else { 01299 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mohclass->mode); 01300 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (unknown mode)"); 01301 return -1; 01302 } 01303 } 01304 } else { 01305 ast_variables_destroy(var); 01306 } 01307 } 01308 01309 if (!mohclass) { 01310 return -1; 01311 } 01312 01313 manager_event(EVENT_FLAG_CALL, "MusicOnHold", 01314 "State: Start\r\n" 01315 "Channel: %s\r\n" 01316 "UniqueID: %s\r\n", 01317 chan->name, chan->uniqueid); 01318 01319 ast_set_flag(chan, AST_FLAG_MOH); 01320 01321 if (mohclass->total_files) { 01322 res = ast_activate_generator(chan, &moh_file_stream, mohclass); 01323 } else { 01324 res = ast_activate_generator(chan, &mohgen, mohclass); 01325 } 01326 01327 mohclass = mohclass_unref(mohclass, "unreffing local reference to mohclass in local_ast_moh_start"); 01328 01329 return res; 01330 }
| static void local_ast_moh_stop | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1332 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, ast_channel::name, ast_channel::stream, and ast_channel::uniqueid.
Referenced by load_module().
01333 { 01334 struct moh_files_state *state = chan->music_state; 01335 ast_clear_flag(chan, AST_FLAG_MOH); 01336 ast_deactivate_generator(chan); 01337 01338 if (state) { 01339 if (chan->stream) { 01340 ast_closestream(chan->stream); 01341 chan->stream = NULL; 01342 } 01343 } 01344 01345 manager_event(EVENT_FLAG_CALL, "MusicOnHold", 01346 "State: Stop\r\n" 01347 "Channel: %s\r\n" 01348 "UniqueID: %s\r\n", 01349 chan->name, chan->uniqueid); 01350 }
| static int moh_add_file | ( | struct mohclass * | class, | |
| const char * | filepath | |||
| ) | [static] |
Definition at line 854 of file res_musiconhold.c.
References ast_calloc, ast_realloc, ast_strdup, and INITIAL_NUM_FILES.
Referenced by moh_scan_files().
00855 { 00856 if (!class->allowed_files) { 00857 if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray)))) 00858 return -1; 00859 class->allowed_files = INITIAL_NUM_FILES; 00860 } else if (class->total_files == class->allowed_files) { 00861 if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) { 00862 class->allowed_files = 0; 00863 class->total_files = 0; 00864 return -1; 00865 } 00866 class->allowed_files *= 2; 00867 } 00868 00869 if (!(class->filearray[class->total_files] = ast_strdup(filepath))) 00870 return -1; 00871 00872 class->total_files++; 00873 00874 return 0; 00875 }
| static void* moh_alloc | ( | struct ast_channel * | chan, | |
| void * | params | |||
| ) | [static] |
Definition at line 790 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.
00791 { 00792 struct mohdata *res; 00793 struct mohclass *class = params; 00794 struct moh_files_state *state; 00795 00796 /* Initiating music_state for current channel. Channel should know name of moh class */ 00797 if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) { 00798 chan->music_state = state; 00799 state->class = class; 00800 } else 00801 state = chan->music_state; 00802 if (state && state->class != class) { 00803 memset(state, 0, sizeof(*state)); 00804 state->class = class; 00805 } 00806 00807 if ((res = mohalloc(class))) { 00808 res->origwfmt = chan->writeformat; 00809 if (ast_set_write_format(chan, class->format)) { 00810 ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format)); 00811 moh_release(NULL, res); 00812 res = NULL; 00813 } 00814 ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name); 00815 } 00816 return res; 00817 }
| static int moh_class_cmp | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1640 of file res_musiconhold.c.
References CMP_MATCH, and CMP_STOP.
Referenced by load_module().
01641 { 01642 struct mohclass *class = obj, *class2 = arg; 01643 01644 return strcasecmp(class->name, class2->name) ? 0 : CMP_MATCH | CMP_STOP; 01645 }
| static void moh_class_destructor | ( | void * | obj | ) | [static] |
Definition at line 1352 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().
01353 { 01354 struct mohclass *class = obj; 01355 struct mohdata *member; 01356 01357 ast_debug(1, "Destroying MOH class '%s'\n", class->name); 01358 01359 if (class->pid > 1) { 01360 char buff[8192]; 01361 int bytes, tbytes = 0, stime = 0, pid = 0; 01362 01363 ast_log(LOG_DEBUG, "killing %d!\n", class->pid); 01364 01365 stime = time(NULL) + 2; 01366 pid = class->pid; 01367 class->pid = 0; 01368 01369 /* Back when this was just mpg123, SIGKILL was fine. Now we need 01370 * to give the process a reason and time enough to kill off its 01371 * children. */ 01372 killpg(pid, SIGHUP); 01373 usleep(100000); 01374 killpg(pid, SIGTERM); 01375 usleep(100000); 01376 killpg(pid, SIGKILL); 01377 01378 while ((ast_wait_for_input(class->srcfd, 100) > 0) && 01379 (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) { 01380 tbytes = tbytes + bytes; 01381 } 01382 01383 ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes); 01384 01385 close(class->srcfd); 01386 } 01387 01388 while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) { 01389 free(member); 01390 } 01391 01392 if (class->thread) { 01393 pthread_cancel(class->thread); 01394 pthread_join(class->thread, NULL); 01395 class->thread = AST_PTHREADT_NULL; 01396 } 01397 01398 if (class->filearray) { 01399 int i; 01400 for (i = 0; i < class->total_files; i++) { 01401 free(class->filearray[i]); 01402 } 01403 free(class->filearray); 01404 class->filearray = NULL; 01405 } 01406 }
| static int moh_class_hash | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 1633 of file res_musiconhold.c.
References ast_str_case_hash().
Referenced by load_module().
01634 { 01635 const struct mohclass *class = obj; 01636 01637 return ast_str_case_hash(class->name); 01638 }
| static int moh_class_inuse | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1688 of file res_musiconhold.c.
References AST_LIST_EMPTY, CMP_MATCH, and CMP_STOP.
Referenced by unload_module().
01689 { 01690 struct mohclass *class = obj; 01691 01692 return AST_LIST_EMPTY(&class->members) ? 0 : CMP_MATCH | CMP_STOP; 01693 }
| static struct mohclass* moh_class_malloc | ( | void | ) | [static, read] |
Definition at line 1111 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().
01112 { 01113 struct mohclass *class; 01114 01115 if ((class = ao2_t_alloc(sizeof(*class), moh_class_destructor, "Allocating new moh class"))) { 01116 class->format = AST_FORMAT_SLINEAR; 01117 } 01118 01119 return class; 01120 }
| static int moh_class_mark | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1408 of file res_musiconhold.c.
Referenced by load_moh_classes().
01409 { 01410 struct mohclass *class = obj; 01411 01412 class->delete = 1; 01413 01414 return 0; 01415 }
| static int moh_classes_delete_marked | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1417 of file res_musiconhold.c.
References CMP_MATCH.
Referenced by load_moh_classes().
01418 { 01419 struct mohclass *class = obj; 01420 01421 return class->delete ? CMP_MATCH : 0; 01422 }
Definition at line 988 of file res_musiconhold.c.
References mohclass::args, mohclass::dir, mohclass::flags, and mohclass::mode.
Referenced by moh_register().
00989 { 00990 if (!old || !new) { 00991 return -1; 00992 } 00993 00994 if (strcmp(old->dir, new->dir)) { 00995 return -1; 00996 } else if (strcmp(old->mode, new->mode)) { 00997 return -1; 00998 } else if (strcmp(old->args, new->args)) { 00999 return -1; 01000 } else if (old->flags != new->flags) { 01001 return -1; 01002 } 01003 01004 return 0; 01005 }
| 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().
00341 { 00342 char *digit = arg; 00343 struct mohclass *class = obj; 00344 00345 return (*digit == class->digit) ? CMP_MATCH | CMP_STOP : 0; 00346 }
| 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, ast_channel::name, 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, ast_channel::name, 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, 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.
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 819 of file res_musiconhold.c.
References ast_codec_get_len(), ast_codec_get_samples(), AST_FRIENDLY_OFFSET, ast_log(), ast_write(), buf, ast_frame::data, ast_frame::datalen, errno, mohdata::f, mohclass::format, LOG_WARNING, moh, ast_channel::name, mohdata::parent, mohdata::pipe, ast_frame::ptr, and ast_frame::samples.
00820 { 00821 struct mohdata *moh = data; 00822 short buf[1280 + AST_FRIENDLY_OFFSET / 2]; 00823 int res; 00824 00825 len = ast_codec_get_len(moh->parent->format, samples); 00826 00827 if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) { 00828 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name); 00829 len = sizeof(buf) - AST_FRIENDLY_OFFSET; 00830 } 00831 res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len); 00832 if (res <= 0) 00833 return 0; 00834 00835 moh->f.datalen = res; 00836 moh->f.data.ptr = buf + AST_FRIENDLY_OFFSET / 2; 00837 moh->f.samples = ast_codec_get_samples(&moh->f); 00838 00839 if (ast_write(chan, &moh->f) < 0) { 00840 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); 00841 return -1; 00842 } 00843 00844 return 0; 00845 }
| 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, ast_string_field_set, get_mohbydigit(), mohclass_unref, and musicclass.
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 ast_string_field_set(chan,musicclass,classname); 00363 ast_moh_stop(chan); 00364 ast_moh_start(chan, classname, NULL); 00365 } 00366 }
| static int moh_register | ( | struct mohclass * | moh, | |
| int | reload, | |||
| int | unref | |||
| ) | [static] |
Definition at line 1053 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().
01054 { 01055 struct mohclass *mohclass = NULL; 01056 01057 if ((mohclass = get_mohbyname(moh->name, 0)) && !moh_diff(mohclass, moh)) { 01058 if (!mohclass->delete) { 01059 ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name); 01060 mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name"); 01061 if (unref) { 01062 moh = mohclass_unref(moh, "unreffing potential new moh class (it is a duplicate)"); 01063 } 01064 return -1; 01065 } 01066 mohclass = mohclass_unref(mohclass, "Unreffing mohclass we just found by name"); 01067 } 01068 01069 time(&moh->start); 01070 moh->start -= respawn_time; 01071 01072 if (!strcasecmp(moh->mode, "files")) { 01073 if (init_files_class(moh)) { 01074 moh = mohclass_unref(moh, "unreffing potential new moh class (init_files_class failed)"); 01075 return -1; 01076 } 01077 } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || 01078 !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || 01079 !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) { 01080 if (init_app_class(moh)) { 01081 moh = mohclass_unref(moh, "unreffing potential new moh class (init_app_class_failed)"); 01082 return -1; 01083 } 01084 } else { 01085 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode); 01086 moh = mohclass_unref(moh, "unreffing potential new moh class (unknown mode)"); 01087 return -1; 01088 } 01089 01090 ao2_t_link(mohclasses, moh, "Adding class to container"); 01091 01092 if (unref) { 01093 moh = mohclass_unref(moh, "Unreffing new moh class because we just added it to the container"); 01094 } 01095 01096 return 0; 01097 }
| static void moh_release | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 761 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().
00762 { 00763 struct mohdata *moh = data; 00764 struct mohclass *class = moh->parent; 00765 int oldwfmt; 00766 00767 ao2_lock(class); 00768 AST_LIST_REMOVE(&moh->parent->members, moh, list); 00769 ao2_unlock(class); 00770 00771 close(moh->pipe[0]); 00772 close(moh->pipe[1]); 00773 00774 oldwfmt = moh->origwfmt; 00775 00776 moh->parent = class = mohclass_unref(class, "unreffing moh->parent upon deactivation of generator"); 00777 00778 ast_free(moh); 00779 00780 if (chan) { 00781 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) { 00782 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", 00783 chan->name, ast_getformatname(oldwfmt)); 00784 } 00785 00786 ast_verb(3, "Stopped music on hold on %s\n", chan->name); 00787 } 00788 }
| static int moh_scan_files | ( | struct mohclass * | class | ) | [static] |
Definition at line 887 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().
00887 { 00888 00889 DIR *files_DIR; 00890 struct dirent *files_dirent; 00891 char path[PATH_MAX]; 00892 char filepath[PATH_MAX]; 00893 char *ext; 00894 struct stat statbuf; 00895 int dirnamelen; 00896 int i; 00897 00898 files_DIR = opendir(class->dir); 00899 if (!files_DIR) { 00900 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", class->dir); 00901 return -1; 00902 } 00903 00904 for (i = 0; i < class->total_files; i++) 00905 ast_free(class->filearray[i]); 00906 00907 class->total_files = 0; 00908 dirnamelen = strlen(class->dir) + 2; 00909 if (!getcwd(path, sizeof(path))) { 00910 ast_log(LOG_WARNING, "getcwd() failed: %s\n", strerror(errno)); 00911 return -1; 00912 } 00913 if (chdir(class->dir) < 0) { 00914 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 00915 return -1; 00916 } 00917 while ((files_dirent = readdir(files_DIR))) { 00918 /* The file name must be at least long enough to have the file type extension */ 00919 if ((strlen(files_dirent->d_name) < 4)) 00920 continue; 00921 00922 /* Skip files that starts with a dot */ 00923 if (files_dirent->d_name[0] == '.') 00924 continue; 00925 00926 /* Skip files without extensions... they are not audio */ 00927 if (!strchr(files_dirent->d_name, '.')) 00928 continue; 00929 00930 snprintf(filepath, sizeof(filepath), "%s/%s", class->dir, files_dirent->d_name); 00931 00932 if (stat(filepath, &statbuf)) 00933 continue; 00934 00935 if (!S_ISREG(statbuf.st_mode)) 00936 continue; 00937 00938 if ((ext = strrchr(filepath, '.'))) 00939 *ext = '\0'; 00940 00941 /* if the file is present in multiple formats, ensure we only put it into the list once */ 00942 for (i = 0; i < class->total_files; i++) 00943 if (!strcmp(filepath, class->filearray[i])) 00944 break; 00945 00946 if (i == class->total_files) { 00947 if (moh_add_file(class, filepath)) 00948 break; 00949 } 00950 } 00951 00952 closedir(files_DIR); 00953 if (chdir(path) < 0) { 00954 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 00955 return -1; 00956 } 00957 if (ast_test_flag(class, MOH_SORTALPHA)) 00958 qsort(&class->filearray[0], class->total_files, sizeof(char *), moh_sort_compare); 00959 return class->total_files; 00960 }
| static int moh_sort_compare | ( | const void * | i1, | |
| const void * | i2 | |||
| ) | [static] |
Definition at line 877 of file res_musiconhold.c.
Referenced by moh_scan_files().
00878 { 00879 char *s1, *s2; 00880 00881 s1 = ((char **)i1)[0]; 00882 s2 = ((char **)i2)[0]; 00883 00884 return strcasecmp(s1, s2); 00885 }
Definition at line 728 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().
00729 { 00730 struct mohdata *moh; 00731 long flags; 00732 00733 if (!(moh = ast_calloc(1, sizeof(*moh)))) 00734 return NULL; 00735 00736 if (pipe(moh->pipe)) { 00737 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno)); 00738 ast_free(moh); 00739 return NULL; 00740 } 00741 00742 /* Make entirely non-blocking */ 00743 flags = fcntl(moh->pipe[0], F_GETFL); 00744 fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK); 00745 flags = fcntl(moh->pipe[1], F_GETFL); 00746 fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK); 00747 00748 moh->f.frametype = AST_FRAME_VOICE; 00749 moh->f.subclass = cl->format; 00750 moh->f.offset = AST_FRIENDLY_OFFSET; 00751 00752 moh->parent = mohclass_ref(cl, "Reffing music class for mohdata parent"); 00753 00754 ao2_lock(cl); 00755 AST_LIST_INSERT_HEAD(&cl->members, moh, list); 00756 ao2_unlock(cl); 00757 00758 return moh; 00759 }
| static void* monmp3thread | ( | void * | data | ) | [static] |
Definition at line 517 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().
00518 { 00519 #define MOH_MS_INTERVAL 100 00520 00521 struct mohclass *class = data; 00522 struct mohdata *moh; 00523 char buf[8192]; 00524 short sbuf[8192]; 00525 int res, res2; 00526 int len; 00527 struct timeval deadline, tv_tmp; 00528 00529 deadline.tv_sec = 0; 00530 deadline.tv_usec = 0; 00531 for(;/* ever */;) { 00532 pthread_testcancel(); 00533 /* Spawn mp3 player if it's not there */ 00534 if (class->srcfd < 0) { 00535 if ((class->srcfd = spawn_mp3(class)) < 0) { 00536 ast_log(LOG_WARNING, "Unable to spawn mp3player\n"); 00537 /* Try again later */ 00538 sleep(500); 00539 pthread_testcancel(); 00540 } 00541 } 00542 if (class->pseudofd > -1) { 00543 #ifdef SOLARIS 00544 thr_yield(); 00545 #endif 00546 /* Pause some amount of time */ 00547 res = read(class->pseudofd, buf, sizeof(buf)); 00548 pthread_testcancel(); 00549 } else { 00550 long delta; 00551 /* Reliable sleep */ 00552 tv_tmp = ast_tvnow(); 00553 if (ast_tvzero(deadline)) 00554 deadline = tv_tmp; 00555 delta = ast_tvdiff_ms(tv_tmp, deadline); 00556 if (delta < MOH_MS_INTERVAL) { /* too early */ 00557 deadline = ast_tvadd(deadline, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */ 00558 usleep(1000 * (MOH_MS_INTERVAL - delta)); 00559 pthread_testcancel(); 00560 } else { 00561 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n"); 00562 deadline = tv_tmp; 00563 } 00564 res = 8 * MOH_MS_INTERVAL; /* 8 samples per millisecond */ 00565 } 00566 if ((strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir")) && AST_LIST_EMPTY(&class->members)) 00567 continue; 00568 /* Read mp3 audio */ 00569 len = ast_codec_get_len(class->format, res); 00570 00571 if ((res2 = read(class->srcfd, sbuf, len)) != len) { 00572 if (!res2) { 00573 close(class->srcfd); 00574 class->srcfd = -1; 00575 pthread_testcancel(); 00576 if (class->pid > 1) { 00577 killpg(class->pid, SIGHUP); 00578 usleep(100000); 00579 killpg(class->pid, SIGTERM); 00580 usleep(100000); 00581 killpg(class->pid, SIGKILL); 00582 class->pid = 0; 00583 } 00584 } else { 00585 ast_debug(1, "Read %d bytes of audio while expecting %d\n", res2, len); 00586 } 00587 continue; 00588 } 00589 00590 pthread_testcancel(); 00591 00592 ao2_lock(class); 00593 AST_LIST_TRAVERSE(&class->members, moh, list) { 00594 /* Write data */ 00595 if ((res = write(moh->pipe[1], sbuf, res2)) != res2) { 00596 ast_debug(1, "Only wrote %d of %d bytes to pipe\n", res, res2); 00597 } 00598 } 00599 ao2_unlock(class); 00600 } 00601 return NULL; 00602 }
| static int play_moh_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 604 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().
00605 { 00606 char *parse; 00607 char *class; 00608 int timeout = -1; 00609 int res; 00610 AST_DECLARE_APP_ARGS(args, 00611 AST_APP_ARG(class); 00612 AST_APP_ARG(duration); 00613 ); 00614 00615 parse = ast_strdupa(data); 00616 00617 AST_STANDARD_APP_ARGS(args, parse); 00618 00619 if (!ast_strlen_zero(args.duration)) { 00620 if (sscanf(args.duration, "%30d", &timeout) == 1) { 00621 timeout *= 1000; 00622 } else { 00623 ast_log(LOG_WARNING, "Invalid MusicOnHold duration '%s'. Will wait indefinitely.\n", args.duration); 00624 } 00625 } 00626 00627 class = S_OR(args.class, NULL); 00628 if (ast_moh_start(chan, class, NULL)) { 00629 ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, chan->name); 00630 return 0; 00631 } 00632 00633 if (timeout > 0) 00634 res = ast_safe_sleep(chan, timeout); 00635 else { 00636 while (!(res = ast_safe_sleep(chan, 10000))); 00637 } 00638 00639 ast_moh_stop(chan); 00640 00641 return res; 00642 }
| static int reload | ( | void | ) | [static] |
| static int set_moh_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 667 of file res_musiconhold.c.
References ast_log(), ast_string_field_set, ast_strlen_zero(), LOG_WARNING, and musicclass.
Referenced by load_module().
00668 { 00669 static int deprecation_warning = 0; 00670 00671 if (!deprecation_warning) { 00672 deprecation_warning = 1; 00673 ast_log(LOG_WARNING, "SetMusicOnHold application is deprecated and will be removed. Use Set(CHANNEL(musicclass)=...) instead\n"); 00674 } 00675 00676 if (ast_strlen_zero(data)) { 00677 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n"); 00678 return -1; 00679 } 00680 ast_string_field_set(chan, musicclass, data); 00681 return 0; 00682 }
| static int spawn_mp3 | ( | struct mohclass * | class | ) | [static] |
Definition at line 376 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().
00377 { 00378 int fds[2]; 00379 int files = 0; 00380 char fns[MAX_MP3S][80]; 00381 char *argv[MAX_MP3S + 50]; 00382 char xargs[256]; 00383 char *argptr; 00384 int argc = 0; 00385 DIR *dir = NULL; 00386 struct dirent *de; 00387 00388 00389 if (!strcasecmp(class->dir, "nodir")) { 00390 files = 1; 00391 } else { 00392 dir = opendir(class->dir); 00393 if (!dir && strncasecmp(class->dir, "http://", 7)) { 00394 ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir); 00395 return -1; 00396 } 00397 } 00398 00399 if (!ast_test_flag(class, MOH_CUSTOM)) { 00400 argv[argc++] = "mpg123"; 00401 argv[argc++] = "-q"; 00402 argv[argc++] = "-s"; 00403 argv[argc++] = "--mono"; 00404 argv[argc++] = "-r"; 00405 argv[argc++] = "8000"; 00406 00407 if (!ast_test_flag(class, MOH_SINGLE)) { 00408 argv[argc++] = "-b"; 00409 argv[argc++] = "2048"; 00410 } 00411 00412 argv[argc++] = "-f"; 00413 00414 if (ast_test_flag(class, MOH_QUIET)) 00415 argv[argc++] = "4096"; 00416 else 00417 argv[argc++] = "8192"; 00418 00419 /* Look for extra arguments and add them to the list */ 00420 ast_copy_string(xargs, class->args, sizeof(xargs)); 00421 argptr = xargs; 00422 while (!ast_strlen_zero(argptr)) { 00423 argv[argc++] = argptr; 00424 strsep(&argptr, ","); 00425 } 00426 } else { 00427 /* Format arguments for argv vector */ 00428 ast_copy_string(xargs, class->args, sizeof(xargs)); 00429 argptr = xargs; 00430 while (!ast_strlen_zero(argptr)) { 00431 argv[argc++] = argptr; 00432 strsep(&argptr, " "); 00433 } 00434 } 00435 00436 if (!strncasecmp(class->dir, "http://", 7)) { 00437 ast_copy_string(fns[files], class->dir, sizeof(fns[files])); 00438 argv[argc++] = fns[files]; 00439 files++; 00440 } else if (dir) { 00441 while ((de = readdir(dir)) && (files < MAX_MP3S)) { 00442 if ((strlen(de->d_name) > 3) && 00443 ((ast_test_flag(class, MOH_CUSTOM) && 00444 (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 00445 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) || 00446 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) { 00447 ast_copy_string(fns[files], de->d_name, sizeof(fns[files])); 00448 argv[argc++] = fns[files]; 00449 files++; 00450 } 00451 } 00452 } 00453 argv[argc] = NULL; 00454 if (dir) { 00455 closedir(dir); 00456 } 00457 if (pipe(fds)) { 00458 ast_log(LOG_WARNING, "Pipe failed\n"); 00459 return -1; 00460 } 00461 if (!files) { 00462 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir); 00463 close(fds[0]); 00464 close(fds[1]); 00465 return -1; 00466 } 00467 if (!strncasecmp(class->dir, "http://", 7) && time(NULL) - class->start < respawn_time) { 00468 sleep(respawn_time - (time(NULL) - class->start)); 00469 } 00470 00471 time(&class->start); 00472 class->pid = ast_safe_fork(0); 00473 if (class->pid < 0) { 00474 close(fds[0]); 00475 close(fds[1]); 00476 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno)); 00477 return -1; 00478 } 00479 if (!class->pid) { 00480 if (ast_opt_high_priority) 00481 ast_set_priority(0); 00482 00483 close(fds[0]); 00484 /* Stdout goes to pipe */ 00485 dup2(fds[1], STDOUT_FILENO); 00486 00487 /* Close everything else */ 00488 ast_close_fds_above_n(STDERR_FILENO); 00489 00490 /* Child */ 00491 if (strcasecmp(class->dir, "nodir") && chdir(class->dir) < 0) { 00492 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 00493 _exit(1); 00494 } 00495 setpgid(0, getpid()); 00496 if (ast_test_flag(class, MOH_CUSTOM)) { 00497 execv(argv[0], argv); 00498 } else { 00499 /* Default install is /usr/local/bin */ 00500 execv(LOCAL_MPG_123, argv); 00501 /* Many places have it in /usr/bin */ 00502 execv(MPG_123, argv); 00503 /* Check PATH as a last-ditch effort */ 00504 execvp("mpg123", argv); 00505 } 00506 /* Can't use logger, since log FDs are closed */ 00507 fprintf(stderr, "MOH: exec failed: %s\n", strerror(errno)); 00508 close(fds[1]); 00509 _exit(1); 00510 } else { 00511 /* Parent */ 00512 close(fds[1]); 00513 } 00514 return fds[0]; 00515 }
| static int start_moh_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 684 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().
00685 { 00686 char *parse; 00687 char *class; 00688 AST_DECLARE_APP_ARGS(args, 00689 AST_APP_ARG(class); 00690 ); 00691 00692 parse = ast_strdupa(data); 00693 00694 AST_STANDARD_APP_ARGS(args, parse); 00695 00696 class = S_OR(args.class, NULL); 00697 if (ast_moh_start(chan, class, NULL)) 00698 ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, chan->name); 00699 00700 return 0; 00701 }
| static int stop_moh_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 703 of file res_musiconhold.c.
References ast_moh_stop().
Referenced by load_module().
00704 { 00705 ast_moh_stop(chan); 00706 00707 return 0; 00708 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 1695 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.
01696 { 01697 int res = 0; 01698 struct mohclass *class = NULL; 01699 01700 /* XXX This check shouldn't be required if module ref counting was being used 01701 * properly ... */ 01702 if ((class = ao2_t_callback(mohclasses, 0, moh_class_inuse, NULL, "Module unload callback"))) { 01703 class = mohclass_unref(class, "unref of class from module unload callback"); 01704 res = -1; 01705 } 01706 01707 if (res < 0) { 01708 ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n"); 01709 return res; 01710 } 01711 01712 ast_uninstall_music_functions(); 01713 01714 ast_moh_destroy(); 01715 res = ast_unregister_application(play_moh); 01716 res |= ast_unregister_application(wait_moh); 01717 res |= ast_unregister_application(set_moh); 01718 res |= ast_unregister_application(start_moh); 01719 res |= ast_unregister_application(stop_moh); 01720 ast_cli_unregister_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry)); 01721 ast_unregister_atexit(ast_moh_destroy); 01722 01723 return res; 01724 }
| static int wait_moh_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 644 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().
00645 { 00646 static int deprecation_warning = 0; 00647 int res; 00648 00649 if (!deprecation_warning) { 00650 deprecation_warning = 1; 00651 ast_log(LOG_WARNING, "WaitMusicOnHold application is deprecated and will be removed. Use MusicOnHold with duration parameter instead\n"); 00652 } 00653 00654 if (!data || !atoi(data)) { 00655 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n"); 00656 return -1; 00657 } 00658 if (ast_moh_start(chan, NULL, NULL)) { 00659 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name); 00660 return 0; 00661 } 00662 res = ast_safe_sleep(chan, atoi(data) * 1000); 00663 ast_moh_stop(chan); 00664 return res; 00665 }
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 1730 of file res_musiconhold.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1730 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 1627 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 368 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 847 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] |
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 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] |
Initial value:
" 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.5.6