Sat Sep 16 05:48:06 2006

Asterisk developer's documentation


res_musiconhold.c File Reference

Routines implementing music on hold. More...

#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.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"

Go to the source code of this file.

Data Structures

struct  moh_files_state
struct  mohclass
struct  mohdata

Defines

#define LOCAL_MPG_123   "/usr/local/bin/mpg123"
#define MAX_MOHFILE_LEN   128
#define MAX_MOHFILES   512
#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

static void ast_moh_destroy (void)
static int ast_moh_files_next (struct ast_channel *chan)
static void ast_moh_free_class (struct mohclass **class)
 AST_MUTEX_DEFINE_STATIC (moh_lock)
static int cli_files_show (int fd, int argc, char *argv[])
char * description (void)
 Provides a description of the module.
static struct mohclassget_mohbyname (char *name)
static int init_classes (int reload)
char * key ()
 Returns the ASTERISK_GPL_KEY.
int load_module (void)
 Initialize the module.
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, char *class)
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 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)
int reload (void)
 Reload stuff.
static int spawn_mp3 (struct mohclass *class)
int unload_module (void)
 Cleanup all module structures, sockets, etc.
int usecount (void)
 Provides a usecount.

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 = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL}
static struct ast_cli_entry cli_moh_classes_show = { { "moh", "classes", "show"}, moh_classes_show, "List MOH classes", "Lists all MOH classes", NULL}
static struct ast_cli_entry cli_moh_files_show = { { "moh", "files", "show"}, cli_files_show, "List MOH file-based classes", "Lists all loaded file-based MOH classes and their files", NULL}
static char * descrip0
static char * descrip1
static char * descrip2
static char * descrip3
static char * descrip4
static struct ast_generator moh_file_stream
static struct mohclassmohclasses
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.

Definition in file res_musiconhold.c.


Define Documentation

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

Definition at line 154 of file res_musiconhold.c.

#define MAX_MOHFILE_LEN   128

Definition at line 68 of file res_musiconhold.c.

Referenced by moh_scan_files().

#define MAX_MOHFILES   512

Definition at line 67 of file res_musiconhold.c.

Referenced by moh_scan_files().

#define MAX_MP3S   256

Definition at line 156 of file res_musiconhold.c.

Referenced by spawn_mp3().

#define MOH_CUSTOM   (1 << 2)

Definition at line 120 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 118 of file res_musiconhold.c.

Referenced by moh_register(), and spawn_mp3().

#define MOH_RANDOMIZE   (1 << 3)

Definition at line 121 of file res_musiconhold.c.

Referenced by ast_moh_files_next(), load_moh_classes(), and moh_register().

#define MOH_SINGLE   (1 << 1)

Definition at line 119 of file res_musiconhold.c.

Referenced by moh_register(), and spawn_mp3().

#define MPG_123   "/usr/bin/mpg123"

Definition at line 155 of file res_musiconhold.c.


Function Documentation

static void ast_moh_destroy ( void   )  [static]

Definition at line 1078 of file res_musiconhold.c.

References ast_log(), ast_moh_free_class(), ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), ast_wait_for_input(), moh, mohclasses, option_verbose, mohclass::pid, and VERBOSE_PREFIX_2.

Referenced by load_module(), and moh_cli().

01079 {
01080    struct mohclass *moh, *tmp;
01081    char buff[8192];
01082    int bytes, tbytes=0, stime = 0, pid = 0;
01083 
01084    if (option_verbose > 1)
01085       ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
01086    ast_mutex_lock(&moh_lock);
01087    moh = mohclasses;
01088 
01089    while (moh) {
01090       if (moh->pid) {
01091          ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
01092          stime = time(NULL) + 2;
01093          pid = moh->pid;
01094          moh->pid = 0;
01095          /* Back when this was just mpg123, SIGKILL was fine.  Now we need
01096           * to give the process a reason and time enough to kill off its
01097           * children. */
01098          kill(pid, SIGHUP);
01099          usleep(100000);
01100          kill(pid, SIGTERM);
01101          usleep(100000);
01102          kill(pid, SIGKILL);
01103          while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime) {
01104             tbytes = tbytes + bytes;
01105          }
01106          ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
01107          close(moh->srcfd);
01108       }
01109       tmp = moh;
01110       moh = moh->next;
01111       ast_moh_free_class(&tmp);
01112    }
01113    mohclasses = NULL;
01114    ast_mutex_unlock(&moh_lock);
01115 }

static int ast_moh_files_next ( struct ast_channel chan  )  [static]

Definition at line 198 of file res_musiconhold.c.

References ast_closestream(), ast_fileexists(), ast_test_flag, moh_files_state::class, mohclass::filearray, 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().

00199 {
00200    struct moh_files_state *state = chan->music_state;
00201    int tries;
00202 
00203    if (state->save_pos) {
00204       state->pos = state->save_pos - 1;
00205       state->save_pos = 0;
00206    } else {
00207       /* Try 20 times to find something good */
00208       for (tries=0;tries < 20;tries++) {
00209          state->samples = 0;
00210          if (chan->stream) {
00211             ast_closestream(chan->stream);
00212             chan->stream = NULL;
00213             state->pos++;
00214          }
00215 
00216          if (ast_test_flag(state->class, MOH_RANDOMIZE))
00217             state->pos = rand();
00218 
00219          state->pos %= state->class->total_files;
00220 
00221          /* check to see if this file's format can be opened */
00222          if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0)
00223             break;
00224 
00225       }
00226    }
00227 
00228    state->pos = state->pos % state->class->total_files;
00229    
00230    if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
00231       ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
00232       state->pos++;
00233       return -1;
00234    }
00235 
00236    if (option_debug)
00237       ast_log(LOG_DEBUG, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]);
00238 
00239    if (state->samples)
00240       ast_seekstream(chan->stream, state->samples, SEEK_SET);
00241 
00242    return 0;
00243 }

static void ast_moh_free_class ( struct mohclass **  class  )  [static]

Definition at line 159 of file res_musiconhold.c.

References free, and mohdata::next.

Referenced by ast_moh_destroy(), and moh_register().

00160 {
00161    struct mohdata *members, *mtmp;
00162    
00163    members = (*class)->members;
00164    while(members) {
00165       mtmp = members;
00166       members = members->next;
00167       free(mtmp);
00168    }
00169    if ((*class)->thread) {
00170       pthread_cancel((*class)->thread);
00171       (*class)->thread = 0;
00172    }
00173    free(*class);
00174    *class = NULL;
00175 }

AST_MUTEX_DEFINE_STATIC ( moh_lock   ) 

static int cli_files_show ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 1144 of file res_musiconhold.c.

References ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), and mohclasses.

01145 {
01146    int i;
01147    struct mohclass *class;
01148 
01149    ast_mutex_lock(&moh_lock);
01150    for (class = mohclasses; class; class = class->next) {
01151       if (!class->total_files)
01152          continue;
01153 
01154       ast_cli(fd, "Class: %s\n", class->name);
01155       for (i = 0; i < class->total_files; i++)
01156          ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
01157    }
01158    ast_mutex_unlock(&moh_lock);
01159 
01160    return 0;
01161 }

char* description ( void   ) 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 1242 of file res_musiconhold.c.

01243 {
01244    return "Music On Hold Resource";
01245 }

static struct mohclass* get_mohbyname ( char *  name  )  [static]

Definition at line 612 of file res_musiconhold.c.

References moh, and mohclasses.

Referenced by load_moh_classes(), local_ast_moh_start(), and moh_register().

00613 {
00614    struct mohclass *moh;
00615    moh = mohclasses;
00616    while (moh) {
00617       if (!strcasecmp(name, moh->name))
00618          return moh;
00619       moh = moh->next;
00620    }
00621    return NULL;
00622 }

static int init_classes ( int  reload  )  [static]

Definition at line 1187 of file res_musiconhold.c.

References load_moh_classes(), moh, moh_scan_files(), and mohclasses.

Referenced by load_module(), and reload().

01188 {
01189    struct mohclass *moh;
01190     
01191    if (!load_moh_classes(reload))      /* Load classes from config */
01192       return 0;         /* Return if nothing is found */
01193    moh = mohclasses;
01194    while (moh) {
01195       if (moh->total_files)
01196          moh_scan_files(moh);
01197       moh = moh->next;
01198    }
01199    return 1;
01200 }

char* key ( void   ) 

Returns the ASTERISK_GPL_KEY.

This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:

 char *key(void) {
         return ASTERISK_GPL_KEY;
 }

Returns:
ASTERISK_GPL_KEY

Definition at line 1260 of file res_musiconhold.c.

References ASTERISK_GPL_KEY.

01261 {
01262    return ASTERISK_GPL_KEY;
01263 }

int load_module ( void   ) 

Initialize the module.

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.

Returns:
int Always 0.

Definition at line 1202 of file res_musiconhold.c.

References ast_cli_register(), ast_install_music_functions(), ast_log(), ast_moh_destroy(), ast_register_application(), ast_register_atexit(), cli_moh, cli_moh_classes_show, cli_moh_files_show, 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().

01203 {
01204    int res;
01205 
01206    res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
01207    ast_register_atexit(ast_moh_destroy);
01208    ast_cli_register(&cli_moh);
01209    ast_cli_register(&cli_moh_files_show);
01210    ast_cli_register(&cli_moh_classes_show);
01211    if (!res)
01212       res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
01213    if (!res)
01214       res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
01215    if (!res)
01216       res = ast_register_application(app3, moh3_exec, synopsis3, descrip3);
01217    if (!res)
01218       res = ast_register_application(app4, moh4_exec, synopsis4, descrip4);
01219 
01220    if (!init_classes(0)) {    /* No music classes configured, so skip it */
01221       ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold.");
01222    } else {
01223       ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
01224    }
01225 
01226    return 0;
01227 }

static int load_moh_classes ( int  reload  )  [static]

Definition at line 940 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(), cfg, dep_warning, free, get_mohbyname(), LOG_WARNING, moh_class_malloc(), MOH_RANDOMIZE, moh_register(), and var.

Referenced by init_classes(), and moh_cli().

00941 {
00942    struct ast_config *cfg;
00943    struct ast_variable *var;
00944    struct mohclass *class; 
00945    char *data;
00946    char *args;
00947    char *cat;
00948    int numclasses = 0;
00949    static int dep_warning = 0;
00950 
00951    cfg = ast_config_load("musiconhold.conf");
00952 
00953    if (!cfg)
00954       return 0;
00955 
00956    cat = ast_category_browse(cfg, NULL);
00957    for (; cat; cat = ast_category_browse(cfg, cat)) {
00958       if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) {
00959          class = moh_class_malloc();
00960          if (!class) {
00961             ast_log(LOG_WARNING, "Out of memory!\n");
00962             break;
00963          }           
00964          ast_copy_string(class->name, cat, sizeof(class->name));  
00965          var = ast_variable_browse(cfg, cat);
00966          while (var) {
00967             if (!strcasecmp(var->name, "mode"))
00968                ast_copy_string(class->mode, var->value, sizeof(class->mode)); 
00969             else if (!strcasecmp(var->name, "directory"))
00970                ast_copy_string(class->dir, var->value, sizeof(class->dir));
00971             else if (!strcasecmp(var->name, "application"))
00972                ast_copy_string(class->args, var->value, sizeof(class->args));
00973             else if (!strcasecmp(var->name, "random"))
00974                ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
00975             else if (!strcasecmp(var->name, "format")) {
00976                class->format = ast_getformatbyname(var->value);
00977                if (!class->format) {
00978                   ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
00979                   class->format = AST_FORMAT_SLINEAR;
00980                }
00981             }
00982                var = var->next;
00983          }
00984 
00985          if (ast_strlen_zero(class->dir)) {
00986             if (!strcasecmp(class->mode, "custom")) {
00987                strcpy(class->dir, "nodir");
00988             } else {
00989                ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
00990                free(class);
00991                continue;
00992             }
00993          }
00994          if (ast_strlen_zero(class->mode)) {
00995             ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
00996             free(class);
00997             continue;
00998          }
00999          if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
01000             ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
01001             free(class);
01002             continue;
01003          }
01004 
01005          /* Don't leak a class when it's already registered */
01006          moh_register(class, reload);
01007 
01008          numclasses++;
01009       }
01010    }
01011    
01012 
01013    /* Deprecated Old-School Configuration */
01014    var = ast_variable_browse(cfg, "classes");
01015    while (var) {
01016       if (!dep_warning) {
01017          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");
01018          dep_warning = 1;
01019       }
01020       data = strchr(var->value, ':');
01021       if (data) {
01022          *data++ = '\0';
01023          args = strchr(data, ',');
01024          if (args)
01025             *args++ = '\0';
01026          if (!(get_mohbyname(var->name))) {
01027             class = moh_class_malloc();
01028             if (!class) {
01029                ast_log(LOG_WARNING, "Out of memory!\n");
01030                return numclasses;
01031             }
01032             
01033             ast_copy_string(class->name, var->name, sizeof(class->name));
01034             ast_copy_string(class->dir, data, sizeof(class->dir));
01035             ast_copy_string(class->mode, var->value, sizeof(class->mode));
01036             if (args)
01037                ast_copy_string(class->args, args, sizeof(class->args));
01038             
01039             moh_register(class, reload);
01040             numclasses++;
01041          }
01042       }
01043       var = var->next;
01044    }
01045    var = ast_variable_browse(cfg, "moh_files");
01046    while (var) {
01047       if (!dep_warning) {
01048          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");
01049          dep_warning = 1;
01050       }
01051       if (!(get_mohbyname(var->name))) {
01052          args = strchr(var->value, ',');
01053          if (args)
01054             *args++ = '\0';
01055          class = moh_class_malloc();
01056          if (!class) {
01057             ast_log(LOG_WARNING, "Out of memory!\n");
01058             return numclasses;
01059          }
01060          
01061          ast_copy_string(class->name, var->name, sizeof(class->name));
01062          ast_copy_string(class->dir, var->value, sizeof(class->dir));
01063          strcpy(class->mode, "files");
01064          if (args)   
01065             ast_copy_string(class->args, args, sizeof(class->args));
01066          
01067          moh_register(class, reload);
01068          numclasses++;
01069       }
01070       var = var->next;
01071    }
01072 
01073    ast_config_destroy(cfg);
01074 
01075    return numclasses;
01076 }

static void local_ast_moh_cleanup ( struct ast_channel chan  )  [static]

Definition at line 879 of file res_musiconhold.c.

References free, and ast_channel::music_state.

Referenced by load_module(), and reload().

00880 {
00881    if (chan->music_state) {
00882       free(chan->music_state);
00883       chan->music_state = NULL;
00884    }
00885 }

static int local_ast_moh_start ( struct ast_channel chan,
char *  class 
) [static]

Definition at line 887 of file res_musiconhold.c.

References ast_activate_generator(), AST_FLAG_MOH, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), 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().

00888 {
00889    struct mohclass *mohclass;
00890 
00891    if (ast_strlen_zero(class))
00892       class = chan->musicclass;
00893    if (ast_strlen_zero(class))
00894       class = "default";
00895    ast_mutex_lock(&moh_lock);
00896    mohclass = get_mohbyname(class);
00897    ast_mutex_unlock(&moh_lock);
00898 
00899    if (!mohclass) {
00900       ast_log(LOG_WARNING, "No class: %s\n", (char *)class);
00901       return -1;
00902    }
00903 
00904    ast_set_flag(chan, AST_FLAG_MOH);
00905    if (mohclass->total_files) {
00906       return ast_activate_generator(chan, &moh_file_stream, mohclass);
00907    } else
00908       return ast_activate_generator(chan, &mohgen, mohclass);
00909 }

static void local_ast_moh_stop ( struct ast_channel chan  )  [static]

Definition at line 911 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().

00912 {
00913    ast_clear_flag(chan, AST_FLAG_MOH);
00914    ast_deactivate_generator(chan);
00915 
00916    if (chan->music_state) {
00917       if (chan->stream) {
00918          ast_closestream(chan->stream);
00919          chan->stream = NULL;
00920       }
00921    }
00922 }

static int moh0_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 557 of file res_musiconhold.c.

References ast_log(), ast_moh_start(), ast_moh_stop(), ast_safe_sleep(), LOG_WARNING, and ast_channel::name.

Referenced by load_module().

00558 {
00559    if (ast_moh_start(chan, data)) {
00560       ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
00561       return -1;
00562    }
00563    while (!ast_safe_sleep(chan, 10000));
00564    ast_moh_stop(chan);
00565    return -1;
00566 }

static int moh1_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 568 of file res_musiconhold.c.

References ast_log(), ast_moh_start(), ast_moh_stop(), ast_safe_sleep(), LOG_WARNING, and ast_channel::name.

Referenced by load_module().

00569 {
00570    int res;
00571    if (!data || !atoi(data)) {
00572       ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
00573       return -1;
00574    }
00575    if (ast_moh_start(chan, NULL)) {
00576       ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name);
00577       return -1;
00578    }
00579    res = ast_safe_sleep(chan, atoi(data) * 1000);
00580    ast_moh_stop(chan);
00581    return res;
00582 }

static int moh2_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 584 of file res_musiconhold.c.

References ast_log(), ast_strlen_zero(), LOG_WARNING, and ast_channel::musicclass.

Referenced by load_module().

00585 {
00586    if (ast_strlen_zero(data)) {
00587       ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
00588       return -1;
00589    }
00590    strncpy(chan->musicclass, data, sizeof(chan->musicclass) - 1);
00591    return 0;
00592 }

static int moh3_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 594 of file res_musiconhold.c.

References ast_log(), ast_moh_start(), and LOG_NOTICE.

Referenced by load_module().

00595 {
00596    char *class = NULL;
00597    if (data && strlen(data))
00598       class = data;
00599    if (ast_moh_start(chan, class)) 
00600       ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name);
00601 
00602    return 0;
00603 }

static int moh4_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 605 of file res_musiconhold.c.

References ast_moh_stop().

Referenced by load_module().

00606 {
00607    ast_moh_stop(chan);
00608 
00609    return 0;
00610 }

static void* moh_alloc ( struct ast_channel chan,
void *  params 
) [static]

Definition at line 680 of file res_musiconhold.c.

References ast_codec2str(), ast_log(), ast_set_write_format(), ast_verbose(), LOG_WARNING, moh_release(), mohalloc(), ast_channel::name, option_verbose, VERBOSE_PREFIX_3, and ast_channel::writeformat.

00681 {
00682    struct mohdata *res;
00683    struct mohclass *class = params;
00684 
00685    res = mohalloc(class);
00686    if (res) {
00687       res->origwfmt = chan->writeformat;
00688       if (ast_set_write_format(chan, class->format)) {
00689          ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format));
00690          moh_release(NULL, res);
00691          res = NULL;
00692       }
00693       if (option_verbose > 2)
00694          ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name);
00695    }
00696    return res;
00697 }

static struct mohclass* moh_class_malloc ( void   )  [static]

Definition at line 924 of file res_musiconhold.c.

References AST_FORMAT_SLINEAR, and malloc.

Referenced by load_moh_classes().

00925 {
00926    struct mohclass *class;
00927 
00928    class = malloc(sizeof(struct mohclass));
00929 
00930    if (!class)
00931       return NULL;
00932 
00933    memset(class, 0, sizeof(struct mohclass));
00934 
00935    class->format = AST_FORMAT_SLINEAR;
00936 
00937    return class;
00938 }

static int moh_classes_show ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 1163 of file res_musiconhold.c.

References ast_cli(), ast_getformatname(), ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), ast_test_flag, MOH_CUSTOM, and mohclasses.

01164 {
01165    struct mohclass *class;
01166 
01167    ast_mutex_lock(&moh_lock);
01168    for (class = mohclasses; class; class = class->next) {
01169       ast_cli(fd, "Class: %s\n", class->name);
01170       ast_cli(fd, "\tMode: %s\n", ast_strlen_zero(class->mode) ? "<none>" : class->mode);
01171       ast_cli(fd, "\tDirectory: %s\n", ast_strlen_zero(class->dir) ? "<none>" : class->dir);
01172       if (ast_test_flag(class, MOH_CUSTOM))
01173          ast_cli(fd, "\tApplication: %s\n", ast_strlen_zero(class->args) ? "<none>" : class->args);
01174       ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format));
01175    }
01176    ast_mutex_unlock(&moh_lock);
01177 
01178    return 0;
01179 }

static int moh_cli ( int  fd,
int  argc,
char *  argv[] 
) [static]

Definition at line 1132 of file res_musiconhold.c.

References ast_cli(), ast_moh_destroy(), load_moh_classes(), and moh_on_off().

01133 {
01134    int x;
01135 
01136    moh_on_off(0);
01137    ast_moh_destroy();
01138    x = load_moh_classes(1);
01139    moh_on_off(1);
01140    ast_cli(fd, "\n%d class%s reloaded.\n", x, x == 1 ? "" : "es");
01141    return 0;
01142 }

static void* moh_files_alloc ( struct ast_channel chan,
void *  params 
) [static]

Definition at line 283 of file res_musiconhold.c.

References ast_verbose(), moh_files_state::class, malloc, ast_channel::music_state, ast_channel::name, option_verbose, moh_files_state::origwfmt, VERBOSE_PREFIX_3, and ast_channel::writeformat.

00284 {
00285    struct moh_files_state *state;
00286    struct mohclass *class = params;
00287    int allocated = 0;
00288 
00289    if (!chan->music_state && (state = malloc(sizeof(struct moh_files_state)))) {
00290       chan->music_state = state;
00291       allocated = 1;
00292    } else 
00293       state = chan->music_state;
00294 
00295    if (state) {
00296       if (allocated || state->class != class) {
00297          /* initialize */
00298          memset(state, 0, sizeof(struct moh_files_state));
00299          state->class = class;
00300       }
00301 
00302       state->origwfmt = chan->writeformat;
00303 
00304       if (option_verbose > 2)
00305          ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->name, chan->name);
00306    }
00307    
00308    return chan->music_state;
00309 }

static int moh_files_generator ( struct ast_channel chan,
void *  data,
int  len,
int  samples 
) [static]

Definition at line 258 of file res_musiconhold.c.

References ast_frfree(), ast_log(), ast_write(), LOG_WARNING, moh_files_readframe(), ast_channel::music_state, ast_channel::name, moh_files_state::sample_queue, ast_frame::samples, and moh_files_state::samples.

00259 {
00260    struct moh_files_state *state = chan->music_state;
00261    struct ast_frame *f = NULL;
00262    int res = 0;
00263 
00264    state->sample_queue += samples;
00265 
00266    while (state->sample_queue > 0) {
00267       if ((f = moh_files_readframe(chan))) {
00268          state->samples += f->samples;
00269          res = ast_write(chan, f);
00270          state->sample_queue -= f->samples;
00271          ast_frfree(f);
00272          if (res < 0) {
00273             ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
00274             return -1;
00275          }
00276       } else
00277          return -1;  
00278    }
00279    return res;
00280 }

static struct ast_frame* moh_files_readframe ( struct ast_channel chan  )  [static]

Definition at line 246 of file res_musiconhold.c.

References ast_moh_files_next(), ast_readframe(), and ast_channel::stream.

Referenced by moh_files_generator().

00247 {
00248    struct ast_frame *f = NULL;
00249    
00250    if (!(chan->stream && (f = ast_readframe(chan->stream)))) {
00251       if (!ast_moh_files_next(chan))
00252          f = ast_readframe(chan->stream);
00253    }
00254 
00255    return f;
00256 }

static void moh_files_release ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 178 of file res_musiconhold.c.

References ast_closestream(), ast_log(), ast_set_write_format(), ast_verbose(), LOG_WARNING, ast_channel::music_state, ast_channel::name, option_verbose, moh_files_state::origwfmt, moh_files_state::pos, moh_files_state::save_pos, ast_channel::stream, and VERBOSE_PREFIX_3.

00179 {
00180    struct moh_files_state *state = chan->music_state;
00181 
00182    if (chan && state) {
00183       if (chan->stream) {
00184                         ast_closestream(chan->stream);
00185                         chan->stream = NULL;
00186                 }
00187       if (option_verbose > 2)
00188          ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
00189 
00190       if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
00191          ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt);
00192       }
00193       state->save_pos = state->pos + 1;
00194    }
00195 }

static int moh_generate ( struct ast_channel chan,
void *  data,
int  len,
int  samples 
) [static]

Definition at line 699 of file res_musiconhold.c.

References ast_codec_get_len(), ast_codec_get_samples(), AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), ast_write(), LOG_WARNING, moh, and ast_channel::name.

00700 {
00701    struct ast_frame f;
00702    struct mohdata *moh = data;
00703    short buf[1280 + AST_FRIENDLY_OFFSET / 2];
00704    int res;
00705 
00706    if (!moh->parent->pid)
00707       return -1;
00708 
00709    len = ast_codec_get_len(moh->parent->format, samples);
00710 
00711    if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
00712       ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name);
00713       len = sizeof(buf) - AST_FRIENDLY_OFFSET;
00714    }
00715    res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
00716 #if 0
00717    if (res != len) {
00718       ast_log(LOG_WARNING, "Read only %d of %d bytes: %s\n", res, len, strerror(errno));
00719    }
00720 #endif
00721    if (res <= 0)
00722       return 0;
00723 
00724    memset(&f, 0, sizeof(f));
00725    
00726    f.frametype = AST_FRAME_VOICE;
00727    f.subclass = moh->parent->format;
00728    f.mallocd = 0;
00729    f.datalen = res;
00730    f.data = buf + AST_FRIENDLY_OFFSET / 2;
00731    f.offset = AST_FRIENDLY_OFFSET;
00732    f.samples = ast_codec_get_samples(&f);
00733 
00734    if (ast_write(chan, &f) < 0) {
00735       ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
00736       return -1;
00737    }
00738 
00739    return 0;
00740 }

static void moh_on_off ( int  on  )  [static]

Definition at line 1117 of file res_musiconhold.c.

References ast_channel_walk_locked(), ast_deactivate_generator(), AST_FLAG_MOH, ast_mutex_unlock(), ast_test_flag, and local_ast_moh_start().

Referenced by moh_cli().

01118 {
01119    struct ast_channel *chan = NULL;
01120 
01121    while ( (chan = ast_channel_walk_locked(chan)) != NULL) {
01122       if (ast_test_flag(chan, AST_FLAG_MOH)) {
01123          if (on)
01124             local_ast_moh_start(chan, NULL);
01125          else
01126             ast_deactivate_generator(chan);
01127       }
01128       ast_mutex_unlock(&chan->lock);
01129    }
01130 }

static int moh_register ( struct mohclass moh,
int  reload 
) [static]

Definition at line 807 of file res_musiconhold.c.

References ast_log(), ast_moh_free_class(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create, ast_set_flag, free, get_mohbyname(), LOG_WARNING, moh, MOH_CUSTOM, MOH_QUIET, MOH_RANDOMIZE, moh_scan_files(), MOH_SINGLE, mohclasses, and monmp3thread().

Referenced by load_moh_classes().

00808 {
00809 #ifdef ZAPATA_MOH
00810    int x;
00811 #endif
00812    ast_mutex_lock(&moh_lock);
00813    if (get_mohbyname(moh->name)) {
00814       if (reload) {
00815          ast_log(LOG_DEBUG, "Music on Hold class '%s' left alone from initial load.\n", moh->name);
00816       } else {
00817          ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
00818       }
00819       free(moh);  
00820       ast_mutex_unlock(&moh_lock);
00821       return -1;
00822    }
00823    ast_mutex_unlock(&moh_lock);
00824 
00825    time(&moh->start);
00826    moh->start -= respawn_time;
00827    
00828    if (!strcasecmp(moh->mode, "files")) {
00829       if (!moh_scan_files(moh)) {
00830          ast_moh_free_class(&moh);
00831          return -1;
00832       }
00833       if (strchr(moh->args, 'r'))
00834          ast_set_flag(moh, MOH_RANDOMIZE);
00835    } 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")) {
00836 
00837       if (!strcasecmp(moh->mode, "custom"))
00838          ast_set_flag(moh, MOH_CUSTOM);
00839       else if (!strcasecmp(moh->mode, "mp3nb"))
00840          ast_set_flag(moh, MOH_SINGLE);
00841       else if (!strcasecmp(moh->mode, "quietmp3nb"))
00842          ast_set_flag(moh, MOH_SINGLE | MOH_QUIET);
00843       else if (!strcasecmp(moh->mode, "quietmp3"))
00844          ast_set_flag(moh, MOH_QUIET);
00845       
00846       moh->srcfd = -1;
00847 #ifdef ZAPATA_MOH
00848       /* Open /dev/zap/pseudo for timing...  Is
00849          there a better, yet reliable way to do this? */
00850       moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
00851       if (moh->pseudofd < 0) {
00852          ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
00853       } else {
00854          x = 320;
00855          ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
00856       }
00857 #else
00858       moh->pseudofd = -1;
00859 #endif
00860       if (ast_pthread_create(&moh->thread, NULL, monmp3thread, moh)) {
00861          ast_log(LOG_WARNING, "Unable to create moh...\n");
00862          if (moh->pseudofd > -1)
00863             close(moh->pseudofd);
00864          ast_moh_free_class(&moh);
00865          return -1;
00866       }
00867    } else {
00868       ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
00869       ast_moh_free_class(&moh);
00870       return -1;
00871    }
00872    ast_mutex_lock(&moh_lock);
00873    moh->next = mohclasses;
00874    mohclasses = moh;
00875    ast_mutex_unlock(&moh_lock);
00876    return 0;
00877 }

static void moh_release ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 648 of file res_musiconhold.c.

References ast_getformatname(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_write_format(), ast_verbose(), free, LOG_WARNING, moh, ast_channel::name, option_verbose, and VERBOSE_PREFIX_3.

Referenced by moh_alloc().

00649 {
00650    struct mohdata *moh = data, *prev, *cur;
00651    int oldwfmt;
00652    ast_mutex_lock(&moh_lock);
00653    /* Unlink */
00654    prev = NULL;
00655    cur = moh->parent->members;
00656    while (cur) {
00657       if (cur == moh) {
00658          if (prev)
00659             prev->next = cur->next;
00660          else
00661             moh->parent->members = cur->next;
00662          break;
00663       }
00664       prev = cur;
00665       cur = cur->next;
00666    }
00667    ast_mutex_unlock(&moh_lock);
00668    close(moh->pipe[0]);
00669    close(moh->pipe[1]);
00670    oldwfmt = moh->origwfmt;
00671    free(moh);
00672    if (chan) {
00673       if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
00674          ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
00675       if (option_verbose > 2)
00676          ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
00677    }
00678 }

static int moh_scan_files ( struct mohclass class  )  [static]

Definition at line 749 of file res_musiconhold.c.

References ast_log(), mohclass::dir, mohclass::filearray, LOG_WARNING, MAX_MOHFILE_LEN, MAX_MOHFILES, and mohclass::total_files.

Referenced by init_classes(), and moh_register().

00749                                                   {
00750 
00751    DIR *files_DIR;
00752    struct dirent *files_dirent;
00753    char path[512];
00754    char filepath[MAX_MOHFILE_LEN];
00755    char *ext;
00756    struct stat statbuf;
00757    int dirnamelen;
00758    int i;
00759    
00760    files_DIR = opendir(class->dir);
00761    if (!files_DIR) {
00762       ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist", class->dir);
00763       return -1;
00764    }
00765 
00766    class->total_files = 0;
00767    dirnamelen = strlen(class->dir) + 2;
00768    getcwd(path, 512);
00769    chdir(class->dir);
00770    memset(class->filearray, 0, MAX_MOHFILES*MAX_MOHFILE_LEN);
00771    while ((files_dirent = readdir(files_DIR))) {
00772       if ((strlen(files_dirent->d_name) < 4) || ((strlen(files_dirent->d_name) + dirnamelen) >= MAX_MOHFILE_LEN))
00773          continue;
00774 
00775       snprintf(filepath, MAX_MOHFILE_LEN, "%s/%s", class->dir, files_dirent->d_name);
00776 
00777       if (stat(filepath, &statbuf))
00778          continue;
00779 
00780       if (!S_ISREG(statbuf.st_mode))
00781          continue;
00782 
00783       if ((ext = strrchr(filepath, '.'))) {
00784          *ext = '\0';
00785          ext++;
00786       }
00787 
00788       /* if the file is present in multiple formats, ensure we only put it into the list once */
00789       for (i = 0; i < class->total_files; i++)
00790          if (!strcmp(filepath, class->filearray[i]))
00791             break;
00792 
00793       if (i == class->total_files)
00794          strcpy(class->filearray[class->total_files++], filepath);
00795 
00796       /* If the new total files is equal to the maximum allowed, stop adding new ones */
00797       if (class->total_files == MAX_MOHFILES)
00798          break;
00799 
00800    }
00801 
00802    closedir(files_DIR);
00803    chdir(path);
00804    return class->total_files;
00805 }

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

Definition at line 624 of file res_musiconhold.c.

References ast_log(), free, LOG_WARNING, malloc, mohclass::members, moh, and mohdata::pipe.

Referenced by moh_alloc().

00625 {
00626    struct mohdata *moh;
00627    long flags;
00628    moh = malloc(sizeof(struct mohdata));
00629    if (!moh)
00630       return NULL;
00631    memset(moh, 0, sizeof(struct mohdata));
00632    if (pipe(moh->pipe)) {
00633       ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
00634       free(moh);
00635       return NULL;
00636    }
00637    /* Make entirely non-blocking */
00638    flags = fcntl(moh->pipe[0], F_GETFL);
00639    fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
00640    flags = fcntl(moh->pipe[1], F_GETFL);
00641    fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
00642    moh->parent = cl;
00643    moh->next = cl->members;
00644    cl->members = moh;
00645    return moh;
00646 }

static void* monmp3thread ( void *  data  )  [static]

Definition at line 474 of file res_musiconhold.c.

References ast_codec_get_len(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_tvadd(), LOG_NOTICE, LOG_WARNING, moh, MOH_MS_INTERVAL, option_debug, and spawn_mp3().

Referenced by moh_register().

00475 {
00476 #define  MOH_MS_INTERVAL      100
00477 
00478    struct mohclass *class = data;
00479    struct mohdata *moh;
00480    char buf[8192];
00481    short sbuf[8192];
00482    int res, res2;
00483    int len;
00484    struct timeval tv, tv_tmp;
00485 
00486    tv.tv_sec = 0;
00487    tv.tv_usec = 0;
00488    for(;/* ever */;) {
00489       pthread_testcancel();
00490       /* Spawn mp3 player if it's not there */
00491       if (class->srcfd < 0) {
00492          if ((class->srcfd = spawn_mp3(class)) < 0) {
00493             ast_log(LOG_WARNING, "Unable to spawn mp3player\n");
00494             /* Try again later */
00495             sleep(500);
00496             pthread_testcancel();
00497          }
00498       }
00499       if (class->pseudofd > -1) {
00500          /* Pause some amount of time */
00501          res = read(class->pseudofd, buf, sizeof(buf));
00502          pthread_testcancel();
00503       } else {
00504          long delta;
00505          /* Reliable sleep */
00506          tv_tmp = ast_tvnow();
00507          if (ast_tvzero(tv))
00508             tv = tv_tmp;
00509          delta = ast_tvdiff_ms(tv_tmp, tv);
00510          if (delta < MOH_MS_INTERVAL) {   /* too early */
00511             tv = ast_tvadd(tv, ast_samp2tv(MOH_MS_INTERVAL, 1000));  /* next deadline */
00512             usleep(1000 * (MOH_MS_INTERVAL - delta));
00513             pthread_testcancel();
00514          } else {
00515             ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
00516             tv = tv_tmp;
00517          }
00518          res = 8 * MOH_MS_INTERVAL; /* 8 samples per millisecond */
00519       }
00520       if (!class->members)
00521          continue;
00522       /* Read mp3 audio */
00523       len = ast_codec_get_len(class->format, res);
00524       
00525       if ((res2 = read(class->srcfd, sbuf, len)) != len) {
00526          if (!res2) {
00527             close(class->srcfd);
00528             class->srcfd = -1;
00529             pthread_testcancel();
00530             if (class->pid) {
00531                kill(class->pid, SIGHUP);
00532                usleep(100000);
00533                kill(class->pid, SIGTERM);
00534                usleep(100000);
00535                kill(class->pid, SIGKILL);
00536                class->pid = 0;
00537             }
00538          } else
00539             ast_log(LOG_DEBUG, "Read %d bytes of audio while expecting %d\n", res2, len);
00540          continue;
00541       }
00542       pthread_testcancel();
00543       ast_mutex_lock(&moh_lock);
00544       moh = class->members;
00545       while (moh) {
00546          /* Write data */
00547          if ((res = write(moh->pipe[1], sbuf, res2)) != res2) 
00548             if (option_debug)
00549                ast_log(LOG_DEBUG, "Only wrote %d of %d bytes to pipe\n", res, res2);
00550          moh = moh->next;
00551       }
00552       ast_mutex_unlock(&moh_lock);
00553    }
00554    return NULL;
00555 }

int reload ( void   ) 

Reload stuff.

This function is where any reload routines take place. Re-read config files, change signalling, whatever is appropriate on a reload.

Returns:
The return value is not used.

Definition at line 1229 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().

01230 {
01231    if (init_classes(1))
01232       ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
01233 
01234    return 0;
01235 }

static int spawn_mp3 ( struct mohclass class  )  [static]

Definition at line 318 of file res_musiconhold.c.

References mohclass::args, ast_log(), 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, option_highpriority, mohclass::pid, and mohclass::start.

Referenced by monmp3thread().

00319 {
00320    int fds[2];
00321    int files = 0;
00322    char fns[MAX_MP3S][80];
00323    char *argv[MAX_MP3S + 50];
00324    char xargs[256];
00325    char *argptr;
00326    int argc = 0;
00327    DIR *dir = NULL;
00328    struct dirent *de;
00329 
00330    
00331    if (!strcasecmp(class->dir, "nodir")) {
00332       files = 1;
00333    } else {
00334       dir = opendir(class->dir);
00335       if (!dir && !strstr(class->dir,"http://") && !strstr(class->dir,"HTTP://")) {
00336          ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
00337          return -1;
00338       }
00339    }
00340 
00341    if (!ast_test_flag(class, MOH_CUSTOM)) {
00342       argv[argc++] = "mpg123";
00343       argv[argc++] = "-q";
00344       argv[argc++] = "-s";
00345       argv[argc++] = "--mono";
00346       argv[argc++] = "-r";
00347       argv[argc++] = "8000";
00348       
00349       if (!ast_test_flag(class, MOH_SINGLE)) {
00350          argv[argc++] = "-b";
00351          argv[argc++] = "2048";
00352       }
00353       
00354       argv[argc++] = "-f";
00355       
00356       if (ast_test_flag(class, MOH_QUIET))
00357          argv[argc++] = "4096";
00358       else
00359          argv[argc++] = "8192";
00360       
00361       /* Look for extra arguments and add them to the list */
00362       strncpy(xargs, class->args, sizeof(xargs) - 1);
00363       argptr = xargs;
00364       while (!ast_strlen_zero(argptr)) {
00365          argv[argc++] = argptr;
00366          argptr = strchr(argptr, ',');
00367          if (argptr) {
00368             *argptr = '\0';
00369             argptr++;
00370          }
00371       }
00372    } else  {
00373       /* Format arguments for argv vector */
00374       strncpy(xargs, class->args, sizeof(xargs) - 1);
00375       argptr = xargs;
00376       while (!ast_strlen_zero(argptr)) {
00377          argv[argc++] = argptr;
00378          argptr = strchr(argptr, ' ');
00379          if (argptr) {
00380             *argptr = '\0';
00381             argptr++;
00382          }
00383       }
00384    }
00385 
00386 
00387    if (strstr(class->dir,"http://") || strstr(class->dir,"HTTP://")) {
00388       strncpy(fns[files], class->dir, sizeof(fns[files]) - 1);
00389       argv[argc++] = fns[files];
00390       files++;
00391    } else if (dir) {
00392       while ((de = readdir(dir)) && (files < MAX_MP3S)) {
00393          if ((strlen(de->d_name) > 3) && 
00394              ((ast_test_flag(class, MOH_CUSTOM) && 
00395                (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 
00396                 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) ||
00397               !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
00398             strncpy(fns[files], de->d_name, sizeof(fns[files]) - 1);
00399             argv[argc++] = fns[files];
00400             files++;
00401          }
00402       }
00403    }
00404    argv[argc] = NULL;
00405    if (dir) {
00406       closedir(dir);
00407    }
00408    if (pipe(fds)) {  
00409       ast_log(LOG_WARNING, "Pipe failed\n");
00410       return -1;
00411    }
00412 #if 0
00413    printf("%d files total, %d args total\n", files, argc);
00414    {
00415       int x;
00416       for (x=0;argv[x];x++)
00417          printf("arg%d: %s\n", x, argv[x]);
00418    }
00419 #endif   
00420    if (!files) {
00421       ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
00422       close(fds[0]);
00423       close(fds[1]);
00424       return -1;
00425    }
00426    if (time(NULL) - class->start < respawn_time) {
00427       sleep(respawn_time - (time(NULL) - class->start));
00428    }
00429    time(&class->start);
00430    class->pid = fork();
00431    if (class->pid < 0) {
00432       close(fds[0]);
00433       close(fds[1]);
00434       ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
00435       return -1;
00436    }
00437    if (!class->pid) {
00438       int x;
00439 
00440       if (option_highpriority)
00441          ast_set_priority(0);
00442 
00443       close(fds[0]);
00444       /* Stdout goes to pipe */
00445       dup2(fds[1], STDOUT_FILENO);
00446       /* Close unused file descriptors */
00447       for (x=3;x<8192;x++) {
00448          if (-1 != fcntl(x, F_GETFL)) {
00449             close(x);
00450          }
00451       }
00452       /* Child */
00453       chdir(class->dir);
00454       if (ast_test_flag(class, MOH_CUSTOM)) {
00455          execv(argv[0], argv);
00456       } else {
00457          /* Default install is /usr/local/bin */
00458          execv(LOCAL_MPG_123, argv);
00459          /* Many places have it in /usr/bin */
00460          execv(MPG_123, argv);
00461          /* Check PATH as a last-ditch effort */
00462          execvp("mpg123", argv);
00463       }
00464       ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
00465       close(fds[1]);
00466       exit(1);
00467    } else {
00468       /* Parent */
00469       close(fds[1]);
00470    }
00471    return fds[0];
00472 }

int unload_module ( void   ) 

Cleanup all module structures, sockets, etc.

Standard module functions ...

Definition at line 1237 of file res_musiconhold.c.

01238 {
01239    return -1;
01240 }

int usecount ( void   ) 

Provides a usecount.

This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.

Returns:
The module's usecount.

Definition at line 1247 of file res_musiconhold.c.

References STANDARD_USECOUNT.

01248 {
01249    /* Never allow Music On Hold to be unloaded
01250       unresolve needed symbols in the dialer */
01251 #if 0
01252    int res;
01253    STANDARD_USECOUNT(res);
01254    return res;
01255 #else
01256    return 1;
01257 #endif
01258 }


Variable Documentation

char* app0 = "MusicOnHold" [static]

Definition at line 70 of file res_musiconhold.c.

char* app1 = "WaitMusicOnHold" [static]

Definition at line 71 of file res_musiconhold.c.

char* app2 = "SetMusicOnHold" [static]

Definition at line 72 of file res_musiconhold.c.

char* app3 = "StartMusicOnHold" [static]

Definition at line 73 of file res_musiconhold.c.

char* app4 = "StopMusicOnHold" [static]

Definition at line 74 of file res_musiconhold.c.

struct ast_cli_entry cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL} [static]

Definition at line 1181 of file res_musiconhold.c.

Referenced by load_module().

struct ast_cli_entry cli_moh_classes_show = { { "moh", "classes", "show"}, moh_classes_show, "List MOH classes", "Lists all MOH classes", NULL} [static]

Definition at line 1183 of file res_musiconhold.c.

Referenced by load_module().

struct ast_cli_entry cli_moh_files_show = { { "moh", "files", "show"}, cli_files_show, "List MOH file-based classes", "Lists all loaded file-based MOH classes and their files", NULL} [static]

Definition at line 1185 of file res_musiconhold.c.

Referenced by load_module().

char* descrip0 [static]

Definition at line 82 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 89 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 94 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 99 of file res_musiconhold.c.

char* descrip4 [static]

Initial value:

 "StopMusicOnHold: "
"Stops playing music on hold.\n"

Definition at line 104 of file res_musiconhold.c.

struct ast_generator moh_file_stream [static]

Definition at line 311 of file res_musiconhold.c.

Referenced by local_ast_moh_start().

struct mohclass* mohclasses [static]

Definition at line 150 of file res_musiconhold.c.

Referenced by ast_moh_destroy(), cli_files_show(), get_mohbyname(), init_classes(), moh_classes_show(), and moh_register().

struct ast_generator mohgen [static]

Definition at line 742 of file res_musiconhold.c.

Referenced by local_ast_moh_start().

int respawn_time = 20 [static]

Definition at line 107 of file res_musiconhold.c.

char* synopsis0 = "Play Music On Hold indefinitely" [static]

Definition at line 76 of file res_musiconhold.c.

char* synopsis1 = "Wait, playing Music On Hold" [static]

Definition at line 77 of file res_musiconhold.c.

char* synopsis2 = "Set default Music On Hold class" [static]

Definition at line 78 of file res_musiconhold.c.

char* synopsis3 = "Play Music On Hold" [static]

Definition at line 79 of file res_musiconhold.c.

char* synopsis4 = "Stop Playing Music On Hold" [static]

Definition at line 80 of file res_musiconhold.c.


Generated on Sat Sep 16 05:48:06 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.7