Sun Aug 6 15:15:30 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

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.

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

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

Referenced by load_module(), and moh_cli().

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

static int ast_moh_files_next struct ast_channel chan  )  [static]
 

Definition at line 194 of file res_musiconhold.c.

References ast_closestream(), ast_fileexists(), ast_log(), ast_openstream_full(), ast_seekstream(), ast_test_flag, moh_files_state::class, mohclass::filearray, ast_channel::language, LOG_DEBUG, LOG_WARNING, MOH_RANDOMIZE, ast_channel::music_state, ast_channel::name, option_debug, moh_files_state::pos, moh_files_state::samples, moh_files_state::save_pos, ast_channel::stream, and mohclass::total_files.

Referenced by moh_files_readframe().

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

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

References ast_cli(), ast_mutex_lock(), ast_mutex_unlock(), mohclass::next, and mohclass::total_files.

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

char* description void   ) 
 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 1238 of file res_musiconhold.c.

01239 {
01240    return "Music On Hold Resource";
01241 }

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

Definition at line 608 of file res_musiconhold.c.

References moh, mohclass::name, and mohclass::next.

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

00609 {
00610    struct mohclass *moh;
00611    moh = mohclasses;
00612    while (moh) {
00613       if (!strcasecmp(name, moh->name))
00614          return moh;
00615       moh = moh->next;
00616    }
00617    return NULL;
00618 }

static int init_classes int  reload  )  [static]
 

Definition at line 1183 of file res_musiconhold.c.

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

Referenced by load_module(), and reload().

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

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

References ASTERISK_GPL_KEY.

01257 {
01258    return ASTERISK_GPL_KEY;
01259 }

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 1198 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(), 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.

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

static int load_moh_classes int  reload  )  [static]
 

Definition at line 936 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(), ast_variable::name, ast_variable::next, ast_variable::value, and var.

Referenced by init_classes(), and moh_cli().

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

static void local_ast_moh_cleanup struct ast_channel chan  )  [static]
 

Definition at line 875 of file res_musiconhold.c.

References free, and ast_channel::music_state.

Referenced by load_module(), and reload().

00876 {
00877    if (chan->music_state) {
00878       free(chan->music_state);
00879       chan->music_state = NULL;
00880    }
00881 }

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

Definition at line 883 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, and mohclass::total_files.

Referenced by load_module(), moh_on_off(), and reload().

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

static void local_ast_moh_stop struct ast_channel chan  )  [static]
 

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

00908 {
00909    ast_clear_flag(chan, AST_FLAG_MOH);
00910    ast_deactivate_generator(chan);
00911 
00912    if (chan->music_state) {
00913       if (chan->stream) {
00914          ast_closestream(chan->stream);
00915          chan->stream = NULL;
00916       }
00917    }
00918 }

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

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

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

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

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

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

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

Definition at line 580 of file res_musiconhold.c.

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

Referenced by load_module().

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

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

Definition at line 590 of file res_musiconhold.c.

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

Referenced by load_module().

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

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

Definition at line 601 of file res_musiconhold.c.

References ast_moh_stop().

Referenced by load_module().

00602 {
00603    ast_moh_stop(chan);
00604 
00605    return 0;
00606 }

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

Definition at line 676 of file res_musiconhold.c.

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

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

static struct mohclass* moh_class_malloc void   )  [static]
 

Definition at line 920 of file res_musiconhold.c.

References AST_FORMAT_SLINEAR, and malloc.

Referenced by load_moh_classes().

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

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

Definition at line 1159 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 mohclass::next.

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

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

Definition at line 1128 of file res_musiconhold.c.

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

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

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

Definition at line 279 of file res_musiconhold.c.

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

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

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

Definition at line 254 of file res_musiconhold.c.

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

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

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

Definition at line 242 of file res_musiconhold.c.

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

Referenced by moh_files_generator().

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

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

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

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

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

Definition at line 695 of file res_musiconhold.c.

References ast_codec_get_len(), ast_codec_get_samples(), AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), ast_write(), mohclass::format, LOG_WARNING, moh, ast_channel::name, mohdata::parent, mohclass::pid, and mohdata::pipe.

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

static void moh_on_off int  on  )  [static]
 

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

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

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

Definition at line 803 of file res_musiconhold.c.

References mohclass::args, ast_log(), ast_moh_free_class(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create, ast_set_flag, free, get_mohbyname(), LOG_DEBUG, LOG_WARNING, mohclass::mode, MOH_CUSTOM, MOH_QUIET, MOH_RANDOMIZE, moh_scan_files(), MOH_SINGLE, monmp3thread(), mohclass::name, mohclass::next, mohclass::pseudofd, respawn_time, mohclass::srcfd, mohclass::start, and mohclass::thread.

Referenced by load_moh_classes().

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

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

Definition at line 644 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, mohclass::members, moh, ast_channel::name, mohdata::next, option_verbose, mohdata::origwfmt, mohdata::parent, mohdata::pipe, and VERBOSE_PREFIX_3.

Referenced by moh_alloc().

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

static int moh_scan_files struct mohclass class  )  [static]
 

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

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

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

Definition at line 620 of file res_musiconhold.c.

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

Referenced by moh_alloc().

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

static void* monmp3thread void *  data  )  [static]
 

Definition at line 470 of file res_musiconhold.c.

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

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

01226 {
01227    if (init_classes(1))
01228       ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
01229 
01230    return 0;
01231 }

static int spawn_mp3 struct mohclass class  )  [static]
 

Definition at line 314 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, respawn_time, and mohclass::start.

Referenced by monmp3thread().

00315 {
00316    int fds[2];
00317    int files = 0;
00318    char fns[MAX_MP3S][80];
00319    char *argv[MAX_MP3S + 50];
00320    char xargs[256];
00321    char *argptr;
00322    int argc = 0;
00323    DIR *dir = NULL;
00324    struct dirent *de;
00325 
00326    
00327    if (!strcasecmp(class->dir, "nodir")) {
00328       files = 1;
00329    } else {
00330       dir = opendir(class->dir);
00331       if (!dir && !strstr(class->dir,"http://") && !strstr(class->dir,"HTTP://")) {
00332          ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
00333          return -1;
00334       }
00335    }
00336 
00337    if (!ast_test_flag(class, MOH_CUSTOM)) {
00338       argv[argc++] = "mpg123";
00339       argv[argc++] = "-q";
00340       argv[argc++] = "-s";
00341       argv[argc++] = "--mono";
00342       argv[argc++] = "-r";
00343       argv[argc++] = "8000";
00344       
00345       if (!ast_test_flag(class, MOH_SINGLE)) {
00346          argv[argc++] = "-b";
00347          argv[argc++] = "2048";
00348       }
00349       
00350       argv[argc++] = "-f";
00351       
00352       if (ast_test_flag(class, MOH_QUIET))
00353          argv[argc++] = "4096";
00354       else
00355          argv[argc++] = "8192";
00356       
00357       /* Look for extra arguments and add them to the list */
00358       strncpy(xargs, class->args, sizeof(xargs) - 1);
00359       argptr = xargs;
00360       while (!ast_strlen_zero(argptr)) {
00361          argv[argc++] = argptr;
00362          argptr = strchr(argptr, ',');
00363          if (argptr) {
00364             *argptr = '\0';
00365             argptr++;
00366          }
00367       }
00368    } else  {
00369       /* Format arguments for argv vector */
00370       strncpy(xargs, class->args, sizeof(xargs) - 1);
00371       argptr = xargs;
00372       while (!ast_strlen_zero(argptr)) {
00373          argv[argc++] = argptr;
00374          argptr = strchr(argptr, ' ');
00375          if (argptr) {
00376             *argptr = '\0';
00377             argptr++;
00378          }
00379       }
00380    }
00381 
00382 
00383    if (strstr(class->dir,"http://") || strstr(class->dir,"HTTP://")) {
00384       strncpy(fns[files], class->dir, sizeof(fns[files]) - 1);
00385       argv[argc++] = fns[files];
00386       files++;
00387    } else if (dir) {
00388       while ((de = readdir(dir)) && (files < MAX_MP3S)) {
00389          if ((strlen(de->d_name) > 3) && 
00390              ((ast_test_flag(class, MOH_CUSTOM) && 
00391                (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 
00392                 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) ||
00393               !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
00394             strncpy(fns[files], de->d_name, sizeof(fns[files]) - 1);
00395             argv[argc++] = fns[files];
00396             files++;
00397          }
00398       }
00399    }
00400    argv[argc] = NULL;
00401    if (dir) {
00402       closedir(dir);
00403    }
00404    if (pipe(fds)) {  
00405       ast_log(LOG_WARNING, "Pipe failed\n");
00406       return -1;
00407    }
00408 #if 0
00409    printf("%d files total, %d args total\n", files, argc);
00410    {
00411       int x;
00412       for (x=0;argv[x];x++)
00413          printf("arg%d: %s\n", x, argv[x]);
00414    }
00415 #endif   
00416    if (!files) {
00417       ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
00418       close(fds[0]);
00419       close(fds[1]);
00420       return -1;
00421    }
00422    if (time(NULL) - class->start < respawn_time) {
00423       sleep(respawn_time - (time(NULL) - class->start));
00424    }
00425    time(&class->start);
00426    class->pid = fork();
00427    if (class->pid < 0) {
00428       close(fds[0]);
00429       close(fds[1]);
00430       ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
00431       return -1;
00432    }
00433    if (!class->pid) {
00434       int x;
00435 
00436       if (option_highpriority)
00437          ast_set_priority(0);
00438 
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 1233 of file res_musiconhold.c.

01234 {
01235    return -1;
01236 }

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

References STANDARD_USECOUNT.

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


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

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

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

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

struct mohclass* mohclasses [static]
 

Definition at line 150 of file res_musiconhold.c.

struct ast_generator mohgen [static]
 

Definition at line 738 of file res_musiconhold.c.

int respawn_time = 20 [static]
 

Definition at line 107 of file res_musiconhold.c.

Referenced by moh_register(), and spawn_mp3().

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 Sun Aug 6 15:15:32 2006 for Asterisk - the Open Source PBX by  doxygen 1.4.2