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