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