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