#include "asterisk.h"
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <stdio.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 "asterisk/dahdi_compat.h"
#include <sys/capability.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/options.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/astobj2.h"
Go to the source code of this file.
Data Structures | |
struct | moh_files_state |
struct | mohclass |
struct | mohdata |
Defines | |
#define | INITIAL_NUM_FILES 8 |
#define | LOCAL_MPG_123 "/usr/local/bin/mpg123" |
#define | MAX_MP3S 256 |
#define | MOH_CUSTOM (1 << 2) |
#define | MOH_MS_INTERVAL 100 |
#define | MOH_QUIET (1 << 0) |
#define | MOH_RANDOMIZE (1 << 3) |
#define | MOH_SINGLE (1 << 1) |
#define | mohclass_ref(class) (ao2_ref((class), +1), class) |
#define | mohclass_unref(class) (ao2_ref((class), -1), (struct mohclass *) NULL) |
#define | MPG_123 "/usr/bin/mpg123" |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static void | ast_moh_destroy (void) |
static int | ast_moh_files_next (struct ast_channel *chan) |
static int | cli_files_show (int fd, int argc, char *argv[]) |
static struct mohclass * | get_mohbyname (const char *name, int warn) |
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 | moh0_exec (struct ast_channel *chan, void *data) |
static int | moh1_exec (struct ast_channel *chan, void *data) |
static int | moh2_exec (struct ast_channel *chan, void *data) |
static int | moh3_exec (struct ast_channel *chan, void *data) |
static int | moh4_exec (struct ast_channel *chan, void *data) |
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 struct mohclass * | moh_class_malloc (void) |
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_classes_show (int fd, int argc, char *argv[]) |
static int | moh_cli (int fd, int argc, char *argv[]) |
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 int | moh_register (struct mohclass *moh, int reload) |
static void | moh_release (struct ast_channel *chan, void *data) |
static int | moh_scan_files (struct mohclass *class) |
static struct mohdata * | mohalloc (struct mohclass *cl) |
static void * | monmp3thread (void *data) |
static int | reload (void) |
static int | spawn_mp3 (struct mohclass *class) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_BUILDSUM, .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 = "f450f61f60e761b3aa089ebed76ca8a5" , .load = load_module, .unload = unload_module, .reload = reload, } |
static char * | app0 = "MusicOnHold" |
static char * | app1 = "WaitMusicOnHold" |
static char * | app2 = "SetMusicOnHold" |
static char * | app3 = "StartMusicOnHold" |
static char * | app4 = "StopMusicOnHold" |
static const struct ast_module_info * | ast_module_info = &__mod_info |
static struct ast_cli_entry | cli_moh [] |
static struct ast_cli_entry | cli_moh_classes_show_deprecated |
static struct ast_cli_entry | cli_moh_files_show_deprecated |
static char * | descrip0 |
static char * | descrip1 |
static char * | descrip2 |
static char * | descrip3 |
static char * | descrip4 |
static struct ast_generator | moh_file_stream |
static struct ao2_container * | mohclasses |
static struct ast_generator | mohgen |
static int | respawn_time = 20 |
static char * | synopsis0 = "Play Music On Hold indefinitely" |
static char * | synopsis1 = "Wait, playing Music On Hold" |
static char * | synopsis2 = "Set default Music On Hold class" |
static char * | synopsis3 = "Play Music On Hold" |
static char * | synopsis4 = "Stop Playing Music On Hold" |
Definition in file res_musiconhold.c.
#define INITIAL_NUM_FILES 8 |
#define LOCAL_MPG_123 "/usr/local/bin/mpg123" |
Definition at line 174 of file res_musiconhold.c.
#define MAX_MP3S 256 |
#define MOH_CUSTOM (1 << 2) |
Definition at line 134 of file res_musiconhold.c.
Referenced by init_app_class(), moh_classes_show(), and spawn_mp3().
#define MOH_MS_INTERVAL 100 |
Referenced by monmp3thread().
#define MOH_QUIET (1 << 0) |
#define MOH_RANDOMIZE (1 << 3) |
Definition at line 135 of file res_musiconhold.c.
Referenced by ast_moh_files_next(), init_files_class(), and moh_files_alloc().
#define MOH_SINGLE (1 << 1) |
#define mohclass_ref | ( | class | ) | (ao2_ref((class), +1), class) |
#define mohclass_unref | ( | class | ) | (ao2_ref((class), -1), (struct mohclass *) NULL) |
Definition at line 181 of file res_musiconhold.c.
Referenced by cli_files_show(), local_ast_moh_start(), moh_classes_show(), moh_files_release(), moh_register(), moh_release(), and unload_module().
#define MPG_123 "/usr/bin/mpg123" |
Definition at line 175 of file res_musiconhold.c.
static void __reg_module | ( | void | ) | [static] |
Definition at line 1493 of file res_musiconhold.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1493 of file res_musiconhold.c.
static void ast_moh_destroy | ( | void | ) | [static] |
Definition at line 1310 of file res_musiconhold.c.
References ao2_callback(), ast_verbose(), option_verbose, and VERBOSE_PREFIX_2.
Referenced by load_module(), and unload_module().
01311 { 01312 if (option_verbose > 1) { 01313 ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n"); 01314 } 01315 01316 ao2_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL); 01317 }
static int ast_moh_files_next | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 212 of file res_musiconhold.c.
References ast_closestream(), ast_fileexists(), ast_log(), ast_openstream_full(), ast_random(), ast_test_flag, 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().
00213 { 00214 struct moh_files_state *state = chan->music_state; 00215 int tries; 00216 00217 /* Discontinue a stream if it is running already */ 00218 if (chan->stream) { 00219 ast_closestream(chan->stream); 00220 chan->stream = NULL; 00221 } 00222 00223 if (!state->class->total_files) { 00224 ast_log(LOG_WARNING, "No files available for class '%s'\n", state->class->name); 00225 return -1; 00226 } 00227 00228 /* If a specific file has been saved confirm it still exists and that it is still valid */ 00229 if (state->save_pos >= 0 && state->save_pos < state->class->total_files && state->class->filearray[state->save_pos] == state->save_pos_filename) { 00230 state->pos = state->save_pos; 00231 state->save_pos = -1; 00232 } else if (ast_test_flag(state->class, MOH_RANDOMIZE)) { 00233 /* Get a random file and ensure we can open it */ 00234 for (tries = 0; tries < 20; tries++) { 00235 state->pos = ast_random() % state->class->total_files; 00236 if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0) 00237 break; 00238 } 00239 state->save_pos = -1; 00240 state->samples = 0; 00241 } else { 00242 /* This is easy, just increment our position and make sure we don't exceed the total file count */ 00243 state->pos++; 00244 state->pos %= state->class->total_files; 00245 state->save_pos = -1; 00246 state->samples = 0; 00247 } 00248 00249 if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) { 00250 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno)); 00251 state->pos++; 00252 state->pos %= state->class->total_files; 00253 return -1; 00254 } 00255 00256 /* Record the pointer to the filename for position resuming later */ 00257 state->save_pos_filename = state->class->filearray[state->pos]; 00258 00259 if (option_debug) 00260 ast_log(LOG_DEBUG, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]); 00261 00262 if (state->samples) 00263 ast_seekstream(chan->stream, state->samples, SEEK_SET); 00264 00265 return 0; 00266 }
static int cli_files_show | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1325 of file res_musiconhold.c.
References ao2_iterator_init(), ao2_iterator_next(), ast_cli(), and mohclass_unref.
01326 { 01327 struct mohclass *class; 01328 struct ao2_iterator i; 01329 01330 i = ao2_iterator_init(mohclasses, 0); 01331 01332 for (; (class = ao2_iterator_next(&i)); mohclass_unref(class)) { 01333 int x; 01334 01335 if (!class->total_files) { 01336 continue; 01337 } 01338 01339 ast_cli(fd, "Class: %s\n", class->name); 01340 01341 for (x = 0; x < class->total_files; x++) { 01342 ast_cli(fd, "\tFile: %s\n", class->filearray[x]); 01343 } 01344 } 01345 01346 return 0; 01347 }
static struct mohclass* get_mohbyname | ( | const char * | name, | |
int | warn | |||
) | [static] |
Definition at line 653 of file res_musiconhold.c.
References ao2_find(), ast_copy_string(), ast_log(), mohclass::flags, LOG_WARNING, moh, and mohclass::name.
Referenced by local_ast_moh_start(), and moh_register().
00654 { 00655 struct mohclass *moh = NULL; 00656 struct mohclass tmp_class = { 00657 .flags = 0, 00658 }; 00659 00660 ast_copy_string(tmp_class.name, name, sizeof(tmp_class.name)); 00661 00662 moh = ao2_find(mohclasses, &tmp_class, 0); 00663 00664 if (!moh && warn) { 00665 ast_log(LOG_WARNING, "Music on Hold class '%s' not found\n", name); 00666 } 00667 00668 return moh; 00669 }
static int init_app_class | ( | struct mohclass * | class | ) | [static] |
Definition at line 909 of file res_musiconhold.c.
References ast_log(), ast_pthread_create_background, ast_set_flag, DAHDI_FILE_PSEUDO, LOG_WARNING, mohclass::mode, MOH_CUSTOM, MOH_QUIET, MOH_SINGLE, monmp3thread(), mohclass::pseudofd, and mohclass::thread.
Referenced by moh_register().
00910 { 00911 #ifdef HAVE_DAHDI 00912 int x; 00913 #endif 00914 00915 if (!strcasecmp(class->mode, "custom")) { 00916 ast_set_flag(class, MOH_CUSTOM); 00917 } else if (!strcasecmp(class->mode, "mp3nb")) { 00918 ast_set_flag(class, MOH_SINGLE); 00919 } else if (!strcasecmp(class->mode, "quietmp3nb")) { 00920 ast_set_flag(class, MOH_SINGLE | MOH_QUIET); 00921 } else if (!strcasecmp(class->mode, "quietmp3")) { 00922 ast_set_flag(class, MOH_QUIET); 00923 } 00924 00925 class->srcfd = -1; 00926 class->pseudofd = -1; 00927 00928 #ifdef HAVE_DAHDI 00929 /* Open /dev/zap/pseudo for timing... Is 00930 there a better, yet reliable way to do this? */ 00931 class->pseudofd = open(DAHDI_FILE_PSEUDO, O_RDONLY); 00932 if (class->pseudofd < 0) { 00933 ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n"); 00934 } else { 00935 x = 320; 00936 ioctl(class->pseudofd, DAHDI_SET_BLOCKSIZE, &x); 00937 } 00938 #endif 00939 00940 if (ast_pthread_create_background(&class->thread, NULL, monmp3thread, class)) { 00941 ast_log(LOG_WARNING, "Unable to create moh thread...\n"); 00942 if (class->pseudofd > -1) { 00943 close(class->pseudofd); 00944 class->pseudofd = -1; 00945 } 00946 return -1; 00947 } 00948 00949 return 0; 00950 }
static int init_files_class | ( | struct mohclass * | class | ) | [static] |
Definition at line 884 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().
00885 { 00886 int res; 00887 00888 res = moh_scan_files(class); 00889 00890 if (res < 0) { 00891 return -1; 00892 } 00893 00894 if (!res) { 00895 if (option_verbose > 2) { 00896 ast_verbose(VERBOSE_PREFIX_3 "Files not found in %s for moh class:%s\n", 00897 class->dir, class->name); 00898 } 00899 return -1; 00900 } 00901 00902 if (strchr(class->args, 'r')) { 00903 ast_set_flag(class, MOH_RANDOMIZE); 00904 } 00905 00906 return 0; 00907 }
static int load_module | ( | void | ) | [static] |
Definition at line 1409 of file res_musiconhold.c.
References ao2_container_alloc(), ARRAY_LEN, 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, moh0_exec(), moh1_exec(), moh2_exec(), moh3_exec(), moh4_exec(), moh_class_cmp(), and moh_class_hash().
01410 { 01411 int res; 01412 01413 if (!(mohclasses = ao2_container_alloc(53, moh_class_hash, moh_class_cmp))) { 01414 return AST_MODULE_LOAD_DECLINE; 01415 } 01416 01417 if (!load_moh_classes(0)) { /* No music classes configured, so skip it */ 01418 ast_log(LOG_WARNING, "No music on hold classes configured, " 01419 "disabling music on hold.\n"); 01420 } else { 01421 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, 01422 local_ast_moh_cleanup); 01423 } 01424 01425 res = ast_register_application(app0, moh0_exec, synopsis0, descrip0); 01426 ast_register_atexit(ast_moh_destroy); 01427 ast_cli_register_multiple(cli_moh, ARRAY_LEN(cli_moh)); 01428 if (!res) 01429 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1); 01430 if (!res) 01431 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2); 01432 if (!res) 01433 res = ast_register_application(app3, moh3_exec, synopsis3, descrip3); 01434 if (!res) 01435 res = ast_register_application(app4, moh4_exec, synopsis4, descrip4); 01436 01437 return AST_MODULE_LOAD_SUCCESS; 01438 }
static int load_moh_classes | ( | int | reload | ) | [static] |
Definition at line 1148 of file res_musiconhold.c.
References ao2_callback(), mohclass::args, ast_category_browse(), ast_config_load(), ast_copy_string(), ast_variable_browse(), moh_class_malloc(), moh_class_mark(), and var.
Referenced by load_module(), and reload().
01149 { 01150 struct ast_config *cfg; 01151 struct ast_variable *var; 01152 struct mohclass *class; 01153 char *data; 01154 char *args; 01155 char *cat; 01156 int numclasses = 0; 01157 static int dep_warning = 0; 01158 01159 cfg = ast_config_load("musiconhold.conf"); 01160 01161 if (!cfg) { 01162 return 0; 01163 } 01164 01165 if (reload) { 01166 ao2_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL); 01167 } 01168 01169 cat = ast_category_browse(cfg, NULL); 01170 for (; cat; cat = ast_category_browse(cfg, cat)) { 01171 if (!strcasecmp(cat, "classes") || !strcasecmp(cat, "moh_files")) { 01172 continue; 01173 } 01174 01175 if (!(class = moh_class_malloc())) { 01176 break; 01177 } 01178 01179 ast_copy_string(class->name, cat, sizeof(class->name)); 01180 01181 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 01182 if (!strcasecmp(var->name, "mode")) { 01183 ast_copy_string(class->mode, var->value, sizeof(class->mode)); 01184 } else if (!strcasecmp(var->name, "directory")) { 01185 ast_copy_string(class->dir, var->value, sizeof(class->dir)); 01186 } else if (!strcasecmp(var->name, "application")) { 01187 ast_copy_string(class->args, var->value, sizeof(class->args)); 01188 } else if (!strcasecmp(var->name, "random")) { 01189 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE); 01190 } else if (!strcasecmp(var->name, "format")) { 01191 class->format = ast_getformatbyname(var->value); 01192 if (!class->format) { 01193 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value); 01194 class->format = AST_FORMAT_SLINEAR; 01195 } 01196 } 01197 } 01198 01199 if (ast_strlen_zero(class->dir)) { 01200 if (!strcasecmp(class->mode, "custom")) { 01201 ast_copy_string(class->dir, "nodir", sizeof(class->dir)); 01202 } else { 01203 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name); 01204 class = mohclass_unref(class); 01205 continue; 01206 } 01207 } 01208 01209 if (ast_strlen_zero(class->mode)) { 01210 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name); 01211 class = mohclass_unref(class); 01212 continue; 01213 } 01214 01215 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) { 01216 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name); 01217 class = mohclass_unref(class); 01218 continue; 01219 } 01220 01221 /* Don't leak a class when it's already registered */ 01222 moh_register(class, reload); 01223 01224 numclasses++; 01225 } 01226 01227 01228 /* Deprecated Old-School Configuration */ 01229 for (var = ast_variable_browse(cfg, "classes"); var; var = var->next) { 01230 struct mohclass *tmp_class; 01231 01232 if (!dep_warning) { 01233 ast_log(LOG_WARNING, "The old musiconhold.conf syntax has been deprecated! Please refer to the sample configuration for information on the new syntax.\n"); 01234 dep_warning = 1; 01235 } 01236 01237 if (!(data = strchr(var->value, ':'))) { 01238 continue; 01239 } 01240 *data++ = '\0'; 01241 01242 if ((args = strchr(data, ','))) { 01243 *args++ = '\0'; 01244 } 01245 01246 if ((tmp_class = get_mohbyname(var->name, 0))) { 01247 tmp_class = mohclass_unref(tmp_class); 01248 continue; 01249 } 01250 01251 if (!(class = moh_class_malloc())) { 01252 break; 01253 } 01254 01255 ast_copy_string(class->name, var->name, sizeof(class->name)); 01256 ast_copy_string(class->dir, data, sizeof(class->dir)); 01257 ast_copy_string(class->mode, var->value, sizeof(class->mode)); 01258 if (args) { 01259 ast_copy_string(class->args, args, sizeof(class->args)); 01260 } 01261 01262 moh_register(class, reload); 01263 class = NULL; 01264 01265 numclasses++; 01266 } 01267 01268 for (var = ast_variable_browse(cfg, "moh_files"); var; var = var->next) { 01269 struct mohclass *tmp_class; 01270 01271 if (!dep_warning) { 01272 ast_log(LOG_WARNING, "The old musiconhold.conf syntax has been deprecated! Please refer to the sample configuration for information on the new syntax.\n"); 01273 dep_warning = 1; 01274 } 01275 01276 if ((tmp_class = get_mohbyname(var->name, 0))) { 01277 tmp_class = mohclass_unref(tmp_class); 01278 continue; 01279 } 01280 01281 if ((args = strchr(var->value, ','))) { 01282 *args++ = '\0'; 01283 } 01284 01285 if (!(class = moh_class_malloc())) { 01286 break; 01287 } 01288 01289 ast_copy_string(class->name, var->name, sizeof(class->name)); 01290 ast_copy_string(class->dir, var->value, sizeof(class->dir)); 01291 ast_copy_string(class->mode, "files", sizeof(class->mode)); 01292 if (args) { 01293 ast_copy_string(class->args, args, sizeof(class->args)); 01294 } 01295 01296 moh_register(class, reload); 01297 class = NULL; 01298 01299 numclasses++; 01300 } 01301 01302 ast_config_destroy(cfg); 01303 01304 ao2_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, 01305 moh_classes_delete_marked, NULL); 01306 01307 return numclasses; 01308 }
static void local_ast_moh_cleanup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 997 of file res_musiconhold.c.
References free, and ast_channel::music_state.
Referenced by load_module(), and reload().
00998 { 00999 if (chan->music_state) { 01000 free(chan->music_state); 01001 chan->music_state = NULL; 01002 } 01003 }
static int local_ast_moh_start | ( | struct ast_channel * | chan, | |
const char * | mclass, | |||
const char * | interpclass | |||
) | [static] |
Definition at line 1005 of file res_musiconhold.c.
References ast_activate_generator(), AST_FLAG_MOH, ast_set_flag, ast_strlen_zero(), get_mohbyname(), moh_file_stream, mohclass_unref, mohgen, ast_channel::musicclass, and mohclass::total_files.
Referenced by load_module(), and reload().
01006 { 01007 struct mohclass *mohclass = NULL; 01008 int res; 01009 01010 /* The following is the order of preference for which class to use: 01011 * 1) The channels explicitly set musicclass, which should *only* be 01012 * set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan. 01013 * 2) The mclass argument. If a channel is calling ast_moh_start() as the 01014 * result of receiving a HOLD control frame, this should be the 01015 * payload that came with the frame. 01016 * 3) The interpclass argument. This would be from the mohinterpret 01017 * option from channel drivers. This is the same as the old musicclass 01018 * option. 01019 * 4) The default class. 01020 */ 01021 if (!ast_strlen_zero(chan->musicclass)) { 01022 mohclass = get_mohbyname(chan->musicclass, 1); 01023 } 01024 if (!mohclass && !ast_strlen_zero(mclass)) { 01025 mohclass = get_mohbyname(mclass, 1); 01026 } 01027 if (!mohclass && !ast_strlen_zero(interpclass)) { 01028 mohclass = get_mohbyname(interpclass, 1); 01029 } 01030 if (!mohclass) { 01031 mohclass = get_mohbyname("default", 1); 01032 } 01033 01034 if (!mohclass) { 01035 return -1; 01036 } 01037 01038 ast_set_flag(chan, AST_FLAG_MOH); 01039 01040 if (mohclass->total_files) { 01041 res = ast_activate_generator(chan, &moh_file_stream, mohclass); 01042 } else { 01043 res = ast_activate_generator(chan, &mohgen, mohclass); 01044 } 01045 01046 mohclass = mohclass_unref(mohclass); 01047 01048 return res; 01049 }
static void local_ast_moh_stop | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1051 of file res_musiconhold.c.
References ast_clear_flag, ast_closestream(), ast_deactivate_generator(), AST_FLAG_MOH, ast_channel::music_state, and ast_channel::stream.
Referenced by load_module(), and reload().
01052 { 01053 ast_clear_flag(chan, AST_FLAG_MOH); 01054 ast_deactivate_generator(chan); 01055 01056 if (chan->music_state) { 01057 if (chan->stream) { 01058 ast_closestream(chan->stream); 01059 chan->stream = NULL; 01060 } 01061 } 01062 }
static int moh0_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 598 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().
00599 { 00600 if (ast_moh_start(chan, data, NULL)) { 00601 ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name); 00602 return 0; 00603 } 00604 while (!ast_safe_sleep(chan, 10000)); 00605 ast_moh_stop(chan); 00606 return -1; 00607 }
static int moh1_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 609 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().
00610 { 00611 int res; 00612 if (!data || !atoi(data)) { 00613 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n"); 00614 return -1; 00615 } 00616 if (ast_moh_start(chan, NULL, NULL)) { 00617 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name); 00618 return 0; 00619 } 00620 res = ast_safe_sleep(chan, atoi(data) * 1000); 00621 ast_moh_stop(chan); 00622 return res; 00623 }
static int moh2_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 625 of file res_musiconhold.c.
References ast_log(), ast_string_field_set, ast_strlen_zero(), LOG_WARNING, and musicclass.
Referenced by load_module().
00626 { 00627 if (ast_strlen_zero(data)) { 00628 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n"); 00629 return -1; 00630 } 00631 ast_string_field_set(chan, musicclass, data); 00632 return 0; 00633 }
static int moh3_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 635 of file res_musiconhold.c.
References ast_log(), ast_moh_start(), and LOG_NOTICE.
Referenced by load_module().
00636 { 00637 char *class = NULL; 00638 if (data && strlen(data)) 00639 class = data; 00640 if (ast_moh_start(chan, class, NULL)) 00641 ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name); 00642 00643 return 0; 00644 }
static int moh4_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 646 of file res_musiconhold.c.
References ast_moh_stop().
Referenced by load_module().
00647 { 00648 ast_moh_stop(chan); 00649 00650 return 0; 00651 }
static int moh_add_file | ( | struct mohclass * | class, | |
const char * | filepath | |||
) | [static] |
Definition at line 786 of file res_musiconhold.c.
References mohclass::allowed_files, ast_calloc, ast_realloc, ast_strdup, mohclass::filearray, INITIAL_NUM_FILES, and mohclass::total_files.
00787 { 00788 if (!class->allowed_files) { 00789 if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray)))) 00790 return -1; 00791 class->allowed_files = INITIAL_NUM_FILES; 00792 } else if (class->total_files == class->allowed_files) { 00793 if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) { 00794 class->allowed_files = 0; 00795 class->total_files = 0; 00796 return -1; 00797 } 00798 class->allowed_files *= 2; 00799 } 00800 00801 if (!(class->filearray[class->total_files] = ast_strdup(filepath))) 00802 return -1; 00803 00804 class->total_files++; 00805 00806 return 0; 00807 }
static void* moh_alloc | ( | struct ast_channel * | chan, | |
void * | params | |||
) | [static] |
Definition at line 734 of file res_musiconhold.c.
References ast_codec2str(), ast_log(), ast_set_write_format(), ast_verbose(), LOG_WARNING, moh_release(), mohalloc(), ast_channel::name, option_verbose, mohdata::origwfmt, VERBOSE_PREFIX_3, and ast_channel::writeformat.
00735 { 00736 struct mohdata *res; 00737 struct mohclass *class = params; 00738 00739 if ((res = mohalloc(class))) { 00740 res->origwfmt = chan->writeformat; 00741 if (ast_set_write_format(chan, class->format)) { 00742 ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format)); 00743 moh_release(NULL, res); 00744 res = NULL; 00745 } 00746 if (option_verbose > 2) 00747 ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name); 00748 } 00749 return res; 00750 }
static int moh_class_cmp | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1402 of file res_musiconhold.c.
Referenced by load_module().
01403 { 01404 struct mohclass *class = obj, *class2 = arg; 01405 01406 return strcasecmp(class->name, class2->name) ? 0 : CMP_MATCH | CMP_STOP; 01407 }
static void moh_class_destructor | ( | void * | obj | ) | [static] |
Definition at line 1064 of file res_musiconhold.c.
References AST_LIST_REMOVE_HEAD, ast_log(), AST_PTHREADT_NULL, ast_wait_for_input(), free, mohdata::list, and option_debug.
Referenced by moh_class_malloc().
01065 { 01066 struct mohclass *class = obj; 01067 struct mohdata *member; 01068 01069 if (option_debug) { 01070 ast_log(LOG_DEBUG, "Destroying MOH class '%s'\n", class->name); 01071 } 01072 01073 if (class->pid > 1) { 01074 char buff[8192]; 01075 int bytes, tbytes = 0, stime = 0, pid = 0; 01076 01077 ast_log(LOG_DEBUG, "killing %d!\n", class->pid); 01078 01079 stime = time(NULL) + 2; 01080 pid = class->pid; 01081 class->pid = 0; 01082 01083 /* Back when this was just mpg123, SIGKILL was fine. Now we need 01084 * to give the process a reason and time enough to kill off its 01085 * children. */ 01086 killpg(pid, SIGHUP); 01087 usleep(100000); 01088 killpg(pid, SIGTERM); 01089 usleep(100000); 01090 killpg(pid, SIGKILL); 01091 01092 while ((ast_wait_for_input(class->srcfd, 100) > 0) && 01093 (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) { 01094 tbytes = tbytes + bytes; 01095 } 01096 01097 ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes); 01098 01099 close(class->srcfd); 01100 } 01101 01102 while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) { 01103 free(member); 01104 } 01105 01106 if (class->thread) { 01107 pthread_cancel(class->thread); 01108 class->thread = AST_PTHREADT_NULL; 01109 } 01110 01111 if (class->filearray) { 01112 int i; 01113 for (i = 0; i < class->total_files; i++) { 01114 free(class->filearray[i]); 01115 } 01116 free(class->filearray); 01117 class->filearray = NULL; 01118 } 01119 }
static int moh_class_hash | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 1395 of file res_musiconhold.c.
References ast_str_case_hash().
Referenced by load_module().
01396 { 01397 const struct mohclass *class = obj; 01398 01399 return ast_str_case_hash(class->name); 01400 }
static int moh_class_inuse | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1450 of file res_musiconhold.c.
References AST_LIST_EMPTY.
Referenced by unload_module().
01451 { 01452 struct mohclass *class = obj; 01453 01454 return AST_LIST_EMPTY(&class->members) ? 0 : CMP_MATCH | CMP_STOP; 01455 }
static struct mohclass* moh_class_malloc | ( | void | ) | [static] |
Definition at line 1121 of file res_musiconhold.c.
References ao2_alloc(), AST_FORMAT_SLINEAR, mohclass::format, and moh_class_destructor().
Referenced by load_moh_classes().
01122 { 01123 struct mohclass *class; 01124 01125 if ((class = ao2_alloc(sizeof(*class), moh_class_destructor))) { 01126 class->format = AST_FORMAT_SLINEAR; 01127 } 01128 01129 return class; 01130 }
static int moh_class_mark | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1132 of file res_musiconhold.c.
Referenced by load_moh_classes().
01133 { 01134 struct mohclass *class = obj; 01135 01136 class->delete = 1; 01137 01138 return 0; 01139 }
static int moh_classes_delete_marked | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1141 of file res_musiconhold.c.
01142 { 01143 struct mohclass *class = obj; 01144 01145 return class->delete ? CMP_MATCH : 0; 01146 }
static int moh_classes_show | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1349 of file res_musiconhold.c.
References ao2_iterator_init(), ao2_iterator_next(), ast_cli(), ast_getformatname(), ast_test_flag, MOH_CUSTOM, mohclass_unref, and S_OR.
01350 { 01351 struct mohclass *class; 01352 struct ao2_iterator i; 01353 01354 i = ao2_iterator_init(mohclasses, 0); 01355 01356 for (; (class = ao2_iterator_next(&i)); mohclass_unref(class)) { 01357 ast_cli(fd, "Class: %s\n", class->name); 01358 ast_cli(fd, "\tMode: %s\n", S_OR(class->mode, "<none>")); 01359 ast_cli(fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>")); 01360 if (ast_test_flag(class, MOH_CUSTOM)) { 01361 ast_cli(fd, "\tApplication: %s\n", S_OR(class->args, "<none>")); 01362 } 01363 if (strcasecmp(class->mode, "files")) { 01364 ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format)); 01365 } 01366 } 01367 01368 return 0; 01369 }
static int moh_cli | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1319 of file res_musiconhold.c.
References reload().
01320 { 01321 reload(); 01322 return 0; 01323 }
static void* moh_files_alloc | ( | struct ast_channel * | chan, | |
void * | params | |||
) | [static] |
Definition at line 306 of file res_musiconhold.c.
References ast_calloc, ast_random(), ast_test_flag, ast_verbose(), MOH_RANDOMIZE, mohclass_ref, ast_channel::music_state, ast_channel::name, option_verbose, VERBOSE_PREFIX_3, and ast_channel::writeformat.
00307 { 00308 struct moh_files_state *state; 00309 struct mohclass *class = params; 00310 00311 if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) { 00312 chan->music_state = state; 00313 } else { 00314 state = chan->music_state; 00315 } 00316 00317 if (!state) { 00318 return NULL; 00319 } 00320 00321 if (state->class != class) { 00322 memset(state, 0, sizeof(*state)); 00323 if (ast_test_flag(class, MOH_RANDOMIZE) && class->total_files) { 00324 state->pos = ast_random() % class->total_files; 00325 } 00326 } 00327 00328 state->class = mohclass_ref(class); 00329 state->origwfmt = chan->writeformat; 00330 00331 if (option_verbose > 2) { 00332 ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", 00333 class->name, chan->name); 00334 } 00335 00336 return chan->music_state; 00337 }
static int moh_files_generator | ( | struct ast_channel * | chan, | |
void * | data, | |||
int | len, | |||
int | samples | |||
) | [static] |
Definition at line 281 of file res_musiconhold.c.
References ast_frfree, ast_log(), ast_write(), errno, f, LOG_WARNING, moh_files_readframe(), ast_channel::music_state, ast_channel::name, moh_files_state::sample_queue, and moh_files_state::samples.
00282 { 00283 struct moh_files_state *state = chan->music_state; 00284 struct ast_frame *f = NULL; 00285 int res = 0; 00286 00287 state->sample_queue += samples; 00288 00289 while (state->sample_queue > 0) { 00290 if ((f = moh_files_readframe(chan))) { 00291 state->samples += f->samples; 00292 state->sample_queue -= f->samples; 00293 res = ast_write(chan, f); 00294 ast_frfree(f); 00295 if (res < 0) { 00296 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); 00297 return -1; 00298 } 00299 } else 00300 return -1; 00301 } 00302 return res; 00303 }
static struct ast_frame* moh_files_readframe | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 269 of file res_musiconhold.c.
References ast_moh_files_next(), ast_readframe(), f, and ast_channel::stream.
Referenced by moh_files_generator().
00270 { 00271 struct ast_frame *f = NULL; 00272 00273 if (!(chan->stream && (f = ast_readframe(chan->stream)))) { 00274 if (!ast_moh_files_next(chan)) 00275 f = ast_readframe(chan->stream); 00276 } 00277 00278 return f; 00279 }
static void moh_files_release | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 183 of file res_musiconhold.c.
References ast_closestream(), ast_log(), ast_set_write_format(), ast_verbose(), moh_files_state::class, LOG_WARNING, mohclass_unref, ast_channel::music_state, 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.
00184 { 00185 struct moh_files_state *state; 00186 00187 if (!chan || !chan->music_state) { 00188 return; 00189 } 00190 00191 state = chan->music_state; 00192 00193 if (chan->stream) { 00194 ast_closestream(chan->stream); 00195 chan->stream = NULL; 00196 } 00197 00198 if (option_verbose > 2) { 00199 ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name); 00200 } 00201 00202 if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) { 00203 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt); 00204 } 00205 00206 state->save_pos = state->pos; 00207 00208 mohclass_unref(state->class); 00209 }
static int moh_generate | ( | struct ast_channel * | chan, | |
void * | data, | |||
int | len, | |||
int | samples | |||
) | [static] |
Definition at line 752 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.
00753 { 00754 struct mohdata *moh = data; 00755 short buf[1280 + AST_FRIENDLY_OFFSET / 2]; 00756 int res; 00757 00758 len = ast_codec_get_len(moh->parent->format, samples); 00759 00760 if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) { 00761 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name); 00762 len = sizeof(buf) - AST_FRIENDLY_OFFSET; 00763 } 00764 res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len); 00765 if (res <= 0) 00766 return 0; 00767 00768 moh->f.datalen = res; 00769 moh->f.data = buf + AST_FRIENDLY_OFFSET / 2; 00770 moh->f.samples = ast_codec_get_samples(&moh->f); 00771 00772 if (ast_write(chan, &moh->f) < 0) { 00773 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); 00774 return -1; 00775 } 00776 00777 return 0; 00778 }
static int moh_register | ( | struct mohclass * | moh, | |
int | reload | |||
) | [static] |
Definition at line 955 of file res_musiconhold.c.
References ast_log(), mohclass::delete, get_mohbyname(), init_app_class(), init_files_class(), LOG_WARNING, moh, and mohclass_unref.
00956 { 00957 struct mohclass *mohclass = NULL; 00958 00959 if ((mohclass = get_mohbyname(moh->name, 0))) { 00960 if (!mohclass->delete) { 00961 ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name); 00962 mohclass = mohclass_unref(mohclass); 00963 moh = mohclass_unref(moh); 00964 return -1; 00965 } 00966 mohclass = mohclass_unref(mohclass); 00967 } 00968 00969 time(&moh->start); 00970 moh->start -= respawn_time; 00971 00972 if (!strcasecmp(moh->mode, "files")) { 00973 if (init_files_class(moh)) { 00974 moh = mohclass_unref(moh); 00975 return -1; 00976 } 00977 } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || 00978 !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || 00979 !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) { 00980 if (init_app_class(moh)) { 00981 moh = mohclass_unref(moh); 00982 return -1; 00983 } 00984 } else { 00985 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode); 00986 moh = mohclass_unref(moh); 00987 return -1; 00988 } 00989 00990 ao2_link(mohclasses, moh); 00991 00992 moh = mohclass_unref(moh); 00993 00994 return 0; 00995 }
static void moh_release | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 704 of file res_musiconhold.c.
References ao2_lock(), ao2_unlock(), ast_getformatname(), AST_LIST_REMOVE, ast_log(), ast_set_write_format(), ast_verbose(), free, LOG_WARNING, moh, mohclass_unref, ast_channel::name, option_verbose, and VERBOSE_PREFIX_3.
Referenced by moh_alloc().
00705 { 00706 struct mohdata *moh = data; 00707 struct mohclass *class = moh->parent; 00708 int oldwfmt; 00709 00710 ao2_lock(class); 00711 AST_LIST_REMOVE(&moh->parent->members, moh, list); 00712 ao2_unlock(class); 00713 00714 close(moh->pipe[0]); 00715 close(moh->pipe[1]); 00716 00717 oldwfmt = moh->origwfmt; 00718 00719 moh->parent = class = mohclass_unref(class); 00720 00721 free(moh); 00722 00723 if (chan) { 00724 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) { 00725 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", 00726 chan->name, ast_getformatname(oldwfmt)); 00727 } 00728 if (option_verbose > 2) { 00729 ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name); 00730 } 00731 } 00732 }
static int moh_scan_files | ( | struct mohclass * | class | ) | [static] |
Definition at line 809 of file res_musiconhold.c.
References ast_log(), mohclass::dir, errno, ext, mohclass::filearray, free, LOG_WARNING, and mohclass::total_files.
Referenced by init_files_class().
00809 { 00810 00811 DIR *files_DIR; 00812 struct dirent *files_dirent; 00813 char path[PATH_MAX]; 00814 char filepath[PATH_MAX]; 00815 char *ext; 00816 struct stat statbuf; 00817 int dirnamelen; 00818 int i; 00819 00820 files_DIR = opendir(class->dir); 00821 if (!files_DIR) { 00822 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", class->dir); 00823 return -1; 00824 } 00825 00826 for (i = 0; i < class->total_files; i++) 00827 free(class->filearray[i]); 00828 00829 class->total_files = 0; 00830 dirnamelen = strlen(class->dir) + 2; 00831 if (!getcwd(path, sizeof(path))) { 00832 ast_log(LOG_WARNING, "getcwd() failed: %s\n", strerror(errno)); 00833 return -1; 00834 } 00835 if (chdir(class->dir) < 0) { 00836 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 00837 return -1; 00838 } 00839 while ((files_dirent = readdir(files_DIR))) { 00840 /* The file name must be at least long enough to have the file type extension */ 00841 if ((strlen(files_dirent->d_name) < 4)) 00842 continue; 00843 00844 /* Skip files that starts with a dot */ 00845 if (files_dirent->d_name[0] == '.') 00846 continue; 00847 00848 /* Skip files without extensions... they are not audio */ 00849 if (!strchr(files_dirent->d_name, '.')) 00850 continue; 00851 00852 snprintf(filepath, sizeof(filepath), "%s/%s", class->dir, files_dirent->d_name); 00853 00854 if (stat(filepath, &statbuf)) 00855 continue; 00856 00857 if (!S_ISREG(statbuf.st_mode)) 00858 continue; 00859 00860 if ((ext = strrchr(filepath, '.'))) { 00861 *ext = '\0'; 00862 ext++; 00863 } 00864 00865 /* if the file is present in multiple formats, ensure we only put it into the list once */ 00866 for (i = 0; i < class->total_files; i++) 00867 if (!strcmp(filepath, class->filearray[i])) 00868 break; 00869 00870 if (i == class->total_files) { 00871 if (moh_add_file(class, filepath)) 00872 break; 00873 } 00874 } 00875 00876 closedir(files_DIR); 00877 if (chdir(path) < 0) { 00878 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 00879 return -1; 00880 } 00881 return class->total_files; 00882 }
Definition at line 671 of file res_musiconhold.c.
References ao2_lock(), ao2_unlock(), ast_calloc, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, AST_LIST_INSERT_HEAD, ast_log(), errno, mohclass::format, free, mohdata::list, LOG_WARNING, mohclass::members, moh, mohclass_ref, and mohdata::pipe.
Referenced by moh_alloc().
00672 { 00673 struct mohdata *moh; 00674 long flags; 00675 00676 if (!(moh = ast_calloc(1, sizeof(*moh)))) 00677 return NULL; 00678 00679 if (pipe(moh->pipe)) { 00680 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno)); 00681 free(moh); 00682 return NULL; 00683 } 00684 00685 /* Make entirely non-blocking */ 00686 flags = fcntl(moh->pipe[0], F_GETFL); 00687 fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK); 00688 flags = fcntl(moh->pipe[1], F_GETFL); 00689 fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK); 00690 00691 moh->f.frametype = AST_FRAME_VOICE; 00692 moh->f.subclass = cl->format; 00693 moh->f.offset = AST_FRIENDLY_OFFSET; 00694 00695 moh->parent = mohclass_ref(cl); 00696 00697 ao2_lock(cl); 00698 AST_LIST_INSERT_HEAD(&cl->members, moh, list); 00699 ao2_unlock(cl); 00700 00701 return moh; 00702 }
static void* monmp3thread | ( | void * | data | ) | [static] |
Definition at line 511 of file res_musiconhold.c.
References ao2_lock(), ao2_unlock(), ast_codec_get_len(), AST_LIST_EMPTY, AST_LIST_TRAVERSE, ast_log(), ast_samp2tv(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), len(), mohclass::list, LOG_NOTICE, LOG_WARNING, moh, MOH_MS_INTERVAL, option_debug, and spawn_mp3().
Referenced by init_app_class().
00512 { 00513 #define MOH_MS_INTERVAL 100 00514 00515 struct mohclass *class = data; 00516 struct mohdata *moh; 00517 char buf[8192]; 00518 short sbuf[8192]; 00519 int res, res2; 00520 int len; 00521 struct timeval tv, tv_tmp; 00522 00523 tv.tv_sec = 0; 00524 tv.tv_usec = 0; 00525 for(;/* ever */;) { 00526 pthread_testcancel(); 00527 /* Spawn mp3 player if it's not there */ 00528 if (class->srcfd < 0) { 00529 if ((class->srcfd = spawn_mp3(class)) < 0) { 00530 ast_log(LOG_WARNING, "Unable to spawn mp3player\n"); 00531 /* Try again later */ 00532 sleep(500); 00533 pthread_testcancel(); 00534 } 00535 } 00536 if (class->pseudofd > -1) { 00537 #ifdef SOLARIS 00538 thr_yield(); 00539 #endif 00540 /* Pause some amount of time */ 00541 res = read(class->pseudofd, buf, sizeof(buf)); 00542 pthread_testcancel(); 00543 } else { 00544 long delta; 00545 /* Reliable sleep */ 00546 tv_tmp = ast_tvnow(); 00547 if (ast_tvzero(tv)) 00548 tv = tv_tmp; 00549 delta = ast_tvdiff_ms(tv_tmp, tv); 00550 if (delta < MOH_MS_INTERVAL) { /* too early */ 00551 tv = ast_tvadd(tv, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */ 00552 usleep(1000 * (MOH_MS_INTERVAL - delta)); 00553 pthread_testcancel(); 00554 } else { 00555 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n"); 00556 tv = tv_tmp; 00557 } 00558 res = 8 * MOH_MS_INTERVAL; /* 8 samples per millisecond */ 00559 } 00560 if (AST_LIST_EMPTY(&class->members)) 00561 continue; 00562 /* Read mp3 audio */ 00563 len = ast_codec_get_len(class->format, res); 00564 00565 if ((res2 = read(class->srcfd, sbuf, len)) != len) { 00566 if (!res2) { 00567 close(class->srcfd); 00568 class->srcfd = -1; 00569 pthread_testcancel(); 00570 if (class->pid > 1) { 00571 killpg(class->pid, SIGHUP); 00572 usleep(100000); 00573 killpg(class->pid, SIGTERM); 00574 usleep(100000); 00575 killpg(class->pid, SIGKILL); 00576 class->pid = 0; 00577 } 00578 } else 00579 ast_log(LOG_DEBUG, "Read %d bytes of audio while expecting %d\n", res2, len); 00580 continue; 00581 } 00582 00583 pthread_testcancel(); 00584 00585 ao2_lock(class); 00586 AST_LIST_TRAVERSE(&class->members, moh, list) { 00587 /* Write data */ 00588 if ((res = write(moh->pipe[1], sbuf, res2)) != res2) { 00589 if (option_debug) 00590 ast_log(LOG_DEBUG, "Only wrote %d of %d bytes to pipe\n", res, res2); 00591 } 00592 } 00593 ao2_unlock(class); 00594 } 00595 return NULL; 00596 }
static int reload | ( | void | ) | [static] |
Definition at line 1440 of file res_musiconhold.c.
References ast_install_music_functions(), load_moh_classes(), local_ast_moh_cleanup(), local_ast_moh_start(), and local_ast_moh_stop().
01441 { 01442 if (load_moh_classes(1)) { 01443 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, 01444 local_ast_moh_cleanup); 01445 } 01446 01447 return 0; 01448 }
static int spawn_mp3 | ( | struct mohclass * | class | ) | [static] |
Definition at line 345 of file res_musiconhold.c.
References mohclass::args, ast_copy_string(), ast_log(), ast_opt_high_priority, 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, and mohclass::start.
Referenced by monmp3thread().
00346 { 00347 int fds[2]; 00348 int files = 0; 00349 char fns[MAX_MP3S][80]; 00350 char *argv[MAX_MP3S + 50]; 00351 char xargs[256]; 00352 char *argptr; 00353 int argc = 0; 00354 DIR *dir = NULL; 00355 struct dirent *de; 00356 sigset_t signal_set, old_set; 00357 00358 00359 if (!strcasecmp(class->dir, "nodir")) { 00360 files = 1; 00361 } else { 00362 dir = opendir(class->dir); 00363 if (!dir && strncasecmp(class->dir, "http://", 7)) { 00364 ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir); 00365 return -1; 00366 } 00367 } 00368 00369 if (!ast_test_flag(class, MOH_CUSTOM)) { 00370 argv[argc++] = "mpg123"; 00371 argv[argc++] = "-q"; 00372 argv[argc++] = "-s"; 00373 argv[argc++] = "--mono"; 00374 argv[argc++] = "-r"; 00375 argv[argc++] = "8000"; 00376 00377 if (!ast_test_flag(class, MOH_SINGLE)) { 00378 argv[argc++] = "-b"; 00379 argv[argc++] = "2048"; 00380 } 00381 00382 argv[argc++] = "-f"; 00383 00384 if (ast_test_flag(class, MOH_QUIET)) 00385 argv[argc++] = "4096"; 00386 else 00387 argv[argc++] = "8192"; 00388 00389 /* Look for extra arguments and add them to the list */ 00390 ast_copy_string(xargs, class->args, sizeof(xargs)); 00391 argptr = xargs; 00392 while (!ast_strlen_zero(argptr)) { 00393 argv[argc++] = argptr; 00394 strsep(&argptr, ","); 00395 } 00396 } else { 00397 /* Format arguments for argv vector */ 00398 ast_copy_string(xargs, class->args, sizeof(xargs)); 00399 argptr = xargs; 00400 while (!ast_strlen_zero(argptr)) { 00401 argv[argc++] = argptr; 00402 strsep(&argptr, " "); 00403 } 00404 } 00405 00406 if (!strncasecmp(class->dir, "http://", 7)) { 00407 ast_copy_string(fns[files], class->dir, sizeof(fns[files])); 00408 argv[argc++] = fns[files]; 00409 files++; 00410 } else if (dir) { 00411 while ((de = readdir(dir)) && (files < MAX_MP3S)) { 00412 if ((strlen(de->d_name) > 3) && 00413 ((ast_test_flag(class, MOH_CUSTOM) && 00414 (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 00415 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) || 00416 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) { 00417 ast_copy_string(fns[files], de->d_name, sizeof(fns[files])); 00418 argv[argc++] = fns[files]; 00419 files++; 00420 } 00421 } 00422 } 00423 argv[argc] = NULL; 00424 if (dir) { 00425 closedir(dir); 00426 } 00427 if (pipe(fds)) { 00428 ast_log(LOG_WARNING, "Pipe failed\n"); 00429 return -1; 00430 } 00431 if (!files) { 00432 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir); 00433 close(fds[0]); 00434 close(fds[1]); 00435 return -1; 00436 } 00437 if (!strncasecmp(class->dir, "http://", 7) && time(NULL) - class->start < respawn_time) { 00438 sleep(respawn_time - (time(NULL) - class->start)); 00439 } 00440 00441 /* Block signals during the fork() */ 00442 sigfillset(&signal_set); 00443 pthread_sigmask(SIG_BLOCK, &signal_set, &old_set); 00444 00445 time(&class->start); 00446 class->pid = fork(); 00447 if (class->pid < 0) { 00448 close(fds[0]); 00449 close(fds[1]); 00450 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno)); 00451 return -1; 00452 } 00453 if (!class->pid) { 00454 /* Child */ 00455 int x; 00456 #ifdef HAVE_CAP 00457 cap_t cap; 00458 #endif 00459 if (strcasecmp(class->dir, "nodir") && chdir(class->dir) < 0) { 00460 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 00461 _exit(1); 00462 } 00463 00464 if (ast_opt_high_priority) 00465 ast_set_priority(0); 00466 00467 /* Reset ignored signals back to default */ 00468 signal(SIGPIPE, SIG_DFL); 00469 pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL); 00470 00471 #ifdef HAVE_CAP 00472 cap = cap_from_text("cap_net_admin-eip"); 00473 00474 if (cap_set_proc(cap)) { 00475 ast_log(LOG_WARNING, "Unable to remove capabilities.\n"); 00476 } 00477 cap_free(cap); 00478 #endif 00479 close(fds[0]); 00480 /* Stdout goes to pipe */ 00481 dup2(fds[1], STDOUT_FILENO); 00482 /* Close unused file descriptors */ 00483 for (x=3;x<8192;x++) { 00484 if (-1 != fcntl(x, F_GETFL)) { 00485 close(x); 00486 } 00487 } 00488 setpgid(0, getpid()); 00489 00490 if (ast_test_flag(class, MOH_CUSTOM)) { 00491 execv(argv[0], argv); 00492 } else { 00493 /* Default install is /usr/local/bin */ 00494 execv(LOCAL_MPG_123, argv); 00495 /* Many places have it in /usr/bin */ 00496 execv(MPG_123, argv); 00497 /* Check PATH as a last-ditch effort */ 00498 execvp("mpg123", argv); 00499 } 00500 ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno)); 00501 close(fds[1]); 00502 _exit(1); 00503 } else { 00504 /* Parent */ 00505 pthread_sigmask(SIG_SETMASK, &old_set, NULL); 00506 close(fds[1]); 00507 } 00508 return fds[0]; 00509 }
static int unload_module | ( | void | ) | [static] |
Definition at line 1457 of file res_musiconhold.c.
References ao2_callback(), ARRAY_LEN, ast_cli_unregister_multiple(), ast_log(), ast_moh_destroy(), ast_uninstall_music_functions(), ast_unregister_application(), cli_moh, LOG_WARNING, moh_class_inuse(), and mohclass_unref.
01458 { 01459 int res = 0; 01460 struct mohclass *class = NULL; 01461 01462 /* XXX This check shouldn't be required if module ref counting was being used 01463 * properly ... */ 01464 if ((class = ao2_callback(mohclasses, 0, moh_class_inuse, NULL))) { 01465 class = mohclass_unref(class); 01466 res = -1; 01467 } 01468 01469 if (res < 0) { 01470 ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n"); 01471 return res; 01472 } 01473 01474 ast_uninstall_music_functions(); 01475 01476 ast_moh_destroy(); 01477 01478 res = ast_unregister_application(app0); 01479 res |= ast_unregister_application(app1); 01480 res |= ast_unregister_application(app2); 01481 res |= ast_unregister_application(app3); 01482 res |= ast_unregister_application(app4); 01483 01484 ast_cli_unregister_multiple(cli_moh, ARRAY_LEN(cli_moh)); 01485 01486 return res; 01487 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_BUILDSUM, .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 = "f450f61f60e761b3aa089ebed76ca8a5" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 1493 of file res_musiconhold.c.
char* app0 = "MusicOnHold" [static] |
Definition at line 83 of file res_musiconhold.c.
char* app1 = "WaitMusicOnHold" [static] |
Definition at line 84 of file res_musiconhold.c.
char* app2 = "SetMusicOnHold" [static] |
Definition at line 85 of file res_musiconhold.c.
char* app3 = "StartMusicOnHold" [static] |
Definition at line 86 of file res_musiconhold.c.
char* app4 = "StopMusicOnHold" [static] |
Definition at line 87 of file res_musiconhold.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1493 of file res_musiconhold.c.
struct ast_cli_entry cli_moh[] [static] |
Definition at line 1381 of file res_musiconhold.c.
Referenced by load_module(), and unload_module().
struct ast_cli_entry cli_moh_classes_show_deprecated [static] |
Initial value:
{ { "moh", "classes", "show"}, moh_classes_show, NULL, NULL }
Definition at line 1371 of file res_musiconhold.c.
struct ast_cli_entry cli_moh_files_show_deprecated [static] |
Initial value:
{ { "moh", "files", "show"}, cli_files_show, NULL, NULL }
Definition at line 1376 of file res_musiconhold.c.
char* descrip0 [static] |
Definition at line 95 of file res_musiconhold.c.
char* descrip1 [static] |
Initial value:
"WaitMusicOnHold(delay): " "Plays hold music specified number of seconds. Returns 0 when\n" "done, or -1 on hangup. If no hold music is available, the delay will\n" "still occur with no sound.\n"
Definition at line 102 of file res_musiconhold.c.
char* descrip2 [static] |
Initial value:
"SetMusicOnHold(class): " "Sets the default class for music on hold for a given channel. When\n" "music on hold is activated, this class will be used to select which\n" "music is played.\n"
Definition at line 107 of file res_musiconhold.c.
char* descrip3 [static] |
Initial value:
"StartMusicOnHold(class): " "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 112 of file res_musiconhold.c.
char* descrip4 [static] |
Initial value:
"StopMusicOnHold: " "Stops playing music on hold.\n"
Definition at line 117 of file res_musiconhold.c.
struct ast_generator moh_file_stream [static] |
Initial value:
{ .alloc = moh_files_alloc, .release = moh_files_release, .generate = moh_files_generator, }
Definition at line 339 of file res_musiconhold.c.
Referenced by local_ast_moh_start().
struct ao2_container* mohclasses [static] |
Definition at line 172 of file res_musiconhold.c.
struct ast_generator mohgen [static] |
Initial value:
{ .alloc = moh_alloc, .release = moh_release, .generate = moh_generate, }
Definition at line 780 of file res_musiconhold.c.
Referenced by local_ast_moh_start().
int respawn_time = 20 [static] |
Definition at line 120 of file res_musiconhold.c.
char* synopsis0 = "Play Music On Hold indefinitely" [static] |
Definition at line 89 of file res_musiconhold.c.
char* synopsis1 = "Wait, playing Music On Hold" [static] |
Definition at line 90 of file res_musiconhold.c.
char* synopsis2 = "Set default Music On Hold class" [static] |
Definition at line 91 of file res_musiconhold.c.
char* synopsis3 = "Play Music On Hold" [static] |
Definition at line 92 of file res_musiconhold.c.
char* synopsis4 = "Stop Playing Music On Hold" [static] |
Definition at line 93 of file res_musiconhold.c.