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