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