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