Sat Mar 24 23:30:08 2007

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"

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

#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 1064 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().

01065 {
01066    struct mohclass *moh, *tmp;
01067    char buff[8192];
01068    int bytes, tbytes=0, stime = 0, pid = 0;
01069 
01070    if (option_verbose > 1)
01071       ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
01072    ast_mutex_lock(&moh_lock);
01073    moh = mohclasses;
01074 
01075    while (moh) {
01076       if (moh->pid) {
01077          ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
01078          stime = time(NULL) + 2;
01079          pid = moh->pid;
01080          moh->pid = 0;
01081          kill(pid, SIGKILL);
01082          while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime) {
01083             tbytes = tbytes + bytes;
01084          }
01085          ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
01086          close(moh->srcfd);
01087       }
01088       tmp = moh;
01089       moh = moh->next;
01090       ast_moh_free_class(&tmp);
01091    }
01092    mohclasses = NULL;
01093    ast_mutex_unlock(&moh_lock);
01094 }

static int ast_moh_files_next struct ast_channel chan  )  [static]
 

Definition at line 190 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, and ast_channel::stream.

Referenced by moh_files_readframe().

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

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    free(*class);
00170    *class = NULL;
00171 }

AST_MUTEX_DEFINE_STATIC moh_lock   ) 
 

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

Definition at line 1123 of file res_musiconhold.c.

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

01124 {
01125    int i;
01126    struct mohclass *class;
01127 
01128    ast_mutex_lock(&moh_lock);
01129    for (class = mohclasses; class; class = class->next) {
01130       if (!class->total_files)
01131          continue;
01132 
01133       ast_cli(fd, "Class: %s\n", class->name);
01134       for (i = 0; i < class->total_files; i++)
01135          ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
01136    }
01137    ast_mutex_unlock(&moh_lock);
01138 
01139    return 0;
01140 }

char* description void   ) 
 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 1221 of file res_musiconhold.c.

01222 {
01223    return "Music On Hold Resource";
01224 }

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

Definition at line 598 of file res_musiconhold.c.

References moh, and mohclasses.

Referenced by local_ast_moh_start(), and moh_register().

00599 {
00600    struct mohclass *moh;
00601    moh = mohclasses;
00602    while (moh) {
00603       if (!strcasecmp(name, moh->name))
00604          return moh;
00605       moh = moh->next;
00606    }
00607    return NULL;
00608 }

static int init_classes int  reload  )  [static]
 

Definition at line 1166 of file res_musiconhold.c.

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

Referenced by load_module(), and reload().

01167 {
01168    struct mohclass *moh;
01169     
01170    if (!load_moh_classes(reload))      /* Load classes from config */
01171       return 0;         /* Return if nothing is found */
01172    moh = mohclasses;
01173    while (moh) {
01174       if (moh->total_files)
01175          moh_scan_files(moh);
01176       moh = moh->next;
01177    }
01178    return 1;
01179 }

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 1239 of file res_musiconhold.c.

References ASTERISK_GPL_KEY.

01240 {
01241    return ASTERISK_GPL_KEY;
01242 }

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 1181 of file res_musiconhold.c.

References app0, app1, app2, app3, app4, 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, descrip0, descrip1, descrip2, descrip3, descrip4, init_classes(), local_ast_moh_cleanup(), local_ast_moh_start(), local_ast_moh_stop(), LOG_WARNING, moh0_exec(), moh1_exec(), moh2_exec(), moh3_exec(), moh4_exec(), synopsis0, synopsis1, synopsis2, synopsis3, and synopsis4.

01182 {
01183    int res;
01184 
01185    res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
01186    ast_register_atexit(ast_moh_destroy);
01187    ast_cli_register(&cli_moh);
01188    ast_cli_register(&cli_moh_files_show);
01189    ast_cli_register(&cli_moh_classes_show);
01190    if (!res)
01191       res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
01192    if (!res)
01193       res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
01194    if (!res)
01195       res = ast_register_application(app3, moh3_exec, synopsis3, descrip3);
01196    if (!res)
01197       res = ast_register_application(app4, moh4_exec, synopsis4, descrip4);
01198 
01199    if (!init_classes(0)) {    /* No music classes configured, so skip it */
01200       ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold.");
01201    } else {
01202       ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
01203    }
01204 
01205    return 0;
01206 }

static int load_moh_classes int  reload  )  [static]
 

Definition at line 926 of file res_musiconhold.c.

References mohclass::args, ast_category_browse(), 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, LOG_WARNING, moh_class_malloc(), MOH_RANDOMIZE, moh_register(), and var.

Referenced by init_classes(), and moh_cli().

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

static void local_ast_moh_cleanup struct ast_channel chan  )  [static]
 

Definition at line 865 of file res_musiconhold.c.

References free, and ast_channel::music_state.

Referenced by load_module(), and reload().

00866 {
00867    if (chan->music_state) {
00868       free(chan->music_state);
00869       chan->music_state = NULL;
00870    }
00871 }

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

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

00874 {
00875    struct mohclass *mohclass;
00876 
00877    if (ast_strlen_zero(class))
00878       class = chan->musicclass;
00879    if (ast_strlen_zero(class))
00880       class = "default";
00881    ast_mutex_lock(&moh_lock);
00882    mohclass = get_mohbyname(class);
00883    ast_mutex_unlock(&moh_lock);
00884 
00885    if (!mohclass) {
00886       ast_log(LOG_WARNING, "No class: %s\n", (char *)class);
00887       return -1;
00888    }
00889 
00890    ast_set_flag(chan, AST_FLAG_MOH);
00891    if (mohclass->total_files) {
00892       return ast_activate_generator(chan, &moh_file_stream, mohclass);
00893    } else
00894       return ast_activate_generator(chan, &mohgen, mohclass);
00895 }

static void local_ast_moh_stop struct ast_channel chan  )  [static]
 

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

00898 {
00899    ast_clear_flag(chan, AST_FLAG_MOH);
00900    ast_deactivate_generator(chan);
00901 
00902    if (chan->music_state) {
00903       if (chan->stream) {
00904          ast_closestream(chan->stream);
00905          chan->stream = NULL;
00906       }
00907    }
00908 }

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

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

00544 {
00545    if (ast_moh_start(chan, data)) {
00546       ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
00547       return -1;
00548    }
00549    while (!ast_safe_sleep(chan, 10000));
00550    ast_moh_stop(chan);
00551    return -1;
00552 }

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

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

00555 {
00556    int res;
00557    if (!data || !atoi(data)) {
00558       ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
00559       return -1;
00560    }
00561    if (ast_moh_start(chan, NULL)) {
00562       ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name);
00563       return -1;
00564    }
00565    res = ast_safe_sleep(chan, atoi(data) * 1000);
00566    ast_moh_stop(chan);
00567    return res;
00568 }

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

Definition at line 570 of file res_musiconhold.c.

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

Referenced by load_module().

00571 {
00572    if (ast_strlen_zero(data)) {
00573       ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
00574       return -1;
00575    }
00576    strncpy(chan->musicclass, data, sizeof(chan->musicclass) - 1);
00577    return 0;
00578 }

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

Definition at line 580 of file res_musiconhold.c.

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

Referenced by load_module().

00581 {
00582    char *class = NULL;
00583    if (data && strlen(data))
00584       class = data;
00585    if (ast_moh_start(chan, class)) 
00586       ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name);
00587 
00588    return 0;
00589 }

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

Definition at line 591 of file res_musiconhold.c.

References ast_moh_stop().

Referenced by load_module().

00592 {
00593    ast_moh_stop(chan);
00594 
00595    return 0;
00596 }

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

Definition at line 666 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.

00667 {
00668    struct mohdata *res;
00669    struct mohclass *class = params;
00670 
00671    res = mohalloc(class);
00672    if (res) {
00673       res->origwfmt = chan->writeformat;
00674       if (ast_set_write_format(chan, class->format)) {
00675          ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format));
00676          moh_release(NULL, res);
00677          res = NULL;
00678       }
00679       if (option_verbose > 2)
00680          ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name);
00681    }
00682    return res;
00683 }

static struct mohclass* moh_class_malloc void   )  [static]
 

Definition at line 910 of file res_musiconhold.c.

References AST_FORMAT_SLINEAR, and malloc.

Referenced by load_moh_classes().

00911 {
00912    struct mohclass *class;
00913 
00914    class = malloc(sizeof(struct mohclass));
00915 
00916    if (!class)
00917       return NULL;
00918 
00919    memset(class, 0, sizeof(struct mohclass));
00920 
00921    class->format = AST_FORMAT_SLINEAR;
00922 
00923    return class;
00924 }

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

Definition at line 1142 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.

01143 {
01144    struct mohclass *class;
01145 
01146    ast_mutex_lock(&moh_lock);
01147    for (class = mohclasses; class; class = class->next) {
01148       ast_cli(fd, "Class: %s\n", class->name);
01149       ast_cli(fd, "\tMode: %s\n", ast_strlen_zero(class->mode) ? "<none>" : class->mode);
01150       ast_cli(fd, "\tDirectory: %s\n", ast_strlen_zero(class->dir) ? "<none>" : class->dir);
01151       if (ast_test_flag(class, MOH_CUSTOM))
01152          ast_cli(fd, "\tApplication: %s\n", ast_strlen_zero(class->args) ? "<none>" : class->args);
01153       ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format));
01154    }
01155    ast_mutex_unlock(&moh_lock);
01156 
01157    return 0;
01158 }

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

Definition at line 1111 of file res_musiconhold.c.

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

01112 {
01113    int x;
01114 
01115    moh_on_off(0);
01116    ast_moh_destroy();
01117    x = load_moh_classes(1);
01118    moh_on_off(1);
01119    ast_cli(fd, "\n%d class%s reloaded.\n", x, x == 1 ? "" : "es");
01120    return 0;
01121 }

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

Definition at line 277 of file res_musiconhold.c.

References AST_FORMAT_SLINEAR, ast_log(), ast_set_write_format(), ast_verbose(), moh_files_state::class, free, LOG_WARNING, malloc, ast_channel::music_state, ast_channel::name, option_verbose, moh_files_state::origwfmt, VERBOSE_PREFIX_3, and ast_channel::writeformat.

00278 {
00279    struct moh_files_state *state;
00280    struct mohclass *class = params;
00281    int allocated = 0;
00282 
00283    if (!chan->music_state && (state = malloc(sizeof(struct moh_files_state)))) {
00284       chan->music_state = state;
00285       allocated = 1;
00286    } else 
00287       state = chan->music_state;
00288 
00289    if (state) {
00290       if (allocated || state->class != class) {
00291          /* initialize */
00292          memset(state, 0, sizeof(struct moh_files_state));
00293          state->class = class;
00294       }
00295 
00296       state->origwfmt = chan->writeformat;
00297 
00298       if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
00299          ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
00300          free(chan->music_state);
00301          chan->music_state = NULL;
00302       } else {
00303          if (option_verbose > 2)
00304             ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->name, chan->name);
00305       }
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 252 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.

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

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

Definition at line 240 of file res_musiconhold.c.

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

Referenced by moh_files_generator().

00241 {
00242    struct ast_frame *f = NULL;
00243    
00244    if (!(chan->stream && (f = ast_readframe(chan->stream)))) {
00245       if (!ast_moh_files_next(chan))
00246          f = ast_readframe(chan->stream);
00247    }
00248 
00249    return f;
00250 }

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

Definition at line 174 of file res_musiconhold.c.

References 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, and VERBOSE_PREFIX_3.

00175 {
00176    struct moh_files_state *state = chan->music_state;
00177 
00178    if (chan && state) {
00179       if (option_verbose > 2)
00180          ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
00181 
00182       if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
00183          ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt);
00184       }
00185       state->save_pos = state->pos + 1;
00186    }
00187 }

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

Definition at line 685 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.

00686 {
00687    struct ast_frame f;
00688    struct mohdata *moh = data;
00689    short buf[1280 + AST_FRIENDLY_OFFSET / 2];
00690    int res;
00691 
00692    if (!moh->parent->pid)
00693       return -1;
00694 
00695    len = ast_codec_get_len(moh->parent->format, samples);
00696 
00697    if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
00698       ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name);
00699       len = sizeof(buf) - AST_FRIENDLY_OFFSET;
00700    }
00701    res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
00702 #if 0
00703    if (res != len) {
00704       ast_log(LOG_WARNING, "Read only %d of %d bytes: %s\n", res, len, strerror(errno));
00705    }
00706 #endif
00707    if (res <= 0)
00708       return 0;
00709 
00710    memset(&f, 0, sizeof(f));
00711    
00712    f.frametype = AST_FRAME_VOICE;
00713    f.subclass = moh->parent->format;
00714    f.mallocd = 0;
00715    f.datalen = res;
00716    f.data = buf + AST_FRIENDLY_OFFSET / 2;
00717    f.offset = AST_FRIENDLY_OFFSET;
00718    f.samples = ast_codec_get_samples(&f);
00719 
00720    if (ast_write(chan, &f) < 0) {
00721       ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
00722       return -1;
00723    }
00724 
00725    return 0;
00726 }

static void moh_on_off int  on  )  [static]
 

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

01097 {
01098    struct ast_channel *chan = NULL;
01099 
01100    while ( (chan = ast_channel_walk_locked(chan)) != NULL) {
01101       if (ast_test_flag(chan, AST_FLAG_MOH)) {
01102          if (on)
01103             local_ast_moh_start(chan, NULL);
01104          else
01105             ast_deactivate_generator(chan);
01106       }
01107       ast_mutex_unlock(&chan->lock);
01108    }
01109 }

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

Definition at line 793 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, monmp3thread(), and respawn_time.

Referenced by load_moh_classes().

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

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

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

00635 {
00636    struct mohdata *moh = data, *prev, *cur;
00637    int oldwfmt;
00638    ast_mutex_lock(&moh_lock);
00639    /* Unlink */
00640    prev = NULL;
00641    cur = moh->parent->members;
00642    while (cur) {
00643       if (cur == moh) {
00644          if (prev)
00645             prev->next = cur->next;
00646          else
00647             moh->parent->members = cur->next;
00648          break;
00649       }
00650       prev = cur;
00651       cur = cur->next;
00652    }
00653    ast_mutex_unlock(&moh_lock);
00654    close(moh->pipe[0]);
00655    close(moh->pipe[1]);
00656    oldwfmt = moh->origwfmt;
00657    free(moh);
00658    if (chan) {
00659       if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
00660          ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
00661       if (option_verbose > 2)
00662          ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
00663    }
00664 }

static int moh_scan_files struct mohclass class  )  [static]
 

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

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

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

Definition at line 610 of file res_musiconhold.c.

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

Referenced by moh_alloc().

00611 {
00612    struct mohdata *moh;
00613    long flags;
00614    moh = malloc(sizeof(struct mohdata));
00615    if (!moh)
00616       return NULL;
00617    memset(moh, 0, sizeof(struct mohdata));
00618    if (pipe(moh->pipe)) {
00619       ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
00620       free(moh);
00621       return NULL;
00622    }
00623    /* Make entirely non-blocking */
00624    flags = fcntl(moh->pipe[0], F_GETFL);
00625    fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
00626    flags = fcntl(moh->pipe[1], F_GETFL);
00627    fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
00628    moh->parent = cl;
00629    moh->next = cl->members;
00630    cl->members = moh;
00631    return moh;
00632 }

static void* monmp3thread void *  data  )  [static]
 

Definition at line 470 of file res_musiconhold.c.

References ast_log(), LOG_WARNING, moh, and spawn_mp3().

Referenced by moh_register().

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

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 1208 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().

01209 {
01210    if (init_classes(1))
01211       ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
01212 
01213    return 0;
01214 }

static int spawn_mp3 struct mohclass class  )  [static]
 

Definition at line 318 of file res_musiconhold.c.

References mohclass::args, ast_log(), ast_strlen_zero(), ast_test_flag, mohclass::dir, LOG_WARNING, MAX_MP3S, MOH_CUSTOM, MOH_QUIET, and MOH_SINGLE.

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       close(fds[0]);
00440       /* Stdout goes to pipe */
00441       dup2(fds[1], STDOUT_FILENO);
00442       /* Close unused file descriptors */
00443       for (x=3;x<8192;x++) {
00444          if (-1 != fcntl(x, F_GETFL)) {
00445             close(x);
00446          }
00447       }
00448       /* Child */
00449       chdir(class->dir);
00450       if (ast_test_flag(class, MOH_CUSTOM)) {
00451          execv(argv[0], argv);
00452       } else {
00453          /* Default install is /usr/local/bin */
00454          execv(LOCAL_MPG_123, argv);
00455          /* Many places have it in /usr/bin */
00456          execv(MPG_123, argv);
00457          /* Check PATH as a last-ditch effort */
00458          execvp("mpg123", argv);
00459       }
00460       ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
00461       close(fds[1]);
00462       exit(1);
00463    } else {
00464       /* Parent */
00465       close(fds[1]);
00466    }
00467    return fds[0];
00468 }

int unload_module void   ) 
 

Cleanup all module structures, sockets, etc.

Standard module functions ...

Definition at line 1216 of file res_musiconhold.c.

01217 {
01218    return -1;
01219 }

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 1226 of file res_musiconhold.c.

References STANDARD_USECOUNT.

01227 {
01228    /* Never allow Music On Hold to be unloaded
01229       unresolve needed symbols in the dialer */
01230 #if 0
01231    int res;
01232    STANDARD_USECOUNT(res);
01233    return res;
01234 #else
01235    return 1;
01236 #endif
01237 }


Variable Documentation

char* app0 = "MusicOnHold" [static]
 

Definition at line 70 of file res_musiconhold.c.

Referenced by load_module().

char* app1 = "WaitMusicOnHold" [static]
 

Definition at line 71 of file res_musiconhold.c.

Referenced by load_module().

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 1160 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 1162 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 1164 of file res_musiconhold.c.

Referenced by load_module().

char* descrip0 [static]
 

Definition at line 82 of file res_musiconhold.c.

Referenced by load_module().

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.

Referenced by load_module().

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.

Referenced by load_module().

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 728 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.

Referenced by moh_register().

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

Definition at line 76 of file res_musiconhold.c.

Referenced by load_module().

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

Definition at line 77 of file res_musiconhold.c.

Referenced by load_module().

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.

Referenced by load_module().


Generated on Sat Mar 24 23:30:09 2007 for Asterisk - the Open Source PBX by  doxygen 1.4.6