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