Mon Mar 20 08:20: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"

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

void ast_moh_destroy (void)
int ast_moh_files_next (struct ast_channel *chan)
void ast_moh_free_class (struct mohclass **class)
 AST_MUTEX_DEFINE_STATIC (moh_lock)
int cli_files_show (int fd, int argc, char *argv[])
char * description (void)
 Provides a description of the module.
mohclassget_mohbyname (char *name)
int init_classes (int reload)
char * key ()
 Returns the ASTERISK_GPL_KEY.
int load_module (void)
 Initialize the module.
int load_moh_classes (int reload)
void local_ast_moh_cleanup (struct ast_channel *chan)
int local_ast_moh_start (struct ast_channel *chan, char *class)
void local_ast_moh_stop (struct ast_channel *chan)
int moh0_exec (struct ast_channel *chan, void *data)
int moh1_exec (struct ast_channel *chan, void *data)
int moh2_exec (struct ast_channel *chan, void *data)
int moh3_exec (struct ast_channel *chan, void *data)
int moh4_exec (struct ast_channel *chan, void *data)
void * moh_alloc (struct ast_channel *chan, void *params)
mohclassmoh_class_malloc (void)
int moh_classes_show (int fd, int argc, char *argv[])
int moh_cli (int fd, int argc, char *argv[])
void * moh_files_alloc (struct ast_channel *chan, void *params)
int moh_files_generator (struct ast_channel *chan, void *data, int len, int samples)
ast_framemoh_files_readframe (struct ast_channel *chan)
void moh_files_release (struct ast_channel *chan, void *data)
int moh_generate (struct ast_channel *chan, void *data, int len, int samples)
void moh_on_off (int on)
int moh_register (struct mohclass *moh, int reload)
void moh_release (struct ast_channel *chan, void *data)
int moh_scan_files (struct mohclass *class)
mohdatamohalloc (struct mohclass *cl)
void * monmp3thread (void *data)
int reload (void)
 Reload stuff.
int spawn_mp3 (struct mohclass *class)
int unload_module (void)
 Cleanup all module structures, sockets, etc.
int usecount (void)
 Provides a usecount.

Variables

char * app0 = "MusicOnHold"
char * app1 = "WaitMusicOnHold"
char * app2 = "SetMusicOnHold"
char * app3 = "StartMusicOnHold"
char * app4 = "StopMusicOnHold"
ast_cli_entry cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL}
ast_cli_entry cli_moh_classes_show = { { "moh", "classes", "show"}, moh_classes_show, "List MOH classes", "Lists all MOH classes", NULL}
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}
char * descrip0
char * descrip1
char * descrip2
char * descrip3
char * descrip4
ast_generator moh_file_stream
mohclassmohclasses
ast_generator mohgen
int respawn_time = 20
char * synopsis0 = "Play Music On Hold indefinitely"
char * synopsis1 = "Wait, playing Music On Hold"
char * synopsis2 = "Set default Music On Hold class"
char * synopsis3 = "Play Music On Hold"
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

void ast_moh_destroy void   )  [static]
 

Definition at line 1059 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, mohclasses, mohclass::next, option_verbose, mohclass::pid, mohclass::srcfd, and VERBOSE_PREFIX_2.

Referenced by load_module(), and moh_cli().

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

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_FORMAT_SLINEAR, ast_log(), ast_openstream_full(), ast_seekstream(), ast_set_write_format(), 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, 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().

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 }

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   ) 
 

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

Definition at line 1118 of file res_musiconhold.c.

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

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

char* description void   ) 
 

Provides a description of the module.

Returns:
a short description of your module

Definition at line 1216 of file res_musiconhold.c.

01217 {
01218    return "Music On Hold Resource";
01219 }

struct mohclass* get_mohbyname char *  name  )  [static]
 

Definition at line 598 of file res_musiconhold.c.

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

Referenced by load_moh_classes(), 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 }

int init_classes int  reload  )  [static]
 

Definition at line 1161 of file res_musiconhold.c.

References load_moh_classes(), moh_scan_files(), mohclass::next, reload(), and mohclass::total_files.

Referenced by load_module(), and reload().

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

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

01235 {
01236    return ASTERISK_GPL_KEY;
01237 }

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

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

int load_moh_classes int  reload  )  [static]
 

Definition at line 921 of file res_musiconhold.c.

References ast_category_browse(), ast_config_destroy(), ast_config_load(), 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, reload(), ast_variable::value, and var.

Referenced by init_classes(), and moh_cli().

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

void local_ast_moh_cleanup struct ast_channel chan  )  [static]
 

Definition at line 860 of file res_musiconhold.c.

References free, and ast_channel::music_state.

Referenced by load_module(), and reload().

00861 {
00862    if (chan->music_state) {
00863       free(chan->music_state);
00864       chan->music_state = NULL;
00865    }
00866 }

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

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

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

void local_ast_moh_stop struct ast_channel chan  )  [static]
 

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

00893 {
00894    ast_clear_flag(chan, AST_FLAG_MOH);
00895    ast_deactivate_generator(chan);
00896 
00897    if (chan->music_state) {
00898       if (chan->stream) {
00899          ast_closestream(chan->stream);
00900          chan->stream = NULL;
00901       }
00902    }
00903 }

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 }

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 }

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 }

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(), LOG_NOTICE, and ast_channel::name.

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 }

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 }

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 }

struct mohclass* moh_class_malloc void   )  [static]
 

Definition at line 905 of file res_musiconhold.c.

References mohclass::format, and malloc.

Referenced by load_moh_classes().

00906 {
00907    struct mohclass *class;
00908 
00909    class = malloc(sizeof(struct mohclass));
00910 
00911    if (!class)
00912       return NULL;
00913 
00914    memset(class, 0, sizeof(struct mohclass));
00915 
00916    class->format = AST_FORMAT_SLINEAR;
00917 
00918    return class;
00919 }

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

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

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

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

Definition at line 1106 of file res_musiconhold.c.

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

01107 {
01108    int x;
01109 
01110    moh_on_off(0);
01111    ast_moh_destroy();
01112    x = load_moh_classes(1);
01113    moh_on_off(1);
01114    ast_cli(fd, "\n%d class%s reloaded.\n", x, x == 1 ? "" : "es");
01115    return 0;
01116 }

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 }

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 }

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 }

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 }

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_FRIENDLY_OFFSET, ast_log(), ast_write(), mohclass::format, ast_frame::frametype, LOG_WARNING, ast_channel::name, mohdata::parent, mohclass::pid, mohdata::pipe, and ast_frame::subclass.

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 }

void moh_on_off int  on  )  [static]
 

Definition at line 1091 of file res_musiconhold.c.

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

Referenced by moh_cli().

01092 {
01093    struct ast_channel *chan = NULL;
01094 
01095    while ( (chan = ast_channel_walk_locked(chan)) != NULL) {
01096       if (ast_test_flag(chan, AST_FLAG_MOH)) {
01097          if (on)
01098             local_ast_moh_start(chan, NULL);
01099          else
01100             ast_deactivate_generator(chan);
01101       }
01102       ast_mutex_unlock(&chan->lock);
01103    }
01104 }

int moh_register struct mohclass moh,
int  reload
[static]
 

Definition at line 788 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, mohclasses, monmp3thread(), mohclass::name, mohclass::next, mohclass::pseudofd, mohclass::srcfd, mohclass::start, and mohclass::thread.

Referenced by load_moh_classes().

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

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, mohclass::members, ast_channel::name, mohdata::next, option_verbose, mohdata::origwfmt, mohdata::parent, mohdata::pipe, 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 }

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 
00783    closedir(files_DIR);
00784    chdir(path);
00785    return class->total_files;
00786 }

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, mohdata::next, mohdata::parent, 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 }

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_MS_INTERVAL, mohdata::next, mohdata::pipe, spawn_mp3(), and tv.

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

01204 {
01205    if (init_classes(1))
01206       ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
01207 
01208    return 0;
01209 }

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, LOCAL_MPG_123, LOG_WARNING, MAX_MP3S, MOH_CUSTOM, MOH_QUIET, MOH_SINGLE, MPG_123, respawn_time, and mohclass::start.

Referenced by monmp3thread().

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

01212 {
01213    return -1;
01214 }

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

References STANDARD_USECOUNT.

01222 {
01223    /* Never allow Music On Hold to be unloaded
01224       unresolve needed symbols in the dialer */
01225 #if 0
01226    int res;
01227    STANDARD_USECOUNT(res);
01228    return res;
01229 #else
01230    return 1;
01231 #endif
01232 }


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.

Referenced by load_module().

char* app3 = "StartMusicOnHold" [static]
 

Definition at line 73 of file res_musiconhold.c.

Referenced by load_module().

char* app4 = "StopMusicOnHold" [static]
 

Definition at line 74 of file res_musiconhold.c.

Referenced by load_module().

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

Definition at line 1155 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 1157 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 1159 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.

Referenced by load_module().

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.

Referenced by load_module().

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

Referenced by load_module().

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

Definition at line 79 of file res_musiconhold.c.

Referenced by load_module().

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

Definition at line 80 of file res_musiconhold.c.

Referenced by load_module().


Generated on Mon Mar 20 08:20:30 2006 for Asterisk - the Open Source PBX by  doxygen 1.3.9.1