Wed Aug 15 01:25:29 2007

Asterisk developer's documentation


res_musiconhold.c File Reference

Routines implementing music on hold. More...

#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 mohclassget_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 mohclassmoh_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_framemoh_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 mohdatamohalloc (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"


Detailed Description

Routines implementing music on hold.

Author:
Mark Spencer <markster@digium.com>

Definition in file res_musiconhold.c.


Define Documentation

#define INITIAL_NUM_FILES   8

Definition at line 75 of file res_musiconhold.c.

Referenced by moh_add_file().

#define LOCAL_MPG_123   "/usr/local/bin/mpg123"

Definition at line 166 of file res_musiconhold.c.

#define MAX_MP3S   256

Definition at line 168 of file res_musiconhold.c.

Referenced by spawn_mp3().

#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)

Definition at line 125 of file res_musiconhold.c.

Referenced by moh_register(), and spawn_mp3().

#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)

Definition at line 126 of file res_musiconhold.c.

Referenced by moh_register(), and spawn_mp3().

#define MPG_123   "/usr/bin/mpg123"

Definition at line 167 of file res_musiconhold.c.


Function Documentation

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]

Note:
This function should be called with the mohclasses list locked

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 }

static struct mohdata* mohalloc ( struct mohclass cl  )  [static, read]

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]

Definition at line 1287 of file res_musiconhold.c.

01288 {
01289    return -1;
01290 }


Variable Documentation

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.


Generated on Wed Aug 15 01:25:30 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.3