#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 dependency graph for res_musiconhold.c:
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 1180 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().
01181 { 01182 struct mohclass *moh; 01183 01184 if (option_verbose > 1) 01185 ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n"); 01186 01187 AST_LIST_LOCK(&mohclasses); 01188 while ((moh = AST_LIST_REMOVE_HEAD(&mohclasses, list))) { 01189 ast_moh_destroy_one(moh); 01190 } 01191 AST_LIST_UNLOCK(&mohclasses); 01192 }
static int ast_moh_destroy_one | ( | struct mohclass * | moh | ) | [static] |
Definition at line 1150 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().
01151 { 01152 char buff[8192]; 01153 int bytes, tbytes = 0, stime = 0, pid = 0; 01154 01155 if (moh) { 01156 if (moh->pid > 1) { 01157 ast_log(LOG_DEBUG, "killing %d!\n", moh->pid); 01158 stime = time(NULL) + 2; 01159 pid = moh->pid; 01160 moh->pid = 0; 01161 /* Back when this was just mpg123, SIGKILL was fine. Now we need 01162 * to give the process a reason and time enough to kill off its 01163 * children. */ 01164 kill(pid, SIGHUP); 01165 usleep(100000); 01166 kill(pid, SIGTERM); 01167 usleep(100000); 01168 kill(pid, SIGKILL); 01169 while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime) 01170 tbytes = tbytes + bytes; 01171 ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes); 01172 close(moh->srcfd); 01173 } 01174 ast_moh_free_class(&moh); 01175 } 01176 01177 return 0; 01178 }
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_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 = rand() % 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 1200 of file res_musiconhold.c.
References ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, and AST_LIST_UNLOCK.
01201 { 01202 int i; 01203 struct mohclass *class; 01204 01205 AST_LIST_LOCK(&mohclasses); 01206 AST_LIST_TRAVERSE(&mohclasses, class, list) { 01207 if (!class->total_files) 01208 continue; 01209 01210 ast_cli(fd, "Class: %s\n", class->name); 01211 for (i = 0; i < class->total_files; i++) 01212 ast_cli(fd, "\tFile: %s\n", class->filearray[i]); 01213 } 01214 AST_LIST_UNLOCK(&mohclasses); 01215 01216 return 0; 01217 }
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 1263 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_log(), ast_moh_destroy_one(), load_moh_classes(), LOG_WARNING, moh, and moh_scan_files().
Referenced by load_module(), and reload().
01264 { 01265 struct mohclass *moh; 01266 01267 if (!load_moh_classes(reload)) /* Load classes from config */ 01268 return 0; /* Return if nothing is found */ 01269 01270 AST_LIST_LOCK(&mohclasses); 01271 AST_LIST_TRAVERSE_SAFE_BEGIN(&mohclasses, moh, list) { 01272 if (reload && moh->delete) { 01273 AST_LIST_REMOVE_CURRENT(&mohclasses, list); 01274 if (!moh->inuse) 01275 ast_moh_destroy_one(moh); 01276 } else if (moh->total_files) { 01277 if (moh_scan_files(moh) <= 0) { 01278 ast_log(LOG_WARNING, "No files found for class '%s'\n", moh->name); 01279 moh->delete = 1; 01280 AST_LIST_REMOVE_CURRENT(&mohclasses, list); 01281 if (!moh->inuse) 01282 ast_moh_destroy_one(moh); 01283 } 01284 } 01285 } 01286 AST_LIST_TRAVERSE_SAFE_END 01287 AST_LIST_UNLOCK(&mohclasses); 01288 01289 return 1; 01290 }
static int load_module | ( | void | ) | [static] |
Definition at line 1292 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().
01293 { 01294 int res; 01295 01296 res = ast_register_application(app0, moh0_exec, synopsis0, descrip0); 01297 ast_register_atexit(ast_moh_destroy); 01298 ast_cli_register_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry)); 01299 if (!res) 01300 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1); 01301 if (!res) 01302 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2); 01303 if (!res) 01304 res = ast_register_application(app3, moh3_exec, synopsis3, descrip3); 01305 if (!res) 01306 res = ast_register_application(app4, moh4_exec, synopsis4, descrip4); 01307 01308 if (!init_classes(0)) { /* No music classes configured, so skip it */ 01309 ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold.\n"); 01310 } else { 01311 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup); 01312 } 01313 01314 return 0; 01315 }
static int load_moh_classes | ( | int | reload | ) | [static] |
Definition at line 1011 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().
01012 { 01013 struct ast_config *cfg; 01014 struct ast_variable *var; 01015 struct mohclass *class; 01016 char *data; 01017 char *args; 01018 char *cat; 01019 int numclasses = 0; 01020 static int dep_warning = 0; 01021 01022 cfg = ast_config_load("musiconhold.conf"); 01023 01024 if (!cfg) 01025 return 0; 01026 01027 if (reload) { 01028 AST_LIST_LOCK(&mohclasses); 01029 AST_LIST_TRAVERSE(&mohclasses, class, list) 01030 class->delete = 1; 01031 AST_LIST_UNLOCK(&mohclasses); 01032 } 01033 01034 cat = ast_category_browse(cfg, NULL); 01035 for (; cat; cat = ast_category_browse(cfg, cat)) { 01036 if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) { 01037 if (!(class = moh_class_malloc())) { 01038 break; 01039 } 01040 ast_copy_string(class->name, cat, sizeof(class->name)); 01041 var = ast_variable_browse(cfg, cat); 01042 while (var) { 01043 if (!strcasecmp(var->name, "mode")) 01044 ast_copy_string(class->mode, var->value, sizeof(class->mode)); 01045 else if (!strcasecmp(var->name, "directory")) 01046 ast_copy_string(class->dir, var->value, sizeof(class->dir)); 01047 else if (!strcasecmp(var->name, "application")) 01048 ast_copy_string(class->args, var->value, sizeof(class->args)); 01049 else if (!strcasecmp(var->name, "random")) 01050 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE); 01051 else if (!strcasecmp(var->name, "format")) { 01052 class->format = ast_getformatbyname(var->value); 01053 if (!class->format) { 01054 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value); 01055 class->format = AST_FORMAT_SLINEAR; 01056 } 01057 } 01058 var = var->next; 01059 } 01060 01061 if (ast_strlen_zero(class->dir)) { 01062 if (!strcasecmp(class->mode, "custom")) { 01063 strcpy(class->dir, "nodir"); 01064 } else { 01065 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name); 01066 free(class); 01067 continue; 01068 } 01069 } 01070 if (ast_strlen_zero(class->mode)) { 01071 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name); 01072 free(class); 01073 continue; 01074 } 01075 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) { 01076 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name); 01077 free(class); 01078 continue; 01079 } 01080 01081 /* Don't leak a class when it's already registered */ 01082 moh_register(class, reload); 01083 01084 numclasses++; 01085 } 01086 } 01087 01088 01089 /* Deprecated Old-School Configuration */ 01090 var = ast_variable_browse(cfg, "classes"); 01091 while (var) { 01092 if (!dep_warning) { 01093 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"); 01094 dep_warning = 1; 01095 } 01096 data = strchr(var->value, ':'); 01097 if (data) { 01098 *data++ = '\0'; 01099 args = strchr(data, ','); 01100 if (args) 01101 *args++ = '\0'; 01102 if (!(get_mohbyname(var->name, 0))) { 01103 if (!(class = moh_class_malloc())) { 01104 break; 01105 } 01106 01107 ast_copy_string(class->name, var->name, sizeof(class->name)); 01108 ast_copy_string(class->dir, data, sizeof(class->dir)); 01109 ast_copy_string(class->mode, var->value, sizeof(class->mode)); 01110 if (args) 01111 ast_copy_string(class->args, args, sizeof(class->args)); 01112 01113 moh_register(class, reload); 01114 numclasses++; 01115 } 01116 } 01117 var = var->next; 01118 } 01119 var = ast_variable_browse(cfg, "moh_files"); 01120 while (var) { 01121 if (!dep_warning) { 01122 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"); 01123 dep_warning = 1; 01124 } 01125 if (!(get_mohbyname(var->name, 0))) { 01126 args = strchr(var->value, ','); 01127 if (args) 01128 *args++ = '\0'; 01129 if (!(class = moh_class_malloc())) { 01130 break; 01131 } 01132 01133 ast_copy_string(class->name, var->name, sizeof(class->name)); 01134 ast_copy_string(class->dir, var->value, sizeof(class->dir)); 01135 strcpy(class->mode, "files"); 01136 if (args) 01137 ast_copy_string(class->args, args, sizeof(class->args)); 01138 01139 moh_register(class, reload); 01140 numclasses++; 01141 } 01142 var = var->next; 01143 } 01144 01145 ast_config_destroy(cfg); 01146 01147 return numclasses; 01148 }
static void local_ast_moh_cleanup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 942 of file res_musiconhold.c.
References free, and ast_channel::music_state.
Referenced by load_module(), and reload().
00943 { 00944 if (chan->music_state) { 00945 free(chan->music_state); 00946 chan->music_state = NULL; 00947 } 00948 }
static int local_ast_moh_start | ( | struct ast_channel * | chan, | |
const char * | mclass, | |||
const char * | interpclass | |||
) | [static] |
Definition at line 950 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().
00951 { 00952 struct mohclass *mohclass = NULL; 00953 00954 /* The following is the order of preference for which class to use: 00955 * 1) The channels explicitly set musicclass, which should *only* be 00956 * set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan. 00957 * 2) The mclass argument. If a channel is calling ast_moh_start() as the 00958 * result of receiving a HOLD control frame, this should be the 00959 * payload that came with the frame. 00960 * 3) The interpclass argument. This would be from the mohinterpret 00961 * option from channel drivers. This is the same as the old musicclass 00962 * option. 00963 * 4) The default class. 00964 */ 00965 AST_LIST_LOCK(&mohclasses); 00966 if (!ast_strlen_zero(chan->musicclass)) 00967 mohclass = get_mohbyname(chan->musicclass, 1); 00968 if (!mohclass && !ast_strlen_zero(mclass)) 00969 mohclass = get_mohbyname(mclass, 1); 00970 if (!mohclass && !ast_strlen_zero(interpclass)) 00971 mohclass = get_mohbyname(interpclass, 1); 00972 if (!mohclass) 00973 mohclass = get_mohbyname("default", 1); 00974 if (mohclass) 00975 ast_atomic_fetchadd_int(&mohclass->inuse, +1); 00976 AST_LIST_UNLOCK(&mohclasses); 00977 00978 if (!mohclass) 00979 return -1; 00980 00981 ast_set_flag(chan, AST_FLAG_MOH); 00982 if (mohclass->total_files) { 00983 return ast_activate_generator(chan, &moh_file_stream, mohclass); 00984 } else 00985 return ast_activate_generator(chan, &mohgen, mohclass); 00986 }
static void local_ast_moh_stop | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 988 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().
00989 { 00990 ast_clear_flag(chan, AST_FLAG_MOH); 00991 ast_deactivate_generator(chan); 00992 00993 if (chan->music_state) { 00994 if (chan->stream) { 00995 ast_closestream(chan->stream); 00996 chan->stream = NULL; 00997 } 00998 } 00999 }
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 1001 of file res_musiconhold.c.
References ast_calloc, AST_FORMAT_SLINEAR, and mohclass::format.
Referenced by load_moh_classes().
01002 { 01003 struct mohclass *class; 01004 01005 if ((class = ast_calloc(1, sizeof(*class)))) 01006 class->format = AST_FORMAT_SLINEAR; 01007 01008 return class; 01009 }
static int moh_classes_show | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1219 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.
01220 { 01221 struct mohclass *class; 01222 01223 AST_LIST_LOCK(&mohclasses); 01224 AST_LIST_TRAVERSE(&mohclasses, class, list) { 01225 ast_cli(fd, "Class: %s\n", class->name); 01226 ast_cli(fd, "\tMode: %s\n", S_OR(class->mode, "<none>")); 01227 ast_cli(fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>")); 01228 ast_cli(fd, "\tUse Count: %d\n", class->inuse); 01229 if (ast_test_flag(class, MOH_CUSTOM)) 01230 ast_cli(fd, "\tApplication: %s\n", S_OR(class->args, "<none>")); 01231 if (strcasecmp(class->mode, "files")) 01232 ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format)); 01233 } 01234 AST_LIST_UNLOCK(&mohclasses); 01235 01236 return 0; 01237 }
static int moh_cli | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1194 of file res_musiconhold.c.
References reload().
01195 { 01196 reload(); 01197 return 0; 01198 }
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 res = ast_write(chan, f); 00308 state->sample_queue -= f->samples; 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, mohclass::delete, free, get_mohbyname(), LOG_DEBUG, LOG_WARNING, moh, MOH_CUSTOM, MOH_QUIET, MOH_RANDOMIZE, moh_scan_files(), MOH_SINGLE, and monmp3thread().
Referenced by load_moh_classes().
00867 { 00868 #ifdef HAVE_ZAPTEL 00869 int x; 00870 #endif 00871 struct mohclass *mohclass = NULL; 00872 00873 AST_LIST_LOCK(&mohclasses); 00874 if ((mohclass = get_mohbyname(moh->name, 0))) { 00875 mohclass->delete = 0; 00876 if (reload) { 00877 ast_log(LOG_DEBUG, "Music on Hold class '%s' left alone from initial load.\n", moh->name); 00878 } else { 00879 ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name); 00880 } 00881 free(moh); 00882 AST_LIST_UNLOCK(&mohclasses); 00883 return -1; 00884 } 00885 AST_LIST_UNLOCK(&mohclasses); 00886 00887 time(&moh->start); 00888 moh->start -= respawn_time; 00889 00890 if (!strcasecmp(moh->mode, "files")) { 00891 if (!moh_scan_files(moh)) { 00892 ast_moh_free_class(&moh); 00893 return -1; 00894 } 00895 if (strchr(moh->args, 'r')) 00896 ast_set_flag(moh, MOH_RANDOMIZE); 00897 } 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")) { 00898 00899 if (!strcasecmp(moh->mode, "custom")) 00900 ast_set_flag(moh, MOH_CUSTOM); 00901 else if (!strcasecmp(moh->mode, "mp3nb")) 00902 ast_set_flag(moh, MOH_SINGLE); 00903 else if (!strcasecmp(moh->mode, "quietmp3nb")) 00904 ast_set_flag(moh, MOH_SINGLE | MOH_QUIET); 00905 else if (!strcasecmp(moh->mode, "quietmp3")) 00906 ast_set_flag(moh, MOH_QUIET); 00907 00908 moh->srcfd = -1; 00909 #ifdef HAVE_ZAPTEL 00910 /* Open /dev/zap/pseudo for timing... Is 00911 there a better, yet reliable way to do this? */ 00912 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY); 00913 if (moh->pseudofd < 0) { 00914 ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n"); 00915 } else { 00916 x = 320; 00917 ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x); 00918 } 00919 #else 00920 moh->pseudofd = -1; 00921 #endif 00922 if (ast_pthread_create_background(&moh->thread, NULL, monmp3thread, moh)) { 00923 ast_log(LOG_WARNING, "Unable to create moh...\n"); 00924 if (moh->pseudofd > -1) 00925 close(moh->pseudofd); 00926 ast_moh_free_class(&moh); 00927 return -1; 00928 } 00929 } else { 00930 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode); 00931 ast_moh_free_class(&moh); 00932 return -1; 00933 } 00934 00935 AST_LIST_LOCK(&mohclasses); 00936 AST_LIST_INSERT_HEAD(&mohclasses, moh, list); 00937 AST_LIST_UNLOCK(&mohclasses); 00938 00939 return 0; 00940 }
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 init_classes(), and 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 1317 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().
01318 { 01319 if (init_classes(1)) 01320 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup); 01321 01322 return 0; 01323 }
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] |
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] |
struct ast_cli_entry cli_moh_classes_show_deprecated [static] |
Initial value:
{ { "moh", "classes", "show"}, moh_classes_show, NULL, NULL }
Definition at line 1239 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 1244 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.