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