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