#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"
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 | MPG_123 "/usr/bin/mpg123" |
Functions | |
AST_LIST_HEAD_STATIC (mohclasses, mohclass) | |
AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS,"Music On Hold Resource",.load=load_module,.unload=unload_module,.reload=reload,) | |
static void | ast_moh_destroy (void) |
static int | ast_moh_destroy_one (struct mohclass *moh) |
static int | ast_moh_files_next (struct ast_channel *chan) |
static void | ast_moh_free_class (struct mohclass **mohclass) |
static int | cli_files_show (int fd, int argc, char *argv[]) |
static struct mohclass * | get_mohbyname (const char *name, int warn) |
static int | init_classes (int reload) |
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 struct mohclass * | moh_class_malloc (void) |
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 char * | app0 = "MusicOnHold" |
static char * | app1 = "WaitMusicOnHold" |
static char * | app2 = "SetMusicOnHold" |
static char * | app3 = "StartMusicOnHold" |
static char * | app4 = "StopMusicOnHold" |
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 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 170 of file res_musiconhold.c.
#define MAX_MP3S 256 |
#define MOH_CUSTOM (1 << 2) |
Definition at line 128 of file res_musiconhold.c.
Referenced by moh_classes_show(), moh_register(), and spawn_mp3().
#define MOH_MS_INTERVAL 100 |
Referenced by monmp3thread().
#define MOH_QUIET (1 << 0) |
#define MOH_RANDOMIZE (1 << 3) |
Definition at line 129 of file res_musiconhold.c.
Referenced by ast_moh_files_next(), load_moh_classes(), moh_files_alloc(), and moh_register().
#define MOH_SINGLE (1 << 1) |
#define MPG_123 "/usr/bin/mpg123" |
Definition at line 171 of file res_musiconhold.c.
AST_LIST_HEAD_STATIC | ( | mohclasses | , | |
mohclass | ||||
) |
AST_MODULE_INFO | ( | ASTERISK_GPL_KEY | , | |
AST_MODFLAG_GLOBAL_SYMBOLS | , | |||
"Music On Hold Resource" | , | |||
. | load = load_module , |
|||
. | unload = unload_module , |
|||
. | reload = reload | |||
) |
static void ast_moh_destroy | ( | void | ) | [static] |
Definition at line 1183 of file res_musiconhold.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_moh_destroy_one(), ast_verbose(), moh, option_verbose, and VERBOSE_PREFIX_2.
Referenced by load_module(), and unload_module().
01184 { 01185 struct mohclass *moh; 01186 01187 if (option_verbose > 1) 01188 ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n"); 01189 01190 AST_LIST_LOCK(&mohclasses); 01191 while ((moh = AST_LIST_REMOVE_HEAD(&mohclasses, list))) { 01192 ast_moh_destroy_one(moh); 01193 } 01194 AST_LIST_UNLOCK(&mohclasses); 01195 }
static int ast_moh_destroy_one | ( | struct mohclass * | moh | ) | [static] |
Definition at line 1153 of file res_musiconhold.c.
References ast_log(), ast_moh_free_class(), ast_wait_for_input(), LOG_DEBUG, moh, and mohclass::pid.
Referenced by ast_moh_destroy(), init_classes(), moh_files_release(), and moh_release().
01154 { 01155 char buff[8192]; 01156 int bytes, tbytes = 0, stime = 0, pid = 0; 01157 01158 if (moh) { 01159 if (moh->pid > 1) { 01160 ast_log(LOG_DEBUG, "killing %d!\n", moh->pid); 01161 stime = time(NULL) + 2; 01162 pid = moh->pid; 01163 moh->pid = 0; 01164 /* Back when this was just mpg123, SIGKILL was fine. Now we need 01165 * to give the process a reason and time enough to kill off its 01166 * children. */ 01167 kill(pid, SIGHUP); 01168 usleep(100000); 01169 kill(pid, SIGTERM); 01170 usleep(100000); 01171 kill(pid, SIGKILL); 01172 while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime) 01173 tbytes = tbytes + bytes; 01174 ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes); 01175 close(moh->srcfd); 01176 } 01177 ast_moh_free_class(&moh); 01178 } 01179 01180 return 0; 01181 }
static int ast_moh_files_next | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 227 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, 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().
00228 { 00229 struct moh_files_state *state = chan->music_state; 00230 int tries; 00231 00232 /* Discontinue a stream if it is running already */ 00233 if (chan->stream) { 00234 ast_closestream(chan->stream); 00235 chan->stream = NULL; 00236 } 00237 00238 if (!state->class->total_files) { 00239 ast_log(LOG_WARNING, "No files available for class '%s'\n", state->class->name); 00240 return -1; 00241 } 00242 00243 /* If a specific file has been saved confirm it still exists and that it is still valid */ 00244 if (state->save_pos >= 0 && state->save_pos < state->class->total_files && state->class->filearray[state->save_pos] == state->save_pos_filename) { 00245 state->pos = state->save_pos; 00246 state->save_pos = -1; 00247 } else if (ast_test_flag(state->class, MOH_RANDOMIZE)) { 00248 /* Get a random file and ensure we can open it */ 00249 for (tries = 0; tries < 20; tries++) { 00250 state->pos = ast_random() % state->class->total_files; 00251 if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0) 00252 break; 00253 } 00254 state->save_pos = -1; 00255 state->samples = 0; 00256 } else { 00257 /* This is easy, just increment our position and make sure we don't exceed the total file count */ 00258 state->pos++; 00259 state->pos %= state->class->total_files; 00260 state->save_pos = -1; 00261 state->samples = 0; 00262 } 00263 00264 if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) { 00265 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno)); 00266 state->pos++; 00267 state->pos %= state->class->total_files; 00268 return -1; 00269 } 00270 00271 /* Record the pointer to the filename for position resuming later */ 00272 state->save_pos_filename = state->class->filearray[state->pos]; 00273 00274 if (option_debug) 00275 ast_log(LOG_DEBUG, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]); 00276 00277 if (state->samples) 00278 ast_seekstream(chan->stream, state->samples, SEEK_SET); 00279 00280 return 0; 00281 }
static void ast_moh_free_class | ( | struct mohclass ** | mohclass | ) | [static] |
Definition at line 177 of file res_musiconhold.c.
References AST_LIST_REMOVE_HEAD, and free.
Referenced by ast_moh_destroy_one(), and moh_register().
00178 { 00179 struct mohdata *member; 00180 struct mohclass *class = *mohclass; 00181 int i; 00182 00183 while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) 00184 free(member); 00185 00186 if (class->thread) { 00187 pthread_cancel(class->thread); 00188 class->thread = 0; 00189 } 00190 00191 if (class->filearray) { 00192 for (i = 0; i < class->total_files; i++) 00193 free(class->filearray[i]); 00194 free(class->filearray); 00195 } 00196 00197 free(class); 00198 *mohclass = NULL; 00199 }
static int cli_files_show | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1203 of file res_musiconhold.c.
References ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, and AST_LIST_UNLOCK.
01204 { 01205 int i; 01206 struct mohclass *class; 01207 01208 AST_LIST_LOCK(&mohclasses); 01209 AST_LIST_TRAVERSE(&mohclasses, class, list) { 01210 if (!class->total_files) 01211 continue; 01212 01213 ast_cli(fd, "Class: %s\n", class->name); 01214 for (i = 0; i < class->total_files; i++) 01215 ast_cli(fd, "\tFile: %s\n", class->filearray[i]); 01216 } 01217 AST_LIST_UNLOCK(&mohclasses); 01218 01219 return 0; 01220 }
static struct mohclass* get_mohbyname | ( | const char * | name, | |
int | warn | |||
) | [static] |
Definition at line 650 of file res_musiconhold.c.
References AST_LIST_TRAVERSE, ast_log(), LOG_WARNING, and moh.
Referenced by load_moh_classes(), local_ast_moh_start(), and moh_register().
00651 { 00652 struct mohclass *moh = NULL; 00653 00654 AST_LIST_TRAVERSE(&mohclasses, moh, list) { 00655 if (!strcasecmp(name, moh->name)) 00656 break; 00657 } 00658 00659 if (!moh && warn) 00660 ast_log(LOG_WARNING, "Music on Hold class '%s' not found\n", name); 00661 00662 return moh; 00663 }
static int init_classes | ( | int | reload | ) | [static] |
Definition at line 1266 of file res_musiconhold.c.
References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_moh_destroy_one(), load_moh_classes(), and moh.
Referenced by load_module(), and reload().
01267 { 01268 struct mohclass *moh; 01269 01270 if (!load_moh_classes(reload)) /* Load classes from config */ 01271 return 0; /* Return if nothing is found */ 01272 01273 AST_LIST_LOCK(&mohclasses); 01274 AST_LIST_TRAVERSE_SAFE_BEGIN(&mohclasses, moh, list) { 01275 if (reload && moh->delete) { 01276 AST_LIST_REMOVE_CURRENT(&mohclasses, list); 01277 if (!moh->inuse) 01278 ast_moh_destroy_one(moh); 01279 } 01280 } 01281 AST_LIST_TRAVERSE_SAFE_END 01282 AST_LIST_UNLOCK(&mohclasses); 01283 01284 return 1; 01285 }
static int load_module | ( | void | ) | [static] |
Definition at line 1287 of file res_musiconhold.c.
References ast_cli_register_multiple(), ast_install_music_functions(), ast_log(), ast_moh_destroy(), ast_register_application(), ast_register_atexit(), cli_moh, init_classes(), local_ast_moh_cleanup(), local_ast_moh_start(), local_ast_moh_stop(), LOG_WARNING, moh0_exec(), moh1_exec(), moh2_exec(), moh3_exec(), and moh4_exec().
01288 { 01289 int res; 01290 01291 res = ast_register_application(app0, moh0_exec, synopsis0, descrip0); 01292 ast_register_atexit(ast_moh_destroy); 01293 ast_cli_register_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry)); 01294 if (!res) 01295 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1); 01296 if (!res) 01297 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2); 01298 if (!res) 01299 res = ast_register_application(app3, moh3_exec, synopsis3, descrip3); 01300 if (!res) 01301 res = ast_register_application(app4, moh4_exec, synopsis4, descrip4); 01302 01303 if (!init_classes(0)) { /* No music classes configured, so skip it */ 01304 ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold.\n"); 01305 } else { 01306 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup); 01307 } 01308 01309 return 0; 01310 }
static int load_moh_classes | ( | int | reload | ) | [static] |
Definition at line 1014 of file res_musiconhold.c.
References mohclass::args, ast_category_browse(), ast_config_destroy(), ast_config_load(), AST_FORMAT_SLINEAR, ast_getformatbyname(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_set2_flag, ast_strlen_zero(), ast_true(), ast_variable_browse(), free, get_mohbyname(), LOG_WARNING, moh_class_malloc(), MOH_RANDOMIZE, moh_register(), and var.
Referenced by init_classes().
01015 { 01016 struct ast_config *cfg; 01017 struct ast_variable *var; 01018 struct mohclass *class; 01019 char *data; 01020 char *args; 01021 char *cat; 01022 int numclasses = 0; 01023 static int dep_warning = 0; 01024 01025 cfg = ast_config_load("musiconhold.conf"); 01026 01027 if (!cfg) 01028 return 0; 01029 01030 if (reload) { 01031 AST_LIST_LOCK(&mohclasses); 01032 AST_LIST_TRAVERSE(&mohclasses, class, list) 01033 class->delete = 1; 01034 AST_LIST_UNLOCK(&mohclasses); 01035 } 01036 01037 cat = ast_category_browse(cfg, NULL); 01038 for (; cat; cat = ast_category_browse(cfg, cat)) { 01039 if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) { 01040 if (!(class = moh_class_malloc())) { 01041 break; 01042 } 01043 ast_copy_string(class->name, cat, sizeof(class->name)); 01044 var = ast_variable_browse(cfg, cat); 01045 while (var) { 01046 if (!strcasecmp(var->name, "mode")) 01047 ast_copy_string(class->mode, var->value, sizeof(class->mode)); 01048 else if (!strcasecmp(var->name, "directory")) 01049 ast_copy_string(class->dir, var->value, sizeof(class->dir)); 01050 else if (!strcasecmp(var->name, "application")) 01051 ast_copy_string(class->args, var->value, sizeof(class->args)); 01052 else if (!strcasecmp(var->name, "random")) 01053 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE); 01054 else if (!strcasecmp(var->name, "format")) { 01055 class->format = ast_getformatbyname(var->value); 01056 if (!class->format) { 01057 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value); 01058 class->format = AST_FORMAT_SLINEAR; 01059 } 01060 } 01061 var = var->next; 01062 } 01063 01064 if (ast_strlen_zero(class->dir)) { 01065 if (!strcasecmp(class->mode, "custom")) { 01066 strcpy(class->dir, "nodir"); 01067 } else { 01068 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name); 01069 free(class); 01070 continue; 01071 } 01072 } 01073 if (ast_strlen_zero(class->mode)) { 01074 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name); 01075 free(class); 01076 continue; 01077 } 01078 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) { 01079 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name); 01080 free(class); 01081 continue; 01082 } 01083 01084 /* Don't leak a class when it's already registered */ 01085 moh_register(class, reload); 01086 01087 numclasses++; 01088 } 01089 } 01090 01091 01092 /* Deprecated Old-School Configuration */ 01093 var = ast_variable_browse(cfg, "classes"); 01094 while (var) { 01095 if (!dep_warning) { 01096 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"); 01097 dep_warning = 1; 01098 } 01099 data = strchr(var->value, ':'); 01100 if (data) { 01101 *data++ = '\0'; 01102 args = strchr(data, ','); 01103 if (args) 01104 *args++ = '\0'; 01105 if (!(get_mohbyname(var->name, 0))) { 01106 if (!(class = moh_class_malloc())) { 01107 break; 01108 } 01109 01110 ast_copy_string(class->name, var->name, sizeof(class->name)); 01111 ast_copy_string(class->dir, data, sizeof(class->dir)); 01112 ast_copy_string(class->mode, var->value, sizeof(class->mode)); 01113 if (args) 01114 ast_copy_string(class->args, args, sizeof(class->args)); 01115 01116 moh_register(class, reload); 01117 numclasses++; 01118 } 01119 } 01120 var = var->next; 01121 } 01122 var = ast_variable_browse(cfg, "moh_files"); 01123 while (var) { 01124 if (!dep_warning) { 01125 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"); 01126 dep_warning = 1; 01127 } 01128 if (!(get_mohbyname(var->name, 0))) { 01129 args = strchr(var->value, ','); 01130 if (args) 01131 *args++ = '\0'; 01132 if (!(class = moh_class_malloc())) { 01133 break; 01134 } 01135 01136 ast_copy_string(class->name, var->name, sizeof(class->name)); 01137 ast_copy_string(class->dir, var->value, sizeof(class->dir)); 01138 strcpy(class->mode, "files"); 01139 if (args) 01140 ast_copy_string(class->args, args, sizeof(class->args)); 01141 01142 moh_register(class, reload); 01143 numclasses++; 01144 } 01145 var = var->next; 01146 } 01147 01148 ast_config_destroy(cfg); 01149 01150 return numclasses; 01151 }
static void local_ast_moh_cleanup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 945 of file res_musiconhold.c.
References free, and ast_channel::music_state.
Referenced by load_module(), and reload().
00946 { 00947 if (chan->music_state) { 00948 free(chan->music_state); 00949 chan->music_state = NULL; 00950 } 00951 }
static int local_ast_moh_start | ( | struct ast_channel * | chan, | |
const char * | mclass, | |||
const char * | interpclass | |||
) | [static] |
Definition at line 953 of file res_musiconhold.c.
References ast_activate_generator(), AST_FLAG_MOH, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_set_flag, ast_strlen_zero(), get_mohbyname(), mohclass::inuse, moh_file_stream, mohgen, and mohclass::total_files.
Referenced by load_module(), and reload().
00954 { 00955 struct mohclass *mohclass = NULL; 00956 00957 /* The following is the order of preference for which class to use: 00958 * 1) The channels explicitly set musicclass, which should *only* be 00959 * set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan. 00960 * 2) The mclass argument. If a channel is calling ast_moh_start() as the 00961 * result of receiving a HOLD control frame, this should be the 00962 * payload that came with the frame. 00963 * 3) The interpclass argument. This would be from the mohinterpret 00964 * option from channel drivers. This is the same as the old musicclass 00965 * option. 00966 * 4) The default class. 00967 */ 00968 AST_LIST_LOCK(&mohclasses); 00969 if (!ast_strlen_zero(chan->musicclass)) 00970 mohclass = get_mohbyname(chan->musicclass, 1); 00971 if (!mohclass && !ast_strlen_zero(mclass)) 00972 mohclass = get_mohbyname(mclass, 1); 00973 if (!mohclass && !ast_strlen_zero(interpclass)) 00974 mohclass = get_mohbyname(interpclass, 1); 00975 if (!mohclass) 00976 mohclass = get_mohbyname("default", 1); 00977 if (mohclass) 00978 ast_atomic_fetchadd_int(&mohclass->inuse, +1); 00979 AST_LIST_UNLOCK(&mohclasses); 00980 00981 if (!mohclass) 00982 return -1; 00983 00984 ast_set_flag(chan, AST_FLAG_MOH); 00985 if (mohclass->total_files) { 00986 return ast_activate_generator(chan, &moh_file_stream, mohclass); 00987 } else 00988 return ast_activate_generator(chan, &mohgen, mohclass); 00989 }
static void local_ast_moh_stop | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 991 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().
00992 { 00993 ast_clear_flag(chan, AST_FLAG_MOH); 00994 ast_deactivate_generator(chan); 00995 00996 if (chan->music_state) { 00997 if (chan->stream) { 00998 ast_closestream(chan->stream); 00999 chan->stream = NULL; 01000 } 01001 } 01002 }
static int moh0_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 594 of file res_musiconhold.c.
References ast_log(), ast_moh_start(), ast_moh_stop(), ast_safe_sleep(), and LOG_WARNING.
Referenced by load_module().
00595 { 00596 if (ast_moh_start(chan, data, NULL)) { 00597 ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name); 00598 return 0; 00599 } 00600 while (!ast_safe_sleep(chan, 10000)); 00601 ast_moh_stop(chan); 00602 return -1; 00603 }
static int moh1_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 605 of file res_musiconhold.c.
References ast_log(), ast_moh_start(), ast_moh_stop(), ast_safe_sleep(), and LOG_WARNING.
Referenced by load_module().
00606 { 00607 int res; 00608 if (!data || !atoi(data)) { 00609 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n"); 00610 return -1; 00611 } 00612 if (ast_moh_start(chan, NULL, NULL)) { 00613 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name); 00614 return 0; 00615 } 00616 res = ast_safe_sleep(chan, atoi(data) * 1000); 00617 ast_moh_stop(chan); 00618 return res; 00619 }
static int moh2_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 621 of file res_musiconhold.c.
References ast_log(), ast_string_field_set, ast_strlen_zero(), LOG_WARNING, and musicclass.
Referenced by load_module().
00622 { 00623 if (ast_strlen_zero(data)) { 00624 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n"); 00625 return -1; 00626 } 00627 ast_string_field_set(chan, musicclass, data); 00628 return 0; 00629 }
static int moh3_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 631 of file res_musiconhold.c.
References ast_log(), ast_moh_start(), and LOG_NOTICE.
Referenced by load_module().
00632 { 00633 char *class = NULL; 00634 if (data && strlen(data)) 00635 class = data; 00636 if (ast_moh_start(chan, class, NULL)) 00637 ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name); 00638 00639 return 0; 00640 }
static int moh4_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 642 of file res_musiconhold.c.
References ast_moh_stop().
Referenced by load_module().
00643 { 00644 ast_moh_stop(chan); 00645 00646 return 0; 00647 }
static int moh_add_file | ( | struct mohclass * | class, | |
const char * | filepath | |||
) | [static] |
Definition at line 777 of file res_musiconhold.c.
References mohclass::allowed_files, ast_calloc, ast_realloc, ast_strdup, mohclass::filearray, INITIAL_NUM_FILES, and mohclass::total_files.
Referenced by moh_scan_files().
00778 { 00779 if (!class->allowed_files) { 00780 if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray)))) 00781 return -1; 00782 class->allowed_files = INITIAL_NUM_FILES; 00783 } else if (class->total_files == class->allowed_files) { 00784 if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) { 00785 class->allowed_files = 0; 00786 class->total_files = 0; 00787 return -1; 00788 } 00789 class->allowed_files *= 2; 00790 } 00791 00792 if (!(class->filearray[class->total_files] = ast_strdup(filepath))) 00793 return -1; 00794 00795 class->total_files++; 00796 00797 return 0; 00798 }
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(), 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 struct mohclass* moh_class_malloc | ( | void | ) | [static] |
Definition at line 1004 of file res_musiconhold.c.
References ast_calloc, AST_FORMAT_SLINEAR, and mohclass::format.
Referenced by load_moh_classes().
01005 { 01006 struct mohclass *class; 01007 01008 if ((class = ast_calloc(1, sizeof(*class)))) 01009 class->format = AST_FORMAT_SLINEAR; 01010 01011 return class; 01012 }
static int moh_classes_show | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1222 of file res_musiconhold.c.
References ast_cli(), ast_getformatname(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_test_flag, MOH_CUSTOM, and S_OR.
01223 { 01224 struct mohclass *class; 01225 01226 AST_LIST_LOCK(&mohclasses); 01227 AST_LIST_TRAVERSE(&mohclasses, class, list) { 01228 ast_cli(fd, "Class: %s\n", class->name); 01229 ast_cli(fd, "\tMode: %s\n", S_OR(class->mode, "<none>")); 01230 ast_cli(fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>")); 01231 ast_cli(fd, "\tUse Count: %d\n", class->inuse); 01232 if (ast_test_flag(class, MOH_CUSTOM)) 01233 ast_cli(fd, "\tApplication: %s\n", S_OR(class->args, "<none>")); 01234 if (strcasecmp(class->mode, "files")) 01235 ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format)); 01236 } 01237 AST_LIST_UNLOCK(&mohclasses); 01238 01239 return 0; 01240 }
static int moh_cli | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1197 of file res_musiconhold.c.
References reload().
01198 { 01199 reload(); 01200 return 0; 01201 }
static void* moh_files_alloc | ( | struct ast_channel * | chan, | |
void * | params | |||
) | [static] |
Definition at line 321 of file res_musiconhold.c.
References ast_calloc, ast_random(), ast_test_flag, ast_verbose(), MOH_RANDOMIZE, ast_channel::music_state, option_verbose, VERBOSE_PREFIX_3, and ast_channel::writeformat.
00322 { 00323 struct moh_files_state *state; 00324 struct mohclass *class = params; 00325 00326 if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) { 00327 chan->music_state = state; 00328 state->class = class; 00329 state->save_pos = -1; 00330 } else 00331 state = chan->music_state; 00332 00333 if (state) { 00334 if (state->class != class) { 00335 /* initialize */ 00336 memset(state, 0, sizeof(*state)); 00337 state->class = class; 00338 if (ast_test_flag(state->class, MOH_RANDOMIZE) && class->total_files) 00339 state->pos = ast_random() % class->total_files; 00340 } 00341 00342 state->origwfmt = chan->writeformat; 00343 00344 if (option_verbose > 2) 00345 ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->name, chan->name); 00346 } 00347 00348 return chan->music_state; 00349 }
static int moh_files_generator | ( | struct ast_channel * | chan, | |
void * | data, | |||
int | len, | |||
int | samples | |||
) | [static] |
Definition at line 296 of file res_musiconhold.c.
References ast_frfree, ast_log(), ast_write(), errno, f, LOG_WARNING, moh_files_readframe(), ast_channel::music_state, moh_files_state::sample_queue, and moh_files_state::samples.
00297 { 00298 struct moh_files_state *state = chan->music_state; 00299 struct ast_frame *f = NULL; 00300 int res = 0; 00301 00302 state->sample_queue += samples; 00303 00304 while (state->sample_queue > 0) { 00305 if ((f = moh_files_readframe(chan))) { 00306 state->samples += f->samples; 00307 state->sample_queue -= f->samples; 00308 res = ast_write(chan, f); 00309 ast_frfree(f); 00310 if (res < 0) { 00311 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); 00312 return -1; 00313 } 00314 } else 00315 return -1; 00316 } 00317 return res; 00318 }
static struct ast_frame* moh_files_readframe | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 284 of file res_musiconhold.c.
References ast_moh_files_next(), ast_readframe(), f, and ast_channel::stream.
Referenced by moh_files_generator().
00285 { 00286 struct ast_frame *f = NULL; 00287 00288 if (!(chan->stream && (f = ast_readframe(chan->stream)))) { 00289 if (!ast_moh_files_next(chan)) 00290 f = ast_readframe(chan->stream); 00291 } 00292 00293 return f; 00294 }
static void moh_files_release | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 202 of file res_musiconhold.c.
References ast_closestream(), ast_log(), ast_moh_destroy_one(), ast_set_write_format(), ast_verbose(), moh_files_state::class, mohclass::delete, mohclass::inuse, LOG_WARNING, ast_channel::music_state, option_verbose, moh_files_state::origwfmt, moh_files_state::pos, moh_files_state::save_pos, ast_channel::stream, and VERBOSE_PREFIX_3.
00203 { 00204 struct moh_files_state *state; 00205 00206 if (chan) { 00207 if ((state = chan->music_state)) { 00208 if (chan->stream) { 00209 ast_closestream(chan->stream); 00210 chan->stream = NULL; 00211 } 00212 if (option_verbose > 2) 00213 ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name); 00214 00215 if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) { 00216 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt); 00217 } 00218 state->save_pos = state->pos; 00219 00220 if (ast_atomic_dec_and_test(&state->class->inuse) && state->class->delete) 00221 ast_moh_destroy_one(state->class); 00222 } 00223 } 00224 }
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, and moh.
00740 { 00741 struct mohdata *moh = data; 00742 short buf[1280 + AST_FRIENDLY_OFFSET / 2]; 00743 int res; 00744 00745 if (!moh->parent->pid) 00746 return -1; 00747 00748 len = ast_codec_get_len(moh->parent->format, samples); 00749 00750 if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) { 00751 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name); 00752 len = sizeof(buf) - AST_FRIENDLY_OFFSET; 00753 } 00754 res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len); 00755 if (res <= 0) 00756 return 0; 00757 00758 moh->f.datalen = res; 00759 moh->f.data = buf + AST_FRIENDLY_OFFSET / 2; 00760 moh->f.samples = ast_codec_get_samples(&moh->f); 00761 00762 if (ast_write(chan, &moh->f) < 0) { 00763 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); 00764 return -1; 00765 } 00766 00767 return 0; 00768 }
static int moh_register | ( | struct mohclass * | moh, | |
int | reload | |||
) | [static] |
Definition at line 866 of file res_musiconhold.c.
References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_moh_free_class(), ast_pthread_create_background, ast_set_flag, ast_verbose(), mohclass::delete, free, get_mohbyname(), LOG_WARNING, moh, MOH_CUSTOM, MOH_QUIET, MOH_RANDOMIZE, moh_scan_files(), MOH_SINGLE, monmp3thread(), option_verbose, and VERBOSE_PREFIX_3.
Referenced by load_moh_classes().
00867 { 00868 #ifdef HAVE_ZAPTEL 00869 int x; 00870 #endif 00871 struct mohclass *mohclass = NULL; 00872 int res = 0; 00873 00874 AST_LIST_LOCK(&mohclasses); 00875 if ((mohclass = get_mohbyname(moh->name, 0))) { 00876 if (!mohclass->delete) { 00877 ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name); 00878 free(moh); 00879 AST_LIST_UNLOCK(&mohclasses); 00880 return -1; 00881 } 00882 } 00883 AST_LIST_UNLOCK(&mohclasses); 00884 00885 time(&moh->start); 00886 moh->start -= respawn_time; 00887 00888 if (!strcasecmp(moh->mode, "files")) { 00889 res = moh_scan_files(moh); 00890 if (res <= 0) { 00891 if (res == 0) { 00892 if (option_verbose > 2) 00893 ast_verbose(VERBOSE_PREFIX_3 "Files not found in %s for moh class:%s\n", moh->dir, moh->name); 00894 } 00895 ast_moh_free_class(&moh); 00896 return -1; 00897 } 00898 if (strchr(moh->args, 'r')) 00899 ast_set_flag(moh, MOH_RANDOMIZE); 00900 } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) { 00901 00902 if (!strcasecmp(moh->mode, "custom")) 00903 ast_set_flag(moh, MOH_CUSTOM); 00904 else if (!strcasecmp(moh->mode, "mp3nb")) 00905 ast_set_flag(moh, MOH_SINGLE); 00906 else if (!strcasecmp(moh->mode, "quietmp3nb")) 00907 ast_set_flag(moh, MOH_SINGLE | MOH_QUIET); 00908 else if (!strcasecmp(moh->mode, "quietmp3")) 00909 ast_set_flag(moh, MOH_QUIET); 00910 00911 moh->srcfd = -1; 00912 #ifdef HAVE_ZAPTEL 00913 /* Open /dev/zap/pseudo for timing... Is 00914 there a better, yet reliable way to do this? */ 00915 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY); 00916 if (moh->pseudofd < 0) { 00917 ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n"); 00918 } else { 00919 x = 320; 00920 ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x); 00921 } 00922 #else 00923 moh->pseudofd = -1; 00924 #endif 00925 if (ast_pthread_create_background(&moh->thread, NULL, monmp3thread, moh)) { 00926 ast_log(LOG_WARNING, "Unable to create moh...\n"); 00927 if (moh->pseudofd > -1) 00928 close(moh->pseudofd); 00929 ast_moh_free_class(&moh); 00930 return -1; 00931 } 00932 } else { 00933 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode); 00934 ast_moh_free_class(&moh); 00935 return -1; 00936 } 00937 00938 AST_LIST_LOCK(&mohclasses); 00939 AST_LIST_INSERT_HEAD(&mohclasses, moh, list); 00940 AST_LIST_UNLOCK(&mohclasses); 00941 00942 return 0; 00943 }
static void moh_release | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 698 of file res_musiconhold.c.
References ast_getformatname(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_log(), ast_moh_destroy_one(), ast_set_write_format(), ast_verbose(), free, LOG_WARNING, moh, option_verbose, and VERBOSE_PREFIX_3.
Referenced by moh_alloc().
00699 { 00700 struct mohdata *moh = data; 00701 int oldwfmt; 00702 00703 AST_LIST_LOCK(&mohclasses); 00704 AST_LIST_REMOVE(&moh->parent->members, moh, list); 00705 AST_LIST_UNLOCK(&mohclasses); 00706 00707 close(moh->pipe[0]); 00708 close(moh->pipe[1]); 00709 oldwfmt = moh->origwfmt; 00710 if (moh->parent->delete && ast_atomic_dec_and_test(&moh->parent->inuse)) 00711 ast_moh_destroy_one(moh->parent); 00712 free(moh); 00713 if (chan) { 00714 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 00715 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt)); 00716 if (option_verbose > 2) 00717 ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name); 00718 } 00719 }
static int moh_scan_files | ( | struct mohclass * | class | ) | [static] |
Definition at line 800 of file res_musiconhold.c.
References ast_log(), mohclass::dir, ext, mohclass::filearray, free, LOG_WARNING, moh_add_file(), and mohclass::total_files.
Referenced by moh_register().
00800 { 00801 00802 DIR *files_DIR; 00803 struct dirent *files_dirent; 00804 char path[PATH_MAX]; 00805 char filepath[PATH_MAX]; 00806 char *ext; 00807 struct stat statbuf; 00808 int dirnamelen; 00809 int i; 00810 00811 files_DIR = opendir(class->dir); 00812 if (!files_DIR) { 00813 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", class->dir); 00814 return -1; 00815 } 00816 00817 for (i = 0; i < class->total_files; i++) 00818 free(class->filearray[i]); 00819 00820 class->total_files = 0; 00821 dirnamelen = strlen(class->dir) + 2; 00822 getcwd(path, sizeof(path)); 00823 chdir(class->dir); 00824 while ((files_dirent = readdir(files_DIR))) { 00825 /* The file name must be at least long enough to have the file type extension */ 00826 if ((strlen(files_dirent->d_name) < 4)) 00827 continue; 00828 00829 /* Skip files that starts with a dot */ 00830 if (files_dirent->d_name[0] == '.') 00831 continue; 00832 00833 /* Skip files without extensions... they are not audio */ 00834 if (!strchr(files_dirent->d_name, '.')) 00835 continue; 00836 00837 snprintf(filepath, sizeof(filepath), "%s/%s", class->dir, files_dirent->d_name); 00838 00839 if (stat(filepath, &statbuf)) 00840 continue; 00841 00842 if (!S_ISREG(statbuf.st_mode)) 00843 continue; 00844 00845 if ((ext = strrchr(filepath, '.'))) { 00846 *ext = '\0'; 00847 ext++; 00848 } 00849 00850 /* if the file is present in multiple formats, ensure we only put it into the list once */ 00851 for (i = 0; i < class->total_files; i++) 00852 if (!strcmp(filepath, class->filearray[i])) 00853 break; 00854 00855 if (i == class->total_files) { 00856 if (moh_add_file(class, filepath)) 00857 break; 00858 } 00859 } 00860 00861 closedir(files_DIR); 00862 chdir(path); 00863 return class->total_files; 00864 }
Definition at line 665 of file res_musiconhold.c.
References ast_calloc, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), errno, mohclass::format, free, LOG_WARNING, moh, and mohdata::pipe.
Referenced by moh_alloc().
00666 { 00667 struct mohdata *moh; 00668 long flags; 00669 00670 if (!(moh = ast_calloc(1, sizeof(*moh)))) 00671 return NULL; 00672 00673 if (pipe(moh->pipe)) { 00674 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno)); 00675 free(moh); 00676 return NULL; 00677 } 00678 00679 /* Make entirely non-blocking */ 00680 flags = fcntl(moh->pipe[0], F_GETFL); 00681 fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK); 00682 flags = fcntl(moh->pipe[1], F_GETFL); 00683 fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK); 00684 00685 moh->f.frametype = AST_FRAME_VOICE; 00686 moh->f.subclass = cl->format; 00687 moh->f.offset = AST_FRIENDLY_OFFSET; 00688 00689 moh->parent = cl; 00690 00691 AST_LIST_LOCK(&mohclasses); 00692 AST_LIST_INSERT_HEAD(&cl->members, moh, list); 00693 AST_LIST_UNLOCK(&mohclasses); 00694 00695 return moh; 00696 }
static void* monmp3thread | ( | void * | data | ) | [static] |
Definition at line 509 of file res_musiconhold.c.
References ast_codec_get_len(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_tvadd(), len, LOG_NOTICE, LOG_WARNING, moh, MOH_MS_INTERVAL, option_debug, and spawn_mp3().
Referenced by moh_register().
00510 { 00511 #define MOH_MS_INTERVAL 100 00512 00513 struct mohclass *class = data; 00514 struct mohdata *moh; 00515 char buf[8192]; 00516 short sbuf[8192]; 00517 int res, res2; 00518 int len; 00519 struct timeval tv, tv_tmp; 00520 00521 tv.tv_sec = 0; 00522 tv.tv_usec = 0; 00523 for(;/* ever */;) { 00524 pthread_testcancel(); 00525 /* Spawn mp3 player if it's not there */ 00526 if (class->srcfd < 0) { 00527 if ((class->srcfd = spawn_mp3(class)) < 0) { 00528 ast_log(LOG_WARNING, "Unable to spawn mp3player\n"); 00529 /* Try again later */ 00530 sleep(500); 00531 pthread_testcancel(); 00532 } 00533 } 00534 if (class->pseudofd > -1) { 00535 #ifdef SOLARIS 00536 thr_yield(); 00537 #endif 00538 /* Pause some amount of time */ 00539 res = read(class->pseudofd, buf, sizeof(buf)); 00540 pthread_testcancel(); 00541 } else { 00542 long delta; 00543 /* Reliable sleep */ 00544 tv_tmp = ast_tvnow(); 00545 if (ast_tvzero(tv)) 00546 tv = tv_tmp; 00547 delta = ast_tvdiff_ms(tv_tmp, tv); 00548 if (delta < MOH_MS_INTERVAL) { /* too early */ 00549 tv = ast_tvadd(tv, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */ 00550 usleep(1000 * (MOH_MS_INTERVAL - delta)); 00551 pthread_testcancel(); 00552 } else { 00553 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n"); 00554 tv = tv_tmp; 00555 } 00556 res = 8 * MOH_MS_INTERVAL; /* 8 samples per millisecond */ 00557 } 00558 if (AST_LIST_EMPTY(&class->members)) 00559 continue; 00560 /* Read mp3 audio */ 00561 len = ast_codec_get_len(class->format, res); 00562 00563 if ((res2 = read(class->srcfd, sbuf, len)) != len) { 00564 if (!res2) { 00565 close(class->srcfd); 00566 class->srcfd = -1; 00567 pthread_testcancel(); 00568 if (class->pid > 1) { 00569 kill(class->pid, SIGHUP); 00570 usleep(100000); 00571 kill(class->pid, SIGTERM); 00572 usleep(100000); 00573 kill(class->pid, SIGKILL); 00574 class->pid = 0; 00575 } 00576 } else 00577 ast_log(LOG_DEBUG, "Read %d bytes of audio while expecting %d\n", res2, len); 00578 continue; 00579 } 00580 pthread_testcancel(); 00581 AST_LIST_LOCK(&mohclasses); 00582 AST_LIST_TRAVERSE(&class->members, moh, list) { 00583 /* Write data */ 00584 if ((res = write(moh->pipe[1], sbuf, res2)) != res2) { 00585 if (option_debug) 00586 ast_log(LOG_DEBUG, "Only wrote %d of %d bytes to pipe\n", res, res2); 00587 } 00588 } 00589 AST_LIST_UNLOCK(&mohclasses); 00590 } 00591 return NULL; 00592 }
static int reload | ( | void | ) | [static] |
Definition at line 1312 of file res_musiconhold.c.
References ast_install_music_functions(), init_classes(), local_ast_moh_cleanup(), local_ast_moh_start(), and local_ast_moh_stop().
01313 { 01314 if (init_classes(1)) 01315 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup); 01316 01317 return 0; 01318 }
static int spawn_mp3 | ( | struct mohclass * | class | ) | [static] |
Definition at line 358 of file res_musiconhold.c.
References mohclass::args, 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, mohclass::start, and strsep().
Referenced by monmp3thread().
00359 { 00360 int fds[2]; 00361 int files = 0; 00362 char fns[MAX_MP3S][80]; 00363 char *argv[MAX_MP3S + 50]; 00364 char xargs[256]; 00365 char *argptr; 00366 int argc = 0; 00367 DIR *dir = NULL; 00368 struct dirent *de; 00369 sigset_t signal_set, old_set; 00370 00371 00372 if (!strcasecmp(class->dir, "nodir")) { 00373 files = 1; 00374 } else { 00375 dir = opendir(class->dir); 00376 if (!dir && !strstr(class->dir,"http://") && !strstr(class->dir,"HTTP://")) { 00377 ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir); 00378 return -1; 00379 } 00380 } 00381 00382 if (!ast_test_flag(class, MOH_CUSTOM)) { 00383 argv[argc++] = "mpg123"; 00384 argv[argc++] = "-q"; 00385 argv[argc++] = "-s"; 00386 argv[argc++] = "--mono"; 00387 argv[argc++] = "-r"; 00388 argv[argc++] = "8000"; 00389 00390 if (!ast_test_flag(class, MOH_SINGLE)) { 00391 argv[argc++] = "-b"; 00392 argv[argc++] = "2048"; 00393 } 00394 00395 argv[argc++] = "-f"; 00396 00397 if (ast_test_flag(class, MOH_QUIET)) 00398 argv[argc++] = "4096"; 00399 else 00400 argv[argc++] = "8192"; 00401 00402 /* Look for extra arguments and add them to the list */ 00403 ast_copy_string(xargs, class->args, sizeof(xargs)); 00404 argptr = xargs; 00405 while (!ast_strlen_zero(argptr)) { 00406 argv[argc++] = argptr; 00407 strsep(&argptr, ","); 00408 } 00409 } else { 00410 /* Format arguments for argv vector */ 00411 ast_copy_string(xargs, class->args, sizeof(xargs)); 00412 argptr = xargs; 00413 while (!ast_strlen_zero(argptr)) { 00414 argv[argc++] = argptr; 00415 strsep(&argptr, " "); 00416 } 00417 } 00418 00419 00420 if (strstr(class->dir,"http://") || strstr(class->dir,"HTTP://")) { 00421 ast_copy_string(fns[files], class->dir, sizeof(fns[files])); 00422 argv[argc++] = fns[files]; 00423 files++; 00424 } else if (dir) { 00425 while ((de = readdir(dir)) && (files < MAX_MP3S)) { 00426 if ((strlen(de->d_name) > 3) && 00427 ((ast_test_flag(class, MOH_CUSTOM) && 00428 (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 00429 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) || 00430 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) { 00431 ast_copy_string(fns[files], de->d_name, sizeof(fns[files])); 00432 argv[argc++] = fns[files]; 00433 files++; 00434 } 00435 } 00436 } 00437 argv[argc] = NULL; 00438 if (dir) { 00439 closedir(dir); 00440 } 00441 if (pipe(fds)) { 00442 ast_log(LOG_WARNING, "Pipe failed\n"); 00443 return -1; 00444 } 00445 if (!files) { 00446 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir); 00447 close(fds[0]); 00448 close(fds[1]); 00449 return -1; 00450 } 00451 if (time(NULL) - class->start < respawn_time) { 00452 sleep(respawn_time - (time(NULL) - class->start)); 00453 } 00454 00455 /* Block signals during the fork() */ 00456 sigfillset(&signal_set); 00457 pthread_sigmask(SIG_BLOCK, &signal_set, &old_set); 00458 00459 time(&class->start); 00460 class->pid = fork(); 00461 if (class->pid < 0) { 00462 close(fds[0]); 00463 close(fds[1]); 00464 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno)); 00465 return -1; 00466 } 00467 if (!class->pid) { 00468 int x; 00469 00470 if (ast_opt_high_priority) 00471 ast_set_priority(0); 00472 00473 /* Reset ignored signals back to default */ 00474 signal(SIGPIPE, SIG_DFL); 00475 pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL); 00476 00477 close(fds[0]); 00478 /* Stdout goes to pipe */ 00479 dup2(fds[1], STDOUT_FILENO); 00480 /* Close unused file descriptors */ 00481 for (x=3;x<8192;x++) { 00482 if (-1 != fcntl(x, F_GETFL)) { 00483 close(x); 00484 } 00485 } 00486 /* Child */ 00487 chdir(class->dir); 00488 if (ast_test_flag(class, MOH_CUSTOM)) { 00489 execv(argv[0], argv); 00490 } else { 00491 /* Default install is /usr/local/bin */ 00492 execv(LOCAL_MPG_123, argv); 00493 /* Many places have it in /usr/bin */ 00494 execv(MPG_123, argv); 00495 /* Check PATH as a last-ditch effort */ 00496 execvp("mpg123", argv); 00497 } 00498 ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno)); 00499 close(fds[1]); 00500 _exit(1); 00501 } else { 00502 /* Parent */ 00503 pthread_sigmask(SIG_SETMASK, &old_set, NULL); 00504 close(fds[1]); 00505 } 00506 return fds[0]; 00507 }
static int unload_module | ( | void | ) | [static] |
Definition at line 1320 of file res_musiconhold.c.
References ast_cli_unregister_multiple(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_moh_destroy(), ast_uninstall_music_functions(), ast_unregister_application(), cli_moh, and LOG_WARNING.
01321 { 01322 int res = 0; 01323 struct mohclass *class = NULL; 01324 01325 AST_LIST_LOCK(&mohclasses); 01326 AST_LIST_TRAVERSE(&mohclasses, class, list) { 01327 if (class->inuse > 0) { 01328 res = -1; 01329 break; 01330 } 01331 } 01332 AST_LIST_UNLOCK(&mohclasses); 01333 if (res < 0) { 01334 ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n"); 01335 return res; 01336 } 01337 01338 ast_uninstall_music_functions(); 01339 ast_moh_destroy(); 01340 res = ast_unregister_application(app0); 01341 res |= ast_unregister_application(app1); 01342 res |= ast_unregister_application(app2); 01343 res |= ast_unregister_application(app3); 01344 res |= ast_unregister_application(app4); 01345 ast_cli_unregister_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry)); 01346 return res; 01347 }
char* app0 = "MusicOnHold" [static] |
Definition at line 77 of file res_musiconhold.c.
char* app1 = "WaitMusicOnHold" [static] |
Definition at line 78 of file res_musiconhold.c.
char* app2 = "SetMusicOnHold" [static] |
Definition at line 79 of file res_musiconhold.c.
char* app3 = "StartMusicOnHold" [static] |
Definition at line 80 of file res_musiconhold.c.
char* app4 = "StopMusicOnHold" [static] |
Definition at line 81 of file res_musiconhold.c.
struct ast_cli_entry cli_moh[] [static] |
Definition at line 1252 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 1242 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 1247 of file res_musiconhold.c.
char* descrip0 [static] |
Definition at line 89 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 96 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 101 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 106 of file res_musiconhold.c.
char* descrip4 [static] |
Initial value:
"StopMusicOnHold: " "Stops playing music on hold.\n"
Definition at line 111 of file res_musiconhold.c.
struct ast_generator moh_file_stream [static] |
struct ast_generator mohgen [static] |
int respawn_time = 20 [static] |
Definition at line 114 of file res_musiconhold.c.
char* synopsis0 = "Play Music On Hold indefinitely" [static] |
Definition at line 83 of file res_musiconhold.c.
char* synopsis1 = "Wait, playing Music On Hold" [static] |
Definition at line 84 of file res_musiconhold.c.
char* synopsis2 = "Set default Music On Hold class" [static] |
Definition at line 85 of file res_musiconhold.c.
char* synopsis3 = "Play Music On Hold" [static] |
Definition at line 86 of file res_musiconhold.c.
char* synopsis4 = "Stop Playing Music On Hold" [static] |
Definition at line 87 of file res_musiconhold.c.