Routines implementing music on hold. More...
#include "asterisk.h"#include <ctype.h>#include <signal.h>#include <sys/time.h>#include <sys/signal.h>#include <netinet/in.h>#include <sys/stat.h>#include <dirent.h>#include <sys/ioctl.h>#include <dahdi/user.h>#include "asterisk/lock.h"#include "asterisk/file.h"#include "asterisk/channel.h"#include "asterisk/pbx.h"#include "asterisk/app.h"#include "asterisk/module.h"#include "asterisk/translate.h"#include "asterisk/say.h"#include "asterisk/musiconhold.h"#include "asterisk/config.h"#include "asterisk/utils.h"#include "asterisk/cli.h"#include "asterisk/stringfields.h"#include "asterisk/linkedlists.h"#include "asterisk/manager.h"#include "asterisk/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 | DONT_UNREF 0 |
| #define | get_mohbyname(a, b, c) _get_mohbyname(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__) |
| #define | HANDLE_REF 1 |
| #define | INITIAL_NUM_FILES 8 |
| #define | LOCAL_MPG_123 "/usr/local/bin/mpg123" |
| #define | MAX_MP3S 256 |
| #define | MOH_CACHERTCLASSES (1 << 5) |
| #define | moh_class_malloc() _moh_class_malloc(__FILE__,__LINE__,__PRETTY_FUNCTION__) |
| #define | MOH_CUSTOM (1 << 2) |
| #define | MOH_MS_INTERVAL 100 |
| #define | MOH_NOTDELETED (1 << 30) |
| #define | MOH_QUIET (1 << 0) |
| #define | MOH_RANDOMIZE (1 << 3) |
| #define | moh_register(a, b, c) _moh_register(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__) |
| #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 struct mohclass * | _get_mohbyname (const char *name, int warn, int flags, const char *file, int lineno, const char *funcname) |
| static struct mohclass * | _moh_class_malloc (const char *file, int line, const char *funcname) |
| static int | _moh_register (struct mohclass *moh, int reload, int unref, const char *file, int line, const char *funcname) |
| static void | ast_moh_destroy (void) |
| static int | ast_moh_files_next (struct ast_channel *chan) |
| static struct mohclass * | get_mohbydigit (char digit) |
| 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 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 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 = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload, } |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ast_cli_entry | cli_moh [] |
| static struct ast_flags | global_flags [1] = {{0}} |
| static struct ast_generator | moh_file_stream |
| static struct ao2_container * | mohclasses |
| static struct ast_generator | mohgen |
| static char * | play_moh = "MusicOnHold" |
| static char * | play_moh_desc |
| static char * | play_moh_syn = "Play Music On Hold indefinitely" |
| static int | respawn_time = 20 |
| static char * | set_moh = "SetMusicOnHold" |
| static char * | set_moh_desc |
| static char * | set_moh_syn = "Set default Music On Hold class" |
| static char * | start_moh = "StartMusicOnHold" |
| static char * | start_moh_desc |
| static char * | start_moh_syn = "Play Music On Hold" |
| static char * | stop_moh = "StopMusicOnHold" |
| static char * | stop_moh_desc |
| static char * | stop_moh_syn = "Stop Playing Music On Hold" |
| static char * | wait_moh = "WaitMusicOnHold" |
| static char * | wait_moh_desc |
| static char * | wait_moh_syn = "Wait, playing Music On Hold" |
Routines implementing music on hold.
Definition in file res_musiconhold.c.
| #define DONT_UNREF 0 |
Definition at line 77 of file res_musiconhold.c.
Referenced by local_ast_moh_start().
| #define get_mohbyname | ( | a, | |||
| b, | |||||
| c | ) | _get_mohbyname(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__) |
Definition at line 773 of file res_musiconhold.c.
Referenced by local_ast_moh_start().
| #define HANDLE_REF 1 |
Definition at line 76 of file res_musiconhold.c.
Referenced by load_moh_classes().
| #define INITIAL_NUM_FILES 8 |
Definition at line 75 of file res_musiconhold.c.
Referenced by moh_add_file().
| #define LOCAL_MPG_123 "/usr/local/bin/mpg123" |
Definition at line 194 of file res_musiconhold.c.
| #define MAX_MP3S 256 |
Definition at line 196 of file res_musiconhold.c.
Referenced by spawn_mp3().
| #define MOH_CACHERTCLASSES (1 << 5) |
Should we use a separate instance of MOH for each user or not
Definition at line 147 of file res_musiconhold.c.
Referenced by load_moh_classes(), and local_ast_moh_start().
| #define moh_class_malloc | ( | ) | _moh_class_malloc(__FILE__,__LINE__,__PRETTY_FUNCTION__) |
Definition at line 1202 of file res_musiconhold.c.
Referenced by load_moh_classes(), and local_ast_moh_start().
| #define MOH_CUSTOM (1 << 2) |
Definition at line 143 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_NOTDELETED (1 << 30) |
Find only records that aren't deleted?
Definition at line 150 of file res_musiconhold.c.
Referenced by _moh_register(), and moh_class_cmp().
| #define MOH_QUIET (1 << 0) |
Definition at line 141 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 144 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_register | ( | a, | |||
| b, | |||||
| c | ) | _moh_register(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__) |
Definition at line 1132 of file res_musiconhold.c.
Referenced by load_moh_classes(), and local_ast_moh_start().
| #define MOH_SINGLE (1 << 1) |
Definition at line 142 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 145 of file res_musiconhold.c.
Referenced by load_moh_classes(), local_ast_moh_start(), and moh_scan_files().
| #define mohclass_ref | ( | class, | |||
| string | ) | (ao2_t_ref((class), +1, (string)), class) |
Definition at line 200 of file res_musiconhold.c.
Referenced by moh_alloc(), moh_files_alloc(), and mohalloc().
| #define mohclass_unref | ( | class, | |||
| string | ) | (ao2_t_ref((class), -1, (string)), (struct mohclass *) NULL) |
Definition at line 203 of file res_musiconhold.c.
Referenced by _moh_register(), handle_cli_moh_show_classes(), handle_cli_moh_show_files(), load_moh_classes(), local_ast_moh_cleanup(), local_ast_moh_start(), moh_files_release(), moh_handle_digit(), moh_release(), and unload_module().
| #define MPG_123 "/usr/bin/mpg123" |
Definition at line 195 of file res_musiconhold.c.
| static void __reg_module | ( | void | ) | [static] |
Definition at line 1858 of file res_musiconhold.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 1858 of file res_musiconhold.c.
| static struct mohclass* _get_mohbyname | ( | const char * | name, | |
| int | warn, | |||
| int | flags, | |||
| const char * | file, | |||
| int | lineno, | |||
| const char * | funcname | |||
| ) | [static, read] |
Definition at line 775 of file res_musiconhold.c.
References _ao2_find(), _ao2_find_debug(), ast_copy_string(), ast_log(), mohclass::flags, LOG_DEBUG, moh, and mohclass::name.
Referenced by _moh_register().
00776 { 00777 struct mohclass *moh = NULL; 00778 struct mohclass tmp_class = { 00779 .flags = 0, 00780 }; 00781 00782 ast_copy_string(tmp_class.name, name, sizeof(tmp_class.name)); 00783 00784 #ifdef REF_DEBUG 00785 moh = _ao2_find_debug(mohclasses, &tmp_class, flags, "get_mohbyname", (char *) file, lineno, funcname); 00786 #else 00787 moh = _ao2_find(mohclasses, &tmp_class, flags); 00788 #endif 00789 00790 if (!moh && warn) { 00791 ast_log(LOG_DEBUG, "Music on Hold class '%s' not found in memory\n", name); 00792 } 00793 00794 return moh; 00795 }
| static struct mohclass* _moh_class_malloc | ( | const char * | file, | |
| int | line, | |||
| const char * | funcname | |||
| ) | [static, read] |
Definition at line 1204 of file res_musiconhold.c.
References __AST_DEBUG_MALLOC, _ao2_alloc_debug(), ao2_alloc, AST_FORMAT_SLINEAR, mohclass::format, and moh_class_destructor().
01205 { 01206 struct mohclass *class; 01207 01208 if ((class = 01209 #ifdef REF_DEBUG 01210 _ao2_alloc_debug(sizeof(*class), moh_class_destructor, "Allocating new moh class", file, line, funcname, 1) 01211 #elif defined(__AST_DEBUG_MALLOC) 01212 _ao2_alloc_debug(sizeof(*class), moh_class_destructor, "Allocating new moh class", file, line, funcname, 0) 01213 #else 01214 ao2_alloc(sizeof(*class), moh_class_destructor) 01215 #endif 01216 )) { 01217 class->format = AST_FORMAT_SLINEAR; 01218 } 01219 01220 return class; 01221 }
| static int _moh_register | ( | struct mohclass * | moh, | |
| int | reload, | |||
| int | unref, | |||
| const char * | file, | |||
| int | line, | |||
| const char * | funcname | |||
| ) | [static] |
Definition at line 1133 of file res_musiconhold.c.
References _get_mohbyname(), ao2_t_link, ast_log(), init_app_class(), init_files_class(), LOG_WARNING, mohclass::mode, moh_diff(), MOH_NOTDELETED, mohclass_unref, mohclass::name, and mohclass::start.
01134 { 01135 struct mohclass *mohclass = NULL; 01136 01137 if ((mohclass = _get_mohbyname(moh->name, 0, MOH_NOTDELETED, file, line, funcname)) && !moh_diff(mohclass, moh)) { 01138 ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name); 01139 mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name"); 01140 if (unref) { 01141 moh = mohclass_unref(moh, "unreffing potential new moh class (it is a duplicate)"); 01142 } 01143 return -1; 01144 } else if (mohclass) { 01145 /* Found a class, but it's different from the one being registered */ 01146 mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name"); 01147 } 01148 01149 time(&moh->start); 01150 moh->start -= respawn_time; 01151 01152 if (!strcasecmp(moh->mode, "files")) { 01153 if (init_files_class(moh)) { 01154 if (unref) { 01155 moh = mohclass_unref(moh, "unreffing potential new moh class (init_files_class failed)"); 01156 } 01157 return -1; 01158 } 01159 } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || 01160 !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || 01161 !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) { 01162 if (init_app_class(moh)) { 01163 if (unref) { 01164 moh = mohclass_unref(moh, "unreffing potential new moh class (init_app_class_failed)"); 01165 } 01166 return -1; 01167 } 01168 } else { 01169 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode); 01170 if (unref) { 01171 moh = mohclass_unref(moh, "unreffing potential new moh class (unknown mode)"); 01172 } 01173 return -1; 01174 } 01175 01176 ao2_t_link(mohclasses, moh, "Adding class to container"); 01177 01178 if (unref) { 01179 moh = mohclass_unref(moh, "Unreffing new moh class because we just added it to the container"); 01180 } 01181 01182 return 0; 01183 }
| static void ast_moh_destroy | ( | void | ) | [static] |
Definition at line 1651 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().
01652 { 01653 ast_verb(2, "Destroying musiconhold processes\n"); 01654 ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "Destroy callback"); 01655 }
| static int ast_moh_files_next | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 256 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().
00257 { 00258 struct moh_files_state *state = chan->music_state; 00259 int tries; 00260 00261 /* Discontinue a stream if it is running already */ 00262 if (chan->stream) { 00263 ast_closestream(chan->stream); 00264 chan->stream = NULL; 00265 } 00266 00267 if (!state->class->total_files) { 00268 ast_log(LOG_WARNING, "No files available for class '%s'\n", state->class->name); 00269 return -1; 00270 } 00271 00272 /* If a specific file has been saved confirm it still exists and that it is still valid */ 00273 if (state->save_pos >= 0 && state->save_pos < state->class->total_files && state->class->filearray[state->save_pos] == state->save_pos_filename) { 00274 state->pos = state->save_pos; 00275 state->save_pos = -1; 00276 } else if (ast_test_flag(state->class, MOH_RANDOMIZE)) { 00277 /* Get a random file and ensure we can open it */ 00278 for (tries = 0; tries < 20; tries++) { 00279 state->pos = ast_random() % state->class->total_files; 00280 if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0) 00281 break; 00282 } 00283 state->save_pos = -1; 00284 state->samples = 0; 00285 } else { 00286 /* This is easy, just increment our position and make sure we don't exceed the total file count */ 00287 state->pos++; 00288 state->pos %= state->class->total_files; 00289 state->save_pos = -1; 00290 state->samples = 0; 00291 } 00292 00293 if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) { 00294 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno)); 00295 state->pos++; 00296 state->pos %= state->class->total_files; 00297 return -1; 00298 } 00299 00300 /* Record the pointer to the filename for position resuming later */ 00301 state->save_pos_filename = state->class->filearray[state->pos]; 00302 00303 ast_debug(1, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]); 00304 00305 if (state->samples) 00306 ast_seekstream(chan->stream, state->samples, SEEK_SET); 00307 00308 return 0; 00309 }
| static struct mohclass* get_mohbydigit | ( | char | digit | ) | [static, read] |
Definition at line 395 of file res_musiconhold.c.
References ao2_t_callback, and moh_digit_match().
Referenced by moh_handle_digit().
00396 { 00397 return ao2_t_callback(mohclasses, 0, moh_digit_match, &digit, "digit callback"); 00398 }
| static char* handle_cli_moh_reload | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1657 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.
01658 { 01659 switch (cmd) { 01660 case CLI_INIT: 01661 e->command = "moh reload"; 01662 e->usage = 01663 "Usage: moh reload\n" 01664 " Reloads the MusicOnHold module.\n" 01665 " Alias for 'module reload res_musiconhold.so'\n"; 01666 return NULL; 01667 case CLI_GENERATE: 01668 return NULL; 01669 } 01670 01671 if (a->argc != e->args) 01672 return CLI_SHOWUSAGE; 01673 01674 reload(); 01675 01676 return CLI_SUCCESS; 01677 }
| static char* handle_cli_moh_show_classes | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1717 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.
01718 { 01719 struct mohclass *class; 01720 struct ao2_iterator i; 01721 01722 switch (cmd) { 01723 case CLI_INIT: 01724 e->command = "moh show classes"; 01725 e->usage = 01726 "Usage: moh show classes\n" 01727 " Lists all MusicOnHold classes.\n"; 01728 return NULL; 01729 case CLI_GENERATE: 01730 return NULL; 01731 } 01732 01733 if (a->argc != e->args) 01734 return CLI_SHOWUSAGE; 01735 01736 i = ao2_iterator_init(mohclasses, 0); 01737 for (; (class = ao2_t_iterator_next(&i, "Show classes iterator")); mohclass_unref(class, "Unref iterator in moh show classes")) { 01738 ast_cli(a->fd, "Class: %s\n", class->name); 01739 ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>")); 01740 ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>")); 01741 if (ast_test_flag(class, MOH_CUSTOM)) { 01742 ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>")); 01743 } 01744 if (strcasecmp(class->mode, "files")) { 01745 ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(class->format)); 01746 } 01747 } 01748 ao2_iterator_destroy(&i); 01749 01750 return CLI_SUCCESS; 01751 }
| static char* handle_cli_moh_show_files | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1679 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.
01680 { 01681 struct mohclass *class; 01682 struct ao2_iterator i; 01683 01684 switch (cmd) { 01685 case CLI_INIT: 01686 e->command = "moh show files"; 01687 e->usage = 01688 "Usage: moh show files\n" 01689 " Lists all loaded file-based MusicOnHold classes and their\n" 01690 " files.\n"; 01691 return NULL; 01692 case CLI_GENERATE: 01693 return NULL; 01694 } 01695 01696 if (a->argc != e->args) 01697 return CLI_SHOWUSAGE; 01698 01699 i = ao2_iterator_init(mohclasses, 0); 01700 for (; (class = ao2_t_iterator_next(&i, "Show files iterator")); mohclass_unref(class, "Unref iterator in moh show files")) { 01701 int x; 01702 01703 if (!class->total_files) { 01704 continue; 01705 } 01706 01707 ast_cli(a->fd, "Class: %s\n", class->name); 01708 for (x = 0; x < class->total_files; x++) { 01709 ast_cli(a->fd, "\tFile: %s\n", class->filearray[x]); 01710 } 01711 } 01712 ao2_iterator_destroy(&i); 01713 01714 return CLI_SUCCESS; 01715 }
| static int init_app_class | ( | struct mohclass * | class | ) | [static] |
Definition at line 1086 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().
01087 { 01088 #ifdef HAVE_DAHDI 01089 int x; 01090 #endif 01091 01092 if (!strcasecmp(class->mode, "custom")) { 01093 ast_set_flag(class, MOH_CUSTOM); 01094 } else if (!strcasecmp(class->mode, "mp3nb")) { 01095 ast_set_flag(class, MOH_SINGLE); 01096 } else if (!strcasecmp(class->mode, "quietmp3nb")) { 01097 ast_set_flag(class, MOH_SINGLE | MOH_QUIET); 01098 } else if (!strcasecmp(class->mode, "quietmp3")) { 01099 ast_set_flag(class, MOH_QUIET); 01100 } 01101 01102 class->srcfd = -1; 01103 class->pseudofd = -1; 01104 01105 #ifdef HAVE_DAHDI 01106 /* Open /dev/zap/pseudo for timing... Is 01107 there a better, yet reliable way to do this? */ 01108 class->pseudofd = open("/dev/dahdi/pseudo", O_RDONLY); 01109 if (class->pseudofd < 0) { 01110 ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n"); 01111 } else { 01112 x = 320; 01113 ioctl(class->pseudofd, DAHDI_SET_BLOCKSIZE, &x); 01114 } 01115 #endif 01116 01117 if (ast_pthread_create_background(&class->thread, NULL, monmp3thread, class)) { 01118 ast_log(LOG_WARNING, "Unable to create moh thread...\n"); 01119 if (class->pseudofd > -1) { 01120 close(class->pseudofd); 01121 class->pseudofd = -1; 01122 } 01123 return -1; 01124 } 01125 01126 return 0; 01127 }
| static int init_files_class | ( | struct mohclass * | class | ) | [static] |
Definition at line 1041 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().
01042 { 01043 int res; 01044 01045 res = moh_scan_files(class); 01046 01047 if (res < 0) { 01048 return -1; 01049 } 01050 01051 if (!res) { 01052 if (option_verbose > 2) { 01053 ast_verbose(VERBOSE_PREFIX_3 "Files not found in %s for moh class:%s\n", 01054 class->dir, class->name); 01055 } 01056 return -1; 01057 } 01058 01059 if (strchr(class->args, 'r')) { 01060 ast_set_flag(class, MOH_RANDOMIZE); 01061 } 01062 01063 return 0; 01064 }
| static int load_module | ( | void | ) | [static] |
Definition at line 1775 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, 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().
01776 { 01777 int res; 01778 01779 if (!(mohclasses = ao2_t_container_alloc(53, moh_class_hash, moh_class_cmp, "Moh class container"))) { 01780 return AST_MODULE_LOAD_DECLINE; 01781 } 01782 01783 if (!load_moh_classes(0)) { /* No music classes configured, so skip it */ 01784 ast_log(LOG_WARNING, "No music on hold classes configured, " 01785 "disabling music on hold.\n"); 01786 } else { 01787 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, 01788 local_ast_moh_cleanup); 01789 } 01790 01791 res = ast_register_application(play_moh, play_moh_exec, play_moh_syn, play_moh_desc); 01792 ast_register_atexit(ast_moh_destroy); 01793 ast_cli_register_multiple(cli_moh, ARRAY_LEN(cli_moh)); 01794 if (!res) 01795 res = ast_register_application(wait_moh, wait_moh_exec, wait_moh_syn, wait_moh_desc); 01796 if (!res) 01797 res = ast_register_application(set_moh, set_moh_exec, set_moh_syn, set_moh_desc); 01798 if (!res) 01799 res = ast_register_application(start_moh, start_moh_exec, start_moh_syn, start_moh_desc); 01800 if (!res) 01801 res = ast_register_application(stop_moh, stop_moh_exec, stop_moh_syn, stop_moh_desc); 01802 01803 return AST_MODULE_LOAD_SUCCESS; 01804 }
| static int load_moh_classes | ( | int | reload | ) | [static] |
Definition at line 1549 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, HANDLE_REF, LOG_WARNING, MOH_CACHERTCLASSES, moh_class_malloc, moh_class_mark(), moh_classes_delete_marked(), MOH_RANDOMIZE, moh_register, MOH_SORTALPHA, mohclass_unref, ast_variable::name, ast_variable::next, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, ast_variable::value, and var.
Referenced by load_module(), and reload().
01550 { 01551 struct ast_config *cfg; 01552 struct ast_variable *var; 01553 struct mohclass *class; 01554 char *cat; 01555 int numclasses = 0; 01556 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 01557 01558 cfg = ast_config_load("musiconhold.conf", config_flags); 01559 01560 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEUNCHANGED || cfg == CONFIG_STATUS_FILEINVALID) { 01561 return 0; 01562 } 01563 01564 if (reload) { 01565 ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes"); 01566 } 01567 01568 ast_clear_flag(global_flags, AST_FLAGS_ALL); 01569 01570 cat = ast_category_browse(cfg, NULL); 01571 for (; cat; cat = ast_category_browse(cfg, cat)) { 01572 /* Setup common options from [general] section */ 01573 if (!strcasecmp(cat, "general")) { 01574 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 01575 if (!strcasecmp(var->name, "cachertclasses")) { 01576 ast_set2_flag(global_flags, ast_true(var->value), MOH_CACHERTCLASSES); 01577 } else { 01578 ast_log(LOG_WARNING, "Unknown option '%s' in [general] section of musiconhold.conf\n", var->name); 01579 } 01580 } 01581 } 01582 /* These names were deprecated in 1.4 and should not be used until after the next major release. */ 01583 if (!strcasecmp(cat, "classes") || !strcasecmp(cat, "moh_files") || 01584 !strcasecmp(cat, "general")) { 01585 continue; 01586 } 01587 01588 if (!(class = moh_class_malloc())) { 01589 break; 01590 } 01591 01592 ast_copy_string(class->name, cat, sizeof(class->name)); 01593 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 01594 if (!strcasecmp(var->name, "mode")) 01595 ast_copy_string(class->mode, var->value, sizeof(class->mode)); 01596 else if (!strcasecmp(var->name, "directory")) 01597 ast_copy_string(class->dir, var->value, sizeof(class->dir)); 01598 else if (!strcasecmp(var->name, "application")) 01599 ast_copy_string(class->args, var->value, sizeof(class->args)); 01600 else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value))) 01601 class->digit = *var->value; 01602 else if (!strcasecmp(var->name, "random")) 01603 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE); 01604 else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "random")) 01605 ast_set_flag(class, MOH_RANDOMIZE); 01606 else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) 01607 ast_set_flag(class, MOH_SORTALPHA); 01608 else if (!strcasecmp(var->name, "format")) { 01609 class->format = ast_getformatbyname(var->value); 01610 if (!class->format) { 01611 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value); 01612 class->format = AST_FORMAT_SLINEAR; 01613 } 01614 } 01615 } 01616 01617 if (ast_strlen_zero(class->dir)) { 01618 if (!strcasecmp(class->mode, "custom")) { 01619 strcpy(class->dir, "nodir"); 01620 } else { 01621 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name); 01622 class = mohclass_unref(class, "unreffing potential mohclass (no directory)"); 01623 continue; 01624 } 01625 } 01626 if (ast_strlen_zero(class->mode)) { 01627 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name); 01628 class = mohclass_unref(class, "unreffing potential mohclass (no mode)"); 01629 continue; 01630 } 01631 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) { 01632 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name); 01633 class = mohclass_unref(class, "unreffing potential mohclass (no app for custom mode)"); 01634 continue; 01635 } 01636 01637 /* Don't leak a class when it's already registered */ 01638 if (!moh_register(class, reload, HANDLE_REF)) { 01639 numclasses++; 01640 } 01641 } 01642 01643 ast_config_destroy(cfg); 01644 01645 ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, 01646 moh_classes_delete_marked, NULL, "Purge marked classes"); 01647 01648 return numclasses; 01649 }
| static void local_ast_moh_cleanup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1185 of file res_musiconhold.c.
References ast_free, ast_module_unref(), moh_files_state::class, mohclass_unref, and ast_channel::music_state.
Referenced by load_module(), and reload().
01186 { 01187 struct moh_files_state *state = chan->music_state; 01188 01189 if (state) { 01190 if (state->class) { 01191 state->class = mohclass_unref(state->class, "Channel MOH state destruction"); 01192 } 01193 ast_free(chan->music_state); 01194 chan->music_state = NULL; 01195 /* Only held a module reference if we had a music state */ 01196 ast_module_unref(ast_module_info->self); 01197 } 01198 }
| static int local_ast_moh_start | ( | struct ast_channel * | chan, | |
| const char * | mclass, | |||
| const char * | interpclass | |||
| ) | [static] |
Definition at line 1223 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, DONT_UNREF, 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(), and reload().
01224 { 01225 struct mohclass *mohclass = NULL; 01226 struct moh_files_state *state = chan->music_state; 01227 struct ast_variable *var = NULL; 01228 int res; 01229 int realtime_possible = ast_check_realtime("musiconhold"); 01230 01231 /* The following is the order of preference for which class to use: 01232 * 1) The channels explicitly set musicclass, which should *only* be 01233 * set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan. 01234 * 2) The mclass argument. If a channel is calling ast_moh_start() as the 01235 * result of receiving a HOLD control frame, this should be the 01236 * payload that came with the frame. 01237 * 3) The interpclass argument. This would be from the mohinterpret 01238 * option from channel drivers. This is the same as the old musicclass 01239 * option. 01240 * 4) The default class. 01241 */ 01242 if (!ast_strlen_zero(chan->musicclass)) { 01243 mohclass = get_mohbyname(chan->musicclass, 1, 0); 01244 if (!mohclass && realtime_possible) { 01245 var = ast_load_realtime("musiconhold", "name", chan->musicclass, SENTINEL); 01246 } 01247 } 01248 if (!mohclass && !var && !ast_strlen_zero(mclass)) { 01249 mohclass = get_mohbyname(mclass, 1, 0); 01250 if (!mohclass && realtime_possible) { 01251 var = ast_load_realtime("musiconhold", "name", mclass, SENTINEL); 01252 } 01253 } 01254 if (!mohclass && !var && !ast_strlen_zero(interpclass)) { 01255 mohclass = get_mohbyname(interpclass, 1, 0); 01256 if (!mohclass && realtime_possible) { 01257 var = ast_load_realtime("musiconhold", "name", interpclass, SENTINEL); 01258 } 01259 } 01260 01261 if (!mohclass && !var) { 01262 mohclass = get_mohbyname("default", 1, 0); 01263 if (!mohclass && realtime_possible) { 01264 var = ast_load_realtime("musiconhold", "name", "default", SENTINEL); 01265 } 01266 } 01267 01268 /* If no moh class found in memory, then check RT. Note that the logic used 01269 * above guarantees that if var is non-NULL, then mohclass must be NULL. 01270 */ 01271 if (var) { 01272 struct ast_variable *tmp = NULL; 01273 01274 if ((mohclass = moh_class_malloc())) { 01275 mohclass->realtime = 1; 01276 for (tmp = var; tmp; tmp = tmp->next) { 01277 if (!strcasecmp(tmp->name, "name")) 01278 ast_copy_string(mohclass->name, tmp->value, sizeof(mohclass->name)); 01279 else if (!strcasecmp(tmp->name, "mode")) 01280 ast_copy_string(mohclass->mode, tmp->value, sizeof(mohclass->mode)); 01281 else if (!strcasecmp(tmp->name, "directory")) 01282 ast_copy_string(mohclass->dir, tmp->value, sizeof(mohclass->dir)); 01283 else if (!strcasecmp(tmp->name, "application")) 01284 ast_copy_string(mohclass->args, tmp->value, sizeof(mohclass->args)); 01285 else if (!strcasecmp(tmp->name, "digit") && (isdigit(*tmp->value) || strchr("*#", *tmp->value))) 01286 mohclass->digit = *tmp->value; 01287 else if (!strcasecmp(tmp->name, "random")) 01288 ast_set2_flag(mohclass, ast_true(tmp->value), MOH_RANDOMIZE); 01289 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "random")) 01290 ast_set_flag(mohclass, MOH_RANDOMIZE); 01291 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "alpha")) 01292 ast_set_flag(mohclass, MOH_SORTALPHA); 01293 else if (!strcasecmp(tmp->name, "format")) { 01294 mohclass->format = ast_getformatbyname(tmp->value); 01295 if (!mohclass->format) { 01296 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", tmp->value); 01297 mohclass->format = AST_FORMAT_SLINEAR; 01298 } 01299 } 01300 } 01301 ast_variables_destroy(var); 01302 if (ast_strlen_zero(mohclass->dir)) { 01303 if (!strcasecmp(mohclass->mode, "custom")) { 01304 strcpy(mohclass->dir, "nodir"); 01305 } else { 01306 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", mohclass->name); 01307 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no directory specified)"); 01308 return -1; 01309 } 01310 } 01311 if (ast_strlen_zero(mohclass->mode)) { 01312 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", mohclass->name); 01313 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no mode specified)"); 01314 return -1; 01315 } 01316 if (ast_strlen_zero(mohclass->args) && !strcasecmp(mohclass->mode, "custom")) { 01317 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", mohclass->name); 01318 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no app specified for custom mode"); 01319 return -1; 01320 } 01321 01322 if (ast_test_flag(global_flags, MOH_CACHERTCLASSES)) { 01323 /* CACHERTCLASSES enabled, let's add this class to default tree */ 01324 if (state && state->class) { 01325 /* Class already exist for this channel */ 01326 ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name); 01327 if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) { 01328 /* we found RT class with the same name, seems like we should continue playing existing one */ 01329 /* XXX This code is impossible to reach */ 01330 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has a class)"); 01331 mohclass = state->class; 01332 } 01333 } 01334 /* We don't want moh_register to unref the mohclass because we do it at the end of this function as well. 01335 * If we allowed moh_register to unref the mohclass,too, then the count would be off by one. The result would 01336 * be that the destructor would be called when the generator on the channel is deactivated. The container then 01337 * has a pointer to a freed mohclass, so any operations involving the mohclass container would result in reading 01338 * invalid memory. 01339 */ 01340 moh_register(mohclass, 0, DONT_UNREF); 01341 } else { 01342 /* We don't register RT moh class, so let's init it manualy */ 01343 01344 time(&mohclass->start); 01345 mohclass->start -= respawn_time; 01346 01347 if (!strcasecmp(mohclass->mode, "files")) { 01348 if (!moh_scan_files(mohclass)) { 01349 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)"); 01350 return -1; 01351 } 01352 if (strchr(mohclass->args, 'r')) 01353 ast_set_flag(mohclass, MOH_RANDOMIZE); 01354 } 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")) { 01355 01356 if (!strcasecmp(mohclass->mode, "custom")) 01357 ast_set_flag(mohclass, MOH_CUSTOM); 01358 else if (!strcasecmp(mohclass->mode, "mp3nb")) 01359 ast_set_flag(mohclass, MOH_SINGLE); 01360 else if (!strcasecmp(mohclass->mode, "quietmp3nb")) 01361 ast_set_flag(mohclass, MOH_SINGLE | MOH_QUIET); 01362 else if (!strcasecmp(mohclass->mode, "quietmp3")) 01363 ast_set_flag(mohclass, MOH_QUIET); 01364 01365 mohclass->srcfd = -1; 01366 #ifdef HAVE_DAHDI 01367 /* Open /dev/dahdi/pseudo for timing... Is 01368 there a better, yet reliable way to do this? */ 01369 mohclass->pseudofd = open("/dev/dahdi/pseudo", O_RDONLY); 01370 if (mohclass->pseudofd < 0) { 01371 ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n"); 01372 } else { 01373 int x = 320; 01374 ioctl(mohclass->pseudofd, DAHDI_SET_BLOCKSIZE, &x); 01375 } 01376 #else 01377 mohclass->pseudofd = -1; 01378 #endif 01379 /* Let's check if this channel already had a moh class before */ 01380 if (state && state->class) { 01381 /* Class already exist for this channel */ 01382 ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name); 01383 if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) { 01384 /* we found RT class with the same name, seems like we should continue playing existing one */ 01385 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has one)"); 01386 mohclass = state->class; 01387 } 01388 } else { 01389 if (ast_pthread_create_background(&mohclass->thread, NULL, monmp3thread, mohclass)) { 01390 ast_log(LOG_WARNING, "Unable to create moh...\n"); 01391 if (mohclass->pseudofd > -1) { 01392 close(mohclass->pseudofd); 01393 mohclass->pseudofd = -1; 01394 } 01395 mohclass = mohclass_unref(mohclass, "Unreffing potential mohclass (failed to create background thread)"); 01396 return -1; 01397 } 01398 } 01399 } else { 01400 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mohclass->mode); 01401 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (unknown mode)"); 01402 return -1; 01403 } 01404 } 01405 } else { 01406 ast_variables_destroy(var); 01407 } 01408 } 01409 01410 if (!mohclass) { 01411 return -1; 01412 } 01413 01414 manager_event(EVENT_FLAG_CALL, "MusicOnHold", 01415 "State: Start\r\n" 01416 "Channel: %s\r\n" 01417 "UniqueID: %s\r\n", 01418 chan->name, chan->uniqueid); 01419 01420 ast_set_flag(chan, AST_FLAG_MOH); 01421 01422 if (mohclass->total_files) { 01423 res = ast_activate_generator(chan, &moh_file_stream, mohclass); 01424 } else { 01425 res = ast_activate_generator(chan, &mohgen, mohclass); 01426 } 01427 01428 mohclass = mohclass_unref(mohclass, "unreffing local reference to mohclass in local_ast_moh_start"); 01429 01430 return res; 01431 }
| static void local_ast_moh_stop | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1433 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(), and reload().
01434 { 01435 struct moh_files_state *state = chan->music_state; 01436 ast_clear_flag(chan, AST_FLAG_MOH); 01437 ast_deactivate_generator(chan); 01438 01439 if (state) { 01440 if (chan->stream) { 01441 ast_closestream(chan->stream); 01442 chan->stream = NULL; 01443 } 01444 } 01445 01446 manager_event(EVENT_FLAG_CALL, "MusicOnHold", 01447 "State: Stop\r\n" 01448 "Channel: %s\r\n" 01449 "UniqueID: %s\r\n", 01450 chan->name, chan->uniqueid); 01451 }
| static int moh_add_file | ( | struct mohclass * | class, | |
| const char * | filepath | |||
| ) | [static] |
Definition at line 924 of file res_musiconhold.c.
References ast_calloc, ast_realloc, ast_strdup, and INITIAL_NUM_FILES.
Referenced by moh_scan_files().
00925 { 00926 if (!class->allowed_files) { 00927 if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray)))) 00928 return -1; 00929 class->allowed_files = INITIAL_NUM_FILES; 00930 } else if (class->total_files == class->allowed_files) { 00931 if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) { 00932 class->allowed_files = 0; 00933 class->total_files = 0; 00934 return -1; 00935 } 00936 class->allowed_files *= 2; 00937 } 00938 00939 if (!(class->filearray[class->total_files] = ast_strdup(filepath))) 00940 return -1; 00941 00942 class->total_files++; 00943 00944 return 0; 00945 }
| static void* moh_alloc | ( | struct ast_channel * | chan, | |
| void * | params | |||
| ) | [static] |
Definition at line 859 of file res_musiconhold.c.
References ast_calloc, ast_codec2str(), ast_log(), ast_module_ref(), ast_set_write_format(), ast_verb, moh_files_state::class, mohclass::format, LOG_WARNING, moh_release(), mohalloc(), mohclass_ref, ast_channel::music_state, mohclass::name, ast_channel::name, mohdata::origwfmt, and ast_channel::writeformat.
00860 { 00861 struct mohdata *res; 00862 struct mohclass *class = params; 00863 struct moh_files_state *state; 00864 00865 /* Initiating music_state for current channel. Channel should know name of moh class */ 00866 if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) { 00867 chan->music_state = state; 00868 state->class = mohclass_ref(class, "Copying reference into state container"); 00869 ast_module_ref(ast_module_info->self); 00870 } else 00871 state = chan->music_state; 00872 if (state && state->class != class) { 00873 memset(state, 0, sizeof(*state)); 00874 state->class = class; 00875 } 00876 00877 if ((res = mohalloc(class))) { 00878 res->origwfmt = chan->writeformat; 00879 if (ast_set_write_format(chan, class->format)) { 00880 ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format)); 00881 moh_release(NULL, res); 00882 res = NULL; 00883 } 00884 ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name); 00885 } 00886 return res; 00887 }
| static int moh_class_cmp | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1766 of file res_musiconhold.c.
References CMP_MATCH, CMP_STOP, and MOH_NOTDELETED.
Referenced by load_module().
01767 { 01768 struct mohclass *class = obj, *class2 = arg; 01769 01770 return strcasecmp(class->name, class2->name) ? 0 : 01771 (flags & MOH_NOTDELETED) && (class->delete || class2->delete) ? 0 : 01772 CMP_MATCH | CMP_STOP; 01773 }
| static void moh_class_destructor | ( | void * | obj | ) | [static] |
Definition at line 1453 of file res_musiconhold.c.
References ast_debug, AST_LIST_REMOVE_HEAD, ast_log(), AST_PTHREADT_NULL, ast_wait_for_input(), buff, errno, free, LOG_DEBUG, LOG_WARNING, and mohclass::pid.
Referenced by _moh_class_malloc().
01454 { 01455 struct mohclass *class = obj; 01456 struct mohdata *member; 01457 pthread_t tid = 0; 01458 01459 ast_debug(1, "Destroying MOH class '%s'\n", class->name); 01460 01461 /* Kill the thread first, so it cannot restart the child process while the 01462 * class is being destroyed */ 01463 if (class->thread != AST_PTHREADT_NULL && class->thread != 0) { 01464 tid = class->thread; 01465 class->thread = AST_PTHREADT_NULL; 01466 pthread_cancel(tid); 01467 /* We'll collect the exit status later, after we ensure all the readers 01468 * are dead. */ 01469 } 01470 01471 if (class->pid > 1) { 01472 char buff[8192]; 01473 int bytes, tbytes = 0, stime = 0, pid = 0; 01474 01475 ast_log(LOG_DEBUG, "killing %d!\n", class->pid); 01476 01477 stime = time(NULL) + 2; 01478 pid = class->pid; 01479 class->pid = 0; 01480 01481 /* Back when this was just mpg123, SIGKILL was fine. Now we need 01482 * to give the process a reason and time enough to kill off its 01483 * children. */ 01484 do { 01485 if (killpg(pid, SIGHUP) < 0) { 01486 ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno)); 01487 } 01488 usleep(100000); 01489 if (killpg(pid, SIGTERM) < 0) { 01490 if (errno == ESRCH) { 01491 break; 01492 } 01493 ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno)); 01494 } 01495 usleep(100000); 01496 if (killpg(pid, SIGKILL) < 0) { 01497 if (errno == ESRCH) { 01498 break; 01499 } 01500 ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno)); 01501 } 01502 } while (0); 01503 01504 while ((ast_wait_for_input(class->srcfd, 100) > 0) && 01505 (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) { 01506 tbytes = tbytes + bytes; 01507 } 01508 01509 ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes); 01510 01511 close(class->srcfd); 01512 } 01513 01514 while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) { 01515 free(member); 01516 } 01517 01518 if (class->filearray) { 01519 int i; 01520 for (i = 0; i < class->total_files; i++) { 01521 free(class->filearray[i]); 01522 } 01523 free(class->filearray); 01524 class->filearray = NULL; 01525 } 01526 01527 /* Finally, collect the exit status of the monitor thread */ 01528 if (tid > 0) { 01529 pthread_join(tid, NULL); 01530 } 01531 }
| static int moh_class_hash | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 1759 of file res_musiconhold.c.
References ast_str_case_hash().
Referenced by load_module().
01760 { 01761 const struct mohclass *class = obj; 01762 01763 return ast_str_case_hash(class->name); 01764 }
| static int moh_class_inuse | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1816 of file res_musiconhold.c.
References AST_LIST_EMPTY, CMP_MATCH, and CMP_STOP.
Referenced by unload_module().
01817 { 01818 struct mohclass *class = obj; 01819 01820 return AST_LIST_EMPTY(&class->members) ? 0 : CMP_MATCH | CMP_STOP; 01821 }
| static int moh_class_mark | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1533 of file res_musiconhold.c.
Referenced by load_moh_classes().
01534 { 01535 struct mohclass *class = obj; 01536 01537 class->delete = 1; 01538 01539 return 0; 01540 }
| static int moh_classes_delete_marked | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1542 of file res_musiconhold.c.
References CMP_MATCH.
Referenced by load_moh_classes().
Definition at line 1067 of file res_musiconhold.c.
References mohclass::args, mohclass::dir, mohclass::flags, and mohclass::mode.
Referenced by _moh_register().
01068 { 01069 if (!old || !new) { 01070 return -1; 01071 } 01072 01073 if (strcmp(old->dir, new->dir)) { 01074 return -1; 01075 } else if (strcmp(old->mode, new->mode)) { 01076 return -1; 01077 } else if (strcmp(old->args, new->args)) { 01078 return -1; 01079 } else if (old->flags != new->flags) { 01080 return -1; 01081 } 01082 01083 return 0; 01084 }
| static int moh_digit_match | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 386 of file res_musiconhold.c.
References CMP_MATCH, CMP_STOP, and mohclass::digit.
Referenced by get_mohbydigit().
| static void* moh_files_alloc | ( | struct ast_channel * | chan, | |
| void * | params | |||
| ) | [static] |
Definition at line 347 of file res_musiconhold.c.
References ast_calloc, ast_copy_string(), ast_module_ref(), 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::name, moh_files_state::origwfmt, moh_files_state::pos, moh_files_state::save_total, and ast_channel::writeformat.
00348 { 00349 struct moh_files_state *state; 00350 struct mohclass *class = params; 00351 00352 if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) { 00353 chan->music_state = state; 00354 ast_module_ref(ast_module_info->self); 00355 } else { 00356 state = chan->music_state; 00357 } 00358 00359 if (!state) { 00360 return NULL; 00361 } 00362 00363 /* LOGIC: Comparing an unrefcounted pointer is a really bad idea, because 00364 * malloc may allocate a different class to the same memory block. This 00365 * might only happen when two reloads are generated in a short period of 00366 * time, but it's still important to protect against. 00367 * PROG: Compare the quick operation first, to save CPU. */ 00368 if (state->save_total != class->total_files || strcmp(state->name, class->name) != 0) { 00369 memset(state, 0, sizeof(*state)); 00370 if (ast_test_flag(class, MOH_RANDOMIZE) && class->total_files) { 00371 state->pos = ast_random() % class->total_files; 00372 } 00373 } 00374 00375 state->class = mohclass_ref(class, "Reffing music class for channel"); 00376 state->origwfmt = chan->writeformat; 00377 /* For comparison on restart of MOH (see above) */ 00378 ast_copy_string(state->name, class->name, sizeof(state->name)); 00379 state->save_total = class->total_files; 00380 00381 ast_verb(3, "Started music on hold, class '%s', on %s\n", class->name, chan->name); 00382 00383 return chan->music_state; 00384 }
| static int moh_files_generator | ( | struct ast_channel * | chan, | |
| void * | data, | |||
| int | len, | |||
| int | samples | |||
| ) | [static] |
Definition at line 323 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.
00324 { 00325 struct moh_files_state *state = chan->music_state; 00326 struct ast_frame *f = NULL; 00327 int res = 0; 00328 00329 state->sample_queue += samples; 00330 00331 while (state->sample_queue > 0) { 00332 if ((f = moh_files_readframe(chan))) { 00333 state->samples += f->samples; 00334 state->sample_queue -= f->samples; 00335 res = ast_write(chan, f); 00336 ast_frfree(f); 00337 if (res < 0) { 00338 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); 00339 return -1; 00340 } 00341 } else 00342 return -1; 00343 } 00344 return res; 00345 }
| static struct ast_frame* moh_files_readframe | ( | struct ast_channel * | chan | ) | [static, read] |
Definition at line 311 of file res_musiconhold.c.
References ast_moh_files_next(), ast_readframe(), f, and ast_channel::stream.
Referenced by moh_files_generator().
00312 { 00313 struct ast_frame *f = NULL; 00314 00315 if (!(chan->stream && (f = ast_readframe(chan->stream)))) { 00316 if (!ast_moh_files_next(chan)) 00317 f = ast_readframe(chan->stream); 00318 } 00319 00320 return f; 00321 }
| static void moh_files_release | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 228 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.
00229 { 00230 struct moh_files_state *state; 00231 00232 if (!chan || !chan->music_state) { 00233 return; 00234 } 00235 00236 state = chan->music_state; 00237 00238 if (chan->stream) { 00239 ast_closestream(chan->stream); 00240 chan->stream = NULL; 00241 } 00242 00243 if (option_verbose > 2) { 00244 ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name); 00245 } 00246 00247 if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) { 00248 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt); 00249 } 00250 00251 state->save_pos = state->pos; 00252 00253 state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator"); 00254 }
| static int moh_generate | ( | struct ast_channel * | chan, | |
| void * | data, | |||
| int | len, | |||
| int | samples | |||
| ) | [static] |
Definition at line 889 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.
00890 { 00891 struct mohdata *moh = data; 00892 short buf[1280 + AST_FRIENDLY_OFFSET / 2]; 00893 int res; 00894 00895 len = ast_codec_get_len(moh->parent->format, samples); 00896 00897 if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) { 00898 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name); 00899 len = sizeof(buf) - AST_FRIENDLY_OFFSET; 00900 } 00901 res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len); 00902 if (res <= 0) 00903 return 0; 00904 00905 moh->f.datalen = res; 00906 moh->f.data.ptr = buf + AST_FRIENDLY_OFFSET / 2; 00907 moh->f.samples = ast_codec_get_samples(&moh->f); 00908 00909 if (ast_write(chan, &moh->f) < 0) { 00910 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); 00911 return -1; 00912 } 00913 00914 return 0; 00915 }
| static void moh_handle_digit | ( | struct ast_channel * | chan, | |
| char | digit | |||
| ) | [static] |
Definition at line 400 of file res_musiconhold.c.
References ast_moh_start(), ast_moh_stop(), ast_string_field_set, get_mohbydigit(), mohclass_unref, and musicclass.
00401 { 00402 struct mohclass *class; 00403 const char *classname = NULL; 00404 00405 if ((class = get_mohbydigit(digit))) { 00406 classname = ast_strdupa(class->name); 00407 class = mohclass_unref(class, "Unreffing ao2_find from finding by digit"); 00408 ast_string_field_set(chan,musicclass,classname); 00409 ast_moh_stop(chan); 00410 ast_moh_start(chan, classname, NULL); 00411 } 00412 }
| static void moh_release | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 830 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().
00831 { 00832 struct mohdata *moh = data; 00833 struct mohclass *class = moh->parent; 00834 int oldwfmt; 00835 00836 ao2_lock(class); 00837 AST_LIST_REMOVE(&moh->parent->members, moh, list); 00838 ao2_unlock(class); 00839 00840 close(moh->pipe[0]); 00841 close(moh->pipe[1]); 00842 00843 oldwfmt = moh->origwfmt; 00844 00845 moh->parent = class = mohclass_unref(class, "unreffing moh->parent upon deactivation of generator"); 00846 00847 ast_free(moh); 00848 00849 if (chan) { 00850 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) { 00851 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", 00852 chan->name, ast_getformatname(oldwfmt)); 00853 } 00854 00855 ast_verb(3, "Stopped music on hold on %s\n", chan->name); 00856 } 00857 }
| static int moh_scan_files | ( | struct mohclass * | class | ) | [static] |
Definition at line 957 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().
00957 { 00958 00959 DIR *files_DIR; 00960 struct dirent *files_dirent; 00961 char dir_path[PATH_MAX]; 00962 char path[PATH_MAX]; 00963 char filepath[PATH_MAX]; 00964 char *ext; 00965 struct stat statbuf; 00966 int dirnamelen; 00967 int i; 00968 00969 if (class->dir[0] != '/') { 00970 ast_copy_string(dir_path, ast_config_AST_VAR_DIR, sizeof(dir_path)); 00971 strncat(dir_path, "/", sizeof(dir_path) - 1); 00972 strncat(dir_path, class->dir, sizeof(dir_path) - 1); 00973 } else { 00974 ast_copy_string(dir_path, class->dir, sizeof(dir_path)); 00975 } 00976 ast_debug(4, "Scanning '%s' for files for class '%s'\n", dir_path, class->name); 00977 files_DIR = opendir(dir_path); 00978 if (!files_DIR) { 00979 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", dir_path); 00980 return -1; 00981 } 00982 00983 for (i = 0; i < class->total_files; i++) 00984 ast_free(class->filearray[i]); 00985 00986 class->total_files = 0; 00987 dirnamelen = strlen(dir_path) + 2; 00988 if (!getcwd(path, sizeof(path))) { 00989 ast_log(LOG_WARNING, "getcwd() failed: %s\n", strerror(errno)); 00990 return -1; 00991 } 00992 if (chdir(dir_path) < 0) { 00993 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 00994 return -1; 00995 } 00996 while ((files_dirent = readdir(files_DIR))) { 00997 /* The file name must be at least long enough to have the file type extension */ 00998 if ((strlen(files_dirent->d_name) < 4)) 00999 continue; 01000 01001 /* Skip files that starts with a dot */ 01002 if (files_dirent->d_name[0] == '.') 01003 continue; 01004 01005 /* Skip files without extensions... they are not audio */ 01006 if (!strchr(files_dirent->d_name, '.')) 01007 continue; 01008 01009 snprintf(filepath, sizeof(filepath), "%s/%s", dir_path, files_dirent->d_name); 01010 01011 if (stat(filepath, &statbuf)) 01012 continue; 01013 01014 if (!S_ISREG(statbuf.st_mode)) 01015 continue; 01016 01017 if ((ext = strrchr(filepath, '.'))) 01018 *ext = '\0'; 01019 01020 /* if the file is present in multiple formats, ensure we only put it into the list once */ 01021 for (i = 0; i < class->total_files; i++) 01022 if (!strcmp(filepath, class->filearray[i])) 01023 break; 01024 01025 if (i == class->total_files) { 01026 if (moh_add_file(class, filepath)) 01027 break; 01028 } 01029 } 01030 01031 closedir(files_DIR); 01032 if (chdir(path) < 0) { 01033 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 01034 return -1; 01035 } 01036 if (ast_test_flag(class, MOH_SORTALPHA)) 01037 qsort(&class->filearray[0], class->total_files, sizeof(char *), moh_sort_compare); 01038 return class->total_files; 01039 }
| static int moh_sort_compare | ( | const void * | i1, | |
| const void * | i2 | |||
| ) | [static] |
Definition at line 947 of file res_musiconhold.c.
Referenced by moh_scan_files().
Definition at line 797 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().
00798 { 00799 struct mohdata *moh; 00800 long flags; 00801 00802 if (!(moh = ast_calloc(1, sizeof(*moh)))) 00803 return NULL; 00804 00805 if (pipe(moh->pipe)) { 00806 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno)); 00807 ast_free(moh); 00808 return NULL; 00809 } 00810 00811 /* Make entirely non-blocking */ 00812 flags = fcntl(moh->pipe[0], F_GETFL); 00813 fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK); 00814 flags = fcntl(moh->pipe[1], F_GETFL); 00815 fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK); 00816 00817 moh->f.frametype = AST_FRAME_VOICE; 00818 moh->f.subclass = cl->format; 00819 moh->f.offset = AST_FRIENDLY_OFFSET; 00820 00821 moh->parent = mohclass_ref(cl, "Reffing music class for mohdata parent"); 00822 00823 ao2_lock(cl); 00824 AST_LIST_INSERT_HEAD(&cl->members, moh, list); 00825 ao2_unlock(cl); 00826 00827 return moh; 00828 }
| static void* monmp3thread | ( | void * | data | ) | [static] |
Definition at line 563 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, errno, len(), LOG_NOTICE, LOG_WARNING, moh, MOH_MS_INTERVAL, mohdata::pipe, and spawn_mp3().
Referenced by init_app_class(), and local_ast_moh_start().
00564 { 00565 #define MOH_MS_INTERVAL 100 00566 00567 struct mohclass *class = data; 00568 struct mohdata *moh; 00569 char buf[8192]; 00570 short sbuf[8192]; 00571 int res, res2; 00572 int len; 00573 struct timeval deadline, tv_tmp; 00574 00575 deadline.tv_sec = 0; 00576 deadline.tv_usec = 0; 00577 for(;/* ever */;) { 00578 pthread_testcancel(); 00579 /* Spawn mp3 player if it's not there */ 00580 if (class->srcfd < 0) { 00581 if ((class->srcfd = spawn_mp3(class)) < 0) { 00582 ast_log(LOG_WARNING, "Unable to spawn mp3player\n"); 00583 /* Try again later */ 00584 sleep(500); 00585 pthread_testcancel(); 00586 } 00587 } 00588 if (class->pseudofd > -1) { 00589 #ifdef SOLARIS 00590 thr_yield(); 00591 #endif 00592 /* Pause some amount of time */ 00593 res = read(class->pseudofd, buf, sizeof(buf)); 00594 pthread_testcancel(); 00595 } else { 00596 long delta; 00597 /* Reliable sleep */ 00598 tv_tmp = ast_tvnow(); 00599 if (ast_tvzero(deadline)) 00600 deadline = tv_tmp; 00601 delta = ast_tvdiff_ms(tv_tmp, deadline); 00602 if (delta < MOH_MS_INTERVAL) { /* too early */ 00603 deadline = ast_tvadd(deadline, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */ 00604 usleep(1000 * (MOH_MS_INTERVAL - delta)); 00605 pthread_testcancel(); 00606 } else { 00607 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n"); 00608 deadline = tv_tmp; 00609 } 00610 res = 8 * MOH_MS_INTERVAL; /* 8 samples per millisecond */ 00611 } 00612 if ((strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir")) && AST_LIST_EMPTY(&class->members)) 00613 continue; 00614 /* Read mp3 audio */ 00615 len = ast_codec_get_len(class->format, res); 00616 00617 if ((res2 = read(class->srcfd, sbuf, len)) != len) { 00618 if (!res2) { 00619 close(class->srcfd); 00620 class->srcfd = -1; 00621 pthread_testcancel(); 00622 if (class->pid > 1) { 00623 do { 00624 if (killpg(class->pid, SIGHUP) < 0) { 00625 if (errno == ESRCH) { 00626 break; 00627 } 00628 ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno)); 00629 } 00630 usleep(100000); 00631 if (killpg(class->pid, SIGTERM) < 0) { 00632 if (errno == ESRCH) { 00633 break; 00634 } 00635 ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno)); 00636 } 00637 usleep(100000); 00638 if (killpg(class->pid, SIGKILL) < 0) { 00639 if (errno == ESRCH) { 00640 break; 00641 } 00642 ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno)); 00643 } 00644 } while (0); 00645 class->pid = 0; 00646 } 00647 } else { 00648 ast_debug(1, "Read %d bytes of audio while expecting %d\n", res2, len); 00649 } 00650 continue; 00651 } 00652 00653 pthread_testcancel(); 00654 00655 ao2_lock(class); 00656 AST_LIST_TRAVERSE(&class->members, moh, list) { 00657 /* Write data */ 00658 if ((res = write(moh->pipe[1], sbuf, res2)) != res2) { 00659 ast_debug(1, "Only wrote %d of %d bytes to pipe\n", res, res2); 00660 } 00661 } 00662 ao2_unlock(class); 00663 } 00664 return NULL; 00665 }
| static int play_moh_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 667 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_strlen_zero(), LOG_WARNING, ast_channel::name, parse(), and S_OR.
Referenced by load_module().
00668 { 00669 char *parse; 00670 char *class; 00671 int timeout = -1; 00672 int res; 00673 AST_DECLARE_APP_ARGS(args, 00674 AST_APP_ARG(class); 00675 AST_APP_ARG(duration); 00676 ); 00677 00678 parse = ast_strdupa(data); 00679 00680 AST_STANDARD_APP_ARGS(args, parse); 00681 00682 if (!ast_strlen_zero(args.duration)) { 00683 if (sscanf(args.duration, "%30d", &timeout) == 1) { 00684 timeout *= 1000; 00685 } else { 00686 ast_log(LOG_WARNING, "Invalid MusicOnHold duration '%s'. Will wait indefinitely.\n", args.duration); 00687 } 00688 } 00689 00690 class = S_OR(args.class, NULL); 00691 if (ast_moh_start(chan, class, NULL)) { 00692 ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, chan->name); 00693 return 0; 00694 } 00695 00696 if (timeout > 0) 00697 res = ast_safe_sleep(chan, timeout); 00698 else { 00699 while (!(res = ast_safe_sleep(chan, 10000))); 00700 } 00701 00702 ast_moh_stop(chan); 00703 00704 return res; 00705 }
| static int reload | ( | void | ) | [static] |
Definition at line 1806 of file res_musiconhold.c.
References ast_install_music_functions(), AST_MODULE_LOAD_SUCCESS, load_moh_classes(), local_ast_moh_cleanup(), local_ast_moh_start(), and local_ast_moh_stop().
01807 { 01808 if (load_moh_classes(1)) { 01809 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, 01810 local_ast_moh_cleanup); 01811 } 01812 01813 return AST_MODULE_LOAD_SUCCESS; 01814 }
| static int set_moh_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 730 of file res_musiconhold.c.
References ast_log(), ast_string_field_set, ast_strlen_zero(), LOG_WARNING, and musicclass.
Referenced by load_module().
00731 { 00732 static int deprecation_warning = 0; 00733 00734 if (!deprecation_warning) { 00735 deprecation_warning = 1; 00736 ast_log(LOG_WARNING, "SetMusicOnHold application is deprecated and will be removed. Use Set(CHANNEL(musicclass)=...) instead\n"); 00737 } 00738 00739 if (ast_strlen_zero(data)) { 00740 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n"); 00741 return -1; 00742 } 00743 ast_string_field_set(chan, musicclass, data); 00744 return 0; 00745 }
| static int spawn_mp3 | ( | struct mohclass * | class | ) | [static] |
Definition at line 422 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, and MPG_123.
Referenced by monmp3thread().
00423 { 00424 int fds[2]; 00425 int files = 0; 00426 char fns[MAX_MP3S][80]; 00427 char *argv[MAX_MP3S + 50]; 00428 char xargs[256]; 00429 char *argptr; 00430 int argc = 0; 00431 DIR *dir = NULL; 00432 struct dirent *de; 00433 00434 00435 if (!strcasecmp(class->dir, "nodir")) { 00436 files = 1; 00437 } else { 00438 dir = opendir(class->dir); 00439 if (!dir && strncasecmp(class->dir, "http://", 7)) { 00440 ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir); 00441 return -1; 00442 } 00443 } 00444 00445 if (!ast_test_flag(class, MOH_CUSTOM)) { 00446 argv[argc++] = "mpg123"; 00447 argv[argc++] = "-q"; 00448 argv[argc++] = "-s"; 00449 argv[argc++] = "--mono"; 00450 argv[argc++] = "-r"; 00451 argv[argc++] = "8000"; 00452 00453 if (!ast_test_flag(class, MOH_SINGLE)) { 00454 argv[argc++] = "-b"; 00455 argv[argc++] = "2048"; 00456 } 00457 00458 argv[argc++] = "-f"; 00459 00460 if (ast_test_flag(class, MOH_QUIET)) 00461 argv[argc++] = "4096"; 00462 else 00463 argv[argc++] = "8192"; 00464 00465 /* Look for extra arguments and add them to the list */ 00466 ast_copy_string(xargs, class->args, sizeof(xargs)); 00467 argptr = xargs; 00468 while (!ast_strlen_zero(argptr)) { 00469 argv[argc++] = argptr; 00470 strsep(&argptr, ","); 00471 } 00472 } else { 00473 /* Format arguments for argv vector */ 00474 ast_copy_string(xargs, class->args, sizeof(xargs)); 00475 argptr = xargs; 00476 while (!ast_strlen_zero(argptr)) { 00477 argv[argc++] = argptr; 00478 strsep(&argptr, " "); 00479 } 00480 } 00481 00482 if (!strncasecmp(class->dir, "http://", 7)) { 00483 ast_copy_string(fns[files], class->dir, sizeof(fns[files])); 00484 argv[argc++] = fns[files]; 00485 files++; 00486 } else if (dir) { 00487 while ((de = readdir(dir)) && (files < MAX_MP3S)) { 00488 if ((strlen(de->d_name) > 3) && 00489 ((ast_test_flag(class, MOH_CUSTOM) && 00490 (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 00491 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) || 00492 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) { 00493 ast_copy_string(fns[files], de->d_name, sizeof(fns[files])); 00494 argv[argc++] = fns[files]; 00495 files++; 00496 } 00497 } 00498 } 00499 argv[argc] = NULL; 00500 if (dir) { 00501 closedir(dir); 00502 } 00503 if (pipe(fds)) { 00504 ast_log(LOG_WARNING, "Pipe failed\n"); 00505 return -1; 00506 } 00507 if (!files) { 00508 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir); 00509 close(fds[0]); 00510 close(fds[1]); 00511 return -1; 00512 } 00513 if (!strncasecmp(class->dir, "http://", 7) && time(NULL) - class->start < respawn_time) { 00514 sleep(respawn_time - (time(NULL) - class->start)); 00515 } 00516 00517 time(&class->start); 00518 class->pid = ast_safe_fork(0); 00519 if (class->pid < 0) { 00520 close(fds[0]); 00521 close(fds[1]); 00522 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno)); 00523 return -1; 00524 } 00525 if (!class->pid) { 00526 if (ast_opt_high_priority) 00527 ast_set_priority(0); 00528 00529 close(fds[0]); 00530 /* Stdout goes to pipe */ 00531 dup2(fds[1], STDOUT_FILENO); 00532 00533 /* Close everything else */ 00534 ast_close_fds_above_n(STDERR_FILENO); 00535 00536 /* Child */ 00537 if (strcasecmp(class->dir, "nodir") && chdir(class->dir) < 0) { 00538 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 00539 _exit(1); 00540 } 00541 setpgid(0, getpid()); 00542 if (ast_test_flag(class, MOH_CUSTOM)) { 00543 execv(argv[0], argv); 00544 } else { 00545 /* Default install is /usr/local/bin */ 00546 execv(LOCAL_MPG_123, argv); 00547 /* Many places have it in /usr/bin */ 00548 execv(MPG_123, argv); 00549 /* Check PATH as a last-ditch effort */ 00550 execvp("mpg123", argv); 00551 } 00552 /* Can't use logger, since log FDs are closed */ 00553 fprintf(stderr, "MOH: exec failed: %s\n", strerror(errno)); 00554 close(fds[1]); 00555 _exit(1); 00556 } else { 00557 /* Parent */ 00558 close(fds[1]); 00559 } 00560 return fds[0]; 00561 }
| static int start_moh_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 747 of file res_musiconhold.c.
References mohclass::args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_moh_start(), AST_STANDARD_APP_ARGS, LOG_WARNING, ast_channel::name, parse(), and S_OR.
Referenced by load_module().
00748 { 00749 char *parse; 00750 char *class; 00751 AST_DECLARE_APP_ARGS(args, 00752 AST_APP_ARG(class); 00753 ); 00754 00755 parse = ast_strdupa(data); 00756 00757 AST_STANDARD_APP_ARGS(args, parse); 00758 00759 class = S_OR(args.class, NULL); 00760 if (ast_moh_start(chan, class, NULL)) 00761 ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, chan->name); 00762 00763 return 0; 00764 }
| static int stop_moh_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 766 of file res_musiconhold.c.
References ast_moh_stop().
Referenced by load_module().
00767 { 00768 ast_moh_stop(chan); 00769 00770 return 0; 00771 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 1823 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.
01824 { 01825 int res = 0; 01826 struct mohclass *class = NULL; 01827 01828 /* XXX This check shouldn't be required if module ref counting was being used 01829 * properly ... */ 01830 if ((class = ao2_t_callback(mohclasses, 0, moh_class_inuse, NULL, "Module unload callback"))) { 01831 class = mohclass_unref(class, "unref of class from module unload callback"); 01832 res = -1; 01833 } 01834 01835 if (res < 0) { 01836 ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n"); 01837 return res; 01838 } 01839 01840 ast_uninstall_music_functions(); 01841 01842 ast_moh_destroy(); 01843 res = ast_unregister_application(play_moh); 01844 res |= ast_unregister_application(wait_moh); 01845 res |= ast_unregister_application(set_moh); 01846 res |= ast_unregister_application(start_moh); 01847 res |= ast_unregister_application(stop_moh); 01848 ast_cli_unregister_multiple(cli_moh, ARRAY_LEN(cli_moh)); 01849 ast_unregister_atexit(ast_moh_destroy); 01850 01851 return res; 01852 }
| static int wait_moh_exec | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 707 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().
00708 { 00709 static int deprecation_warning = 0; 00710 int res; 00711 00712 if (!deprecation_warning) { 00713 deprecation_warning = 1; 00714 ast_log(LOG_WARNING, "WaitMusicOnHold application is deprecated and will be removed. Use MusicOnHold with duration parameter instead\n"); 00715 } 00716 00717 if (!data || !atoi(data)) { 00718 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n"); 00719 return -1; 00720 } 00721 if (ast_moh_start(chan, NULL, NULL)) { 00722 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name); 00723 return 0; 00724 } 00725 res = ast_safe_sleep(chan, atoi(data) * 1000); 00726 ast_moh_stop(chan); 00727 return res; 00728 }
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 = "0901e4e500243c855563a2d78b0c03e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 1858 of file res_musiconhold.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1858 of file res_musiconhold.c.
struct ast_cli_entry cli_moh[] [static] |
{
AST_CLI_DEFINE(handle_cli_moh_reload, "Reload MusicOnHold"),
AST_CLI_DEFINE(handle_cli_moh_show_classes, "List MusicOnHold classes"),
AST_CLI_DEFINE(handle_cli_moh_show_files, "List MusicOnHold file-based classes")
}
Definition at line 1753 of file res_musiconhold.c.
struct ast_flags global_flags[1] = {{0}} [static] |
global MOH_ flags
Definition at line 152 of file res_musiconhold.c.
struct ast_generator moh_file_stream [static] |
Definition at line 414 of file res_musiconhold.c.
struct ao2_container* mohclasses [static] |
Definition at line 192 of file res_musiconhold.c.
struct ast_generator mohgen [static] |
Definition at line 917 of file res_musiconhold.c.
char* play_moh = "MusicOnHold" [static] |
Definition at line 79 of file res_musiconhold.c.
char* play_moh_desc [static] |
Definition at line 91 of file res_musiconhold.c.
char* play_moh_syn = "Play Music On Hold indefinitely" [static] |
Definition at line 85 of file res_musiconhold.c.
int respawn_time = 20 [static] |
Definition at line 127 of file res_musiconhold.c.
char* set_moh = "SetMusicOnHold" [static] |
Definition at line 81 of file res_musiconhold.c.
char* set_moh_desc [static] |
Definition at line 109 of file res_musiconhold.c.
char* set_moh_syn = "Set default Music On Hold class" [static] |
Definition at line 87 of file res_musiconhold.c.
char* start_moh = "StartMusicOnHold" [static] |
Definition at line 82 of file res_musiconhold.c.
char* start_moh_desc [static] |
" StartMusicOnHold(class):\n" "Starts playing music on hold, uses default music class for channel.\n" "Starts playing music specified by class. If omitted, the default\n" "music source for the channel will be used. Always returns 0.\n"
Definition at line 119 of file res_musiconhold.c.
char* start_moh_syn = "Play Music On Hold" [static] |
Definition at line 88 of file res_musiconhold.c.
char* stop_moh = "StopMusicOnHold" [static] |
Definition at line 83 of file res_musiconhold.c.
char* stop_moh_desc [static] |
" StopMusicOnHold(): " "Stops playing music on hold.\n"
Definition at line 124 of file res_musiconhold.c.
char* stop_moh_syn = "Stop Playing Music On Hold" [static] |
Definition at line 89 of file res_musiconhold.c.
char* wait_moh = "WaitMusicOnHold" [static] |
Definition at line 80 of file res_musiconhold.c.
char* wait_moh_desc [static] |
Definition at line 99 of file res_musiconhold.c.
char* wait_moh_syn = "Wait, playing Music On Hold" [static] |
Definition at line 86 of file res_musiconhold.c.
1.6.2