#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_DEFAULT | 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 = "361d7bb937402d51e4658efb5b4d76e4" , .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 133 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 134 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 1543 of file res_musiconhold.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 1543 of file res_musiconhold.c.
static void ast_moh_destroy | ( | void | ) | [static] |
Definition at line 1356 of file res_musiconhold.c.
References ao2_callback(), ast_verbose(), option_verbose, and VERBOSE_PREFIX_2.
Referenced by load_module(), and unload_module().
01357 { 01358 if (option_verbose > 1) { 01359 ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n"); 01360 } 01361 01362 ao2_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL); 01363 }
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_random(), ast_test_flag, moh_files_state::class, mohclass::filearray, LOG_WARNING, MOH_RANDOMIZE, ast_channel::music_state, mohclass::name, moh_files_state::pos, moh_files_state::samples, moh_files_state::save_pos, moh_files_state::save_pos_filename, ast_channel::stream, and mohclass::total_files.
Referenced by moh_files_readframe().
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 (state->pos == 0 && state->save_pos_filename == NULL) { 00229 /* First time so lets play the file. */ 00230 state->save_pos = -1; 00231 } else if (state->save_pos >= 0 && state->save_pos < state->class->total_files && state->class->filearray[state->save_pos] == state->save_pos_filename) { 00232 /* If a specific file has been saved confirm it still exists and that it is still valid */ 00233 state->pos = state->save_pos; 00234 state->save_pos = -1; 00235 } else if (ast_test_flag(state->class, MOH_RANDOMIZE)) { 00236 /* Get a random file and ensure we can open it */ 00237 for (tries = 0; tries < 20; tries++) { 00238 state->pos = ast_random() % state->class->total_files; 00239 if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0) { 00240 break; 00241 } 00242 } 00243 state->save_pos = -1; 00244 state->samples = 0; 00245 } else { 00246 /* This is easy, just increment our position and make sure we don't exceed the total file count */ 00247 state->pos++; 00248 state->pos %= state->class->total_files; 00249 state->save_pos = -1; 00250 state->samples = 0; 00251 } 00252 00253 for (tries = 0; tries < state->class->total_files; ++tries) { 00254 if (ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) { 00255 break; 00256 } 00257 00258 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno)); 00259 state->pos++; 00260 state->pos %= state->class->total_files; 00261 } 00262 00263 if (tries == state->class->total_files) { 00264 return -1; 00265 } 00266 00267 /* Record the pointer to the filename for position resuming later */ 00268 state->save_pos_filename = state->class->filearray[state->pos]; 00269 00270 if (option_debug) 00271 ast_log(LOG_DEBUG, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]); 00272 00273 if (state->samples) { 00274 ast_seekstream(chan->stream, state->samples, SEEK_SET); 00275 } 00276 00277 return 0; 00278 }
static int cli_files_show | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1371 of file res_musiconhold.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ast_cli(), and mohclass_unref.
01372 { 01373 struct mohclass *class; 01374 struct ao2_iterator i; 01375 01376 i = ao2_iterator_init(mohclasses, 0); 01377 01378 for (; (class = ao2_iterator_next(&i)); mohclass_unref(class)) { 01379 int x; 01380 01381 if (!class->total_files) { 01382 continue; 01383 } 01384 01385 ast_cli(fd, "Class: %s\n", class->name); 01386 01387 for (x = 0; x < class->total_files; x++) { 01388 ast_cli(fd, "\tFile: %s\n", class->filearray[x]); 01389 } 01390 } 01391 01392 ao2_iterator_destroy(&i); 01393 01394 return 0; 01395 }
static struct mohclass* get_mohbyname | ( | const char * | name, | |
int | warn | |||
) | [static] |
Definition at line 677 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().
00678 { 00679 struct mohclass *moh = NULL; 00680 struct mohclass tmp_class = { 00681 .flags = 0, 00682 }; 00683 00684 ast_copy_string(tmp_class.name, name, sizeof(tmp_class.name)); 00685 00686 moh = ao2_find(mohclasses, &tmp_class, 0); 00687 00688 if (!moh && warn) { 00689 ast_log(LOG_WARNING, "Music on Hold class '%s' not found\n", name); 00690 } 00691 00692 return moh; 00693 }
static int init_app_class | ( | struct mohclass * | class | ) | [static] |
Definition at line 934 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().
00935 { 00936 #ifdef HAVE_DAHDI 00937 int x; 00938 #endif 00939 00940 if (!strcasecmp(class->mode, "custom")) { 00941 ast_set_flag(class, MOH_CUSTOM); 00942 } else if (!strcasecmp(class->mode, "mp3nb")) { 00943 ast_set_flag(class, MOH_SINGLE); 00944 } else if (!strcasecmp(class->mode, "quietmp3nb")) { 00945 ast_set_flag(class, MOH_SINGLE | MOH_QUIET); 00946 } else if (!strcasecmp(class->mode, "quietmp3")) { 00947 ast_set_flag(class, MOH_QUIET); 00948 } 00949 00950 class->srcfd = -1; 00951 class->pseudofd = -1; 00952 00953 #ifdef HAVE_DAHDI 00954 /* Open /dev/zap/pseudo for timing... Is 00955 there a better, yet reliable way to do this? */ 00956 class->pseudofd = open(DAHDI_FILE_PSEUDO, O_RDONLY); 00957 if (class->pseudofd < 0) { 00958 ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n"); 00959 } else { 00960 x = 320; 00961 ioctl(class->pseudofd, DAHDI_SET_BLOCKSIZE, &x); 00962 } 00963 #endif 00964 00965 if (ast_pthread_create_background(&class->thread, NULL, monmp3thread, class)) { 00966 ast_log(LOG_WARNING, "Unable to create moh thread...\n"); 00967 if (class->pseudofd > -1) { 00968 close(class->pseudofd); 00969 class->pseudofd = -1; 00970 } 00971 return -1; 00972 } 00973 00974 return 0; 00975 }
static int init_files_class | ( | struct mohclass * | class | ) | [static] |
Definition at line 908 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().
00909 { 00910 int res; 00911 00912 res = moh_scan_files(class); 00913 00914 if (res < 0) { 00915 return -1; 00916 } 00917 00918 if (!res) { 00919 if (option_verbose > 2) { 00920 ast_verbose(VERBOSE_PREFIX_3 "Files not found in %s for moh class:%s\n", 00921 class->dir, class->name); 00922 } 00923 return -1; 00924 } 00925 00926 if (strchr(class->args, 'r')) { 00927 ast_set_flag(class, MOH_RANDOMIZE); 00928 } 00929 00930 return 0; 00931 }
static int load_module | ( | void | ) | [static] |
Definition at line 1459 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().
01460 { 01461 int res; 01462 01463 if (!(mohclasses = ao2_container_alloc(53, moh_class_hash, moh_class_cmp))) { 01464 return AST_MODULE_LOAD_DECLINE; 01465 } 01466 01467 if (!load_moh_classes(0)) { /* No music classes configured, so skip it */ 01468 ast_log(LOG_WARNING, "No music on hold classes configured, " 01469 "disabling music on hold.\n"); 01470 } else { 01471 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, 01472 local_ast_moh_cleanup); 01473 } 01474 01475 res = ast_register_application(app0, moh0_exec, synopsis0, descrip0); 01476 ast_register_atexit(ast_moh_destroy); 01477 ast_cli_register_multiple(cli_moh, ARRAY_LEN(cli_moh)); 01478 if (!res) 01479 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1); 01480 if (!res) 01481 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2); 01482 if (!res) 01483 res = ast_register_application(app3, moh3_exec, synopsis3, descrip3); 01484 if (!res) 01485 res = ast_register_application(app4, moh4_exec, synopsis4, descrip4); 01486 01487 return AST_MODULE_LOAD_SUCCESS; 01488 }
static int load_moh_classes | ( | int | reload | ) | [static] |
Definition at line 1190 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().
01191 { 01192 struct ast_config *cfg; 01193 struct ast_variable *var; 01194 struct mohclass *class; 01195 char *data; 01196 char *args; 01197 char *cat; 01198 int numclasses = 0; 01199 static int dep_warning = 0; 01200 01201 cfg = ast_config_load("musiconhold.conf"); 01202 01203 if (!cfg) { 01204 return 0; 01205 } 01206 01207 if (reload) { 01208 ao2_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL); 01209 } 01210 01211 cat = ast_category_browse(cfg, NULL); 01212 for (; cat; cat = ast_category_browse(cfg, cat)) { 01213 if (!strcasecmp(cat, "classes") || !strcasecmp(cat, "moh_files")) { 01214 continue; 01215 } 01216 01217 if (!(class = moh_class_malloc())) { 01218 break; 01219 } 01220 01221 ast_copy_string(class->name, cat, sizeof(class->name)); 01222 01223 for (var = ast_variable_browse(cfg, cat); var; var = var->next) { 01224 if (!strcasecmp(var->name, "mode")) { 01225 ast_copy_string(class->mode, var->value, sizeof(class->mode)); 01226 } else if (!strcasecmp(var->name, "directory")) { 01227 ast_copy_string(class->dir, var->value, sizeof(class->dir)); 01228 } else if (!strcasecmp(var->name, "application")) { 01229 ast_copy_string(class->args, var->value, sizeof(class->args)); 01230 } else if (!strcasecmp(var->name, "random")) { 01231 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE); 01232 } else if (!strcasecmp(var->name, "format")) { 01233 class->format = ast_getformatbyname(var->value); 01234 if (!class->format) { 01235 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value); 01236 class->format = AST_FORMAT_SLINEAR; 01237 } 01238 } 01239 } 01240 01241 if (ast_strlen_zero(class->dir)) { 01242 if (!strcasecmp(class->mode, "custom")) { 01243 ast_copy_string(class->dir, "nodir", sizeof(class->dir)); 01244 } else { 01245 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name); 01246 class = mohclass_unref(class); 01247 continue; 01248 } 01249 } 01250 01251 if (ast_strlen_zero(class->mode)) { 01252 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name); 01253 class = mohclass_unref(class); 01254 continue; 01255 } 01256 01257 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) { 01258 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name); 01259 class = mohclass_unref(class); 01260 continue; 01261 } 01262 01263 /* Don't leak a class when it's already registered */ 01264 if (!moh_register(class, reload)) { 01265 numclasses++; 01266 } 01267 } 01268 01269 01270 /* Deprecated Old-School Configuration */ 01271 for (var = ast_variable_browse(cfg, "classes"); var; var = var->next) { 01272 struct mohclass *tmp_class; 01273 01274 if (!dep_warning) { 01275 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"); 01276 dep_warning = 1; 01277 } 01278 01279 if (!(data = strchr(var->value, ':'))) { 01280 continue; 01281 } 01282 *data++ = '\0'; 01283 01284 if ((args = strchr(data, ','))) { 01285 *args++ = '\0'; 01286 } 01287 01288 /* Only skip if this is a duplicate of an above item */ 01289 if ((tmp_class = get_mohbyname(var->name, 0)) && !tmp_class->deprecated && !tmp_class->delete) { 01290 tmp_class = mohclass_unref(tmp_class); 01291 continue; 01292 } 01293 01294 if (!(class = moh_class_malloc())) { 01295 break; 01296 } 01297 01298 class->deprecated = 1; 01299 ast_copy_string(class->name, var->name, sizeof(class->name)); 01300 ast_copy_string(class->dir, data, sizeof(class->dir)); 01301 ast_copy_string(class->mode, var->value, sizeof(class->mode)); 01302 if (args) { 01303 ast_copy_string(class->args, args, sizeof(class->args)); 01304 } 01305 01306 moh_register(class, reload); 01307 class = NULL; 01308 01309 numclasses++; 01310 } 01311 01312 for (var = ast_variable_browse(cfg, "moh_files"); var; var = var->next) { 01313 struct mohclass *tmp_class; 01314 01315 if (!dep_warning) { 01316 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"); 01317 dep_warning = 1; 01318 } 01319 01320 /* Only skip if this is a duplicate of an above item */ 01321 if ((tmp_class = get_mohbyname(var->name, 0)) && !tmp_class->deprecated && !tmp_class->delete) { 01322 tmp_class = mohclass_unref(tmp_class); 01323 continue; 01324 } 01325 01326 if ((args = strchr(var->value, ','))) { 01327 *args++ = '\0'; 01328 } 01329 01330 if (!(class = moh_class_malloc())) { 01331 break; 01332 } 01333 01334 class->deprecated = 1; 01335 ast_copy_string(class->name, var->name, sizeof(class->name)); 01336 ast_copy_string(class->dir, var->value, sizeof(class->dir)); 01337 ast_copy_string(class->mode, "files", sizeof(class->mode)); 01338 if (args) { 01339 ast_copy_string(class->args, args, sizeof(class->args)); 01340 } 01341 01342 moh_register(class, reload); 01343 class = NULL; 01344 01345 numclasses++; 01346 } 01347 01348 ast_config_destroy(cfg); 01349 01350 ao2_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, 01351 moh_classes_delete_marked, NULL); 01352 01353 return numclasses; 01354 }
static void local_ast_moh_cleanup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1029 of file res_musiconhold.c.
References free, and ast_channel::music_state.
Referenced by load_module(), and reload().
01030 { 01031 if (chan->music_state) { 01032 free(chan->music_state); 01033 chan->music_state = NULL; 01034 } 01035 }
static int local_ast_moh_start | ( | struct ast_channel * | chan, | |
const char * | mclass, | |||
const char * | interpclass | |||
) | [static] |
Definition at line 1037 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().
01038 { 01039 struct mohclass *mohclass = NULL; 01040 int res; 01041 01042 /* The following is the order of preference for which class to use: 01043 * 1) The channels explicitly set musicclass, which should *only* be 01044 * set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan. 01045 * 2) The mclass argument. If a channel is calling ast_moh_start() as the 01046 * result of receiving a HOLD control frame, this should be the 01047 * payload that came with the frame. 01048 * 3) The interpclass argument. This would be from the mohinterpret 01049 * option from channel drivers. This is the same as the old musicclass 01050 * option. 01051 * 4) The default class. 01052 */ 01053 if (!ast_strlen_zero(chan->musicclass)) { 01054 mohclass = get_mohbyname(chan->musicclass, 1); 01055 } 01056 if (!mohclass && !ast_strlen_zero(mclass)) { 01057 mohclass = get_mohbyname(mclass, 1); 01058 } 01059 if (!mohclass && !ast_strlen_zero(interpclass)) { 01060 mohclass = get_mohbyname(interpclass, 1); 01061 } 01062 if (!mohclass) { 01063 mohclass = get_mohbyname("default", 1); 01064 } 01065 01066 if (!mohclass) { 01067 return -1; 01068 } 01069 01070 ast_set_flag(chan, AST_FLAG_MOH); 01071 01072 if (mohclass->total_files) { 01073 res = ast_activate_generator(chan, &moh_file_stream, mohclass); 01074 } else { 01075 res = ast_activate_generator(chan, &mohgen, mohclass); 01076 } 01077 01078 mohclass = mohclass_unref(mohclass); 01079 01080 return res; 01081 }
static void local_ast_moh_stop | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 1083 of file res_musiconhold.c.
References ast_channel_lock, ast_channel_unlock, 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().
01084 { 01085 ast_clear_flag(chan, AST_FLAG_MOH); 01086 ast_deactivate_generator(chan); 01087 01088 ast_channel_lock(chan); 01089 if (chan->music_state) { 01090 if (chan->stream) { 01091 ast_closestream(chan->stream); 01092 chan->stream = NULL; 01093 } 01094 } 01095 ast_channel_unlock(chan); 01096 }
static int moh0_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 622 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().
00623 { 00624 if (ast_moh_start(chan, data, NULL)) { 00625 ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name); 00626 return 0; 00627 } 00628 while (!ast_safe_sleep(chan, 10000)); 00629 ast_moh_stop(chan); 00630 return -1; 00631 }
static int moh1_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 633 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().
00634 { 00635 int res; 00636 if (!data || !atoi(data)) { 00637 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n"); 00638 return -1; 00639 } 00640 if (ast_moh_start(chan, NULL, NULL)) { 00641 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name); 00642 return 0; 00643 } 00644 res = ast_safe_sleep(chan, atoi(data) * 1000); 00645 ast_moh_stop(chan); 00646 return res; 00647 }
static int moh2_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 649 of file res_musiconhold.c.
References ast_log(), ast_string_field_set, ast_strlen_zero(), LOG_WARNING, and musicclass.
Referenced by load_module().
00650 { 00651 if (ast_strlen_zero(data)) { 00652 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n"); 00653 return -1; 00654 } 00655 ast_string_field_set(chan, musicclass, data); 00656 return 0; 00657 }
static int moh3_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 659 of file res_musiconhold.c.
References ast_log(), ast_moh_start(), and LOG_NOTICE.
Referenced by load_module().
00660 { 00661 char *class = NULL; 00662 if (data && strlen(data)) 00663 class = data; 00664 if (ast_moh_start(chan, class, NULL)) 00665 ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name); 00666 00667 return 0; 00668 }
static int moh4_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 670 of file res_musiconhold.c.
References ast_moh_stop().
Referenced by load_module().
00671 { 00672 ast_moh_stop(chan); 00673 00674 return 0; 00675 }
static int moh_add_file | ( | struct mohclass * | class, | |
const char * | filepath | |||
) | [static] |
Definition at line 810 of file res_musiconhold.c.
References mohclass::allowed_files, ast_calloc, ast_realloc, ast_strdup, mohclass::filearray, INITIAL_NUM_FILES, and mohclass::total_files.
00811 { 00812 if (!class->allowed_files) { 00813 if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray)))) 00814 return -1; 00815 class->allowed_files = INITIAL_NUM_FILES; 00816 } else if (class->total_files == class->allowed_files) { 00817 if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) { 00818 class->allowed_files = 0; 00819 class->total_files = 0; 00820 return -1; 00821 } 00822 class->allowed_files *= 2; 00823 } 00824 00825 if (!(class->filearray[class->total_files] = ast_strdup(filepath))) 00826 return -1; 00827 00828 class->total_files++; 00829 00830 return 0; 00831 }
static void* moh_alloc | ( | struct ast_channel * | chan, | |
void * | params | |||
) | [static] |
Definition at line 758 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.
00759 { 00760 struct mohdata *res; 00761 struct mohclass *class = params; 00762 00763 if ((res = mohalloc(class))) { 00764 res->origwfmt = chan->writeformat; 00765 if (ast_set_write_format(chan, class->format)) { 00766 ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format)); 00767 moh_release(NULL, res); 00768 res = NULL; 00769 } 00770 if (option_verbose > 2) 00771 ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name); 00772 } 00773 return res; 00774 }
static int moh_class_cmp | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1452 of file res_musiconhold.c.
Referenced by load_module().
01453 { 01454 struct mohclass *class = obj, *class2 = arg; 01455 01456 return strcasecmp(class->name, class2->name) ? 0 : CMP_MATCH | CMP_STOP; 01457 }
static void moh_class_destructor | ( | void * | obj | ) | [static] |
Definition at line 1098 of file res_musiconhold.c.
References AST_LIST_REMOVE_HEAD, ast_log(), AST_PTHREADT_NULL, ast_wait_for_input(), free, mohdata::list, LOG_DEBUG, and option_debug.
Referenced by moh_class_malloc().
01099 { 01100 struct mohclass *class = obj; 01101 struct mohdata *member; 01102 01103 if (option_debug) { 01104 ast_log(LOG_DEBUG, "Destroying MOH class '%s'\n", class->name); 01105 } 01106 01107 if (class->pid > 1) { 01108 char buff[8192]; 01109 int bytes, tbytes = 0, stime = 0, pid = 0; 01110 01111 ast_log(LOG_DEBUG, "killing %d!\n", class->pid); 01112 01113 stime = time(NULL) + 2; 01114 pid = class->pid; 01115 class->pid = 0; 01116 01117 /* Back when this was just mpg123, SIGKILL was fine. Now we need 01118 * to give the process a reason and time enough to kill off its 01119 * children. */ 01120 killpg(pid, SIGHUP); 01121 usleep(100000); 01122 killpg(pid, SIGTERM); 01123 usleep(100000); 01124 killpg(pid, SIGKILL); 01125 01126 while ((ast_wait_for_input(class->srcfd, 100) > 0) && 01127 (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) { 01128 tbytes = tbytes + bytes; 01129 } 01130 01131 ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes); 01132 01133 close(class->srcfd); 01134 } 01135 01136 while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) { 01137 free(member); 01138 } 01139 01140 if (class->thread) { 01141 pthread_cancel(class->thread); 01142 pthread_join(class->thread, NULL); 01143 class->thread = AST_PTHREADT_NULL; 01144 } 01145 01146 if (class->pseudofd > -1) { 01147 close(class->pseudofd); 01148 class->pseudofd = -1; 01149 } 01150 01151 if (class->filearray) { 01152 int i; 01153 for (i = 0; i < class->total_files; i++) { 01154 free(class->filearray[i]); 01155 } 01156 free(class->filearray); 01157 class->filearray = NULL; 01158 } 01159 }
static int moh_class_hash | ( | const void * | obj, | |
const int | flags | |||
) | [static] |
Definition at line 1445 of file res_musiconhold.c.
References ast_str_case_hash().
Referenced by load_module().
01446 { 01447 const struct mohclass *class = obj; 01448 01449 return ast_str_case_hash(class->name); 01450 }
static int moh_class_inuse | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1500 of file res_musiconhold.c.
References AST_LIST_EMPTY.
Referenced by unload_module().
01501 { 01502 struct mohclass *class = obj; 01503 01504 return AST_LIST_EMPTY(&class->members) ? 0 : CMP_MATCH | CMP_STOP; 01505 }
static struct mohclass* moh_class_malloc | ( | void | ) | [static] |
Definition at line 1161 of file res_musiconhold.c.
References ao2_alloc(), AST_FORMAT_SLINEAR, mohclass::format, and moh_class_destructor().
Referenced by load_moh_classes().
01162 { 01163 struct mohclass *class; 01164 01165 if ((class = ao2_alloc(sizeof(*class), moh_class_destructor))) { 01166 class->format = AST_FORMAT_SLINEAR; 01167 class->srcfd = -1; 01168 class->pseudofd = -1; 01169 } 01170 01171 return class; 01172 }
static int moh_class_mark | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1174 of file res_musiconhold.c.
Referenced by load_moh_classes().
01175 { 01176 struct mohclass *class = obj; 01177 01178 class->delete = 1; 01179 01180 return 0; 01181 }
static int moh_classes_delete_marked | ( | void * | obj, | |
void * | arg, | |||
int | flags | |||
) | [static] |
Definition at line 1183 of file res_musiconhold.c.
01184 { 01185 struct mohclass *class = obj; 01186 01187 return class->delete ? CMP_MATCH : 0; 01188 }
static int moh_classes_show | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1397 of file res_musiconhold.c.
References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ast_cli(), ast_getformatname(), ast_test_flag, MOH_CUSTOM, mohclass_unref, and S_OR.
01398 { 01399 struct mohclass *class; 01400 struct ao2_iterator i; 01401 01402 i = ao2_iterator_init(mohclasses, 0); 01403 01404 for (; (class = ao2_iterator_next(&i)); mohclass_unref(class)) { 01405 ast_cli(fd, "Class: %s\n", class->name); 01406 ast_cli(fd, "\tMode: %s\n", S_OR(class->mode, "<none>")); 01407 ast_cli(fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>")); 01408 if (ast_test_flag(class, MOH_CUSTOM)) { 01409 ast_cli(fd, "\tApplication: %s\n", S_OR(class->args, "<none>")); 01410 } 01411 if (strcasecmp(class->mode, "files")) { 01412 ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format)); 01413 } 01414 } 01415 01416 ao2_iterator_destroy(&i); 01417 01418 return 0; 01419 }
static int moh_cli | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1365 of file res_musiconhold.c.
References reload().
01366 { 01367 reload(); 01368 return 0; 01369 }
static void* moh_files_alloc | ( | struct ast_channel * | chan, | |
void * | params | |||
) | [static] |
Definition at line 328 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.
00329 { 00330 struct moh_files_state *state; 00331 struct mohclass *class = params; 00332 00333 if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) { 00334 chan->music_state = state; 00335 } else { 00336 state = chan->music_state; 00337 } 00338 00339 if (!state) { 00340 return NULL; 00341 } 00342 00343 if (state->class != class) { 00344 memset(state, 0, sizeof(*state)); 00345 if (ast_test_flag(class, MOH_RANDOMIZE) && class->total_files) { 00346 state->pos = ast_random() % class->total_files; 00347 } 00348 } 00349 00350 state->class = mohclass_ref(class); 00351 state->origwfmt = chan->writeformat; 00352 00353 if (option_verbose > 2) { 00354 ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", 00355 class->name, chan->name); 00356 } 00357 00358 return chan->music_state; 00359 }
static int moh_files_generator | ( | struct ast_channel * | chan, | |
void * | data, | |||
int | len, | |||
int | samples | |||
) | [static] |
Definition at line 293 of file res_musiconhold.c.
References ast_channel_lock, ast_channel_unlock, ast_frfree, ast_log(), ast_write(), errno, f, LOG_WARNING, moh_files_readframe(), ast_channel::music_state, moh_files_state::sample_queue, and moh_files_state::samples.
00294 { 00295 struct moh_files_state *state = chan->music_state; 00296 struct ast_frame *f = NULL; 00297 int res = 0; 00298 00299 state->sample_queue += samples; 00300 00301 while (state->sample_queue > 0) { 00302 ast_channel_lock(chan); 00303 if ((f = moh_files_readframe(chan))) { 00304 /* We need to be sure that we unlock 00305 * the channel prior to calling 00306 * ast_write. Otherwise, the recursive locking 00307 * that occurs can cause deadlocks when using 00308 * indirect channels, like local channels 00309 */ 00310 ast_channel_unlock(chan); 00311 state->samples += f->samples; 00312 state->sample_queue -= f->samples; 00313 res = ast_write(chan, f); 00314 ast_frfree(f); 00315 if (res < 0) { 00316 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); 00317 return -1; 00318 } 00319 } else { 00320 ast_channel_unlock(chan); 00321 return -1; 00322 } 00323 } 00324 return res; 00325 }
static struct ast_frame* moh_files_readframe | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 281 of file res_musiconhold.c.
References ast_moh_files_next(), ast_readframe(), f, and ast_channel::stream.
Referenced by moh_files_generator().
00282 { 00283 struct ast_frame *f = NULL; 00284 00285 if (!(chan->stream && (f = ast_readframe(chan->stream)))) { 00286 if (!ast_moh_files_next(chan)) 00287 f = ast_readframe(chan->stream); 00288 } 00289 00290 return f; 00291 }
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 776 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.
00777 { 00778 struct mohdata *moh = data; 00779 short buf[1280 + AST_FRIENDLY_OFFSET / 2]; 00780 int res; 00781 00782 len = ast_codec_get_len(moh->parent->format, samples); 00783 00784 if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) { 00785 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name); 00786 len = sizeof(buf) - AST_FRIENDLY_OFFSET; 00787 } 00788 res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len); 00789 if (res <= 0) 00790 return 0; 00791 00792 moh->f.datalen = res; 00793 moh->f.data = buf + AST_FRIENDLY_OFFSET / 2; 00794 moh->f.samples = ast_codec_get_samples(&moh->f); 00795 00796 if (ast_write(chan, &moh->f) < 0) { 00797 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); 00798 return -1; 00799 } 00800 00801 return 0; 00802 }
static int moh_register | ( | struct mohclass * | moh, | |
int | reload | |||
) | [static] |
Definition at line 981 of file res_musiconhold.c.
References ast_log(), mohclass::delete, get_mohbyname(), init_app_class(), init_files_class(), LOG_WARNING, moh, and mohclass_unref.
00982 { 00983 struct mohclass *mohclass = NULL; 00984 00985 if ((mohclass = get_mohbyname(moh->name, 0))) { 00986 if (!mohclass->delete) { 00987 ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name); 00988 mohclass = mohclass_unref(mohclass); 00989 moh = mohclass_unref(moh); 00990 return -1; 00991 } 00992 mohclass = mohclass_unref(mohclass); 00993 } 00994 00995 time(&moh->start); 00996 moh->start -= respawn_time; 00997 00998 if (!strcasecmp(moh->mode, "files")) { 00999 if (init_files_class(moh)) { 01000 moh = mohclass_unref(moh); 01001 return -1; 01002 } 01003 } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || 01004 !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || 01005 !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) { 01006 #ifdef HAVE_WORKING_FORK 01007 if (init_app_class(moh)) { 01008 moh = mohclass_unref(moh); 01009 return -1; 01010 } 01011 #else 01012 ast_log(LOG_WARNING, "Cannot use mode '%s' music on hold, as there is no working fork().\n", moh->mode); 01013 moh = mohclass_unref(moh); 01014 return -1; 01015 #endif 01016 } else { 01017 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode); 01018 moh = mohclass_unref(moh); 01019 return -1; 01020 } 01021 01022 ao2_link(mohclasses, moh); 01023 01024 moh = mohclass_unref(moh); 01025 01026 return 0; 01027 }
static void moh_release | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 728 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().
00729 { 00730 struct mohdata *moh = data; 00731 struct mohclass *class = moh->parent; 00732 int oldwfmt; 00733 00734 ao2_lock(class); 00735 AST_LIST_REMOVE(&moh->parent->members, moh, list); 00736 ao2_unlock(class); 00737 00738 close(moh->pipe[0]); 00739 close(moh->pipe[1]); 00740 00741 oldwfmt = moh->origwfmt; 00742 00743 moh->parent = class = mohclass_unref(class); 00744 00745 free(moh); 00746 00747 if (chan) { 00748 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) { 00749 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", 00750 chan->name, ast_getformatname(oldwfmt)); 00751 } 00752 if (option_verbose > 2) { 00753 ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name); 00754 } 00755 } 00756 }
static int moh_scan_files | ( | struct mohclass * | class | ) | [static] |
Definition at line 833 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().
00833 { 00834 00835 DIR *files_DIR; 00836 struct dirent *files_dirent; 00837 char path[PATH_MAX]; 00838 char filepath[PATH_MAX]; 00839 char *ext; 00840 struct stat statbuf; 00841 int dirnamelen; 00842 int i; 00843 00844 files_DIR = opendir(class->dir); 00845 if (!files_DIR) { 00846 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", class->dir); 00847 return -1; 00848 } 00849 00850 for (i = 0; i < class->total_files; i++) 00851 free(class->filearray[i]); 00852 00853 class->total_files = 0; 00854 dirnamelen = strlen(class->dir) + 2; 00855 if (!getcwd(path, sizeof(path))) { 00856 ast_log(LOG_WARNING, "getcwd() failed: %s\n", strerror(errno)); 00857 return -1; 00858 } 00859 if (chdir(class->dir) < 0) { 00860 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 00861 return -1; 00862 } 00863 while ((files_dirent = readdir(files_DIR))) { 00864 /* The file name must be at least long enough to have the file type extension */ 00865 if ((strlen(files_dirent->d_name) < 4)) 00866 continue; 00867 00868 /* Skip files that starts with a dot */ 00869 if (files_dirent->d_name[0] == '.') 00870 continue; 00871 00872 /* Skip files without extensions... they are not audio */ 00873 if (!strchr(files_dirent->d_name, '.')) 00874 continue; 00875 00876 snprintf(filepath, sizeof(filepath), "%s/%s", class->dir, files_dirent->d_name); 00877 00878 if (stat(filepath, &statbuf)) 00879 continue; 00880 00881 if (!S_ISREG(statbuf.st_mode)) 00882 continue; 00883 00884 if ((ext = strrchr(filepath, '.'))) { 00885 *ext = '\0'; 00886 ext++; 00887 } 00888 00889 /* if the file is present in multiple formats, ensure we only put it into the list once */ 00890 for (i = 0; i < class->total_files; i++) 00891 if (!strcmp(filepath, class->filearray[i])) 00892 break; 00893 00894 if (i == class->total_files) { 00895 if (moh_add_file(class, filepath)) 00896 break; 00897 } 00898 } 00899 00900 closedir(files_DIR); 00901 if (chdir(path) < 0) { 00902 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 00903 return -1; 00904 } 00905 return class->total_files; 00906 }
Definition at line 695 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().
00696 { 00697 struct mohdata *moh; 00698 long flags; 00699 00700 if (!(moh = ast_calloc(1, sizeof(*moh)))) 00701 return NULL; 00702 00703 if (pipe(moh->pipe)) { 00704 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno)); 00705 free(moh); 00706 return NULL; 00707 } 00708 00709 /* Make entirely non-blocking */ 00710 flags = fcntl(moh->pipe[0], F_GETFL); 00711 fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK); 00712 flags = fcntl(moh->pipe[1], F_GETFL); 00713 fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK); 00714 00715 moh->f.frametype = AST_FRAME_VOICE; 00716 moh->f.subclass = cl->format; 00717 moh->f.offset = AST_FRIENDLY_OFFSET; 00718 00719 moh->parent = mohclass_ref(cl); 00720 00721 ao2_lock(cl); 00722 AST_LIST_INSERT_HEAD(&cl->members, moh, list); 00723 ao2_unlock(cl); 00724 00725 return moh; 00726 }
static void* monmp3thread | ( | void * | data | ) | [static] |
Definition at line 534 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(), LOG_DEBUG, LOG_NOTICE, LOG_WARNING, moh, MOH_MS_INTERVAL, option_debug, and spawn_mp3().
Referenced by init_app_class().
00535 { 00536 #define MOH_MS_INTERVAL 100 00537 00538 struct mohclass *class = data; 00539 struct mohdata *moh; 00540 char buf[8192]; 00541 short sbuf[8192]; 00542 int res, res2; 00543 int len; 00544 struct timeval tv, tv_tmp; 00545 00546 tv.tv_sec = 0; 00547 tv.tv_usec = 0; 00548 for(;/* ever */;) { 00549 pthread_testcancel(); 00550 /* Spawn mp3 player if it's not there */ 00551 if (class->srcfd < 0) { 00552 if ((class->srcfd = spawn_mp3(class)) < 0) { 00553 ast_log(LOG_WARNING, "Unable to spawn mp3player\n"); 00554 /* Try again later */ 00555 sleep(500); 00556 pthread_testcancel(); 00557 } 00558 } 00559 if (class->pseudofd > -1) { 00560 #ifdef SOLARIS 00561 thr_yield(); 00562 #endif 00563 /* Pause some amount of time */ 00564 res = read(class->pseudofd, buf, sizeof(buf)); 00565 pthread_testcancel(); 00566 } else { 00567 long delta; 00568 /* Reliable sleep */ 00569 tv_tmp = ast_tvnow(); 00570 if (ast_tvzero(tv)) 00571 tv = tv_tmp; 00572 delta = ast_tvdiff_ms(tv_tmp, tv); 00573 if (delta < MOH_MS_INTERVAL) { /* too early */ 00574 tv = ast_tvadd(tv, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */ 00575 usleep(1000 * (MOH_MS_INTERVAL - delta)); 00576 pthread_testcancel(); 00577 } else { 00578 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n"); 00579 tv = tv_tmp; 00580 } 00581 res = 8 * MOH_MS_INTERVAL; /* 8 samples per millisecond */ 00582 } 00583 if ((strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir")) && AST_LIST_EMPTY(&class->members)) 00584 continue; 00585 /* Read mp3 audio */ 00586 len = ast_codec_get_len(class->format, res); 00587 00588 if ((res2 = read(class->srcfd, sbuf, len)) != len) { 00589 if (!res2) { 00590 close(class->srcfd); 00591 class->srcfd = -1; 00592 pthread_testcancel(); 00593 if (class->pid > 1) { 00594 killpg(class->pid, SIGHUP); 00595 usleep(100000); 00596 killpg(class->pid, SIGTERM); 00597 usleep(100000); 00598 killpg(class->pid, SIGKILL); 00599 class->pid = 0; 00600 } 00601 } else 00602 ast_log(LOG_DEBUG, "Read %d bytes of audio while expecting %d\n", res2, len); 00603 continue; 00604 } 00605 00606 pthread_testcancel(); 00607 00608 ao2_lock(class); 00609 AST_LIST_TRAVERSE(&class->members, moh, list) { 00610 /* Write data */ 00611 if ((res = write(moh->pipe[1], sbuf, res2)) != res2) { 00612 if (option_debug) 00613 ast_log(LOG_DEBUG, "Only wrote %d of %d bytes to pipe\n", res, res2); 00614 } 00615 } 00616 ao2_unlock(class); 00617 } 00618 return NULL; 00619 }
static int reload | ( | void | ) | [static] |
Definition at line 1490 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().
01491 { 01492 if (load_moh_classes(1)) { 01493 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, 01494 local_ast_moh_cleanup); 01495 } 01496 01497 return 0; 01498 }
static int spawn_mp3 | ( | struct mohclass * | class | ) | [static] |
Definition at line 368 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().
00369 { 00370 int fds[2]; 00371 int files = 0; 00372 char fns[MAX_MP3S][80]; 00373 char *argv[MAX_MP3S + 50]; 00374 char xargs[256]; 00375 char *argptr; 00376 int argc = 0; 00377 DIR *dir = NULL; 00378 struct dirent *de; 00379 sigset_t signal_set, old_set; 00380 00381 00382 if (!strcasecmp(class->dir, "nodir")) { 00383 files = 1; 00384 } else { 00385 dir = opendir(class->dir); 00386 if (!dir && strncasecmp(class->dir, "http://", 7)) { 00387 ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir); 00388 return -1; 00389 } 00390 } 00391 00392 if (!ast_test_flag(class, MOH_CUSTOM)) { 00393 argv[argc++] = "mpg123"; 00394 argv[argc++] = "-q"; 00395 argv[argc++] = "-s"; 00396 argv[argc++] = "--mono"; 00397 argv[argc++] = "-r"; 00398 argv[argc++] = "8000"; 00399 00400 if (!ast_test_flag(class, MOH_SINGLE)) { 00401 argv[argc++] = "-b"; 00402 argv[argc++] = "2048"; 00403 } 00404 00405 argv[argc++] = "-f"; 00406 00407 if (ast_test_flag(class, MOH_QUIET)) 00408 argv[argc++] = "4096"; 00409 else 00410 argv[argc++] = "8192"; 00411 00412 /* Look for extra arguments and add them to the list */ 00413 ast_copy_string(xargs, class->args, sizeof(xargs)); 00414 argptr = xargs; 00415 while (!ast_strlen_zero(argptr)) { 00416 argv[argc++] = argptr; 00417 strsep(&argptr, ","); 00418 } 00419 } else { 00420 /* Format arguments for argv vector */ 00421 ast_copy_string(xargs, class->args, sizeof(xargs)); 00422 argptr = xargs; 00423 while (!ast_strlen_zero(argptr)) { 00424 argv[argc++] = argptr; 00425 strsep(&argptr, " "); 00426 } 00427 } 00428 00429 if (!strncasecmp(class->dir, "http://", 7)) { 00430 ast_copy_string(fns[files], class->dir, sizeof(fns[files])); 00431 argv[argc++] = fns[files]; 00432 files++; 00433 } else if (dir) { 00434 while ((de = readdir(dir)) && (files < MAX_MP3S)) { 00435 if ((strlen(de->d_name) > 3) && 00436 ((ast_test_flag(class, MOH_CUSTOM) && 00437 (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 00438 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) || 00439 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) { 00440 ast_copy_string(fns[files], de->d_name, sizeof(fns[files])); 00441 argv[argc++] = fns[files]; 00442 files++; 00443 } 00444 } 00445 } 00446 argv[argc] = NULL; 00447 if (dir) { 00448 closedir(dir); 00449 } 00450 if (pipe(fds)) { 00451 ast_log(LOG_WARNING, "Pipe failed\n"); 00452 return -1; 00453 } 00454 if (!files) { 00455 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir); 00456 close(fds[0]); 00457 close(fds[1]); 00458 return -1; 00459 } 00460 if (!strncasecmp(class->dir, "http://", 7) && time(NULL) - class->start < respawn_time) { 00461 sleep(respawn_time - (time(NULL) - class->start)); 00462 } 00463 00464 /* Block signals during the fork() */ 00465 sigfillset(&signal_set); 00466 pthread_sigmask(SIG_BLOCK, &signal_set, &old_set); 00467 00468 time(&class->start); 00469 class->pid = fork(); 00470 if (class->pid < 0) { 00471 close(fds[0]); 00472 close(fds[1]); 00473 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno)); 00474 return -1; 00475 } 00476 if (!class->pid) { 00477 /* Child */ 00478 int x; 00479 #ifdef HAVE_CAP 00480 cap_t cap; 00481 #endif 00482 if (strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir") && chdir(class->dir) < 0) { 00483 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno)); 00484 _exit(1); 00485 } 00486 00487 if (ast_opt_high_priority) 00488 ast_set_priority(0); 00489 00490 /* Reset ignored signals back to default */ 00491 signal(SIGPIPE, SIG_DFL); 00492 pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL); 00493 00494 #ifdef HAVE_CAP 00495 cap = cap_from_text("cap_net_admin-eip"); 00496 00497 if (cap_set_proc(cap)) { 00498 ast_log(LOG_WARNING, "Unable to remove capabilities.\n"); 00499 } 00500 cap_free(cap); 00501 #endif 00502 close(fds[0]); 00503 /* Stdout goes to pipe */ 00504 dup2(fds[1], STDOUT_FILENO); 00505 /* Close unused file descriptors */ 00506 for (x=3;x<8192;x++) { 00507 if (-1 != fcntl(x, F_GETFL)) { 00508 close(x); 00509 } 00510 } 00511 setpgid(0, getpid()); 00512 00513 if (ast_test_flag(class, MOH_CUSTOM)) { 00514 execv(argv[0], argv); 00515 } else { 00516 /* Default install is /usr/local/bin */ 00517 execv(LOCAL_MPG_123, argv); 00518 /* Many places have it in /usr/bin */ 00519 execv(MPG_123, argv); 00520 /* Check PATH as a last-ditch effort */ 00521 execvp("mpg123", argv); 00522 } 00523 ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno)); 00524 close(fds[1]); 00525 _exit(1); 00526 } else { 00527 /* Parent */ 00528 pthread_sigmask(SIG_SETMASK, &old_set, NULL); 00529 close(fds[1]); 00530 } 00531 return fds[0]; 00532 }
static int unload_module | ( | void | ) | [static] |
Definition at line 1507 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.
01508 { 01509 int res = 0; 01510 struct mohclass *class = NULL; 01511 01512 /* XXX This check shouldn't be required if module ref counting was being used 01513 * properly ... */ 01514 if ((class = ao2_callback(mohclasses, 0, moh_class_inuse, NULL))) { 01515 class = mohclass_unref(class); 01516 res = -1; 01517 } 01518 01519 if (res < 0) { 01520 ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n"); 01521 return res; 01522 } 01523 01524 ast_uninstall_music_functions(); 01525 01526 ast_moh_destroy(); 01527 01528 res = ast_unregister_application(app0); 01529 res |= ast_unregister_application(app1); 01530 res |= ast_unregister_application(app2); 01531 res |= ast_unregister_application(app3); 01532 res |= ast_unregister_application(app4); 01533 01534 ast_cli_unregister_multiple(cli_moh, ARRAY_LEN(cli_moh)); 01535 01536 return res; 01537 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT | 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 = "361d7bb937402d51e4658efb5b4d76e4" , .load = load_module, .unload = unload_module, .reload = reload, } [static] |
Definition at line 1543 of file res_musiconhold.c.
char* app0 = "MusicOnHold" [static] |
Definition at line 82 of file res_musiconhold.c.
char* app1 = "WaitMusicOnHold" [static] |
Definition at line 83 of file res_musiconhold.c.
char* app2 = "SetMusicOnHold" [static] |
Definition at line 84 of file res_musiconhold.c.
char* app3 = "StartMusicOnHold" [static] |
Definition at line 85 of file res_musiconhold.c.
char* app4 = "StopMusicOnHold" [static] |
Definition at line 86 of file res_musiconhold.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 1543 of file res_musiconhold.c.
struct ast_cli_entry cli_moh[] [static] |
Definition at line 1431 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 1421 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 1426 of file res_musiconhold.c.
char* descrip0 [static] |
Definition at line 94 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 101 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 106 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 111 of file res_musiconhold.c.
char* descrip4 [static] |
Initial value:
"StopMusicOnHold: " "Stops playing music on hold.\n"
Definition at line 116 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 361 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 804 of file res_musiconhold.c.
Referenced by local_ast_moh_start().
int respawn_time = 20 [static] |
Definition at line 119 of file res_musiconhold.c.
char* synopsis0 = "Play Music On Hold indefinitely" [static] |
Definition at line 88 of file res_musiconhold.c.
char* synopsis1 = "Wait, playing Music On Hold" [static] |
Definition at line 89 of file res_musiconhold.c.
char* synopsis2 = "Set default Music On Hold class" [static] |
Definition at line 90 of file res_musiconhold.c.
char* synopsis3 = "Play Music On Hold" [static] |
Definition at line 91 of file res_musiconhold.c.
char* synopsis4 = "Stop Playing Music On Hold" [static] |
Definition at line 92 of file res_musiconhold.c.