Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:01:46 2007

Asterisk developer's documentation :: Codename Pineapple


res_musiconhold.c File Reference


Detailed Description

Routines implementing music on hold.

Author:
Mark Spencer <markster@digium.com>

Definition in file res_musiconhold.c.

#include "asterisk.h"
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <sys/stat.h>
#include <dirent.h>
#include <sys/ioctl.h>
#include "asterisk/zapata.h"
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/logger.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/module.h"
#include "asterisk/translate.h"
#include "asterisk/say.h"
#include "asterisk/musiconhold.h"
#include "asterisk/config.h"
#include "asterisk/utils.h"
#include "asterisk/cli.h"
#include "asterisk/stringfields.h"
#include "asterisk/linkedlists.h"

Include dependency graph for res_musiconhold.c:

Go to the source code of this file.

Data Structures

struct  moh_files_state
struct  mohclass
struct  mohdata

Defines

#define INITIAL_NUM_FILES   8
#define LOCAL_MPG_123   "/usr/local/bin/mpg123"
#define MAX_MP3S   256
#define MOH_CUSTOM   (1 << 2)
#define MOH_MS_INTERVAL   100
#define MOH_QUIET   (1 << 0)
#define MOH_RANDOMIZE   (1 << 3)
#define MOH_SINGLE   (1 << 1)
#define MPG_123   "/usr/bin/mpg123"

Functions

 AST_LIST_HEAD_STATIC (mohclasses, mohclass)
 AST_MODULE_INFO (ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS,"Music On Hold Resource",.load=load_module,.unload=unload_module,.reload=reload,)
static void ast_moh_destroy (void)
static int ast_moh_files_next (struct ast_channel *chan)
static void ast_moh_free_class (struct mohclass **mohclass)
static int cli_files_show (int fd, int argc, char *argv[])
static struct mohclassget_mohbyname (const char *name)
static int init_classes (int reload)
static int load_module (void)
static int load_moh_classes (int reload)
static void local_ast_moh_cleanup (struct ast_channel *chan)
static int local_ast_moh_start (struct ast_channel *chan, const char *mclass, const char *interpclass)
static void local_ast_moh_stop (struct ast_channel *chan)
static int moh0_exec (struct ast_channel *chan, void *data)
static int moh1_exec (struct ast_channel *chan, void *data)
static int moh2_exec (struct ast_channel *chan, void *data)
static int moh3_exec (struct ast_channel *chan, void *data)
static int moh4_exec (struct ast_channel *chan, void *data)
static int moh_add_file (struct mohclass *class, const char *filepath)
static void * moh_alloc (struct ast_channel *chan, void *params)
static struct mohclassmoh_class_malloc (void)
static int moh_classes_show (int fd, int argc, char *argv[])
static int moh_cli (int fd, int argc, char *argv[])
static void * moh_files_alloc (struct ast_channel *chan, void *params)
static int moh_files_generator (struct ast_channel *chan, void *data, int len, int samples)
static struct ast_framemoh_files_readframe (struct ast_channel *chan)
static void moh_files_release (struct ast_channel *chan, void *data)
static int moh_generate (struct ast_channel *chan, void *data, int len, int samples)
static void moh_on_off (int on)
static int moh_register (struct mohclass *moh, int reload)
static void moh_release (struct ast_channel *chan, void *data)
static int moh_scan_files (struct mohclass *class)
static struct mohdatamohalloc (struct mohclass *cl)
static void * monmp3thread (void *data)
static int reload (void)
static int spawn_mp3 (struct mohclass *class)
static int unload_module (void)

Variables

static char * app0 = "MusicOnHold"
static char * app1 = "WaitMusicOnHold"
static char * app2 = "SetMusicOnHold"
static char * app3 = "StartMusicOnHold"
static char * app4 = "StopMusicOnHold"
static struct ast_cli_entry cli_moh []
static char * descrip0
static char * descrip1
static char * descrip2
static char * descrip3
static char * descrip4
static struct ast_generator moh_file_stream
static struct ast_generator mohgen
static int respawn_time = 20
static char * synopsis0 = "Play Music On Hold indefinitely"
static char * synopsis1 = "Wait, playing Music On Hold"
static char * synopsis2 = "Set default Music On Hold class"
static char * synopsis3 = "Play Music On Hold"
static char * synopsis4 = "Stop Playing Music On Hold"


Define Documentation

#define INITIAL_NUM_FILES   8
 

Definition at line 73 of file res_musiconhold.c.

Referenced by moh_add_file().

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

Definition at line 164 of file res_musiconhold.c.

#define MAX_MP3S   256
 

Definition at line 166 of file res_musiconhold.c.

Referenced by spawn_mp3().

#define MOH_CUSTOM   (1 << 2)
 

Definition at line 125 of file res_musiconhold.c.

Referenced by moh_classes_show(), moh_register(), and spawn_mp3().

#define MOH_MS_INTERVAL   100
 

#define MOH_QUIET   (1 << 0)
 

Definition at line 123 of file res_musiconhold.c.

Referenced by moh_register(), and spawn_mp3().

#define MOH_RANDOMIZE   (1 << 3)
 

Definition at line 126 of file res_musiconhold.c.

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

#define MOH_SINGLE   (1 << 1)
 

Definition at line 124 of file res_musiconhold.c.

Referenced by moh_register(), and spawn_mp3().

#define MPG_123   "/usr/bin/mpg123"
 

Definition at line 165 of file res_musiconhold.c.


Function Documentation

AST_LIST_HEAD_STATIC mohclasses  ,
mohclass 
 

AST_MODULE_INFO ASTERISK_GPL_KEY  ,
AST_MODFLAG_GLOBAL_SYMBOLS  ,
"Music On Hold Resource"  ,
load = load_module,
unload = unload_module,
reload = reload
 

static void ast_moh_destroy void   )  [static]
 

Definition at line 1054 of file res_musiconhold.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), ast_moh_free_class(), ast_verbose(), ast_wait_for_input(), moh, option_debug, option_verbose, mohclass::pid, and VERBOSE_PREFIX_2.

Referenced by load_module(), and moh_cli().

01055 {
01056    struct mohclass *moh;
01057    char buff[8192];
01058    int bytes, tbytes = 0, stime = 0, pid = 0;
01059 
01060    if (option_verbose > 1)
01061       ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
01062 
01063    AST_LIST_LOCK(&mohclasses);
01064    while ((moh = AST_LIST_REMOVE_HEAD(&mohclasses, list))) {
01065       if (moh->pid > 1) {
01066          if (option_debug)
01067             ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
01068          stime = time(NULL) + 2;
01069          pid = moh->pid;
01070          moh->pid = 0;
01071          /* Back when this was just mpg123, SIGKILL was fine.  Now we need
01072           * to give the process a reason and time enough to kill off its
01073           * children. */
01074          kill(pid, SIGHUP);
01075          usleep(100000);
01076          kill(pid, SIGTERM);
01077          usleep(100000);
01078          kill(pid, SIGKILL);
01079          while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime)
01080             tbytes = tbytes + bytes;
01081          if (option_debug)
01082             ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
01083          close(moh->srcfd);
01084       }
01085       ast_moh_free_class(&moh);
01086    }
01087    AST_LIST_UNLOCK(&mohclasses);
01088 }

static int ast_moh_files_next struct ast_channel chan  )  [static]
 

Definition at line 214 of file res_musiconhold.c.

References ast_closestream(), ast_fileexists(), ast_test_flag, moh_files_state::class, mohclass::filearray, MOH_RANDOMIZE, ast_channel::music_state, moh_files_state::pos, moh_files_state::samples, moh_files_state::save_pos, ast_channel::stream, and mohclass::total_files.

Referenced by moh_files_readframe().

00215 {
00216    struct moh_files_state *state = chan->music_state;
00217    int tries;
00218 
00219    if (state->save_pos) {
00220       state->pos = state->save_pos;
00221       state->save_pos = 0;
00222    }
00223 
00224    state->samples = 0;
00225    if (chan->stream) {
00226       ast_closestream(chan->stream);
00227       chan->stream = NULL;
00228       state->pos++;
00229       state->pos %= state->class->total_files;
00230    }
00231 
00232    if (ast_test_flag(state->class, MOH_RANDOMIZE)) {
00233       /* Try 20 times to find something good */
00234       for (tries = 0; tries < 20; tries++) {
00235          state->pos = rand() % state->class->total_files;
00236 
00237          /* check to see if this file's format can be opened */
00238          if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0)
00239             break;
00240       }
00241    }
00242 
00243    if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
00244       ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
00245       state->pos++;
00246       state->pos %= state->class->total_files;
00247       return -1;
00248    }
00249 
00250    if (option_debug)
00251       ast_log(LOG_DEBUG, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]);
00252 
00253    if (state->samples)
00254       ast_seekstream(chan->stream, state->samples, SEEK_SET);
00255 
00256    return 0;
00257 }

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

Definition at line 169 of file res_musiconhold.c.

References AST_LIST_REMOVE_HEAD, and free.

Referenced by ast_moh_destroy(), and moh_register().

00170 {
00171    struct mohdata *member;
00172    struct mohclass *class = *mohclass;
00173    int i;
00174    
00175    while ((member = AST_LIST_REMOVE_HEAD(&class->members, list)))
00176       free(member);
00177    
00178    if (class->thread) {
00179       pthread_cancel(class->thread);
00180       class->thread = 0;
00181    }
00182 
00183    if (class->filearray) {
00184       for (i = 0; i < class->total_files; i++)
00185          free(class->filearray[i]);
00186       free(class->filearray);
00187    }
00188 
00189    free(class);
00190    *mohclass = NULL;
00191 }

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

Definition at line 1117 of file res_musiconhold.c.

References ast_cli(), AST_LIST_LOCK, AST_LIST_TRAVERSE, and AST_LIST_UNLOCK.

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

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

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

Definition at line 627 of file res_musiconhold.c.

References AST_LIST_TRAVERSE, and moh.

Referenced by local_ast_moh_start(), and moh_register().

00628 {
00629    struct mohclass *moh = NULL;
00630 
00631    AST_LIST_TRAVERSE(&mohclasses, moh, list) {
00632       if (!strcasecmp(name, moh->name))
00633          break;
00634    }
00635 
00636    return moh;
00637 }

static int init_classes int  reload  )  [static]
 

Definition at line 1169 of file res_musiconhold.c.

References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, load_moh_classes(), moh, and moh_scan_files().

Referenced by load_module(), and reload().

01170 {
01171    struct mohclass *moh;
01172     
01173    if (!load_moh_classes(reload))      /* Load classes from config */
01174       return 0;         /* Return if nothing is found */
01175 
01176    AST_LIST_LOCK(&mohclasses);
01177    AST_LIST_TRAVERSE(&mohclasses, moh, list) {
01178       if (moh->total_files)
01179          moh_scan_files(moh);
01180    }
01181    AST_LIST_UNLOCK(&mohclasses);
01182 
01183    return 1;
01184 }

static int load_module void   )  [static]
 

Definition at line 1186 of file res_musiconhold.c.

References ast_cli_register_multiple(), ast_install_music_functions(), ast_log(), ast_moh_destroy(), ast_register_application(), ast_register_atexit(), cli_moh, init_classes(), local_ast_moh_cleanup(), local_ast_moh_start(), local_ast_moh_stop(), LOG_WARNING, moh0_exec(), moh1_exec(), moh2_exec(), moh3_exec(), and moh4_exec().

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

static int load_moh_classes int  reload  )  [static]
 

Definition at line 981 of file res_musiconhold.c.

References ast_category_browse(), ast_config_load(), AST_FORMAT_SLINEAR, ast_getformatbyname(), ast_log(), ast_set2_flag, ast_strlen_zero(), ast_true(), ast_variable_browse(), free, LOG_WARNING, moh_class_malloc(), MOH_RANDOMIZE, moh_register(), and var.

Referenced by init_classes(), and moh_cli().

00982 {
00983    struct ast_config *cfg;
00984    struct ast_variable *var;
00985    struct mohclass *class; 
00986    char *cat;
00987    int numclasses = 0;
00988 
00989    cfg = ast_config_load("musiconhold.conf");
00990 
00991    if (!cfg)
00992       return 0;
00993 
00994    cat = ast_category_browse(cfg, NULL);
00995    for (; cat; cat = ast_category_browse(cfg, cat)) {
00996       /* These names were deprecated in 1.4 and should not be used until after the next major release. */
00997       if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) {       
00998          if (!(class = moh_class_malloc())) {
00999             break;
01000          }           
01001          ast_copy_string(class->name, cat, sizeof(class->name));  
01002          var = ast_variable_browse(cfg, cat);
01003          while (var) {
01004             if (!strcasecmp(var->name, "mode"))
01005                ast_copy_string(class->mode, var->value, sizeof(class->mode)); 
01006             else if (!strcasecmp(var->name, "directory"))
01007                ast_copy_string(class->dir, var->value, sizeof(class->dir));
01008             else if (!strcasecmp(var->name, "application"))
01009                ast_copy_string(class->args, var->value, sizeof(class->args));
01010             else if (!strcasecmp(var->name, "random"))
01011                ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
01012             else if (!strcasecmp(var->name, "format")) {
01013                class->format = ast_getformatbyname(var->value);
01014                if (!class->format) {
01015                   ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
01016                   class->format = AST_FORMAT_SLINEAR;
01017                }
01018             }
01019             var = var->next;
01020          }
01021 
01022          if (ast_strlen_zero(class->dir)) {
01023             if (!strcasecmp(class->mode, "custom")) {
01024                strcpy(class->dir, "nodir");
01025             } else {
01026                ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
01027                free(class);
01028                continue;
01029             }
01030          }
01031          if (ast_strlen_zero(class->mode)) {
01032             ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
01033             free(class);
01034             continue;
01035          }
01036          if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
01037             ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
01038             free(class);
01039             continue;
01040          }
01041 
01042          /* Don't leak a class when it's already registered */
01043          moh_register(class, reload);
01044 
01045          numclasses++;
01046       }
01047    }
01048    
01049    ast_config_destroy(cfg);
01050 
01051    return numclasses;
01052 }

static void local_ast_moh_cleanup struct ast_channel chan  )  [static]
 

Definition at line 909 of file res_musiconhold.c.

References free, and ast_channel::music_state.

Referenced by load_module(), and reload().

00910 {
00911    if (chan->music_state) {
00912       free(chan->music_state);
00913       chan->music_state = NULL;
00914    }
00915 }

static int local_ast_moh_start struct ast_channel chan,
const char *  mclass,
const char *  interpclass
[static]
 

Definition at line 917 of file res_musiconhold.c.

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

00918 {
00919    struct mohclass *mohclass;
00920    const char *class;
00921 
00922    /* The following is the order of preference for which class to use:
00923     * 1) The channels explicitly set musicclass, which should *only* be
00924     *    set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
00925     * 2) The mclass argument. If a channel is calling ast_moh_start() as the
00926     *    result of receiving a HOLD control frame, this should be the
00927     *    payload that came with the frame.
00928     * 3) The interpclass argument. This would be from the mohinterpret
00929     *    option from channel drivers. This is the same as the old musicclass
00930     *    option.
00931     * 4) The default class.
00932     */
00933    if (!ast_strlen_zero(chan->musicclass))
00934       class = chan->musicclass;
00935    else if (!ast_strlen_zero(mclass))
00936       class = mclass;
00937    else if (!ast_strlen_zero(interpclass))
00938       class = interpclass;
00939    else
00940       class = "default";
00941 
00942    AST_LIST_LOCK(&mohclasses);
00943    mohclass = get_mohbyname(class);
00944    AST_LIST_UNLOCK(&mohclasses);
00945 
00946    if (!mohclass) {
00947       ast_log(LOG_WARNING, "No class: %s\n", class);
00948       return -1;
00949    }
00950 
00951    ast_set_flag(chan, AST_FLAG_MOH);
00952    if (mohclass->total_files) {
00953       return ast_activate_generator(chan, &moh_file_stream, mohclass);
00954    } else
00955       return ast_activate_generator(chan, &mohgen, mohclass);
00956 }

static void local_ast_moh_stop struct ast_channel chan  )  [static]
 

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

00959 {
00960    ast_clear_flag(chan, AST_FLAG_MOH);
00961    ast_deactivate_generator(chan);
00962 
00963    if (chan->music_state) {
00964       if (chan->stream) {
00965          ast_closestream(chan->stream);
00966          chan->stream = NULL;
00967       }
00968    }
00969 }

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

Definition at line 571 of file res_musiconhold.c.

References ast_log(), ast_moh_start(), ast_moh_stop(), ast_safe_sleep(), and LOG_WARNING.

Referenced by load_module().

00572 {
00573    if (ast_moh_start(chan, data, NULL)) {
00574       ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
00575       return -1;
00576    }
00577    while (!ast_safe_sleep(chan, 10000));
00578    ast_moh_stop(chan);
00579    return -1;
00580 }

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

Definition at line 582 of file res_musiconhold.c.

References ast_log(), ast_moh_start(), ast_moh_stop(), ast_safe_sleep(), and LOG_WARNING.

Referenced by load_module().

00583 {
00584    int res;
00585    if (!data || !atoi(data)) {
00586       ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
00587       return -1;
00588    }
00589    if (ast_moh_start(chan, NULL, NULL)) {
00590       ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name);
00591       return -1;
00592    }
00593    res = ast_safe_sleep(chan, atoi(data) * 1000);
00594    ast_moh_stop(chan);
00595    return res;
00596 }

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

Definition at line 598 of file res_musiconhold.c.

References ast_log(), ast_string_field_set, ast_strlen_zero(), LOG_WARNING, and musicclass.

Referenced by load_module().

00599 {
00600    if (ast_strlen_zero(data)) {
00601       ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
00602       return -1;
00603    }
00604    ast_string_field_set(chan, musicclass, data);
00605    return 0;
00606 }

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

Definition at line 608 of file res_musiconhold.c.

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

Referenced by load_module().

00609 {
00610    char *class = NULL;
00611    if (data && strlen(data))
00612       class = data;
00613    if (ast_moh_start(chan, class, NULL)) 
00614       ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name);
00615 
00616    return 0;
00617 }

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

Definition at line 619 of file res_musiconhold.c.

References ast_moh_stop().

Referenced by load_module().

00620 {
00621    ast_moh_stop(chan);
00622 
00623    return 0;
00624 }

static int moh_add_file struct mohclass class,
const char *  filepath
[static]
 

Definition at line 746 of file res_musiconhold.c.

References mohclass::allowed_files, ast_calloc, ast_realloc, ast_strdup, mohclass::filearray, INITIAL_NUM_FILES, and mohclass::total_files.

Referenced by moh_scan_files().

00747 {
00748    if (!class->allowed_files) {
00749       if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray))))
00750          return -1;
00751       class->allowed_files = INITIAL_NUM_FILES;
00752    } else if (class->total_files == class->allowed_files) {
00753       if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) {
00754          class->allowed_files = 0;
00755          class->total_files = 0;
00756          return -1;
00757       }
00758       class->allowed_files *= 2;
00759    }
00760 
00761    if (!(class->filearray[class->total_files] = ast_strdup(filepath)))
00762       return -1;
00763 
00764    class->total_files++;
00765 
00766    return 0;
00767 }

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

Definition at line 690 of file res_musiconhold.c.

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

00691 {
00692    struct mohdata *res;
00693    struct mohclass *class = params;
00694 
00695    if ((res = mohalloc(class))) {
00696       res->origwfmt = chan->writeformat;
00697       if (ast_set_write_format(chan, class->format)) {
00698          ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format));
00699          moh_release(NULL, res);
00700          res = NULL;
00701       }
00702       if (option_verbose > 2)
00703          ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name);
00704    }
00705    return res;
00706 }

static struct mohclass* moh_class_malloc void   )  [static]
 

Definition at line 971 of file res_musiconhold.c.

References ast_calloc, AST_FORMAT_SLINEAR, and mohclass::format.

Referenced by load_moh_classes().

00972 {
00973    struct mohclass *class;
00974 
00975    if ((class = ast_calloc(1, sizeof(*class))))    
00976       class->format = AST_FORMAT_SLINEAR;
00977 
00978    return class;
00979 }

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

Definition at line 1136 of file res_musiconhold.c.

References ast_cli(), ast_getformatname(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_test_flag, MOH_CUSTOM, and S_OR.

01137 {
01138    struct mohclass *class;
01139 
01140    AST_LIST_LOCK(&mohclasses);
01141    AST_LIST_TRAVERSE(&mohclasses, class, list) {
01142       ast_cli(fd, "Class: %s\n", class->name);
01143       ast_cli(fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
01144       ast_cli(fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
01145       if (ast_test_flag(class, MOH_CUSTOM))
01146          ast_cli(fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
01147       if (strcasecmp(class->mode, "files"))
01148          ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format));
01149    }
01150    AST_LIST_UNLOCK(&mohclasses);
01151 
01152    return 0;
01153 }

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

Definition at line 1105 of file res_musiconhold.c.

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

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

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

Definition at line 297 of file res_musiconhold.c.

References ast_calloc, ast_random(), ast_test_flag, ast_verbose(), MOH_RANDOMIZE, ast_channel::music_state, option_verbose, VERBOSE_PREFIX_3, and ast_channel::writeformat.

00298 {
00299    struct moh_files_state *state;
00300    struct mohclass *class = params;
00301 
00302    if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) {
00303       chan->music_state = state;
00304       state->class = class;
00305    } else 
00306       state = chan->music_state;
00307 
00308    if (state) {
00309       if (state->class != class) {
00310          /* initialize */
00311          memset(state, 0, sizeof(*state));
00312          state->class = class;
00313          if (ast_test_flag(state->class, MOH_RANDOMIZE))
00314             state->pos = ast_random() % class->total_files;
00315       }
00316 
00317       state->origwfmt = chan->writeformat;
00318 
00319       if (option_verbose > 2)
00320          ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->name, chan->name);
00321    }
00322    
00323    return chan->music_state;
00324 }

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

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

00273 {
00274    struct moh_files_state *state = chan->music_state;
00275    struct ast_frame *f = NULL;
00276    int res = 0;
00277 
00278    state->sample_queue += samples;
00279 
00280    while (state->sample_queue > 0) {
00281       if ((f = moh_files_readframe(chan))) {
00282          state->samples += f->samples;
00283          res = ast_write(chan, f);
00284          state->sample_queue -= f->samples;
00285          ast_frfree(f);
00286          if (res < 0) {
00287             ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
00288             return -1;
00289          }
00290       } else
00291          return -1;  
00292    }
00293    return res;
00294 }

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

Definition at line 260 of file res_musiconhold.c.

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

Referenced by moh_files_generator().

00261 {
00262    struct ast_frame *f = NULL;
00263    
00264    if (!(chan->stream && (f = ast_readframe(chan->stream)))) {
00265       if (!ast_moh_files_next(chan))
00266          f = ast_readframe(chan->stream);
00267    }
00268 
00269    return f;
00270 }

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

Definition at line 194 of file res_musiconhold.c.

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

00195 {
00196    struct moh_files_state *state = chan->music_state;
00197 
00198    if (chan && state) {
00199       if (chan->stream) {
00200                         ast_closestream(chan->stream);
00201                         chan->stream = NULL;
00202                 }
00203       if (option_verbose > 2)
00204          ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
00205 
00206       if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
00207          ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt);
00208       }
00209       state->save_pos = state->pos;
00210    }
00211 }

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

Definition at line 708 of file res_musiconhold.c.

References ast_codec_get_len(), ast_codec_get_samples(), AST_FRIENDLY_OFFSET, ast_log(), ast_write(), LOG_WARNING, and moh.

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

static void moh_on_off int  on  )  [static]
 

Definition at line 1090 of file res_musiconhold.c.

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

Referenced by moh_cli().

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

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

Definition at line 835 of file res_musiconhold.c.

References AST_LIST_INSERT_HEAD, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_moh_free_class(), ast_pthread_create_background, ast_set_flag, free, get_mohbyname(), LOG_WARNING, moh, MOH_CUSTOM, MOH_QUIET, MOH_RANDOMIZE, moh_scan_files(), MOH_SINGLE, monmp3thread(), and option_debug.

Referenced by load_moh_classes().

00836 {
00837 #ifdef HAVE_ZAPTEL
00838    int x;
00839 #endif
00840    AST_LIST_LOCK(&mohclasses);
00841    if (get_mohbyname(moh->name)) {
00842       if (reload) {
00843          if (option_debug)
00844             ast_log(LOG_DEBUG, "Music on Hold class '%s' left alone from initial load.\n", moh->name);
00845       } else {
00846          ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
00847       }
00848       free(moh);  
00849       AST_LIST_UNLOCK(&mohclasses);
00850       return -1;
00851    }
00852    AST_LIST_UNLOCK(&mohclasses);
00853 
00854    time(&moh->start);
00855    moh->start -= respawn_time;
00856    
00857    if (!strcasecmp(moh->mode, "files")) {
00858       if (!moh_scan_files(moh)) {
00859          ast_moh_free_class(&moh);
00860          return -1;
00861       }
00862       if (strchr(moh->args, 'r'))
00863          ast_set_flag(moh, MOH_RANDOMIZE);
00864    } 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")) {
00865 
00866       if (!strcasecmp(moh->mode, "custom"))
00867          ast_set_flag(moh, MOH_CUSTOM);
00868       else if (!strcasecmp(moh->mode, "mp3nb"))
00869          ast_set_flag(moh, MOH_SINGLE);
00870       else if (!strcasecmp(moh->mode, "quietmp3nb"))
00871          ast_set_flag(moh, MOH_SINGLE | MOH_QUIET);
00872       else if (!strcasecmp(moh->mode, "quietmp3"))
00873          ast_set_flag(moh, MOH_QUIET);
00874       
00875       moh->srcfd = -1;
00876 #ifdef HAVE_ZAPTEL
00877       /* Open /dev/zap/pseudo for timing...  Is
00878          there a better, yet reliable way to do this? */
00879       moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
00880       if (moh->pseudofd < 0) {
00881          ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
00882       } else {
00883          x = 320;
00884          ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
00885       }
00886 #else
00887       moh->pseudofd = -1;
00888 #endif
00889       if (ast_pthread_create_background(&moh->thread, NULL, monmp3thread, moh)) {
00890          ast_log(LOG_WARNING, "Unable to create moh...\n");
00891          if (moh->pseudofd > -1)
00892             close(moh->pseudofd);
00893          ast_moh_free_class(&moh);
00894          return -1;
00895       }
00896    } else {
00897       ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
00898       ast_moh_free_class(&moh);
00899       return -1;
00900    }
00901 
00902    AST_LIST_LOCK(&mohclasses);
00903    AST_LIST_INSERT_HEAD(&mohclasses, moh, list);
00904    AST_LIST_UNLOCK(&mohclasses);
00905    
00906    return 0;
00907 }

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

Definition at line 669 of file res_musiconhold.c.

References ast_getformatname(), AST_LIST_LOCK, AST_LIST_REMOVE, AST_LIST_UNLOCK, ast_log(), ast_set_write_format(), ast_verbose(), free, LOG_WARNING, moh, option_verbose, and VERBOSE_PREFIX_3.

Referenced by moh_alloc().

00670 {
00671    struct mohdata *moh = data;
00672    int oldwfmt;
00673 
00674    AST_LIST_LOCK(&mohclasses);
00675    AST_LIST_REMOVE(&moh->parent->members, moh, list); 
00676    AST_LIST_UNLOCK(&mohclasses);
00677    
00678    close(moh->pipe[0]);
00679    close(moh->pipe[1]);
00680    oldwfmt = moh->origwfmt;
00681    free(moh);
00682    if (chan) {
00683       if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
00684          ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
00685       if (option_verbose > 2)
00686          ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
00687    }
00688 }

static int moh_scan_files struct mohclass class  )  [static]
 

Definition at line 769 of file res_musiconhold.c.

References ast_log(), mohclass::dir, ext, mohclass::filearray, free, LOG_WARNING, moh_add_file(), and mohclass::total_files.

Referenced by init_classes(), and moh_register().

00769                                                   {
00770 
00771    DIR *files_DIR;
00772    struct dirent *files_dirent;
00773    char path[PATH_MAX];
00774    char filepath[PATH_MAX];
00775    char *ext;
00776    struct stat statbuf;
00777    int dirnamelen;
00778    int i;
00779    
00780    files_DIR = opendir(class->dir);
00781    if (!files_DIR) {
00782       ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", class->dir);
00783       return -1;
00784    }
00785 
00786    for (i = 0; i < class->total_files; i++)
00787       free(class->filearray[i]);
00788 
00789    class->total_files = 0;
00790    dirnamelen = strlen(class->dir) + 2;
00791    getcwd(path, sizeof(path));
00792    chdir(class->dir);
00793    while ((files_dirent = readdir(files_DIR))) {
00794       /* The file name must be at least long enough to have the file type extension */
00795       if ((strlen(files_dirent->d_name) < 4))
00796          continue;
00797 
00798       /* Skip files that starts with a dot */
00799       if (files_dirent->d_name[0] == '.')
00800          continue;
00801 
00802       /* Skip files without extensions... they are not audio */
00803       if (!strchr(files_dirent->d_name, '.'))
00804          continue;
00805 
00806       snprintf(filepath, sizeof(filepath), "%s/%s", class->dir, files_dirent->d_name);
00807 
00808       if (stat(filepath, &statbuf))
00809          continue;
00810 
00811       if (!S_ISREG(statbuf.st_mode))
00812          continue;
00813 
00814       if ((ext = strrchr(filepath, '.'))) {
00815          *ext = '\0';
00816          ext++;
00817       }
00818 
00819       /* if the file is present in multiple formats, ensure we only put it into the list once */
00820       for (i = 0; i < class->total_files; i++)
00821          if (!strcmp(filepath, class->filearray[i]))
00822             break;
00823 
00824       if (i == class->total_files) {
00825          if (moh_add_file(class, filepath))
00826             break;
00827       }
00828    }
00829 
00830    closedir(files_DIR);
00831    chdir(path);
00832    return class->total_files;
00833 }

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

Definition at line 639 of file res_musiconhold.c.

References ast_calloc, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, AST_LIST_INSERT_HEAD, ast_log(), mohclass::format, free, LOG_WARNING, moh, and mohdata::pipe.

Referenced by moh_alloc().

00640 {
00641    struct mohdata *moh;
00642    long flags; 
00643    
00644    if (!(moh = ast_calloc(1, sizeof(*moh))))
00645       return NULL;
00646    
00647    if (pipe(moh->pipe)) {
00648       ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
00649       free(moh);
00650       return NULL;
00651    }
00652 
00653    /* Make entirely non-blocking */
00654    flags = fcntl(moh->pipe[0], F_GETFL);
00655    fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
00656    flags = fcntl(moh->pipe[1], F_GETFL);
00657    fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
00658 
00659    moh->f.frametype = AST_FRAME_VOICE;
00660    moh->f.subclass = cl->format;
00661    moh->f.offset = AST_FRIENDLY_OFFSET;
00662 
00663    moh->parent = cl;
00664    AST_LIST_INSERT_HEAD(&cl->members, moh, list);
00665    
00666    return moh;
00667 }

static void* monmp3thread void *  data  )  [static]
 

Definition at line 484 of file res_musiconhold.c.

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

Referenced by moh_register().

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

static int reload void   )  [static]
 

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

01212 {
01213    if (init_classes(1))
01214       ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
01215 
01216    return 0;
01217 }

static int spawn_mp3 struct mohclass class  )  [static]
 

Definition at line 333 of file res_musiconhold.c.

References mohclass::args, ast_log(), ast_opt_high_priority, ast_set_priority(), ast_strlen_zero(), ast_test_flag, mohclass::dir, LOG_WARNING, MAX_MP3S, MOH_CUSTOM, MOH_QUIET, MOH_SINGLE, mohclass::pid, mohclass::start, and strsep().

Referenced by monmp3thread().

00334 {
00335    int fds[2];
00336    int files = 0;
00337    char fns[MAX_MP3S][80];
00338    char *argv[MAX_MP3S + 50];
00339    char xargs[256];
00340    char *argptr;
00341    int argc = 0;
00342    DIR *dir = NULL;
00343    struct dirent *de;
00344    sigset_t signal_set, old_set;
00345 
00346    
00347    if (!strcasecmp(class->dir, "nodir")) {
00348       files = 1;
00349    } else {
00350       dir = opendir(class->dir);
00351       if (!dir && !strstr(class->dir,"http://") && !strstr(class->dir,"HTTP://")) {
00352          ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
00353          return -1;
00354       }
00355    }
00356 
00357    if (!ast_test_flag(class, MOH_CUSTOM)) {
00358       argv[argc++] = "mpg123";
00359       argv[argc++] = "-q";
00360       argv[argc++] = "-s";
00361       argv[argc++] = "--mono";
00362       argv[argc++] = "-r";
00363       argv[argc++] = "8000";
00364       
00365       if (!ast_test_flag(class, MOH_SINGLE)) {
00366          argv[argc++] = "-b";
00367          argv[argc++] = "2048";
00368       }
00369       
00370       argv[argc++] = "-f";
00371       
00372       if (ast_test_flag(class, MOH_QUIET))
00373          argv[argc++] = "4096";
00374       else
00375          argv[argc++] = "8192";
00376       
00377       /* Look for extra arguments and add them to the list */
00378       ast_copy_string(xargs, class->args, sizeof(xargs));
00379       argptr = xargs;
00380       while (!ast_strlen_zero(argptr)) {
00381          argv[argc++] = argptr;
00382          strsep(&argptr, ",");
00383       }
00384    } else  {
00385       /* Format arguments for argv vector */
00386       ast_copy_string(xargs, class->args, sizeof(xargs));
00387       argptr = xargs;
00388       while (!ast_strlen_zero(argptr)) {
00389          argv[argc++] = argptr;
00390          strsep(&argptr, " ");
00391       }
00392    }
00393 
00394 
00395    if (strstr(class->dir,"http://") || strstr(class->dir,"HTTP://")) {
00396       ast_copy_string(fns[files], class->dir, sizeof(fns[files]));
00397       argv[argc++] = fns[files];
00398       files++;
00399    } else if (dir) {
00400       while ((de = readdir(dir)) && (files < MAX_MP3S)) {
00401          if ((strlen(de->d_name) > 3) && 
00402              ((ast_test_flag(class, MOH_CUSTOM) && 
00403                (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 
00404                 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) ||
00405               !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
00406             ast_copy_string(fns[files], de->d_name, sizeof(fns[files]));
00407             argv[argc++] = fns[files];
00408             files++;
00409          }
00410       }
00411    }
00412    argv[argc] = NULL;
00413    if (dir) {
00414       closedir(dir);
00415    }
00416    if (pipe(fds)) {  
00417       ast_log(LOG_WARNING, "Pipe failed\n");
00418       return -1;
00419    }
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 
00430    /* Block signals during the fork() */
00431    sigfillset(&signal_set);
00432    pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
00433 
00434    time(&class->start);
00435    class->pid = fork();
00436    if (class->pid < 0) {
00437       close(fds[0]);
00438       close(fds[1]);
00439       ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
00440       return -1;
00441    }
00442    if (!class->pid) {
00443       int x;
00444 
00445       if (ast_opt_high_priority)
00446          ast_set_priority(0);
00447 
00448       /* Reset ignored signals back to default */
00449       signal(SIGPIPE, SIG_DFL);
00450       pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
00451 
00452       close(fds[0]);
00453       /* Stdout goes to pipe */
00454       dup2(fds[1], STDOUT_FILENO);
00455       /* Close unused file descriptors */
00456       for (x=3;x<8192;x++) {
00457          if (-1 != fcntl(x, F_GETFL)) {
00458             close(x);
00459          }
00460       }
00461       /* Child */
00462       chdir(class->dir);
00463       if (ast_test_flag(class, MOH_CUSTOM)) {
00464          execv(argv[0], argv);
00465       } else {
00466          /* Default install is /usr/local/bin */
00467          execv(LOCAL_MPG_123, argv);
00468          /* Many places have it in /usr/bin */
00469          execv(MPG_123, argv);
00470          /* Check PATH as a last-ditch effort */
00471          execvp("mpg123", argv);
00472       }
00473       ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
00474       close(fds[1]);
00475       _exit(1);
00476    } else {
00477       /* Parent */
00478       pthread_sigmask(SIG_SETMASK, &old_set, NULL);
00479       close(fds[1]);
00480    }
00481    return fds[0];
00482 }

static int unload_module void   )  [static]
 

Definition at line 1219 of file res_musiconhold.c.

01220 {
01221    return -1;
01222 }


Variable Documentation

char* app0 = "MusicOnHold" [static]
 

Definition at line 75 of file res_musiconhold.c.

char* app1 = "WaitMusicOnHold" [static]
 

Definition at line 76 of file res_musiconhold.c.

char* app2 = "SetMusicOnHold" [static]
 

Definition at line 77 of file res_musiconhold.c.

char* app3 = "StartMusicOnHold" [static]
 

Definition at line 78 of file res_musiconhold.c.

char* app4 = "StopMusicOnHold" [static]
 

Definition at line 79 of file res_musiconhold.c.

struct ast_cli_entry cli_moh[] [static]
 

Definition at line 1155 of file res_musiconhold.c.

Referenced by load_module().

char* descrip0 [static]
 

Definition at line 87 of file res_musiconhold.c.

char* descrip1 [static]
 

Initial value:

 "WaitMusicOnHold(delay): "
"Plays hold music specified number of seconds.  Returns 0 when\n"
"done, or -1 on hangup.  If no hold music is available, the delay will\n"
"still occur with no sound.\n"

Definition at line 94 of file res_musiconhold.c.

char* descrip2 [static]
 

Initial value:

 "SetMusicOnHold(class): "
"Sets the default class for music on hold for a given channel.  When\n"
"music on hold is activated, this class will be used to select which\n"
"music is played.\n"

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

char* descrip4 [static]
 

Initial value:

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

Definition at line 109 of file res_musiconhold.c.

struct ast_generator moh_file_stream [static]
 

Definition at line 326 of file res_musiconhold.c.

Referenced by local_ast_moh_start().

struct ast_generator mohgen [static]
 

Definition at line 739 of file res_musiconhold.c.

Referenced by local_ast_moh_start().

int respawn_time = 20 [static]
 

Definition at line 112 of file res_musiconhold.c.

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

Definition at line 81 of file res_musiconhold.c.

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

Definition at line 82 of file res_musiconhold.c.

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

Definition at line 83 of file res_musiconhold.c.

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

Definition at line 84 of file res_musiconhold.c.

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

Definition at line 85 of file res_musiconhold.c.


Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen