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