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