Fri Aug 24 02:28:07 2007

Asterisk developer's documentation


res_musiconhold.c File Reference

Routines implementing music on hold. More...

#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/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_destroy_one (struct mohclass *moh)
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, int warn)
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 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 struct ast_cli_entry cli_moh_classes_show_deprecated
static struct ast_cli_entry cli_moh_files_show_deprecated
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"


Detailed Description

Routines implementing music on hold.

Author:
Mark Spencer <markster@digium.com>

Definition in file res_musiconhold.c.


Define Documentation

#define INITIAL_NUM_FILES   8

Definition at line 75 of file res_musiconhold.c.

Referenced by moh_add_file().

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

Definition at line 169 of file res_musiconhold.c.

#define MAX_MP3S   256

Definition at line 171 of file res_musiconhold.c.

Referenced by spawn_mp3().

#define MOH_CUSTOM   (1 << 2)

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

Referenced by moh_register(), and spawn_mp3().

#define MOH_RANDOMIZE   (1 << 3)

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

Referenced by moh_register(), and spawn_mp3().

#define MPG_123   "/usr/bin/mpg123"

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

References AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_moh_destroy_one(), ast_verbose(), moh, option_verbose, and VERBOSE_PREFIX_2.

Referenced by load_module().

01166 {
01167    struct mohclass *moh;
01168 
01169    if (option_verbose > 1)
01170       ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
01171 
01172    AST_LIST_LOCK(&mohclasses);
01173    while ((moh = AST_LIST_REMOVE_HEAD(&mohclasses, list))) {
01174       ast_moh_destroy_one(moh);
01175    }
01176    AST_LIST_UNLOCK(&mohclasses);
01177 }

static int ast_moh_destroy_one ( struct mohclass moh  )  [static]

Definition at line 1135 of file res_musiconhold.c.

References ast_log(), ast_moh_free_class(), ast_wait_for_input(), LOG_DEBUG, moh, and mohclass::pid.

Referenced by ast_moh_destroy(), init_classes(), moh_files_release(), and moh_release().

01136 {
01137    char buff[8192];
01138    int bytes, tbytes = 0, stime = 0, pid = 0;
01139 
01140    if (moh) {
01141       if (moh->pid > 1) {
01142          ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
01143          stime = time(NULL) + 2;
01144          pid = moh->pid;
01145          moh->pid = 0;
01146          /* Back when this was just mpg123, SIGKILL was fine.  Now we need
01147           * to give the process a reason and time enough to kill off its
01148           * children. */
01149          kill(pid, SIGHUP);
01150          usleep(100000);
01151          kill(pid, SIGTERM);
01152          usleep(100000);
01153          kill(pid, SIGKILL);
01154          while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime)
01155             tbytes = tbytes + bytes;
01156          ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
01157          close(moh->srcfd);
01158       }
01159       ast_moh_free_class(&moh);
01160    }
01161 
01162    return 0;
01163 }

static int ast_moh_files_next ( struct ast_channel chan  )  [static]

Definition at line 223 of file res_musiconhold.c.

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

00224 {
00225    struct moh_files_state *state = chan->music_state;
00226    int tries;
00227 
00228    /* Discontinue a stream if it is running already */
00229    if (chan->stream) {
00230       ast_closestream(chan->stream);
00231       chan->stream = NULL;
00232    }
00233 
00234    /* If a specific file has been saved, use it */
00235    if (state->save_pos) {
00236       state->pos = state->save_pos;
00237       state->save_pos = 0;
00238    } else if (ast_test_flag(state->class, MOH_RANDOMIZE)) {
00239       /* Get a random file and ensure we can open it */
00240       for (tries = 0; tries < 20; tries++) {
00241          state->pos = rand() % state->class->total_files;
00242          if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0)
00243             break;
00244       }
00245       state->samples = 0;
00246    } else {
00247       /* This is easy, just increment our position and make sure we don't exceed the total file count */
00248       state->pos++;
00249       state->pos %= state->class->total_files;
00250       state->samples = 0;
00251    }
00252 
00253    if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
00254       ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
00255       state->pos++;
00256       state->pos %= state->class->total_files;
00257       return -1;
00258    }
00259 
00260    if (option_debug)
00261       ast_log(LOG_DEBUG, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]);
00262 
00263    if (state->samples)
00264       ast_seekstream(chan->stream, state->samples, SEEK_SET);
00265 
00266    return 0;
00267 }

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

Definition at line 176 of file res_musiconhold.c.

References AST_LIST_REMOVE_HEAD, and free.

Referenced by ast_moh_destroy_one(), and moh_register().

00177 {
00178    struct mohdata *member;
00179    struct mohclass *class = *mohclass;
00180    int i;
00181    
00182    while ((member = AST_LIST_REMOVE_HEAD(&class->members, list)))
00183       free(member);
00184    
00185    if (class->thread) {
00186       pthread_cancel(class->thread);
00187       class->thread = 0;
00188    }
00189 
00190    if (class->filearray) {
00191       for (i = 0; i < class->total_files; i++)
00192          free(class->filearray[i]);
00193       free(class->filearray);
00194    }
00195 
00196    free(class);
00197    *mohclass = NULL;
00198 }

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

Definition at line 1185 of file res_musiconhold.c.

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

01186 {
01187    int i;
01188    struct mohclass *class;
01189 
01190    AST_LIST_LOCK(&mohclasses);
01191    AST_LIST_TRAVERSE(&mohclasses, class, list) {
01192       if (!class->total_files)
01193          continue;
01194 
01195       ast_cli(fd, "Class: %s\n", class->name);
01196       for (i = 0; i < class->total_files; i++)
01197          ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
01198    }
01199    AST_LIST_UNLOCK(&mohclasses);
01200 
01201    return 0;
01202 }

static struct mohclass* get_mohbyname ( const char *  name,
int  warn 
) [static]

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

Definition at line 635 of file res_musiconhold.c.

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

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

00636 {
00637    struct mohclass *moh = NULL;
00638 
00639    AST_LIST_TRAVERSE(&mohclasses, moh, list) {
00640       if (!strcasecmp(name, moh->name))
00641          break;
00642    }
00643 
00644    if (!moh && warn)
00645       ast_log(LOG_WARNING, "Music on Hold class '%s' not found\n", name);
00646 
00647    return moh;
00648 }

static int init_classes ( int  reload  )  [static]

Definition at line 1248 of file res_musiconhold.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_moh_destroy_one(), load_moh_classes(), moh, and moh_scan_files().

Referenced by load_module(), and reload().

01249 {
01250    struct mohclass *moh;
01251     
01252    if (!load_moh_classes(reload))      /* Load classes from config */
01253       return 0;         /* Return if nothing is found */
01254 
01255    AST_LIST_LOCK(&mohclasses);
01256    AST_LIST_TRAVERSE_SAFE_BEGIN(&mohclasses, moh, list) {
01257       if (reload && moh->delete) {
01258          AST_LIST_REMOVE_CURRENT(&mohclasses, list);
01259          if (!moh->inuse)
01260             ast_moh_destroy_one(moh);
01261       } else if (moh->total_files)
01262          moh_scan_files(moh);
01263    }
01264    AST_LIST_TRAVERSE_SAFE_END
01265    AST_LIST_UNLOCK(&mohclasses);
01266 
01267    return 1;
01268 }

static int load_module ( void   )  [static]

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

01271 {
01272    int res;
01273 
01274    res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
01275    ast_register_atexit(ast_moh_destroy);
01276    ast_cli_register_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry));
01277    if (!res)
01278       res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
01279    if (!res)
01280       res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
01281    if (!res)
01282       res = ast_register_application(app3, moh3_exec, synopsis3, descrip3);
01283    if (!res)
01284       res = ast_register_application(app4, moh4_exec, synopsis4, descrip4);
01285 
01286    if (!init_classes(0)) {    /* No music classes configured, so skip it */
01287       ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold.\n");
01288    } else {
01289       ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
01290    }
01291 
01292    return 0;
01293 }

static int load_moh_classes ( int  reload  )  [static]

Definition at line 996 of file res_musiconhold.c.

References mohclass::args, ast_category_browse(), ast_config_destroy(), ast_config_load(), AST_FORMAT_SLINEAR, ast_getformatbyname(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_set2_flag, ast_strlen_zero(), ast_true(), ast_variable_browse(), free, get_mohbyname(), LOG_WARNING, moh_class_malloc(), MOH_RANDOMIZE, moh_register(), and var.

Referenced by init_classes().

00997 {
00998    struct ast_config *cfg;
00999    struct ast_variable *var;
01000    struct mohclass *class; 
01001    char *data;
01002    char *args;
01003    char *cat;
01004    int numclasses = 0;
01005    static int dep_warning = 0;
01006 
01007    cfg = ast_config_load("musiconhold.conf");
01008 
01009    if (!cfg)
01010       return 0;
01011 
01012    if (reload) {
01013       AST_LIST_LOCK(&mohclasses);
01014       AST_LIST_TRAVERSE(&mohclasses, class, list)
01015          class->delete = 1;
01016       AST_LIST_UNLOCK(&mohclasses);
01017    }
01018 
01019    cat = ast_category_browse(cfg, NULL);
01020    for (; cat; cat = ast_category_browse(cfg, cat)) {
01021       if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) {       
01022          if (!(class = moh_class_malloc())) {
01023             break;
01024          }           
01025          ast_copy_string(class->name, cat, sizeof(class->name));  
01026          var = ast_variable_browse(cfg, cat);
01027          while (var) {
01028             if (!strcasecmp(var->name, "mode"))
01029                ast_copy_string(class->mode, var->value, sizeof(class->mode)); 
01030             else if (!strcasecmp(var->name, "directory"))
01031                ast_copy_string(class->dir, var->value, sizeof(class->dir));
01032             else if (!strcasecmp(var->name, "application"))
01033                ast_copy_string(class->args, var->value, sizeof(class->args));
01034             else if (!strcasecmp(var->name, "random"))
01035                ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
01036             else if (!strcasecmp(var->name, "format")) {
01037                class->format = ast_getformatbyname(var->value);
01038                if (!class->format) {
01039                   ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
01040                   class->format = AST_FORMAT_SLINEAR;
01041                }
01042             }
01043             var = var->next;
01044          }
01045 
01046          if (ast_strlen_zero(class->dir)) {
01047             if (!strcasecmp(class->mode, "custom")) {
01048                strcpy(class->dir, "nodir");
01049             } else {
01050                ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
01051                free(class);
01052                continue;
01053             }
01054          }
01055          if (ast_strlen_zero(class->mode)) {
01056             ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
01057             free(class);
01058             continue;
01059          }
01060          if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
01061             ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
01062             free(class);
01063             continue;
01064          }
01065 
01066          /* Don't leak a class when it's already registered */
01067          moh_register(class, reload);
01068 
01069          numclasses++;
01070       }
01071    }
01072    
01073 
01074    /* Deprecated Old-School Configuration */
01075    var = ast_variable_browse(cfg, "classes");
01076    while (var) {
01077       if (!dep_warning) {
01078          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");
01079          dep_warning = 1;
01080       }
01081       data = strchr(var->value, ':');
01082       if (data) {
01083          *data++ = '\0';
01084          args = strchr(data, ',');
01085          if (args)
01086             *args++ = '\0';
01087          if (!(get_mohbyname(var->name, 0))) {        
01088             if (!(class = moh_class_malloc())) {
01089                break;
01090             }
01091             
01092             ast_copy_string(class->name, var->name, sizeof(class->name));
01093             ast_copy_string(class->dir, data, sizeof(class->dir));
01094             ast_copy_string(class->mode, var->value, sizeof(class->mode));
01095             if (args)
01096                ast_copy_string(class->args, args, sizeof(class->args));
01097             
01098             moh_register(class, reload);
01099             numclasses++;
01100          }
01101       }
01102       var = var->next;
01103    }
01104    var = ast_variable_browse(cfg, "moh_files");
01105    while (var) {
01106       if (!dep_warning) {
01107          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");
01108          dep_warning = 1;
01109       }
01110       if (!(get_mohbyname(var->name, 0))) {
01111          args = strchr(var->value, ',');
01112          if (args)
01113             *args++ = '\0';         
01114          if (!(class = moh_class_malloc())) {
01115             break;
01116          }
01117          
01118          ast_copy_string(class->name, var->name, sizeof(class->name));
01119          ast_copy_string(class->dir, var->value, sizeof(class->dir));
01120          strcpy(class->mode, "files");
01121          if (args)   
01122             ast_copy_string(class->args, args, sizeof(class->args));
01123          
01124          moh_register(class, reload);
01125          numclasses++;
01126       }
01127       var = var->next;
01128    }
01129 
01130    ast_config_destroy(cfg);
01131 
01132    return numclasses;
01133 }

static void local_ast_moh_cleanup ( struct ast_channel chan  )  [static]

Definition at line 927 of file res_musiconhold.c.

References free, and ast_channel::music_state.

Referenced by load_module(), and reload().

00928 {
00929    if (chan->music_state) {
00930       free(chan->music_state);
00931       chan->music_state = NULL;
00932    }
00933 }

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

Definition at line 935 of file res_musiconhold.c.

References ast_activate_generator(), AST_FLAG_MOH, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_set_flag, ast_strlen_zero(), get_mohbyname(), mohclass::inuse, moh_file_stream, mohgen, and mohclass::total_files.

Referenced by load_module(), and reload().

00936 {
00937    struct mohclass *mohclass = NULL;
00938 
00939    /* The following is the order of preference for which class to use:
00940     * 1) The channels explicitly set musicclass, which should *only* be
00941     *    set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
00942     * 2) The mclass argument. If a channel is calling ast_moh_start() as the
00943     *    result of receiving a HOLD control frame, this should be the
00944     *    payload that came with the frame.
00945     * 3) The interpclass argument. This would be from the mohinterpret
00946     *    option from channel drivers. This is the same as the old musicclass
00947     *    option.
00948     * 4) The default class.
00949     */
00950    AST_LIST_LOCK(&mohclasses);
00951    if (!ast_strlen_zero(chan->musicclass))
00952       mohclass = get_mohbyname(chan->musicclass, 1);
00953    if (!mohclass && !ast_strlen_zero(mclass))
00954       mohclass = get_mohbyname(mclass, 1);
00955    if (!mohclass && !ast_strlen_zero(interpclass))
00956       mohclass = get_mohbyname(interpclass, 1);
00957    if (!mohclass) 
00958       mohclass = get_mohbyname("default", 1);
00959    if (mohclass)
00960       ast_atomic_fetchadd_int(&mohclass->inuse, +1);
00961    AST_LIST_UNLOCK(&mohclasses);
00962 
00963    if (!mohclass)
00964       return -1;
00965 
00966    ast_set_flag(chan, AST_FLAG_MOH);
00967    if (mohclass->total_files) {
00968       return ast_activate_generator(chan, &moh_file_stream, mohclass);
00969    } else
00970       return ast_activate_generator(chan, &mohgen, mohclass);
00971 }

static void local_ast_moh_stop ( struct ast_channel chan  )  [static]

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

00974 {
00975    ast_clear_flag(chan, AST_FLAG_MOH);
00976    ast_deactivate_generator(chan);
00977 
00978    if (chan->music_state) {
00979       if (chan->stream) {
00980          ast_closestream(chan->stream);
00981          chan->stream = NULL;
00982       }
00983    }
00984 }

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

Definition at line 579 of file res_musiconhold.c.

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

Referenced by load_module().

00580 {
00581    if (ast_moh_start(chan, data, NULL)) {
00582       ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
00583       return 0;
00584    }
00585    while (!ast_safe_sleep(chan, 10000));
00586    ast_moh_stop(chan);
00587    return -1;
00588 }

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

Definition at line 590 of file res_musiconhold.c.

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

Referenced by load_module().

00591 {
00592    int res;
00593    if (!data || !atoi(data)) {
00594       ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
00595       return -1;
00596    }
00597    if (ast_moh_start(chan, NULL, NULL)) {
00598       ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name);
00599       return 0;
00600    }
00601    res = ast_safe_sleep(chan, atoi(data) * 1000);
00602    ast_moh_stop(chan);
00603    return res;
00604 }

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

Definition at line 606 of file res_musiconhold.c.

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

Referenced by load_module().

00607 {
00608    if (ast_strlen_zero(data)) {
00609       ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
00610       return -1;
00611    }
00612    ast_string_field_set(chan, musicclass, data);
00613    return 0;
00614 }

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

Definition at line 616 of file res_musiconhold.c.

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

Referenced by load_module().

00617 {
00618    char *class = NULL;
00619    if (data && strlen(data))
00620       class = data;
00621    if (ast_moh_start(chan, class, NULL)) 
00622       ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name);
00623 
00624    return 0;
00625 }

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

Definition at line 627 of file res_musiconhold.c.

References ast_moh_stop().

Referenced by load_module().

00628 {
00629    ast_moh_stop(chan);
00630 
00631    return 0;
00632 }

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

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

00763 {
00764    if (!class->allowed_files) {
00765       if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray))))
00766          return -1;
00767       class->allowed_files = INITIAL_NUM_FILES;
00768    } else if (class->total_files == class->allowed_files) {
00769       if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) {
00770          class->allowed_files = 0;
00771          class->total_files = 0;
00772          return -1;
00773       }
00774       class->allowed_files *= 2;
00775    }
00776 
00777    if (!(class->filearray[class->total_files] = ast_strdup(filepath)))
00778       return -1;
00779 
00780    class->total_files++;
00781 
00782    return 0;
00783 }

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

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

00707 {
00708    struct mohdata *res;
00709    struct mohclass *class = params;
00710 
00711    if ((res = mohalloc(class))) {
00712       res->origwfmt = chan->writeformat;
00713       if (ast_set_write_format(chan, class->format)) {
00714          ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format));
00715          moh_release(NULL, res);
00716          res = NULL;
00717       }
00718       if (option_verbose > 2)
00719          ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name);
00720    }
00721    return res;
00722 }

static struct mohclass* moh_class_malloc ( void   )  [static]

Definition at line 986 of file res_musiconhold.c.

References ast_calloc, AST_FORMAT_SLINEAR, and mohclass::format.

Referenced by load_moh_classes().

00987 {
00988    struct mohclass *class;
00989 
00990    if ((class = ast_calloc(1, sizeof(*class))))
00991       class->format = AST_FORMAT_SLINEAR;
00992 
00993    return class;
00994 }

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

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

01205 {
01206    struct mohclass *class;
01207 
01208    AST_LIST_LOCK(&mohclasses);
01209    AST_LIST_TRAVERSE(&mohclasses, class, list) {
01210       ast_cli(fd, "Class: %s\n", class->name);
01211       ast_cli(fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
01212       ast_cli(fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
01213       ast_cli(fd, "\tUse Count: %d\n", class->inuse);
01214       if (ast_test_flag(class, MOH_CUSTOM))
01215          ast_cli(fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
01216       if (strcasecmp(class->mode, "files"))
01217          ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format));
01218    }
01219    AST_LIST_UNLOCK(&mohclasses);
01220 
01221    return 0;
01222 }

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

Definition at line 1179 of file res_musiconhold.c.

References reload().

01180 {
01181    reload();
01182    return 0;
01183 }

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

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

00308 {
00309    struct moh_files_state *state;
00310    struct mohclass *class = params;
00311 
00312    if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) {
00313       chan->music_state = state;
00314       state->class = class;
00315    } else 
00316       state = chan->music_state;
00317 
00318    if (state) {
00319       if (state->class != class) {
00320          /* initialize */
00321          memset(state, 0, sizeof(*state));
00322          state->class = class;
00323          if (ast_test_flag(state->class, MOH_RANDOMIZE))
00324             state->pos = ast_random() % class->total_files;
00325       }
00326 
00327       state->origwfmt = chan->writeformat;
00328 
00329       if (option_verbose > 2)
00330          ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->name, chan->name);
00331    }
00332    
00333    return chan->music_state;
00334 }

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

Definition at line 282 of file res_musiconhold.c.

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

00283 {
00284    struct moh_files_state *state = chan->music_state;
00285    struct ast_frame *f = NULL;
00286    int res = 0;
00287 
00288    state->sample_queue += samples;
00289 
00290    while (state->sample_queue > 0) {
00291       if ((f = moh_files_readframe(chan))) {
00292          state->samples += f->samples;
00293          res = ast_write(chan, f);
00294          state->sample_queue -= f->samples;
00295          ast_frfree(f);
00296          if (res < 0) {
00297             ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
00298             return -1;
00299          }
00300       } else
00301          return -1;  
00302    }
00303    return res;
00304 }

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

Definition at line 270 of file res_musiconhold.c.

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

Referenced by moh_files_generator().

00271 {
00272    struct ast_frame *f = NULL;
00273    
00274    if (!(chan->stream && (f = ast_readframe(chan->stream)))) {
00275       if (!ast_moh_files_next(chan))
00276          f = ast_readframe(chan->stream);
00277    }
00278 
00279    return f;
00280 }

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

Definition at line 201 of file res_musiconhold.c.

References ast_closestream(), ast_log(), ast_moh_destroy_one(), ast_set_write_format(), ast_verbose(), moh_files_state::class, mohclass::delete, mohclass::inuse, 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.

00202 {
00203    struct moh_files_state *state = chan->music_state;
00204 
00205    if (chan && state) {
00206       if (chan->stream) {
00207                         ast_closestream(chan->stream);
00208                         chan->stream = NULL;
00209                 }
00210       if (option_verbose > 2)
00211          ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
00212 
00213       if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
00214          ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt);
00215       }
00216       state->save_pos = state->pos;
00217    }
00218    if (state->class->delete && ast_atomic_dec_and_test(&state->class->inuse))
00219       ast_moh_destroy_one(state->class);
00220 }

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

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

00725 {
00726    struct mohdata *moh = data;
00727    short buf[1280 + AST_FRIENDLY_OFFSET / 2];
00728    int res;
00729 
00730    if (!moh->parent->pid)
00731       return -1;
00732 
00733    len = ast_codec_get_len(moh->parent->format, samples);
00734 
00735    if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
00736       ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name);
00737       len = sizeof(buf) - AST_FRIENDLY_OFFSET;
00738    }
00739    res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
00740    if (res <= 0)
00741       return 0;
00742 
00743    moh->f.datalen = res;
00744    moh->f.data = buf + AST_FRIENDLY_OFFSET / 2;
00745    moh->f.samples = ast_codec_get_samples(&moh->f);
00746 
00747    if (ast_write(chan, &moh->f) < 0) {
00748       ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
00749       return -1;
00750    }
00751 
00752    return 0;
00753 }

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

Definition at line 851 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, mohclass::delete, free, get_mohbyname(), LOG_DEBUG, LOG_WARNING, moh, MOH_CUSTOM, MOH_QUIET, MOH_RANDOMIZE, moh_scan_files(), MOH_SINGLE, and monmp3thread().

Referenced by load_moh_classes().

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

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

Definition at line 683 of file res_musiconhold.c.

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

Referenced by moh_alloc().

00684 {
00685    struct mohdata *moh = data;
00686    int oldwfmt;
00687 
00688    AST_LIST_LOCK(&mohclasses);
00689    AST_LIST_REMOVE(&moh->parent->members, moh, list); 
00690    AST_LIST_UNLOCK(&mohclasses);
00691    
00692    close(moh->pipe[0]);
00693    close(moh->pipe[1]);
00694    oldwfmt = moh->origwfmt;
00695    if (moh->parent->delete && ast_atomic_dec_and_test(&moh->parent->inuse))
00696       ast_moh_destroy_one(moh->parent);
00697    free(moh);
00698    if (chan) {
00699       if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
00700          ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
00701       if (option_verbose > 2)
00702          ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
00703    }
00704 }

static int moh_scan_files ( struct mohclass class  )  [static]

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

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

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

Definition at line 650 of file res_musiconhold.c.

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

Referenced by moh_alloc().

00651 {
00652    struct mohdata *moh;
00653    long flags; 
00654    
00655    if (!(moh = ast_calloc(1, sizeof(*moh))))
00656       return NULL;
00657    
00658    if (pipe(moh->pipe)) {
00659       ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
00660       free(moh);
00661       return NULL;
00662    }
00663 
00664    /* Make entirely non-blocking */
00665    flags = fcntl(moh->pipe[0], F_GETFL);
00666    fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
00667    flags = fcntl(moh->pipe[1], F_GETFL);
00668    fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
00669 
00670    moh->f.frametype = AST_FRAME_VOICE;
00671    moh->f.subclass = cl->format;
00672    moh->f.offset = AST_FRIENDLY_OFFSET;
00673 
00674    moh->parent = cl;
00675 
00676    AST_LIST_LOCK(&mohclasses);
00677    AST_LIST_INSERT_HEAD(&cl->members, moh, list);
00678    AST_LIST_UNLOCK(&mohclasses);
00679    
00680    return moh;
00681 }

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

Definition at line 494 of file res_musiconhold.c.

References ast_codec_get_len(), AST_LIST_EMPTY, AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_tvadd(), len, LOG_NOTICE, LOG_WARNING, moh, MOH_MS_INTERVAL, option_debug, and spawn_mp3().

Referenced by moh_register().

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

static int reload ( void   )  [static]

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

01296 {
01297    if (init_classes(1))
01298       ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
01299 
01300    return 0;
01301 }

static int spawn_mp3 ( struct mohclass class  )  [static]

Definition at line 343 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, LOCAL_MPG_123, LOG_WARNING, MAX_MP3S, MOH_CUSTOM, MOH_QUIET, MOH_SINGLE, MPG_123, mohclass::pid, mohclass::start, and strsep().

Referenced by monmp3thread().

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

static int unload_module ( void   )  [static]

Definition at line 1303 of file res_musiconhold.c.

01304 {
01305    return -1;
01306 }


Variable Documentation

char* app0 = "MusicOnHold" [static]

Definition at line 77 of file res_musiconhold.c.

char* app1 = "WaitMusicOnHold" [static]

Definition at line 78 of file res_musiconhold.c.

char* app2 = "SetMusicOnHold" [static]

Definition at line 79 of file res_musiconhold.c.

char* app3 = "StartMusicOnHold" [static]

Definition at line 80 of file res_musiconhold.c.

char* app4 = "StopMusicOnHold" [static]

Definition at line 81 of file res_musiconhold.c.

struct ast_cli_entry cli_moh[] [static]

Definition at line 1234 of file res_musiconhold.c.

Referenced by load_module().

struct ast_cli_entry cli_moh_classes_show_deprecated [static]

Initial value:

 {
   { "moh", "classes", "show"},
   moh_classes_show, NULL,
   NULL }

Definition at line 1224 of file res_musiconhold.c.

struct ast_cli_entry cli_moh_files_show_deprecated [static]

Initial value:

 {
   { "moh", "files", "show"},
   cli_files_show, NULL,
   NULL }

Definition at line 1229 of file res_musiconhold.c.

char* descrip0 [static]

Definition at line 89 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 96 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 101 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 106 of file res_musiconhold.c.

char* descrip4 [static]

Initial value:

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

Definition at line 111 of file res_musiconhold.c.

struct ast_generator moh_file_stream [static]

Definition at line 336 of file res_musiconhold.c.

Referenced by local_ast_moh_start().

struct ast_generator mohgen [static]

Definition at line 755 of file res_musiconhold.c.

Referenced by local_ast_moh_start().

int respawn_time = 20 [static]

Definition at line 114 of file res_musiconhold.c.

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

Definition at line 83 of file res_musiconhold.c.

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

Definition at line 84 of file res_musiconhold.c.

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

Definition at line 85 of file res_musiconhold.c.

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

Definition at line 86 of file res_musiconhold.c.

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

Definition at line 87 of file res_musiconhold.c.


Generated on Fri Aug 24 02:28:08 2007 for Asterisk - the Open Source PBX by  doxygen 1.5.1