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