#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 "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
#include "asterisk/stringfields.h"
#include "asterisk/linkedlists.h"
#include "asterisk/manager.h"
#include "asterisk/paths.h"
#include "asterisk/astobj2.h"
#include "asterisk/timing.h"
#include "asterisk/time.h"
#include "asterisk/poll-compat.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_ANNOUNCEMENT (1 << 6) |
| #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 void | moh_files_write_format_change (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 void | moh_rescan_files (void) |
| static int | moh_scan_files (struct mohclass *class) |
| static int | moh_sort_compare (const void *i1, const void *i2) |
| static struct mohdata * | mohalloc (struct mohclass *cl) |
| static void * | monmp3thread (void *data) |
| static int | play_moh_exec (struct ast_channel *chan, const char *data) |
| static int | reload (void) |
| static int | set_moh_exec (struct ast_channel *chan, const char *data) |
| static int | spawn_mp3 (struct mohclass *class) |
| static int | start_moh_exec (struct ast_channel *chan, const char *data) |
| static int | stop_moh_exec (struct ast_channel *chan, const char *data) |
| static int | unload_module (void) |
| static int | wait_moh_exec (struct ast_channel *chan, const char *data) |
Variables | |
| static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Music On Hold Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, } |
| static struct ast_module_info * | ast_module_info = &__mod_info |
| static struct ast_cli_entry | cli_moh [] |
| static struct ast_flags | global_flags [1] = {{0}} |
| static struct ast_generator | moh_file_stream |
| static struct ao2_container * | mohclasses |
| static struct ast_generator | mohgen |
| static const char | play_moh [] = "MusicOnHold" |
| static int | respawn_time = 20 |
| static const char | set_moh [] = "SetMusicOnHold" |
| static const char | start_moh [] = "StartMusicOnHold" |
| static const char | stop_moh [] = "StopMusicOnHold" |
| static const char | wait_moh [] = "WaitMusicOnHold" |
Definition in file res_musiconhold.c.
| #define 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" |
Definition at line 225 of file res_musiconhold.c.
| #define MAX_MP3S 256 |
| #define MOH_ANNOUNCEMENT (1 << 6) |
Do we play announcement files between songs on this channel?
Definition at line 177 of file res_musiconhold.c.
Referenced by ast_moh_files_next(), and load_moh_classes().
| #define MOH_CACHERTCLASSES (1 << 5) |
Should we use a separate instance of MOH for each user or not
Definition at line 176 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 1333 of file res_musiconhold.c.
Referenced by load_moh_classes(), and local_ast_moh_start().
| #define MOH_CUSTOM (1 << 2) |
Definition at line 172 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 180 of file res_musiconhold.c.
Referenced by _moh_register(), and moh_class_cmp().
| #define MOH_QUIET (1 << 0) |
Definition at line 170 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 173 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 1258 of file res_musiconhold.c.
Referenced by load_moh_classes(), and local_ast_moh_start().
| #define MOH_SINGLE (1 << 1) |
Definition at line 171 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 174 of file res_musiconhold.c.
Referenced by load_moh_classes(), local_ast_moh_start(), and moh_scan_files().
Definition at line 231 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 234 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_alloc(), moh_files_alloc(), moh_files_release(), moh_handle_digit(), moh_release(), and unload_module().
| #define MPG_123 "/usr/bin/mpg123" |
Definition at line 226 of file res_musiconhold.c.
| static void __reg_module | ( | void | ) | [static] |
Definition at line 2022 of file res_musiconhold.c.
| static void __unreg_module | ( | void | ) | [static] |
Definition at line 2022 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 882 of file res_musiconhold.c.
References __ao2_find(), __ao2_find_debug(), ast_copy_string(), ast_debug, mohclass::flags, moh, and mohclass::name.
Referenced by _moh_register().
00883 { 00884 struct mohclass *moh = NULL; 00885 struct mohclass tmp_class = { 00886 .flags = 0, 00887 }; 00888 00889 ast_copy_string(tmp_class.name, name, sizeof(tmp_class.name)); 00890 00891 #ifdef REF_DEBUG 00892 moh = __ao2_find_debug(mohclasses, &tmp_class, flags, "get_mohbyname", (char *) file, lineno, funcname); 00893 #else 00894 moh = __ao2_find(mohclasses, &tmp_class, flags); 00895 #endif 00896 00897 if (!moh && warn) { 00898 ast_debug(1, "Music on Hold class '%s' not found in memory\n", name); 00899 } 00900 00901 return moh; 00902 }
| static struct mohclass* _moh_class_malloc | ( | const char * | file, | |
| int | line, | |||
| const char * | funcname | |||
| ) | [static, read] |
Definition at line 1335 of file res_musiconhold.c.
References __ao2_alloc_debug(), __AST_DEBUG_MALLOC, ao2_alloc, ast_format_set(), AST_FORMAT_SLINEAR, and moh_class_destructor().
01336 { 01337 struct mohclass *class; 01338 01339 if ((class = 01340 #ifdef REF_DEBUG 01341 __ao2_alloc_debug(sizeof(*class), moh_class_destructor, "Allocating new moh class", file, line, funcname, 1) 01342 #elif defined(__AST_DEBUG_MALLOC) 01343 __ao2_alloc_debug(sizeof(*class), moh_class_destructor, "Allocating new moh class", file, line, funcname, 0) 01344 #else 01345 ao2_alloc(sizeof(*class), moh_class_destructor) 01346 #endif 01347 )) { 01348 ast_format_set(&class->format, AST_FORMAT_SLINEAR, 0); 01349 class->srcfd = -1; 01350 } 01351 01352 return class; 01353 }
| static int _moh_register | ( | struct mohclass * | moh, | |
| int | reload, | |||
| int | unref, | |||
| const char * | file, | |||
| int | line, | |||
| const char * | funcname | |||
| ) | [static] |
Definition at line 1259 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.
01260 { 01261 struct mohclass *mohclass = NULL; 01262 01263 mohclass = _get_mohbyname(moh->name, 0, MOH_NOTDELETED, file, line, funcname); 01264 01265 if (mohclass && !moh_diff(mohclass, moh)) { 01266 ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name); 01267 mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name"); 01268 if (unref) { 01269 moh = mohclass_unref(moh, "unreffing potential new moh class (it is a duplicate)"); 01270 } 01271 return -1; 01272 } else if (mohclass) { 01273 /* Found a class, but it's different from the one being registered */ 01274 mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name"); 01275 } 01276 01277 time(&moh->start); 01278 moh->start -= respawn_time; 01279 01280 if (!strcasecmp(moh->mode, "files")) { 01281 if (init_files_class(moh)) { 01282 if (unref) { 01283 moh = mohclass_unref(moh, "unreffing potential new moh class (init_files_class failed)"); 01284 } 01285 return -1; 01286 } 01287 } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || 01288 !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || 01289 !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) { 01290 if (init_app_class(moh)) { 01291 if (unref) { 01292 moh = mohclass_unref(moh, "unreffing potential new moh class (init_app_class_failed)"); 01293 } 01294 return -1; 01295 } 01296 } else { 01297 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode); 01298 if (unref) { 01299 moh = mohclass_unref(moh, "unreffing potential new moh class (unknown mode)"); 01300 } 01301 return -1; 01302 } 01303 01304 ao2_t_link(mohclasses, moh, "Adding class to container"); 01305 01306 if (unref) { 01307 moh = mohclass_unref(moh, "Unreffing new moh class because we just added it to the container"); 01308 } 01309 01310 return 0; 01311 }
| static void ast_moh_destroy | ( | void | ) | [static] |
Definition at line 1814 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().
01815 { 01816 ast_verb(2, "Destroying musiconhold processes\n"); 01817 ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "Destroy callback"); 01818 }
| static int ast_moh_files_next | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 287 of file res_musiconhold.c.
References mohclass::announcement, moh_files_state::announcement, ast_channel_language(), ast_channel_name(), ast_closestream(), ast_copy_string(), ast_debug, ast_fileexists(), ast_log(), ast_openstream_full(), ast_random(), ast_seekstream(), ast_strlen_zero(), ast_tellstream(), ast_test_flag, moh_files_state::class, errno, mohclass::filearray, LOG_WARNING, MOH_ANNOUNCEMENT, 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().
00288 { 00289 struct moh_files_state *state = chan->music_state; 00290 int tries; 00291 00292 /* Discontinue a stream if it is running already */ 00293 if (chan->stream) { 00294 ast_closestream(chan->stream); 00295 chan->stream = NULL; 00296 } 00297 00298 if (ast_test_flag(state->class, MOH_ANNOUNCEMENT) && state->announcement == 0) { 00299 state->announcement = 1; 00300 if (ast_openstream_full(chan, state->class->announcement, ast_channel_language(chan), 1)) { 00301 ast_debug(1, "%s Opened announcement '%s'\n", ast_channel_name(chan), state->class->announcement); 00302 return 0; 00303 } 00304 } else { 00305 state->announcement = 0; 00306 } 00307 00308 if (!state->class->total_files) { 00309 ast_log(LOG_WARNING, "No files available for class '%s'\n", state->class->name); 00310 return -1; 00311 } 00312 00313 if (state->pos == 0 && ast_strlen_zero(state->save_pos_filename)) { 00314 /* First time so lets play the file. */ 00315 state->save_pos = -1; 00316 } else if (state->save_pos >= 0 && state->save_pos < state->class->total_files && !strcmp(state->class->filearray[state->save_pos], state->save_pos_filename)) { 00317 /* If a specific file has been saved confirm it still exists and that it is still valid */ 00318 state->pos = state->save_pos; 00319 state->save_pos = -1; 00320 } else if (ast_test_flag(state->class, MOH_RANDOMIZE)) { 00321 /* Get a random file and ensure we can open it */ 00322 for (tries = 0; tries < 20; tries++) { 00323 state->pos = ast_random() % state->class->total_files; 00324 if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0) { 00325 break; 00326 } 00327 } 00328 state->save_pos = -1; 00329 state->samples = 0; 00330 } else { 00331 /* This is easy, just increment our position and make sure we don't exceed the total file count */ 00332 state->pos++; 00333 state->pos %= state->class->total_files; 00334 state->save_pos = -1; 00335 state->samples = 0; 00336 } 00337 00338 for (tries = 0; tries < state->class->total_files; ++tries) { 00339 if (ast_openstream_full(chan, state->class->filearray[state->pos], ast_channel_language(chan), 1)) { 00340 break; 00341 } 00342 00343 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno)); 00344 state->pos++; 00345 state->pos %= state->class->total_files; 00346 } 00347 00348 if (tries == state->class->total_files) { 00349 return -1; 00350 } 00351 00352 /* Record the pointer to the filename for position resuming later */ 00353 ast_copy_string(state->save_pos_filename, state->class->filearray[state->pos], sizeof(state->save_pos_filename)); 00354 00355 ast_debug(1, "%s Opened file %d '%s'\n", ast_channel_name(chan), state->pos, state->class->filearray[state->pos]); 00356 00357 if (state->samples) { 00358 size_t loc; 00359 /* seek *SHOULD* be good since it's from a known location */ 00360 ast_seekstream(chan->stream, state->samples, SEEK_SET); 00361 /* if the seek failed then recover because if there is not a valid read, 00362 * moh_files_generate will return -1 and MOH will stop */ 00363 loc = ast_tellstream(chan->stream); 00364 if (state->samples > loc && loc) { 00365 /* seek one sample from the end for one guaranteed valid read */ 00366 ast_seekstream(chan->stream, 1, SEEK_END); 00367 } 00368 } 00369 00370 return 0; 00371 }
| static struct mohclass* get_mohbydigit | ( | char | digit | ) | [static, read] |
Definition at line 494 of file res_musiconhold.c.
References ao2_t_callback, and moh_digit_match().
Referenced by moh_handle_digit().
00495 { 00496 return ao2_t_callback(mohclasses, 0, moh_digit_match, &digit, "digit callback"); 00497 }
| static char* handle_cli_moh_reload | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1820 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.
01821 { 01822 switch (cmd) { 01823 case CLI_INIT: 01824 e->command = "moh reload"; 01825 e->usage = 01826 "Usage: moh reload\n" 01827 " Reloads the MusicOnHold module.\n" 01828 " Alias for 'module reload res_musiconhold.so'\n"; 01829 return NULL; 01830 case CLI_GENERATE: 01831 return NULL; 01832 } 01833 01834 if (a->argc != e->args) 01835 return CLI_SHOWUSAGE; 01836 01837 reload(); 01838 01839 return CLI_SUCCESS; 01840 }
| static char* handle_cli_moh_show_classes | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1880 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.
01881 { 01882 struct mohclass *class; 01883 struct ao2_iterator i; 01884 01885 switch (cmd) { 01886 case CLI_INIT: 01887 e->command = "moh show classes"; 01888 e->usage = 01889 "Usage: moh show classes\n" 01890 " Lists all MusicOnHold classes.\n"; 01891 return NULL; 01892 case CLI_GENERATE: 01893 return NULL; 01894 } 01895 01896 if (a->argc != e->args) 01897 return CLI_SHOWUSAGE; 01898 01899 i = ao2_iterator_init(mohclasses, 0); 01900 for (; (class = ao2_t_iterator_next(&i, "Show classes iterator")); mohclass_unref(class, "Unref iterator in moh show classes")) { 01901 ast_cli(a->fd, "Class: %s\n", class->name); 01902 ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>")); 01903 ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>")); 01904 if (ast_test_flag(class, MOH_CUSTOM)) { 01905 ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>")); 01906 } 01907 if (strcasecmp(class->mode, "files")) { 01908 ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(&class->format)); 01909 } 01910 } 01911 ao2_iterator_destroy(&i); 01912 01913 return CLI_SUCCESS; 01914 }
| static char* handle_cli_moh_show_files | ( | struct ast_cli_entry * | e, | |
| int | cmd, | |||
| struct ast_cli_args * | a | |||
| ) | [static] |
Definition at line 1842 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.
01843 { 01844 struct mohclass *class; 01845 struct ao2_iterator i; 01846 01847 switch (cmd) { 01848 case CLI_INIT: 01849 e->command = "moh show files"; 01850 e->usage = 01851 "Usage: moh show files\n" 01852 " Lists all loaded file-based MusicOnHold classes and their\n" 01853 " files.\n"; 01854 return NULL; 01855 case CLI_GENERATE: 01856 return NULL; 01857 } 01858 01859 if (a->argc != e->args) 01860 return CLI_SHOWUSAGE; 01861 01862 i = ao2_iterator_init(mohclasses, 0); 01863 for (; (class = ao2_t_iterator_next(&i, "Show files iterator")); mohclass_unref(class, "Unref iterator in moh show files")) { 01864 int x; 01865 01866 if (!class->total_files) { 01867 continue; 01868 } 01869 01870 ast_cli(a->fd, "Class: %s\n", class->name); 01871 for (x = 0; x < class->total_files; x++) { 01872 ast_cli(a->fd, "\tFile: %s\n", class->filearray[x]); 01873 } 01874 } 01875 ao2_iterator_destroy(&i); 01876 01877 return CLI_SUCCESS; 01878 }
| static int init_app_class | ( | struct mohclass * | class | ) | [static] |
Definition at line 1219 of file res_musiconhold.c.
References ast_log(), ast_pthread_create_background, ast_set_flag, ast_timer_close(), ast_timer_open(), ast_timer_set_rate(), errno, LOG_WARNING, MOH_CUSTOM, MOH_QUIET, MOH_SINGLE, and monmp3thread().
Referenced by _moh_register().
01220 { 01221 if (!strcasecmp(class->mode, "custom")) { 01222 ast_set_flag(class, MOH_CUSTOM); 01223 } else if (!strcasecmp(class->mode, "mp3nb")) { 01224 ast_set_flag(class, MOH_SINGLE); 01225 } else if (!strcasecmp(class->mode, "quietmp3nb")) { 01226 ast_set_flag(class, MOH_SINGLE | MOH_QUIET); 01227 } else if (!strcasecmp(class->mode, "quietmp3")) { 01228 ast_set_flag(class, MOH_QUIET); 01229 } 01230 01231 class->srcfd = -1; 01232 01233 if (!(class->timer = ast_timer_open())) { 01234 ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno)); 01235 return -1; 01236 } 01237 if (class->timer && ast_timer_set_rate(class->timer, 25)) { 01238 ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno)); 01239 ast_timer_close(class->timer); 01240 class->timer = NULL; 01241 } 01242 01243 if (ast_pthread_create_background(&class->thread, NULL, monmp3thread, class)) { 01244 ast_log(LOG_WARNING, "Unable to create moh thread...\n"); 01245 if (class->timer) { 01246 ast_timer_close(class->timer); 01247 class->timer = NULL; 01248 } 01249 return -1; 01250 } 01251 01252 return 0; 01253 }
| static int init_files_class | ( | struct mohclass * | class | ) | [static] |
Definition at line 1158 of file res_musiconhold.c.
References ast_set_flag, ast_verb, MOH_RANDOMIZE, and moh_scan_files().
Referenced by _moh_register().
01159 { 01160 int res; 01161 01162 res = moh_scan_files(class); 01163 01164 if (res < 0) { 01165 return -1; 01166 } 01167 01168 if (!res) { 01169 ast_verb(3, "Files not found in %s for moh class:%s\n", 01170 class->dir, class->name); 01171 return -1; 01172 } 01173 01174 #if 0 01175 /* XXX This isn't correct. Args is an application for custom mode. XXX */ 01176 if (strchr(class->args, 'r')) { 01177 ast_set_flag(class, MOH_RANDOMIZE); 01178 } 01179 #endif 01180 01181 return 0; 01182 }
| static int load_module | ( | void | ) | [static] |
Definition at line 1938 of file res_musiconhold.c.
References ao2_t_container_alloc, ARRAY_LEN, ast_check_realtime(), ast_cli_register_multiple(), ast_install_music_functions(), ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_moh_destroy(), ast_register_application_xml, ast_register_atexit(), load_moh_classes(), local_ast_moh_cleanup(), local_ast_moh_start(), local_ast_moh_stop(), LOG_WARNING, moh_class_cmp(), moh_class_hash(), play_moh_exec(), set_moh_exec(), start_moh_exec(), stop_moh_exec(), and wait_moh_exec().
01939 { 01940 int res; 01941 01942 if (!(mohclasses = ao2_t_container_alloc(53, moh_class_hash, moh_class_cmp, "Moh class container"))) { 01943 return AST_MODULE_LOAD_DECLINE; 01944 } 01945 01946 if (!load_moh_classes(0) && ast_check_realtime("musiconhold") == 0) { /* No music classes configured, so skip it */ 01947 ast_log(LOG_WARNING, "No music on hold classes configured, " 01948 "disabling music on hold.\n"); 01949 } else { 01950 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, 01951 local_ast_moh_cleanup); 01952 } 01953 01954 res = ast_register_application_xml(play_moh, play_moh_exec); 01955 ast_register_atexit(ast_moh_destroy); 01956 ast_cli_register_multiple(cli_moh, ARRAY_LEN(cli_moh)); 01957 if (!res) 01958 res = ast_register_application_xml(wait_moh, wait_moh_exec); 01959 if (!res) 01960 res = ast_register_application_xml(set_moh, set_moh_exec); 01961 if (!res) 01962 res = ast_register_application_xml(start_moh, start_moh_exec); 01963 if (!res) 01964 res = ast_register_application_xml(stop_moh, stop_moh_exec); 01965 01966 return AST_MODULE_LOAD_SUCCESS; 01967 }
| static int load_moh_classes | ( | int | reload | ) | [static] |
Definition at line 1701 of file res_musiconhold.c.
References ao2_t_callback, ast_category_browse(), ast_check_realtime(), ast_clear_flag, ast_config_destroy(), ast_config_load, ast_copy_string(), AST_FLAGS_ALL, ast_format_set(), AST_FORMAT_SLINEAR, ast_getformatbyname(), ast_log(), ast_set2_flag, ast_set_flag, ast_strlen_zero(), ast_true(), ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, HANDLE_REF, LOG_WARNING, MOH_ANNOUNCEMENT, MOH_CACHERTCLASSES, moh_class_malloc, moh_class_mark(), moh_classes_delete_marked(), MOH_RANDOMIZE, moh_register, moh_rescan_files(), 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().
01702 { 01703 struct ast_config *cfg; 01704 struct ast_variable *var; 01705 struct mohclass *class; 01706 char *cat; 01707 int numclasses = 0; 01708 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 }; 01709 01710 cfg = ast_config_load("musiconhold.conf", config_flags); 01711 01712 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) { 01713 if (ast_check_realtime("musiconhold") && reload) { 01714 ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes"); 01715 ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, moh_classes_delete_marked, NULL, "Purge marked classes"); 01716 } 01717 return 0; 01718 } 01719 if (cfg == CONFIG_STATUS_FILEUNCHANGED) { 01720 moh_rescan_files(); 01721 return 0; 01722 } 01723 01724 if (reload) { 01725 ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes"); 01726 } 01727 01728 ast_clear_flag(global_flags, AST_FLAGS_ALL); 01729 01730 cat = ast_category_browse(cfg, NULL); 01731 for (; cat; cat = ast_category_browse(cfg, cat)) { 01732 /* Setup common options from [general] section */ 01733 if (!strcasecmp(cat, "general")) { 01734 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 01735 if (!strcasecmp(var->name, "cachertclasses")) { 01736 ast_set2_flag(global_flags, ast_true(var->value), MOH_CACHERTCLASSES); 01737 } else { 01738 ast_log(LOG_WARNING, "Unknown option '%s' in [general] section of musiconhold.conf\n", var->name); 01739 } 01740 } 01741 } 01742 /* These names were deprecated in 1.4 and should not be used until after the next major release. */ 01743 if (!strcasecmp(cat, "classes") || !strcasecmp(cat, "moh_files") || 01744 !strcasecmp(cat, "general")) { 01745 continue; 01746 } 01747 01748 if (!(class = moh_class_malloc())) { 01749 break; 01750 } 01751 01752 ast_copy_string(class->name, cat, sizeof(class->name)); 01753 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 01754 if (!strcasecmp(var->name, "mode")) { 01755 ast_copy_string(class->mode, var->value, sizeof(class->mode)); 01756 } else if (!strcasecmp(var->name, "directory")) { 01757 ast_copy_string(class->dir, var->value, sizeof(class->dir)); 01758 } else if (!strcasecmp(var->name, "application")) { 01759 ast_copy_string(class->args, var->value, sizeof(class->args)); 01760 } else if (!strcasecmp(var->name, "announcement")) { 01761 ast_copy_string(class->announcement, var->value, sizeof(class->announcement)); 01762 ast_set_flag(class, MOH_ANNOUNCEMENT); 01763 } else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value))) { 01764 class->digit = *var->value; 01765 } else if (!strcasecmp(var->name, "random")) { 01766 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE); 01767 } else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "random")) { 01768 ast_set_flag(class, MOH_RANDOMIZE); 01769 } else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) { 01770 ast_set_flag(class, MOH_SORTALPHA); 01771 } else if (!strcasecmp(var->name, "format")) { 01772 ast_getformatbyname(var->value, &class->format); 01773 if (!class->format.id) { 01774 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value); 01775 ast_format_set(&class->format, AST_FORMAT_SLINEAR, 0); 01776 } 01777 } 01778 } 01779 01780 if (ast_strlen_zero(class->dir)) { 01781 if (!strcasecmp(class->mode, "custom")) { 01782 strcpy(class->dir, "nodir"); 01783 } else { 01784 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name); 01785 class = mohclass_unref(class, "unreffing potential mohclass (no directory)"); 01786 continue; 01787 } 01788 } 01789 if (ast_strlen_zero(class->mode)) { 01790 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name); 01791 class = mohclass_unref(class, "unreffing potential mohclass (no mode)"); 01792 continue; 01793 } 01794 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) { 01795 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name); 01796 class = mohclass_unref(class, "unreffing potential mohclass (no app for custom mode)"); 01797 continue; 01798 } 01799 01800 /* Don't leak a class when it's already registered */ 01801 if (!moh_register(class, reload, HANDLE_REF)) { 01802 numclasses++; 01803 } 01804 } 01805 01806 ast_config_destroy(cfg); 01807 01808 ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, 01809 moh_classes_delete_marked, NULL, "Purge marked classes"); 01810 01811 return numclasses; 01812 }
| static void local_ast_moh_cleanup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1313 of file res_musiconhold.c.
References ast_free, ast_log(), ast_module_unref(), moh_files_state::class, LOG_WARNING, mohclass_unref, and ast_channel::music_state.
Referenced by load_module().
01314 { 01315 struct moh_files_state *state = chan->music_state; 01316 01317 if (state) { 01318 if (state->class) { 01319 /* This should never happen. We likely just leaked some resource. */ 01320 state->class = 01321 mohclass_unref(state->class, "Uh Oh. Cleaning up MOH with an active class"); 01322 ast_log(LOG_WARNING, "Uh Oh. Cleaning up MOH with an active class\n"); 01323 } 01324 ast_free(chan->music_state); 01325 chan->music_state = NULL; 01326 /* Only held a module reference if we had a music state */ 01327 ast_module_unref(ast_module_info->self); 01328 } 01329 }
| static int local_ast_moh_start | ( | struct ast_channel * | chan, | |
| const char * | mclass, | |||
| const char * | interpclass | |||
| ) | [static] |
Definition at line 1355 of file res_musiconhold.c.
References mohclass::args, ast_activate_generator(), ast_channel_musicclass(), ast_channel_name(), ast_channel_uniqueid(), ast_check_realtime(), ast_copy_string(), AST_FLAG_MOH, ast_format_set(), AST_FORMAT_SLINEAR, ast_getformatbyname(), ast_load_realtime(), ast_log(), ast_manager_event, ast_pthread_create_background, ast_set2_flag, ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_timer_close(), ast_timer_open(), ast_timer_set_rate(), ast_true(), ast_variables_destroy(), moh_files_state::class, mohclass::digit, mohclass::dir, DONT_UNREF, errno, EVENT_FLAG_CALL, mohclass::format, get_mohbyname, ast_format::id, LOG_NOTICE, LOG_WARNING, mohclass::mode, MOH_CACHERTCLASSES, moh_class_malloc, MOH_CUSTOM, MOH_QUIET, MOH_RANDOMIZE, moh_register, moh_scan_files(), MOH_SINGLE, MOH_SORTALPHA, mohclass_unref, monmp3thread(), ast_channel::music_state, mohclass::name, ast_variable::name, ast_variable::next, mohclass::realtime, SENTINEL, mohclass::srcfd, mohclass::start, mohclass::thread, mohclass::timer, mohclass::total_files, ast_variable::value, and var.
Referenced by load_module().
01356 { 01357 struct mohclass *mohclass = NULL; 01358 struct moh_files_state *state = chan->music_state; 01359 struct ast_variable *var = NULL; 01360 int res; 01361 int realtime_possible = ast_check_realtime("musiconhold"); 01362 01363 /* The following is the order of preference for which class to use: 01364 * 1) The channels explicitly set musicclass, which should *only* be 01365 * set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan. 01366 * 2) The mclass argument. If a channel is calling ast_moh_start() as the 01367 * result of receiving a HOLD control frame, this should be the 01368 * payload that came with the frame. 01369 * 3) The interpclass argument. This would be from the mohinterpret 01370 * option from channel drivers. This is the same as the old musicclass 01371 * option. 01372 * 4) The default class. 01373 */ 01374 if (!ast_strlen_zero(ast_channel_musicclass(chan))) { 01375 mohclass = get_mohbyname(ast_channel_musicclass(chan), 1, 0); 01376 if (!mohclass && realtime_possible) { 01377 var = ast_load_realtime("musiconhold", "name", ast_channel_musicclass(chan), SENTINEL); 01378 } 01379 } 01380 if (!mohclass && !var && !ast_strlen_zero(mclass)) { 01381 mohclass = get_mohbyname(mclass, 1, 0); 01382 if (!mohclass && realtime_possible) { 01383 var = ast_load_realtime("musiconhold", "name", mclass, SENTINEL); 01384 } 01385 } 01386 if (!mohclass && !var && !ast_strlen_zero(interpclass)) { 01387 mohclass = get_mohbyname(interpclass, 1, 0); 01388 if (!mohclass && realtime_possible) { 01389 var = ast_load_realtime("musiconhold", "name", interpclass, SENTINEL); 01390 } 01391 } 01392 01393 if (!mohclass && !var) { 01394 mohclass = get_mohbyname("default", 1, 0); 01395 if (!mohclass && realtime_possible) { 01396 var = ast_load_realtime("musiconhold", "name", "default", SENTINEL); 01397 } 01398 } 01399 01400 /* If no moh class found in memory, then check RT. Note that the logic used 01401 * above guarantees that if var is non-NULL, then mohclass must be NULL. 01402 */ 01403 if (var) { 01404 struct ast_variable *tmp = NULL; 01405 01406 if ((mohclass = moh_class_malloc())) { 01407 mohclass->realtime = 1; 01408 for (tmp = var; tmp; tmp = tmp->next) { 01409 if (!strcasecmp(tmp->name, "name")) 01410 ast_copy_string(mohclass->name, tmp->value, sizeof(mohclass->name)); 01411 else if (!strcasecmp(tmp->name, "mode")) 01412 ast_copy_string(mohclass->mode, tmp->value, sizeof(mohclass->mode)); 01413 else if (!strcasecmp(tmp->name, "directory")) 01414 ast_copy_string(mohclass->dir, tmp->value, sizeof(mohclass->dir)); 01415 else if (!strcasecmp(tmp->name, "application")) 01416 ast_copy_string(mohclass->args, tmp->value, sizeof(mohclass->args)); 01417 else if (!strcasecmp(tmp->name, "digit") && (isdigit(*tmp->value) || strchr("*#", *tmp->value))) 01418 mohclass->digit = *tmp->value; 01419 else if (!strcasecmp(tmp->name, "random")) 01420 ast_set2_flag(mohclass, ast_true(tmp->value), MOH_RANDOMIZE); 01421 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "random")) 01422 ast_set_flag(mohclass, MOH_RANDOMIZE); 01423 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "alpha")) 01424 ast_set_flag(mohclass, MOH_SORTALPHA); 01425 else if (!strcasecmp(tmp->name, "format")) { 01426 ast_getformatbyname(tmp->value, &mohclass->format); 01427 if (!mohclass->format.id) { 01428 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", tmp->value); 01429 ast_format_set(&mohclass->format, AST_FORMAT_SLINEAR, 0); 01430 } 01431 } 01432 } 01433 ast_variables_destroy(var); 01434 if (ast_strlen_zero(mohclass->dir)) { 01435 if (!strcasecmp(mohclass->mode, "custom")) { 01436 strcpy(mohclass->dir, "nodir"); 01437 } else { 01438 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", mohclass->name); 01439 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no directory specified)"); 01440 return -1; 01441 } 01442 } 01443 if (ast_strlen_zero(mohclass->mode)) { 01444 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", mohclass->name); 01445 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no mode specified)"); 01446 return -1; 01447 } 01448 if (ast_strlen_zero(mohclass->args) && !strcasecmp(mohclass->mode, "custom")) { 01449 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", mohclass->name); 01450 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no app specified for custom mode"); 01451 return -1; 01452 } 01453 01454 if (ast_test_flag(global_flags, MOH_CACHERTCLASSES)) { 01455 /* CACHERTCLASSES enabled, let's add this class to default tree */ 01456 if (state && state->class) { 01457 /* Class already exist for this channel */ 01458 ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name); 01459 if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) { 01460 /* we found RT class with the same name, seems like we should continue playing existing one */ 01461 /* XXX This code is impossible to reach */ 01462 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has a class)"); 01463 mohclass = state->class; 01464 } 01465 } 01466 /* We don't want moh_register to unref the mohclass because we do it at the end of this function as well. 01467 * If we allowed moh_register to unref the mohclass,too, then the count would be off by one. The result would 01468 * be that the destructor would be called when the generator on the channel is deactivated. The container then 01469 * has a pointer to a freed mohclass, so any operations involving the mohclass container would result in reading 01470 * invalid memory. 01471 */ 01472 if (moh_register(mohclass, 0, DONT_UNREF) == -1) { 01473 mohclass = mohclass_unref(mohclass, "unreffing mohclass failed to register"); 01474 return -1; 01475 } 01476 } else { 01477 /* We don't register RT moh class, so let's init it manualy */ 01478 01479 time(&mohclass->start); 01480 mohclass->start -= respawn_time; 01481 01482 if (!strcasecmp(mohclass->mode, "files")) { 01483 if (!moh_scan_files(mohclass)) { 01484 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)"); 01485 return -1; 01486 } 01487 if (strchr(mohclass->args, 'r')) 01488 ast_set_flag(mohclass, MOH_RANDOMIZE); 01489 } 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")) { 01490 01491 if (!strcasecmp(mohclass->mode, "custom")) 01492 ast_set_flag(mohclass, MOH_CUSTOM); 01493 else if (!strcasecmp(mohclass->mode, "mp3nb")) 01494 ast_set_flag(mohclass, MOH_SINGLE); 01495 else if (!strcasecmp(mohclass->mode, "quietmp3nb")) 01496 ast_set_flag(mohclass, MOH_SINGLE | MOH_QUIET); 01497 else if (!strcasecmp(mohclass->mode, "quietmp3")) 01498 ast_set_flag(mohclass, MOH_QUIET); 01499 01500 mohclass->srcfd = -1; 01501 if (!(mohclass->timer = ast_timer_open())) { 01502 ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno)); 01503 } 01504 if (mohclass->timer && ast_timer_set_rate(mohclass->timer, 25)) { 01505 ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno)); 01506 ast_timer_close(mohclass->timer); 01507 mohclass->timer = NULL; 01508 } 01509 01510 /* Let's check if this channel already had a moh class before */ 01511 if (state && state->class) { 01512 /* Class already exist for this channel */ 01513 ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name); 01514 if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) { 01515 /* we found RT class with the same name, seems like we should continue playing existing one */ 01516 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has one)"); 01517 mohclass = state->class; 01518 } 01519 } else { 01520 if (ast_pthread_create_background(&mohclass->thread, NULL, monmp3thread, mohclass)) { 01521 ast_log(LOG_WARNING, "Unable to create moh...\n"); 01522 if (mohclass->timer) { 01523 ast_timer_close(mohclass->timer); 01524 mohclass->timer = NULL; 01525 } 01526 mohclass = mohclass_unref(mohclass, "Unreffing potential mohclass (failed to create background thread)"); 01527 return -1; 01528 } 01529 } 01530 } else { 01531 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mohclass->mode); 01532 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (unknown mode)"); 01533 return -1; 01534 } 01535 } 01536 } else { 01537 ast_variables_destroy(var); 01538 var = NULL; 01539 } 01540 } 01541 01542 if (!mohclass) { 01543 return -1; 01544 } 01545 01546 /* If we are using a cached realtime class with files, re-scan the files */ 01547 if (!var && ast_test_flag(global_flags, MOH_CACHERTCLASSES) && mohclass->realtime && !strcasecmp(mohclass->mode, "files")) { 01548 if (!moh_scan_files(mohclass)) { 01549 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)"); 01550 return -1; 01551 } 01552 } 01553 01554 ast_manager_event(chan, EVENT_FLAG_CALL, "MusicOnHold", 01555 "State: Start\r\n" 01556 "Channel: %s\r\n" 01557 "UniqueID: %s\r\n" 01558 "Class: %s\r\n", 01559 ast_channel_name(chan), ast_channel_uniqueid(chan), 01560 mohclass->name); 01561 01562 ast_set_flag(chan, AST_FLAG_MOH); 01563 01564 if (mohclass->total_files) { 01565 res = ast_activate_generator(chan, &moh_file_stream, mohclass); 01566 } else { 01567 res = ast_activate_generator(chan, &mohgen, mohclass); 01568 } 01569 01570 mohclass = mohclass_unref(mohclass, "unreffing local reference to mohclass in local_ast_moh_start"); 01571 01572 return res; 01573 }
| static void local_ast_moh_stop | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1575 of file res_musiconhold.c.
References ast_channel_lock, ast_channel_name(), ast_channel_uniqueid(), ast_channel_unlock, ast_clear_flag, ast_closestream(), ast_deactivate_generator(), AST_FLAG_MOH, ast_manager_event, EVENT_FLAG_CALL, ast_channel::music_state, and ast_channel::stream.
Referenced by load_module().
01576 { 01577 ast_clear_flag(chan, AST_FLAG_MOH); 01578 ast_deactivate_generator(chan); 01579 01580 ast_channel_lock(chan); 01581 if (chan->music_state) { 01582 if (chan->stream) { 01583 ast_closestream(chan->stream); 01584 chan->stream = NULL; 01585 } 01586 } 01587 01588 ast_manager_event(chan, EVENT_FLAG_CALL, "MusicOnHold", 01589 "State: Stop\r\n" 01590 "Channel: %s\r\n" 01591 "UniqueID: %s\r\n", 01592 ast_channel_name(chan), ast_channel_uniqueid(chan)); 01593 ast_channel_unlock(chan); 01594 }
| static int moh_add_file | ( | struct mohclass * | class, | |
| const char * | filepath | |||
| ) | [static] |
Definition at line 1043 of file res_musiconhold.c.
References ast_calloc, ast_realloc, ast_strdup, and INITIAL_NUM_FILES.
Referenced by moh_scan_files().
01044 { 01045 if (!class->allowed_files) { 01046 if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray)))) 01047 return -1; 01048 class->allowed_files = INITIAL_NUM_FILES; 01049 } else if (class->total_files == class->allowed_files) { 01050 if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) { 01051 class->allowed_files = 0; 01052 class->total_files = 0; 01053 return -1; 01054 } 01055 class->allowed_files *= 2; 01056 } 01057 01058 if (!(class->filearray[class->total_files] = ast_strdup(filepath))) 01059 return -1; 01060 01061 class->total_files++; 01062 01063 return 0; 01064 }
| static void* moh_alloc | ( | struct ast_channel * | chan, | |
| void * | params | |||
| ) | [static] |
Definition at line 972 of file res_musiconhold.c.
References ast_calloc, ast_channel_name(), ast_codec2str(), ast_format_copy(), ast_log(), ast_module_ref(), ast_set_write_format(), ast_verb, moh_files_state::class, mohclass::format, LOG_WARNING, moh_release(), mohalloc(), mohclass_ref, mohclass_unref, ast_channel::music_state, mohclass::name, mohdata::origwfmt, and ast_channel::writeformat.
00973 { 00974 struct mohdata *res; 00975 struct mohclass *class = params; 00976 struct moh_files_state *state; 00977 00978 /* Initiating music_state for current channel. Channel should know name of moh class */ 00979 if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) { 00980 chan->music_state = state; 00981 ast_module_ref(ast_module_info->self); 00982 } else { 00983 state = chan->music_state; 00984 if (!state) { 00985 return NULL; 00986 } 00987 if (state->class) { 00988 mohclass_unref(state->class, "Uh Oh. Restarting MOH with an active class"); 00989 ast_log(LOG_WARNING, "Uh Oh. Restarting MOH with an active class\n"); 00990 } 00991 memset(state, 0, sizeof(*state)); 00992 } 00993 00994 if ((res = mohalloc(class))) { 00995 ast_format_copy(&res->origwfmt, &chan->writeformat); 00996 if (ast_set_write_format(chan, &class->format)) { 00997 ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", ast_channel_name(chan), ast_codec2str(&class->format)); 00998 moh_release(NULL, res); 00999 res = NULL; 01000 } else { 01001 state->class = mohclass_ref(class, "Placing reference into state container"); 01002 } 01003 ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n", class->name, ast_channel_name(chan)); 01004 } 01005 return res; 01006 }
| static int moh_class_cmp | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1929 of file res_musiconhold.c.
References CMP_MATCH, CMP_STOP, and MOH_NOTDELETED.
Referenced by load_module().
01930 { 01931 struct mohclass *class = obj, *class2 = arg; 01932 01933 return strcasecmp(class->name, class2->name) ? 0 : 01934 (flags & MOH_NOTDELETED) && (class->delete || class2->delete) ? 0 : 01935 CMP_MATCH | CMP_STOP; 01936 }
| static void moh_class_destructor | ( | void * | obj | ) | [static] |
Definition at line 1596 of file res_musiconhold.c.
References ao2_lock, ao2_unlock, ast_debug, AST_LIST_REMOVE_HEAD, ast_log(), AST_PTHREADT_NULL, ast_timer_close(), ast_wait_for_input(), buff, errno, free, LOG_WARNING, and mohclass::pid.
Referenced by _moh_class_malloc().
01597 { 01598 struct mohclass *class = obj; 01599 struct mohdata *member; 01600 pthread_t tid = 0; 01601 01602 ast_debug(1, "Destroying MOH class '%s'\n", class->name); 01603 01604 ao2_lock(class); 01605 while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) { 01606 free(member); 01607 } 01608 ao2_unlock(class); 01609 01610 /* Kill the thread first, so it cannot restart the child process while the 01611 * class is being destroyed */ 01612 if (class->thread != AST_PTHREADT_NULL && class->thread != 0) { 01613 tid = class->thread; 01614 class->thread = AST_PTHREADT_NULL; 01615 pthread_cancel(tid); 01616 /* We'll collect the exit status later, after we ensure all the readers 01617 * are dead. */ 01618 } 01619 01620 if (class->pid > 1) { 01621 char buff[8192]; 01622 int bytes, tbytes = 0, stime = 0, pid = 0; 01623 01624 ast_debug(1, "killing %d!\n", class->pid); 01625 01626 stime = time(NULL) + 2; 01627 pid = class->pid; 01628 class->pid = 0; 01629 01630 /* Back when this was just mpg123, SIGKILL was fine. Now we need 01631 * to give the process a reason and time enough to kill off its 01632 * children. */ 01633 do { 01634 if (killpg(pid, SIGHUP) < 0) { 01635 ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno)); 01636 } 01637 usleep(100000); 01638 if (killpg(pid, SIGTERM) < 0) { 01639 if (errno == ESRCH) { 01640 break; 01641 } 01642 ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno)); 01643 } 01644 usleep(100000); 01645 if (killpg(pid, SIGKILL) < 0) { 01646 if (errno == ESRCH) { 01647 break; 01648 } 01649 ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno)); 01650 } 01651 } while (0); 01652 01653 while ((ast_wait_for_input(class->srcfd, 100) > 0) && 01654 (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) { 01655 tbytes = tbytes + bytes; 01656 } 01657 01658 ast_debug(1, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes); 01659 01660 close(class->srcfd); 01661 class->srcfd = -1; 01662 } 01663 01664 if (class->filearray) { 01665 int i; 01666 for (i = 0; i < class->total_files; i++) { 01667 free(class->filearray[i]); 01668 } 01669 free(class->filearray); 01670 class->filearray = NULL; 01671 } 01672 01673 if (class->timer) { 01674 ast_timer_close(class->timer); 01675 class->timer = NULL; 01676 } 01677 01678 /* Finally, collect the exit status of the monitor thread */ 01679 if (tid > 0) { 01680 pthread_join(tid, NULL); 01681 } 01682 01683 }
| static int moh_class_hash | ( | const void * | obj, | |
| const int | flags | |||
| ) | [static] |
Definition at line 1922 of file res_musiconhold.c.
References ast_str_case_hash().
Referenced by load_module().
01923 { 01924 const struct mohclass *class = obj; 01925 01926 return ast_str_case_hash(class->name); 01927 }
| static int moh_class_inuse | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1979 of file res_musiconhold.c.
References AST_LIST_EMPTY, CMP_MATCH, and CMP_STOP.
Referenced by unload_module().
01980 { 01981 struct mohclass *class = obj; 01982 01983 return AST_LIST_EMPTY(&class->members) ? 0 : CMP_MATCH | CMP_STOP; 01984 }
| static int moh_class_mark | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1685 of file res_musiconhold.c.
Referenced by load_moh_classes().
01686 { 01687 struct mohclass *class = obj; 01688 01689 class->delete = 1; 01690 01691 return 0; 01692 }
| static int moh_classes_delete_marked | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 1694 of file res_musiconhold.c.
References CMP_MATCH.
Referenced by load_moh_classes().
01695 { 01696 struct mohclass *class = obj; 01697 01698 return class->delete ? CMP_MATCH : 0; 01699 }
Definition at line 1200 of file res_musiconhold.c.
References mohclass::args, mohclass::dir, mohclass::flags, and mohclass::mode.
Referenced by _moh_register().
01201 { 01202 if (!old || !new) { 01203 return -1; 01204 } 01205 01206 if (strcmp(old->dir, new->dir)) { 01207 return -1; 01208 } else if (strcmp(old->mode, new->mode)) { 01209 return -1; 01210 } else if (strcmp(old->args, new->args)) { 01211 return -1; 01212 } else if (old->flags != new->flags) { 01213 return -1; 01214 } 01215 01216 return 0; 01217 }
| static int moh_digit_match | ( | void * | obj, | |
| void * | arg, | |||
| int | flags | |||
| ) | [static] |
Definition at line 485 of file res_musiconhold.c.
References CMP_MATCH, CMP_STOP, and mohclass::digit.
Referenced by get_mohbydigit().
00486 { 00487 char *digit = arg; 00488 struct mohclass *class = obj; 00489 00490 return (*digit == class->digit) ? CMP_MATCH | CMP_STOP : 0; 00491 }
| static void* moh_files_alloc | ( | struct ast_channel * | chan, | |
| void * | params | |||
| ) | [static] |
Definition at line 441 of file res_musiconhold.c.
References ast_calloc, ast_channel_name(), ast_copy_string(), ast_format_copy(), ast_log(), ast_module_ref(), ast_random(), ast_test_flag, ast_verb, moh_files_state::class, LOG_WARNING, MOH_RANDOMIZE, mohclass_ref, mohclass_unref, moh_files_state::mohwfmt, 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.
00442 { 00443 struct moh_files_state *state; 00444 struct mohclass *class = params; 00445 00446 if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) { 00447 chan->music_state = state; 00448 ast_module_ref(ast_module_info->self); 00449 } else { 00450 state = chan->music_state; 00451 if (!state) { 00452 return NULL; 00453 } 00454 if (state->class) { 00455 mohclass_unref(state->class, "Uh Oh. Restarting MOH with an active class"); 00456 ast_log(LOG_WARNING, "Uh Oh. Restarting MOH with an active class\n"); 00457 } 00458 } 00459 00460 /* LOGIC: Comparing an unrefcounted pointer is a really bad idea, because 00461 * malloc may allocate a different class to the same memory block. This 00462 * might only happen when two reloads are generated in a short period of 00463 * time, but it's still important to protect against. 00464 * PROG: Compare the quick operation first, to save CPU. */ 00465 if (state->save_total != class->total_files || strcmp(state->name, class->name) != 0) { 00466 memset(state, 0, sizeof(*state)); 00467 if (ast_test_flag(class, MOH_RANDOMIZE) && class->total_files) { 00468 state->pos = ast_random() % class->total_files; 00469 } 00470 } 00471 00472 state->class = mohclass_ref(class, "Reffing music class for channel"); 00473 ast_format_copy(&state->origwfmt, &chan->writeformat); 00474 ast_format_copy(&state->mohwfmt, &chan->writeformat); 00475 00476 /* For comparison on restart of MOH (see above) */ 00477 ast_copy_string(state->name, class->name, sizeof(state->name)); 00478 state->save_total = class->total_files; 00479 00480 ast_verb(3, "Started music on hold, class '%s', on %s\n", class->name, ast_channel_name(chan)); 00481 00482 return chan->music_state; 00483 }
| static int moh_files_generator | ( | struct ast_channel * | chan, | |
| void * | data, | |||
| int | len, | |||
| int | samples | |||
| ) | [static] |
Definition at line 404 of file res_musiconhold.c.
References ast_channel_lock, ast_channel_name(), ast_channel_unlock, ast_format_cmp(), AST_FORMAT_CMP_NOT_EQUAL, ast_format_copy(), ast_frfree, ast_log(), ast_write(), errno, f, ast_frame_subclass::format, LOG_WARNING, moh_files_readframe(), moh_files_state::mohwfmt, ast_channel::music_state, moh_files_state::sample_queue, ast_frame::samples, moh_files_state::samples, and ast_frame::subclass.
00405 { 00406 struct moh_files_state *state = chan->music_state; 00407 struct ast_frame *f = NULL; 00408 int res = 0; 00409 00410 state->sample_queue += samples; 00411 00412 while (state->sample_queue > 0) { 00413 ast_channel_lock(chan); 00414 if ((f = moh_files_readframe(chan))) { 00415 /* We need to be sure that we unlock 00416 * the channel prior to calling 00417 * ast_write. Otherwise, the recursive locking 00418 * that occurs can cause deadlocks when using 00419 * indirect channels, like local channels 00420 */ 00421 ast_channel_unlock(chan); 00422 state->samples += f->samples; 00423 state->sample_queue -= f->samples; 00424 if (ast_format_cmp(&f->subclass.format, &state->mohwfmt) == AST_FORMAT_CMP_NOT_EQUAL) { 00425 ast_format_copy(&state->mohwfmt, &f->subclass.format); 00426 } 00427 res = ast_write(chan, f); 00428 ast_frfree(f); 00429 if (res < 0) { 00430 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno)); 00431 return -1; 00432 } 00433 } else { 00434 ast_channel_unlock(chan); 00435 return -1; 00436 } 00437 } 00438 return res; 00439 }
| static struct ast_frame* moh_files_readframe | ( | struct ast_channel * | chan | ) | [static, read] |
Definition at line 373 of file res_musiconhold.c.
References ast_moh_files_next(), ast_readframe(), f, and ast_channel::stream.
Referenced by moh_files_generator().
00374 { 00375 struct ast_frame *f = NULL; 00376 00377 if (!(chan->stream && (f = ast_readframe(chan->stream)))) { 00378 if (!ast_moh_files_next(chan)) 00379 f = ast_readframe(chan->stream); 00380 } 00381 00382 return f; 00383 }
| static void moh_files_release | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 259 of file res_musiconhold.c.
References moh_files_state::announcement, ast_channel_name(), ast_closestream(), ast_format_clear(), ast_getformatname(), ast_log(), ast_set_write_format(), ast_verb, moh_files_state::class, ast_format::id, LOG_WARNING, mohclass_unref, moh_files_state::mohwfmt, ast_channel::music_state, moh_files_state::origwfmt, moh_files_state::pos, moh_files_state::save_pos, and ast_channel::stream.
00260 { 00261 struct moh_files_state *state; 00262 00263 if (!chan || !chan->music_state) { 00264 return; 00265 } 00266 00267 state = chan->music_state; 00268 00269 if (chan->stream) { 00270 ast_closestream(chan->stream); 00271 chan->stream = NULL; 00272 } 00273 00274 ast_verb(3, "Stopped music on hold on %s\n", ast_channel_name(chan)); 00275 00276 ast_format_clear(&state->mohwfmt); /* make sure to clear this format before restoring the original format. */ 00277 if (state->origwfmt.id && ast_set_write_format(chan, &state->origwfmt)) { 00278 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%s'\n", ast_channel_name(chan), ast_getformatname(&state->origwfmt)); 00279 } 00280 00281 state->save_pos = state->pos; 00282 state->announcement = 0; 00283 00284 state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator"); 00285 }
| static void moh_files_write_format_change | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 385 of file res_musiconhold.c.
References ast_format_clear(), ast_format_copy(), ast_set_write_format(), ast_format::id, moh_files_state::mohwfmt, ast_channel::music_state, moh_files_state::origwfmt, and ast_channel::writeformat.
00386 { 00387 struct moh_files_state *state = chan->music_state; 00388 00389 /* In order to prevent a recursive call to this function as a result 00390 * of setting the moh write format back on the channel. Clear 00391 * the moh write format before setting the write format on the channel.*/ 00392 if (&state->origwfmt.id) { 00393 struct ast_format tmp; 00394 00395 ast_format_copy(&tmp, &chan->writeformat); 00396 if (state->mohwfmt.id) { 00397 ast_format_clear(&state->origwfmt); 00398 ast_set_write_format(chan, &state->mohwfmt); 00399 } 00400 ast_format_copy(&state->origwfmt, &tmp); 00401 } 00402 }
| static int moh_generate | ( | struct ast_channel * | chan, | |
| void * | data, | |||
| int | len, | |||
| int | samples | |||
| ) | [static] |
Definition at line 1008 of file res_musiconhold.c.
References ast_channel_name(), ast_codec_get_len(), ast_codec_get_samples(), AST_FRIENDLY_OFFSET, ast_log(), ast_write(), 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.
01009 { 01010 struct mohdata *moh = data; 01011 short buf[1280 + AST_FRIENDLY_OFFSET / 2]; 01012 int res; 01013 01014 len = ast_codec_get_len(&moh->parent->format, samples); 01015 01016 if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) { 01017 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, ast_channel_name(chan)); 01018 len = sizeof(buf) - AST_FRIENDLY_OFFSET; 01019 } 01020 res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len); 01021 if (res <= 0) 01022 return 0; 01023 01024 moh->f.datalen = res; 01025 moh->f.data.ptr = buf + AST_FRIENDLY_OFFSET / 2; 01026 moh->f.samples = ast_codec_get_samples(&moh->f); 01027 01028 if (ast_write(chan, &moh->f) < 0) { 01029 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno)); 01030 return -1; 01031 } 01032 01033 return 0; 01034 }
| static void moh_handle_digit | ( | struct ast_channel * | chan, | |
| char | digit | |||
| ) | [static] |
Definition at line 499 of file res_musiconhold.c.
References ast_moh_start(), ast_moh_stop(), ast_strdupa, get_mohbydigit(), and mohclass_unref.
00500 { 00501 struct mohclass *class; 00502 const char *classname = NULL; 00503 00504 if ((class = get_mohbydigit(digit))) { 00505 classname = ast_strdupa(class->name); 00506 class = mohclass_unref(class, "Unreffing ao2_find from finding by digit"); 00507 ast_channel_musicclass_set(chan, classname); 00508 ast_moh_stop(chan); 00509 ast_moh_start(chan, classname, NULL); 00510 } 00511 }
| static void moh_release | ( | struct ast_channel * | chan, | |
| void * | data | |||
| ) | [static] |
Definition at line 937 of file res_musiconhold.c.
References ao2_lock, ao2_unlock, ast_channel_name(), ast_format_copy(), ast_free, ast_getformatname(), AST_LIST_REMOVE, ast_log(), ast_set_write_format(), ast_verb, moh_files_state::class, ast_format::id, LOG_WARNING, mohclass::members, moh, mohclass_unref, ast_channel::music_state, mohdata::origwfmt, mohdata::parent, and mohdata::pipe.
Referenced by moh_alloc().
00938 { 00939 struct mohdata *moh = data; 00940 struct mohclass *class = moh->parent; 00941 struct ast_format oldwfmt; 00942 00943 ao2_lock(class); 00944 AST_LIST_REMOVE(&moh->parent->members, moh, list); 00945 ao2_unlock(class); 00946 00947 close(moh->pipe[0]); 00948 close(moh->pipe[1]); 00949 00950 ast_format_copy(&oldwfmt, &moh->origwfmt); 00951 00952 moh->parent = class = mohclass_unref(class, "unreffing moh->parent upon deactivation of generator"); 00953 00954 ast_free(moh); 00955 00956 if (chan) { 00957 struct moh_files_state *state; 00958 00959 state = chan->music_state; 00960 if (state && state->class) { 00961 state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator"); 00962 } 00963 if (oldwfmt.id && ast_set_write_format(chan, &oldwfmt)) { 00964 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", 00965 ast_channel_name(chan), ast_getformatname(&oldwfmt)); 00966 } 00967 00968 ast_verb(3, "Stopped music on hold on %s\n", ast_channel_name(chan)); 00969 } 00970 }
| static void moh_rescan_files | ( | void | ) | [static] |
Definition at line 1184 of file res_musiconhold.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, mohclass::mode, and moh_scan_files().
Referenced by load_moh_classes().
01184 { 01185 struct ao2_iterator i; 01186 struct mohclass *c; 01187 01188 i = ao2_iterator_init(mohclasses, 0); 01189 01190 while ((c = ao2_iterator_next(&i))) { 01191 if (!strcasecmp(c->mode, "files")) { 01192 moh_scan_files(c); 01193 } 01194 ao2_ref(c, -1); 01195 } 01196 01197 ao2_iterator_destroy(&i); 01198 }
| static int moh_scan_files | ( | struct mohclass * | class | ) | [static] |
Definition at line 1076 of file res_musiconhold.c.
References ast_config_AST_DATA_DIR, ast_copy_string(), ast_debug, ast_free, ast_log(), ast_test_flag, errno, ext, LOG_WARNING, moh_add_file(), moh_sort_compare(), and MOH_SORTALPHA.
Referenced by init_files_class(), local_ast_moh_start(), and moh_rescan_files().
01076 { 01077 01078 DIR *files_DIR; 01079 struct dirent *files_dirent; 01080 char dir_path[PATH_MAX]; 01081 char path[PATH_MAX]; 01082 char filepath[PATH_MAX]; 01083 char *ext; 01084 struct stat statbuf; 01085 int i; 01086 01087 if (class->dir[0] != '/') { 01088 ast_copy_string(dir_path, ast_config_AST_DATA_DIR, sizeof(dir_path)); 01089 strncat(dir_path, "/", sizeof(dir_path) - 1); 01090 strncat(dir_path, class->dir, sizeof(dir_path) - 1); 01091 } else { 01092 ast_copy_string(dir_path, class->dir, sizeof(dir_path)); 01093 } 01094 ast_debug(4, "Scanning '%s' for files for class '%s'\n", dir_path, class->name); 01095 files_DIR = opendir(dir_path); 01096 if (!files_DIR) { 01097 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", dir_path); 01098 return -1; 01099 } 01100 01101 for (i = 0; i < class->total_files; i++) 01102 ast_free(class->filearray[i]); 01103 01104 class->total_files = 0; 01105 if (!getcwd(path, sizeof(path))) { 01106 ast_log(LOG_WARNING, "getcwd() failed: %s\n", strerror(errno)); 01107 return -1; 01108 } 01109 if (chdir(dir_path) < 0) { 01110 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 01111 return -1; 01112 } 01113 while ((files_dirent = readdir(files_DIR))) { 01114 /* The file name must be at least long enough to have the file type extension */ 01115 if ((strlen(files_dirent->d_name) < 4)) 01116 continue; 01117 01118 /* Skip files that starts with a dot */ 01119 if (files_dirent->d_name[0] == '.') 01120 continue; 01121 01122 /* Skip files without extensions... they are not audio */ 01123 if (!strchr(files_dirent->d_name, '.')) 01124 continue; 01125 01126 snprintf(filepath, sizeof(filepath), "%s/%s", dir_path, files_dirent->d_name); 01127 01128 if (stat(filepath, &statbuf)) 01129 continue; 01130 01131 if (!S_ISREG(statbuf.st_mode)) 01132 continue; 01133 01134 if ((ext = strrchr(filepath, '.'))) 01135 *ext = '\0'; 01136 01137 /* if the file is present in multiple formats, ensure we only put it into the list once */ 01138 for (i = 0; i < class->total_files; i++) 01139 if (!strcmp(filepath, class->filearray[i])) 01140 break; 01141 01142 if (i == class->total_files) { 01143 if (moh_add_file(class, filepath)) 01144 break; 01145 } 01146 } 01147 01148 closedir(files_DIR); 01149 if (chdir(path) < 0) { 01150 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 01151 return -1; 01152 } 01153 if (ast_test_flag(class, MOH_SORTALPHA)) 01154 qsort(&class->filearray[0], class->total_files, sizeof(char *), moh_sort_compare); 01155 return class->total_files; 01156 }
| static int moh_sort_compare | ( | const void * | i1, | |
| const void * | i2 | |||
| ) | [static] |
Definition at line 1066 of file res_musiconhold.c.
Referenced by moh_scan_files().
01067 { 01068 char *s1, *s2; 01069 01070 s1 = ((char **)i1)[0]; 01071 s2 = ((char **)i2)[0]; 01072 01073 return strcasecmp(s1, s2); 01074 }
Definition at line 904 of file res_musiconhold.c.
References ao2_lock, ao2_unlock, ast_calloc, ast_format_copy(), AST_FRAME_VOICE, ast_free, AST_FRIENDLY_OFFSET, AST_LIST_INSERT_HEAD, ast_log(), errno, mohdata::f, mohclass::flags, mohclass::format, ast_frame_subclass::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().
00905 { 00906 struct mohdata *moh; 00907 long flags; 00908 00909 if (!(moh = ast_calloc(1, sizeof(*moh)))) 00910 return NULL; 00911 00912 if (pipe(moh->pipe)) { 00913 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno)); 00914 ast_free(moh); 00915 return NULL; 00916 } 00917 00918 /* Make entirely non-blocking */ 00919 flags = fcntl(moh->pipe[0], F_GETFL); 00920 fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK); 00921 flags = fcntl(moh->pipe[1], F_GETFL); 00922 fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK); 00923 00924 moh->f.frametype = AST_FRAME_VOICE; 00925 ast_format_copy(&moh->f.subclass.format, &cl->format); 00926 moh->f.offset = AST_FRIENDLY_OFFSET; 00927 00928 moh->parent = mohclass_ref(cl, "Reffing music class for mohdata parent"); 00929 00930 ao2_lock(cl); 00931 AST_LIST_INSERT_HEAD(&cl->members, moh, list); 00932 ao2_unlock(cl); 00933 00934 return moh; 00935 }
| static void* monmp3thread | ( | void * | data | ) | [static] |
Definition at line 663 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_poll, ast_samp2tv(), ast_timer_ack(), ast_timer_fd(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), 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().
00664 { 00665 #define MOH_MS_INTERVAL 100 00666 00667 struct mohclass *class = data; 00668 struct mohdata *moh; 00669 short sbuf[8192]; 00670 int res = 0, res2; 00671 int len; 00672 struct timeval deadline, tv_tmp; 00673 00674 deadline.tv_sec = 0; 00675 deadline.tv_usec = 0; 00676 for(;/* ever */;) { 00677 pthread_testcancel(); 00678 /* Spawn mp3 player if it's not there */ 00679 if (class->srcfd < 0) { 00680 if ((class->srcfd = spawn_mp3(class)) < 0) { 00681 ast_log(LOG_WARNING, "Unable to spawn mp3player\n"); 00682 /* Try again later */ 00683 sleep(500); 00684 pthread_testcancel(); 00685 } 00686 } 00687 if (class->timer) { 00688 struct pollfd pfd = { .fd = ast_timer_fd(class->timer), .events = POLLIN | POLLPRI, }; 00689 00690 #ifdef SOLARIS 00691 thr_yield(); 00692 #endif 00693 /* Pause some amount of time */ 00694 if (ast_poll(&pfd, 1, -1) > 0) { 00695 ast_timer_ack(class->timer, 1); 00696 res = 320; 00697 } else { 00698 ast_log(LOG_WARNING, "poll() failed: %s\n", strerror(errno)); 00699 res = 0; 00700 } 00701 pthread_testcancel(); 00702 } else { 00703 long delta; 00704 /* Reliable sleep */ 00705 tv_tmp = ast_tvnow(); 00706 if (ast_tvzero(deadline)) 00707 deadline = tv_tmp; 00708 delta = ast_tvdiff_ms(tv_tmp, deadline); 00709 if (delta < MOH_MS_INTERVAL) { /* too early */ 00710 deadline = ast_tvadd(deadline, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */ 00711 usleep(1000 * (MOH_MS_INTERVAL - delta)); 00712 pthread_testcancel(); 00713 } else { 00714 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n"); 00715 deadline = tv_tmp; 00716 } 00717 res = 8 * MOH_MS_INTERVAL; /* 8 samples per millisecond */ 00718 } 00719 if ((strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir")) && AST_LIST_EMPTY(&class->members)) 00720 continue; 00721 /* Read mp3 audio */ 00722 len = ast_codec_get_len(&class->format, res); 00723 00724 if ((res2 = read(class->srcfd, sbuf, len)) != len) { 00725 if (!res2) { 00726 close(class->srcfd); 00727 class->srcfd = -1; 00728 pthread_testcancel(); 00729 if (class->pid > 1) { 00730 do { 00731 if (killpg(class->pid, SIGHUP) < 0) { 00732 if (errno == ESRCH) { 00733 break; 00734 } 00735 ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno)); 00736 } 00737 usleep(100000); 00738 if (killpg(class->pid, SIGTERM) < 0) { 00739 if (errno == ESRCH) { 00740 break; 00741 } 00742 ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno)); 00743 } 00744 usleep(100000); 00745 if (killpg(class->pid, SIGKILL) < 0) { 00746 if (errno == ESRCH) { 00747 break; 00748 } 00749 ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno)); 00750 } 00751 } while (0); 00752 class->pid = 0; 00753 } 00754 } else { 00755 ast_debug(1, "Read %d bytes of audio while expecting %d\n", res2, len); 00756 } 00757 continue; 00758 } 00759 00760 pthread_testcancel(); 00761 00762 ao2_lock(class); 00763 AST_LIST_TRAVERSE(&class->members, moh, list) { 00764 /* Write data */ 00765 if ((res = write(moh->pipe[1], sbuf, res2)) != res2) { 00766 ast_debug(1, "Only wrote %d of %d bytes to pipe\n", res, res2); 00767 } 00768 } 00769 ao2_unlock(class); 00770 } 00771 return NULL; 00772 }
| static int play_moh_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
Definition at line 774 of file res_musiconhold.c.
References mohclass::args, AST_APP_ARG, ast_channel_name(), 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().
00775 { 00776 char *parse; 00777 char *class; 00778 int timeout = -1; 00779 int res; 00780 AST_DECLARE_APP_ARGS(args, 00781 AST_APP_ARG(class); 00782 AST_APP_ARG(duration); 00783 ); 00784 00785 parse = ast_strdupa(data); 00786 00787 AST_STANDARD_APP_ARGS(args, parse); 00788 00789 if (!ast_strlen_zero(args.duration)) { 00790 if (sscanf(args.duration, "%30d", &timeout) == 1) { 00791 timeout *= 1000; 00792 } else { 00793 ast_log(LOG_WARNING, "Invalid MusicOnHold duration '%s'. Will wait indefinitely.\n", args.duration); 00794 } 00795 } 00796 00797 class = S_OR(args.class, NULL); 00798 if (ast_moh_start(chan, class, NULL)) { 00799 ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, ast_channel_name(chan)); 00800 return 0; 00801 } 00802 00803 if (timeout > 0) 00804 res = ast_safe_sleep(chan, timeout); 00805 else { 00806 while (!(res = ast_safe_sleep(chan, 10000))); 00807 } 00808 00809 ast_moh_stop(chan); 00810 00811 return res; 00812 }
| static int reload | ( | void | ) | [static] |
| static int set_moh_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
Definition at line 837 of file res_musiconhold.c.
References ast_log(), ast_strlen_zero(), and LOG_WARNING.
Referenced by load_module().
00838 { 00839 static int deprecation_warning = 0; 00840 00841 if (!deprecation_warning) { 00842 deprecation_warning = 1; 00843 ast_log(LOG_WARNING, "SetMusicOnHold application is deprecated and will be removed. Use Set(CHANNEL(musicclass)=...) instead\n"); 00844 } 00845 00846 if (ast_strlen_zero(data)) { 00847 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n"); 00848 return -1; 00849 } 00850 ast_channel_musicclass_set(chan, data); 00851 return 0; 00852 }
| static int spawn_mp3 | ( | struct mohclass * | class | ) | [static] |
Definition at line 522 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().
00523 { 00524 int fds[2]; 00525 int files = 0; 00526 char fns[MAX_MP3S][80]; 00527 char *argv[MAX_MP3S + 50]; 00528 char xargs[256]; 00529 char *argptr; 00530 int argc = 0; 00531 DIR *dir = NULL; 00532 struct dirent *de; 00533 00534 00535 if (!strcasecmp(class->dir, "nodir")) { 00536 files = 1; 00537 } else { 00538 dir = opendir(class->dir); 00539 if (!dir && strncasecmp(class->dir, "http://", 7)) { 00540 ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir); 00541 return -1; 00542 } 00543 } 00544 00545 if (!ast_test_flag(class, MOH_CUSTOM)) { 00546 argv[argc++] = "mpg123"; 00547 argv[argc++] = "-q"; 00548 argv[argc++] = "-s"; 00549 argv[argc++] = "--mono"; 00550 argv[argc++] = "-r"; 00551 argv[argc++] = "8000"; 00552 00553 if (!ast_test_flag(class, MOH_SINGLE)) { 00554 argv[argc++] = "-b"; 00555 argv[argc++] = "2048"; 00556 } 00557 00558 argv[argc++] = "-f"; 00559 00560 if (ast_test_flag(class, MOH_QUIET)) 00561 argv[argc++] = "4096"; 00562 else 00563 argv[argc++] = "8192"; 00564 00565 /* Look for extra arguments and add them to the list */ 00566 ast_copy_string(xargs, class->args, sizeof(xargs)); 00567 argptr = xargs; 00568 while (!ast_strlen_zero(argptr)) { 00569 argv[argc++] = argptr; 00570 strsep(&argptr, ","); 00571 } 00572 } else { 00573 /* Format arguments for argv vector */ 00574 ast_copy_string(xargs, class->args, sizeof(xargs)); 00575 argptr = xargs; 00576 while (!ast_strlen_zero(argptr)) { 00577 argv[argc++] = argptr; 00578 strsep(&argptr, " "); 00579 } 00580 } 00581 00582 if (!strncasecmp(class->dir, "http://", 7)) { 00583 ast_copy_string(fns[files], class->dir, sizeof(fns[files])); 00584 argv[argc++] = fns[files]; 00585 files++; 00586 } else if (dir) { 00587 while ((de = readdir(dir)) && (files < MAX_MP3S)) { 00588 if ((strlen(de->d_name) > 3) && 00589 ((ast_test_flag(class, MOH_CUSTOM) && 00590 (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 00591 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) || 00592 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) { 00593 ast_copy_string(fns[files], de->d_name, sizeof(fns[files])); 00594 argv[argc++] = fns[files]; 00595 files++; 00596 } 00597 } 00598 } 00599 argv[argc] = NULL; 00600 if (dir) { 00601 closedir(dir); 00602 } 00603 if (pipe(fds)) { 00604 ast_log(LOG_WARNING, "Pipe failed\n"); 00605 return -1; 00606 } 00607 if (!files) { 00608 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir); 00609 close(fds[0]); 00610 close(fds[1]); 00611 return -1; 00612 } 00613 if (!strncasecmp(class->dir, "http://", 7) && time(NULL) - class->start < respawn_time) { 00614 sleep(respawn_time - (time(NULL) - class->start)); 00615 } 00616 00617 time(&class->start); 00618 class->pid = ast_safe_fork(0); 00619 if (class->pid < 0) { 00620 close(fds[0]); 00621 close(fds[1]); 00622 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno)); 00623 return -1; 00624 } 00625 if (!class->pid) { 00626 if (ast_opt_high_priority) 00627 ast_set_priority(0); 00628 00629 close(fds[0]); 00630 /* Stdout goes to pipe */ 00631 dup2(fds[1], STDOUT_FILENO); 00632 00633 /* Close everything else */ 00634 ast_close_fds_above_n(STDERR_FILENO); 00635 00636 /* Child */ 00637 if (strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir") && chdir(class->dir) < 0) { 00638 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 00639 _exit(1); 00640 } 00641 setpgid(0, getpid()); 00642 if (ast_test_flag(class, MOH_CUSTOM)) { 00643 execv(argv[0], argv); 00644 } else { 00645 /* Default install is /usr/local/bin */ 00646 execv(LOCAL_MPG_123, argv); 00647 /* Many places have it in /usr/bin */ 00648 execv(MPG_123, argv); 00649 /* Check PATH as a last-ditch effort */ 00650 execvp("mpg123", argv); 00651 } 00652 /* Can't use logger, since log FDs are closed */ 00653 fprintf(stderr, "MOH: exec failed: %s\n", strerror(errno)); 00654 close(fds[1]); 00655 _exit(1); 00656 } else { 00657 /* Parent */ 00658 close(fds[1]); 00659 } 00660 return fds[0]; 00661 }
| static int start_moh_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
Definition at line 854 of file res_musiconhold.c.
References mohclass::args, AST_APP_ARG, ast_channel_name(), 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().
00855 { 00856 char *parse; 00857 char *class; 00858 AST_DECLARE_APP_ARGS(args, 00859 AST_APP_ARG(class); 00860 ); 00861 00862 parse = ast_strdupa(data); 00863 00864 AST_STANDARD_APP_ARGS(args, parse); 00865 00866 class = S_OR(args.class, NULL); 00867 if (ast_moh_start(chan, class, NULL)) 00868 ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, ast_channel_name(chan)); 00869 00870 return 0; 00871 }
| static int stop_moh_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
Definition at line 873 of file res_musiconhold.c.
References ast_moh_stop().
Referenced by load_module().
00874 { 00875 ast_moh_stop(chan); 00876 00877 return 0; 00878 }
| static int unload_module | ( | void | ) | [static] |
Definition at line 1986 of file res_musiconhold.c.
References ao2_t_callback, ARRAY_LEN, ast_cli_unregister_multiple(), ast_log(), ast_moh_destroy(), ast_uninstall_music_functions(), ast_unregister_application(), ast_unregister_atexit(), LOG_WARNING, moh_class_inuse(), and mohclass_unref.
01987 { 01988 int res = 0; 01989 struct mohclass *class = NULL; 01990 01991 /* XXX This check shouldn't be required if module ref counting was being used 01992 * properly ... */ 01993 if ((class = ao2_t_callback(mohclasses, 0, moh_class_inuse, NULL, "Module unload callback"))) { 01994 class = mohclass_unref(class, "unref of class from module unload callback"); 01995 res = -1; 01996 } 01997 01998 if (res < 0) { 01999 ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n"); 02000 return res; 02001 } 02002 02003 ast_uninstall_music_functions(); 02004 02005 ast_moh_destroy(); 02006 res = ast_unregister_application(play_moh); 02007 res |= ast_unregister_application(wait_moh); 02008 res |= ast_unregister_application(set_moh); 02009 res |= ast_unregister_application(start_moh); 02010 res |= ast_unregister_application(stop_moh); 02011 ast_cli_unregister_multiple(cli_moh, ARRAY_LEN(cli_moh)); 02012 ast_unregister_atexit(ast_moh_destroy); 02013 02014 return res; 02015 }
| static int wait_moh_exec | ( | struct ast_channel * | chan, | |
| const char * | data | |||
| ) | [static] |
Definition at line 814 of file res_musiconhold.c.
References ast_channel_name(), ast_log(), ast_moh_start(), ast_moh_stop(), ast_safe_sleep(), and LOG_WARNING.
Referenced by load_module().
00815 { 00816 static int deprecation_warning = 0; 00817 int res; 00818 00819 if (!deprecation_warning) { 00820 deprecation_warning = 1; 00821 ast_log(LOG_WARNING, "WaitMusicOnHold application is deprecated and will be removed. Use MusicOnHold with duration parameter instead\n"); 00822 } 00823 00824 if (!data || !atoi(data)) { 00825 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n"); 00826 return -1; 00827 } 00828 if (ast_moh_start(chan, NULL, NULL)) { 00829 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), ast_channel_name(chan)); 00830 return 0; 00831 } 00832 res = ast_safe_sleep(chan, atoi(data) * 1000); 00833 ast_moh_stop(chan); 00834 return res; 00835 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "Music On Hold Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, } [static] |
Definition at line 2022 of file res_musiconhold.c.
struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 2022 of file res_musiconhold.c.
struct ast_cli_entry cli_moh[] [static] |
Initial value:
{
AST_CLI_DEFINE(handle_cli_moh_reload, "Reload MusicOnHold"),
AST_CLI_DEFINE(handle_cli_moh_show_classes, "List MusicOnHold classes"),
AST_CLI_DEFINE(handle_cli_moh_show_files, "List MusicOnHold file-based classes")
}
Definition at line 1916 of file res_musiconhold.c.
struct ast_flags global_flags[1] = {{0}} [static] |
global MOH_ flags
Definition at line 182 of file res_musiconhold.c.
struct ast_generator moh_file_stream [static] |
Definition at line 513 of file res_musiconhold.c.
struct ao2_container* mohclasses [static] |
Definition at line 223 of file res_musiconhold.c.
struct ast_generator mohgen [static] |
Definition at line 1036 of file res_musiconhold.c.
const char play_moh[] = "MusicOnHold" [static] |
Definition at line 147 of file res_musiconhold.c.
int respawn_time = 20 [static] |
Definition at line 153 of file res_musiconhold.c.
const char set_moh[] = "SetMusicOnHold" [static] |
Definition at line 149 of file res_musiconhold.c.
const char start_moh[] = "StartMusicOnHold" [static] |
Definition at line 150 of file res_musiconhold.c.
const char stop_moh[] = "StopMusicOnHold" [static] |
Definition at line 151 of file res_musiconhold.c.
const char wait_moh[] = "WaitMusicOnHold" [static] |
Definition at line 148 of file res_musiconhold.c.
1.5.6