#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_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) |
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 1113 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, and VERBOSE_PREFIX_2.
Referenced by load_module(), and moh_cli().
01114 { 01115 struct mohclass *moh; 01116 char buff[8192]; 01117 int bytes, tbytes = 0, stime = 0, pid = 0; 01118 01119 if (option_verbose > 1) 01120 ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n"); 01121 01122 AST_LIST_LOCK(&mohclasses); 01123 while ((moh = AST_LIST_REMOVE_HEAD(&mohclasses, list))) { 01124 if (moh->pid > 1) { 01125 ast_log(LOG_DEBUG, "killing %d!\n", moh->pid); 01126 stime = time(NULL) + 2; 01127 pid = moh->pid; 01128 moh->pid = 0; 01129 /* Back when this was just mpg123, SIGKILL was fine. Now we need 01130 * to give the process a reason and time enough to kill off its 01131 * children. */ 01132 kill(pid, SIGHUP); 01133 usleep(100000); 01134 kill(pid, SIGTERM); 01135 usleep(100000); 01136 kill(pid, SIGKILL); 01137 while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime) 01138 tbytes = tbytes + bytes; 01139 ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes); 01140 close(moh->srcfd); 01141 } 01142 ast_moh_free_class(&moh); 01143 } 01144 AST_LIST_UNLOCK(&mohclasses); 01145 }
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_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().
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 1174 of file res_musiconhold.c.
References ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, and AST_LIST_UNLOCK.
01175 { 01176 int i; 01177 struct mohclass *class; 01178 01179 AST_LIST_LOCK(&mohclasses); 01180 AST_LIST_TRAVERSE(&mohclasses, class, list) { 01181 if (!class->total_files) 01182 continue; 01183 01184 ast_cli(fd, "Class: %s\n", class->name); 01185 for (i = 0; i < class->total_files; i++) 01186 ast_cli(fd, "\tFile: %s\n", class->filearray[i]); 01187 } 01188 AST_LIST_UNLOCK(&mohclasses); 01189 01190 return 0; 01191 }
static struct mohclass* get_mohbyname | ( | const char * | name | ) | [static] |
Definition at line 628 of file res_musiconhold.c.
References AST_LIST_TRAVERSE, and moh.
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 return moh; 00638 }
static int init_classes | ( | int | reload | ) | [static] |
Definition at line 1236 of file res_musiconhold.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, load_moh_classes(), moh, and moh_scan_files().
Referenced by load_module(), and reload().
01237 { 01238 struct mohclass *moh; 01239 01240 if (!load_moh_classes(reload)) /* Load classes from config */ 01241 return 0; /* Return if nothing is found */ 01242 01243 AST_LIST_LOCK(&mohclasses); 01244 AST_LIST_TRAVERSE(&mohclasses, moh, list) { 01245 if (moh->total_files) 01246 moh_scan_files(moh); 01247 } 01248 AST_LIST_UNLOCK(&mohclasses); 01249 01250 return 1; 01251 }
static int load_module | ( | void | ) | [static] |
Definition at line 1253 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().
01254 { 01255 int res; 01256 01257 res = ast_register_application(app0, moh0_exec, synopsis0, descrip0); 01258 ast_register_atexit(ast_moh_destroy); 01259 ast_cli_register_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry)); 01260 if (!res) 01261 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1); 01262 if (!res) 01263 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2); 01264 if (!res) 01265 res = ast_register_application(app3, moh3_exec, synopsis3, descrip3); 01266 if (!res) 01267 res = ast_register_application(app4, moh4_exec, synopsis4, descrip4); 01268 01269 if (!init_classes(0)) { /* No music classes configured, so skip it */ 01270 ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold.\n"); 01271 } else { 01272 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup); 01273 } 01274 01275 return 0; 01276 }
static int load_moh_classes | ( | int | reload | ) | [static] |
Definition at line 981 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(), and var.
Referenced by init_classes(), and moh_cli().
00982 { 00983 struct ast_config *cfg; 00984 struct ast_variable *var; 00985 struct mohclass *class; 00986 char *data; 00987 char *args; 00988 char *cat; 00989 int numclasses = 0; 00990 static int dep_warning = 0; 00991 00992 cfg = ast_config_load("musiconhold.conf"); 00993 00994 if (!cfg) 00995 return 0; 00996 00997 cat = ast_category_browse(cfg, NULL); 00998 for (; cat; cat = ast_category_browse(cfg, cat)) { 00999 if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) { 01000 if (!(class = moh_class_malloc())) { 01001 break; 01002 } 01003 ast_copy_string(class->name, cat, sizeof(class->name)); 01004 var = ast_variable_browse(cfg, cat); 01005 while (var) { 01006 if (!strcasecmp(var->name, "mode")) 01007 ast_copy_string(class->mode, var->value, sizeof(class->mode)); 01008 else if (!strcasecmp(var->name, "directory")) 01009 ast_copy_string(class->dir, var->value, sizeof(class->dir)); 01010 else if (!strcasecmp(var->name, "application")) 01011 ast_copy_string(class->args, var->value, sizeof(class->args)); 01012 else if (!strcasecmp(var->name, "random")) 01013 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE); 01014 else if (!strcasecmp(var->name, "format")) { 01015 class->format = ast_getformatbyname(var->value); 01016 if (!class->format) { 01017 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value); 01018 class->format = AST_FORMAT_SLINEAR; 01019 } 01020 } 01021 var = var->next; 01022 } 01023 01024 if (ast_strlen_zero(class->dir)) { 01025 if (!strcasecmp(class->mode, "custom")) { 01026 strcpy(class->dir, "nodir"); 01027 } else { 01028 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name); 01029 free(class); 01030 continue; 01031 } 01032 } 01033 if (ast_strlen_zero(class->mode)) { 01034 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name); 01035 free(class); 01036 continue; 01037 } 01038 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) { 01039 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name); 01040 free(class); 01041 continue; 01042 } 01043 01044 /* Don't leak a class when it's already registered */ 01045 moh_register(class, reload); 01046 01047 numclasses++; 01048 } 01049 } 01050 01051 01052 /* Deprecated Old-School Configuration */ 01053 var = ast_variable_browse(cfg, "classes"); 01054 while (var) { 01055 if (!dep_warning) { 01056 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"); 01057 dep_warning = 1; 01058 } 01059 data = strchr(var->value, ':'); 01060 if (data) { 01061 *data++ = '\0'; 01062 args = strchr(data, ','); 01063 if (args) 01064 *args++ = '\0'; 01065 if (!(get_mohbyname(var->name))) { 01066 if (!(class = moh_class_malloc())) { 01067 return numclasses; 01068 } 01069 01070 ast_copy_string(class->name, var->name, sizeof(class->name)); 01071 ast_copy_string(class->dir, data, sizeof(class->dir)); 01072 ast_copy_string(class->mode, var->value, sizeof(class->mode)); 01073 if (args) 01074 ast_copy_string(class->args, args, sizeof(class->args)); 01075 01076 moh_register(class, reload); 01077 numclasses++; 01078 } 01079 } 01080 var = var->next; 01081 } 01082 var = ast_variable_browse(cfg, "moh_files"); 01083 while (var) { 01084 if (!dep_warning) { 01085 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"); 01086 dep_warning = 1; 01087 } 01088 if (!(get_mohbyname(var->name))) { 01089 args = strchr(var->value, ','); 01090 if (args) 01091 *args++ = '\0'; 01092 if (!(class = moh_class_malloc())) { 01093 return numclasses; 01094 } 01095 01096 ast_copy_string(class->name, var->name, sizeof(class->name)); 01097 ast_copy_string(class->dir, var->value, sizeof(class->dir)); 01098 strcpy(class->mode, "files"); 01099 if (args) 01100 ast_copy_string(class->args, args, sizeof(class->args)); 01101 01102 moh_register(class, reload); 01103 numclasses++; 01104 } 01105 var = var->next; 01106 } 01107 01108 ast_config_destroy(cfg); 01109 01110 return numclasses; 01111 }
static void local_ast_moh_cleanup | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 909 of file res_musiconhold.c.
References free, and ast_channel::music_state.
Referenced by load_module(), and reload().
00910 { 00911 if (chan->music_state) { 00912 free(chan->music_state); 00913 chan->music_state = NULL; 00914 } 00915 }
static int local_ast_moh_start | ( | struct ast_channel * | chan, | |
const char * | mclass, | |||
const char * | interpclass | |||
) | [static] |
Definition at line 917 of file res_musiconhold.c.
References ast_activate_generator(), AST_FLAG_MOH, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_set_flag, ast_strlen_zero(), get_mohbyname(), LOG_WARNING, moh_file_stream, mohgen, and mohclass::total_files.
Referenced by load_module(), moh_on_off(), and reload().
00918 { 00919 struct mohclass *mohclass; 00920 const char *class; 00921 00922 /* The following is the order of preference for which class to use: 00923 * 1) The channels explicitly set musicclass, which should *only* be 00924 * set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan. 00925 * 2) The mclass argument. If a channel is calling ast_moh_start() as the 00926 * result of receiving a HOLD control frame, this should be the 00927 * payload that came with the frame. 00928 * 3) The interpclass argument. This would be from the mohinterpret 00929 * option from channel drivers. This is the same as the old musicclass 00930 * option. 00931 * 4) The default class. 00932 */ 00933 if (!ast_strlen_zero(chan->musicclass)) 00934 class = chan->musicclass; 00935 else if (!ast_strlen_zero(mclass)) 00936 class = mclass; 00937 else if (!ast_strlen_zero(interpclass)) 00938 class = interpclass; 00939 else 00940 class = "default"; 00941 00942 AST_LIST_LOCK(&mohclasses); 00943 mohclass = get_mohbyname(class); 00944 AST_LIST_UNLOCK(&mohclasses); 00945 00946 if (!mohclass) { 00947 ast_log(LOG_WARNING, "No class: %s\n", class); 00948 return -1; 00949 } 00950 00951 ast_set_flag(chan, AST_FLAG_MOH); 00952 if (mohclass->total_files) { 00953 return ast_activate_generator(chan, &moh_file_stream, mohclass); 00954 } else 00955 return ast_activate_generator(chan, &mohgen, mohclass); 00956 }
static void local_ast_moh_stop | ( | struct ast_channel * | chan | ) | [static] |
Definition at line 958 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().
00959 { 00960 ast_clear_flag(chan, AST_FLAG_MOH); 00961 ast_deactivate_generator(chan); 00962 00963 if (chan->music_state) { 00964 if (chan->stream) { 00965 ast_closestream(chan->stream); 00966 chan->stream = NULL; 00967 } 00968 } 00969 }
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 -1; 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 -1; 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 747 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().
00748 { 00749 if (!class->allowed_files) { 00750 if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray)))) 00751 return -1; 00752 class->allowed_files = INITIAL_NUM_FILES; 00753 } else if (class->total_files == class->allowed_files) { 00754 if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) { 00755 class->allowed_files = 0; 00756 class->total_files = 0; 00757 return -1; 00758 } 00759 class->allowed_files *= 2; 00760 } 00761 00762 if (!(class->filearray[class->total_files] = ast_strdup(filepath))) 00763 return -1; 00764 00765 class->total_files++; 00766 00767 return 0; 00768 }
static void* moh_alloc | ( | struct ast_channel * | chan, | |
void * | params | |||
) | [static] |
Definition at line 691 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.
00692 { 00693 struct mohdata *res; 00694 struct mohclass *class = params; 00695 00696 if ((res = mohalloc(class))) { 00697 res->origwfmt = chan->writeformat; 00698 if (ast_set_write_format(chan, class->format)) { 00699 ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format)); 00700 moh_release(NULL, res); 00701 res = NULL; 00702 } 00703 if (option_verbose > 2) 00704 ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name); 00705 } 00706 return res; 00707 }
static struct mohclass* moh_class_malloc | ( | void | ) | [static] |
Definition at line 971 of file res_musiconhold.c.
References ast_calloc, AST_FORMAT_SLINEAR, and mohclass::format.
Referenced by load_moh_classes().
00972 { 00973 struct mohclass *class; 00974 00975 if ((class = ast_calloc(1, sizeof(*class)))) 00976 class->format = AST_FORMAT_SLINEAR; 00977 00978 return class; 00979 }
static int moh_classes_show | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1193 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.
01194 { 01195 struct mohclass *class; 01196 01197 AST_LIST_LOCK(&mohclasses); 01198 AST_LIST_TRAVERSE(&mohclasses, class, list) { 01199 ast_cli(fd, "Class: %s\n", class->name); 01200 ast_cli(fd, "\tMode: %s\n", S_OR(class->mode, "<none>")); 01201 ast_cli(fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>")); 01202 if (ast_test_flag(class, MOH_CUSTOM)) 01203 ast_cli(fd, "\tApplication: %s\n", S_OR(class->args, "<none>")); 01204 if (strcasecmp(class->mode, "files")) 01205 ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format)); 01206 } 01207 AST_LIST_UNLOCK(&mohclasses); 01208 01209 return 0; 01210 }
static int moh_cli | ( | int | fd, | |
int | argc, | |||
char * | argv[] | |||
) | [static] |
Definition at line 1162 of file res_musiconhold.c.
References ast_cli(), ast_moh_destroy(), load_moh_classes(), and moh_on_off().
01163 { 01164 int x; 01165 01166 moh_on_off(0); 01167 ast_moh_destroy(); 01168 x = load_moh_classes(1); 01169 moh_on_off(1); 01170 ast_cli(fd, "\n%d class%s reloaded.\n", x, x == 1 ? "" : "es"); 01171 return 0; 01172 }
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_RANDOMIZE, ast_channel::music_state, option_verbose, 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, 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] |
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 709 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.
00710 { 00711 struct mohdata *moh = data; 00712 short buf[1280 + AST_FRIENDLY_OFFSET / 2]; 00713 int res; 00714 00715 if (!moh->parent->pid) 00716 return -1; 00717 00718 len = ast_codec_get_len(moh->parent->format, samples); 00719 00720 if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) { 00721 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name); 00722 len = sizeof(buf) - AST_FRIENDLY_OFFSET; 00723 } 00724 res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len); 00725 if (res <= 0) 00726 return 0; 00727 00728 moh->f.datalen = res; 00729 moh->f.data = buf + AST_FRIENDLY_OFFSET / 2; 00730 moh->f.samples = ast_codec_get_samples(&moh->f); 00731 00732 if (ast_write(chan, &moh->f) < 0) { 00733 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno)); 00734 return -1; 00735 } 00736 00737 return 0; 00738 }
static void moh_on_off | ( | int | on | ) | [static] |
Definition at line 1147 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().
01148 { 01149 struct ast_channel *chan = NULL; 01150 01151 while ( (chan = ast_channel_walk_locked(chan)) != NULL) { 01152 if (ast_test_flag(chan, AST_FLAG_MOH)) { 01153 if (on) 01154 local_ast_moh_start(chan, NULL, NULL); 01155 else 01156 ast_deactivate_generator(chan); 01157 } 01158 ast_channel_unlock(chan); 01159 } 01160 }
static int moh_register | ( | struct mohclass * | moh, | |
int | reload | |||
) | [static] |
Definition at line 836 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, 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().
00837 { 00838 #ifdef HAVE_ZAPTEL 00839 int x; 00840 #endif 00841 AST_LIST_LOCK(&mohclasses); 00842 if (get_mohbyname(moh->name)) { 00843 if (reload) { 00844 ast_log(LOG_DEBUG, "Music on Hold class '%s' left alone from initial load.\n", moh->name); 00845 } else { 00846 ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name); 00847 } 00848 free(moh); 00849 AST_LIST_UNLOCK(&mohclasses); 00850 return -1; 00851 } 00852 AST_LIST_UNLOCK(&mohclasses); 00853 00854 time(&moh->start); 00855 moh->start -= respawn_time; 00856 00857 if (!strcasecmp(moh->mode, "files")) { 00858 if (!moh_scan_files(moh)) { 00859 ast_moh_free_class(&moh); 00860 return -1; 00861 } 00862 if (strchr(moh->args, 'r')) 00863 ast_set_flag(moh, MOH_RANDOMIZE); 00864 } 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")) { 00865 00866 if (!strcasecmp(moh->mode, "custom")) 00867 ast_set_flag(moh, MOH_CUSTOM); 00868 else if (!strcasecmp(moh->mode, "mp3nb")) 00869 ast_set_flag(moh, MOH_SINGLE); 00870 else if (!strcasecmp(moh->mode, "quietmp3nb")) 00871 ast_set_flag(moh, MOH_SINGLE | MOH_QUIET); 00872 else if (!strcasecmp(moh->mode, "quietmp3")) 00873 ast_set_flag(moh, MOH_QUIET); 00874 00875 moh->srcfd = -1; 00876 #ifdef HAVE_ZAPTEL 00877 /* Open /dev/zap/pseudo for timing... Is 00878 there a better, yet reliable way to do this? */ 00879 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY); 00880 if (moh->pseudofd < 0) { 00881 ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n"); 00882 } else { 00883 x = 320; 00884 ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x); 00885 } 00886 #else 00887 moh->pseudofd = -1; 00888 #endif 00889 if (ast_pthread_create_background(&moh->thread, NULL, monmp3thread, moh)) { 00890 ast_log(LOG_WARNING, "Unable to create moh...\n"); 00891 if (moh->pseudofd > -1) 00892 close(moh->pseudofd); 00893 ast_moh_free_class(&moh); 00894 return -1; 00895 } 00896 } else { 00897 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode); 00898 ast_moh_free_class(&moh); 00899 return -1; 00900 } 00901 00902 AST_LIST_LOCK(&mohclasses); 00903 AST_LIST_INSERT_HEAD(&mohclasses, moh, list); 00904 AST_LIST_UNLOCK(&mohclasses); 00905 00906 return 0; 00907 }
static void moh_release | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 670 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, and VERBOSE_PREFIX_3.
Referenced by moh_alloc().
00671 { 00672 struct mohdata *moh = data; 00673 int oldwfmt; 00674 00675 AST_LIST_LOCK(&mohclasses); 00676 AST_LIST_REMOVE(&moh->parent->members, moh, list); 00677 AST_LIST_UNLOCK(&mohclasses); 00678 00679 close(moh->pipe[0]); 00680 close(moh->pipe[1]); 00681 oldwfmt = moh->origwfmt; 00682 free(moh); 00683 if (chan) { 00684 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 00685 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt)); 00686 if (option_verbose > 2) 00687 ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name); 00688 } 00689 }
static int moh_scan_files | ( | struct mohclass * | class | ) | [static] |
Definition at line 770 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().
00770 { 00771 00772 DIR *files_DIR; 00773 struct dirent *files_dirent; 00774 char path[PATH_MAX]; 00775 char filepath[PATH_MAX]; 00776 char *ext; 00777 struct stat statbuf; 00778 int dirnamelen; 00779 int i; 00780 00781 files_DIR = opendir(class->dir); 00782 if (!files_DIR) { 00783 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", class->dir); 00784 return -1; 00785 } 00786 00787 for (i = 0; i < class->total_files; i++) 00788 free(class->filearray[i]); 00789 00790 class->total_files = 0; 00791 dirnamelen = strlen(class->dir) + 2; 00792 getcwd(path, sizeof(path)); 00793 chdir(class->dir); 00794 while ((files_dirent = readdir(files_DIR))) { 00795 /* The file name must be at least long enough to have the file type extension */ 00796 if ((strlen(files_dirent->d_name) < 4)) 00797 continue; 00798 00799 /* Skip files that starts with a dot */ 00800 if (files_dirent->d_name[0] == '.') 00801 continue; 00802 00803 /* Skip files without extensions... they are not audio */ 00804 if (!strchr(files_dirent->d_name, '.')) 00805 continue; 00806 00807 snprintf(filepath, sizeof(filepath), "%s/%s", class->dir, files_dirent->d_name); 00808 00809 if (stat(filepath, &statbuf)) 00810 continue; 00811 00812 if (!S_ISREG(statbuf.st_mode)) 00813 continue; 00814 00815 if ((ext = strrchr(filepath, '.'))) { 00816 *ext = '\0'; 00817 ext++; 00818 } 00819 00820 /* if the file is present in multiple formats, ensure we only put it into the list once */ 00821 for (i = 0; i < class->total_files; i++) 00822 if (!strcmp(filepath, class->filearray[i])) 00823 break; 00824 00825 if (i == class->total_files) { 00826 if (moh_add_file(class, filepath)) 00827 break; 00828 } 00829 } 00830 00831 closedir(files_DIR); 00832 chdir(path); 00833 return class->total_files; 00834 }
Definition at line 640 of file res_musiconhold.c.
References ast_calloc, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, AST_LIST_INSERT_HEAD, ast_log(), mohclass::format, free, LOG_WARNING, moh, and mohdata::pipe.
Referenced by moh_alloc().
00641 { 00642 struct mohdata *moh; 00643 long flags; 00644 00645 if (!(moh = ast_calloc(1, sizeof(*moh)))) 00646 return NULL; 00647 00648 if (pipe(moh->pipe)) { 00649 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno)); 00650 free(moh); 00651 return NULL; 00652 } 00653 00654 /* Make entirely non-blocking */ 00655 flags = fcntl(moh->pipe[0], F_GETFL); 00656 fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK); 00657 flags = fcntl(moh->pipe[1], F_GETFL); 00658 fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK); 00659 00660 moh->f.frametype = AST_FRAME_VOICE; 00661 moh->f.subclass = cl->format; 00662 moh->f.offset = AST_FRIENDLY_OFFSET; 00663 00664 moh->parent = cl; 00665 AST_LIST_INSERT_HEAD(&cl->members, moh, list); 00666 00667 return moh; 00668 }
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_NOTICE, LOG_WARNING, moh, MOH_MS_INTERVAL, option_debug, 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 1278 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().
01279 { 01280 if (init_classes(1)) 01281 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup); 01282 01283 return 0; 01284 }
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] |
struct ast_cli_entry cli_moh_classes_show_deprecated [static] |
Initial value:
{ { "moh", "classes", "show"}, moh_classes_show, NULL, NULL }
Definition at line 1212 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 1217 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.