Mon Mar 31 07:42:25 2008

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

#define MAX_MP3S   256

Definition at line 172 of file res_musiconhold.c.

Referenced by spawn_mp3().

#define MOH_CUSTOM   (1 << 2)

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

Referenced by moh_register(), and spawn_mp3().

#define MOH_RANDOMIZE   (1 << 3)

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

Referenced by moh_register(), and spawn_mp3().

#define MPG_123   "/usr/bin/mpg123"

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

01181 {
01182    struct mohclass *moh;
01183 
01184    if (option_verbose > 1)
01185       ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
01186 
01187    AST_LIST_LOCK(&mohclasses);
01188    while ((moh = AST_LIST_REMOVE_HEAD(&mohclasses, list))) {
01189       ast_moh_destroy_one(moh);
01190    }
01191    AST_LIST_UNLOCK(&mohclasses);
01192 }

static int ast_moh_destroy_one ( struct mohclass moh  )  [static]

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

01151 {
01152    char buff[8192];
01153    int bytes, tbytes = 0, stime = 0, pid = 0;
01154 
01155    if (moh) {
01156       if (moh->pid > 1) {
01157          ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
01158          stime = time(NULL) + 2;
01159          pid = moh->pid;
01160          moh->pid = 0;
01161          /* Back when this was just mpg123, SIGKILL was fine.  Now we need
01162           * to give the process a reason and time enough to kill off its
01163           * children. */
01164          kill(pid, SIGHUP);
01165          usleep(100000);
01166          kill(pid, SIGTERM);
01167          usleep(100000);
01168          kill(pid, SIGKILL);
01169          while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime)
01170             tbytes = tbytes + bytes;
01171          ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
01172          close(moh->srcfd);
01173       }
01174       ast_moh_free_class(&moh);
01175    }
01176 
01177    return 0;
01178 }

static int ast_moh_files_next ( struct ast_channel chan  )  [static]

Definition at line 227 of file res_musiconhold.c.

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

Referenced by moh_files_readframe().

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

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

Definition at line 177 of file res_musiconhold.c.

References AST_LIST_REMOVE_HEAD, and free.

Referenced by ast_moh_destroy_one(), and moh_register().

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

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

Definition at line 1200 of file res_musiconhold.c.

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

01201 {
01202    int i;
01203    struct mohclass *class;
01204 
01205    AST_LIST_LOCK(&mohclasses);
01206    AST_LIST_TRAVERSE(&mohclasses, class, list) {
01207       if (!class->total_files)
01208          continue;
01209 
01210       ast_cli(fd, "Class: %s\n", class->name);
01211       for (i = 0; i < class->total_files; i++)
01212          ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
01213    }
01214    AST_LIST_UNLOCK(&mohclasses);
01215 
01216    return 0;
01217 }

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

00651 {
00652    struct mohclass *moh = NULL;
00653 
00654    AST_LIST_TRAVERSE(&mohclasses, moh, list) {
00655       if (!strcasecmp(name, moh->name))
00656          break;
00657    }
00658 
00659    if (!moh && warn)
00660       ast_log(LOG_WARNING, "Music on Hold class '%s' not found\n", name);
00661 
00662    return moh;
00663 }

static int init_classes ( int  reload  )  [static]

Definition at line 1263 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_log(), ast_moh_destroy_one(), load_moh_classes(), LOG_WARNING, moh, and moh_scan_files().

Referenced by load_module(), and reload().

01264 {
01265    struct mohclass *moh;
01266     
01267    if (!load_moh_classes(reload))      /* Load classes from config */
01268       return 0;         /* Return if nothing is found */
01269 
01270    AST_LIST_LOCK(&mohclasses);
01271    AST_LIST_TRAVERSE_SAFE_BEGIN(&mohclasses, moh, list) {
01272       if (reload && moh->delete) {
01273          AST_LIST_REMOVE_CURRENT(&mohclasses, list);
01274          if (!moh->inuse)
01275             ast_moh_destroy_one(moh);
01276       } else if (moh->total_files) {
01277          if (moh_scan_files(moh) <= 0) {
01278             ast_log(LOG_WARNING, "No files found for class '%s'\n", moh->name);
01279             moh->delete = 1;
01280             AST_LIST_REMOVE_CURRENT(&mohclasses, list);
01281             if (!moh->inuse)
01282                ast_moh_destroy_one(moh);
01283          }
01284       }
01285    }
01286    AST_LIST_TRAVERSE_SAFE_END
01287    AST_LIST_UNLOCK(&mohclasses);
01288 
01289    return 1;
01290 }

static int load_module ( void   )  [static]

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

01293 {
01294    int res;
01295 
01296    res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
01297    ast_register_atexit(ast_moh_destroy);
01298    ast_cli_register_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry));
01299    if (!res)
01300       res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
01301    if (!res)
01302       res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
01303    if (!res)
01304       res = ast_register_application(app3, moh3_exec, synopsis3, descrip3);
01305    if (!res)
01306       res = ast_register_application(app4, moh4_exec, synopsis4, descrip4);
01307 
01308    if (!init_classes(0)) {    /* No music classes configured, so skip it */
01309       ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold.\n");
01310    } else {
01311       ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
01312    }
01313 
01314    return 0;
01315 }

static int load_moh_classes ( int  reload  )  [static]

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

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

static void local_ast_moh_cleanup ( struct ast_channel chan  )  [static]

Definition at line 942 of file res_musiconhold.c.

References free, and ast_channel::music_state.

Referenced by load_module(), and reload().

00943 {
00944    if (chan->music_state) {
00945       free(chan->music_state);
00946       chan->music_state = NULL;
00947    }
00948 }

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

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

00951 {
00952    struct mohclass *mohclass = NULL;
00953 
00954    /* The following is the order of preference for which class to use:
00955     * 1) The channels explicitly set musicclass, which should *only* be
00956     *    set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
00957     * 2) The mclass argument. If a channel is calling ast_moh_start() as the
00958     *    result of receiving a HOLD control frame, this should be the
00959     *    payload that came with the frame.
00960     * 3) The interpclass argument. This would be from the mohinterpret
00961     *    option from channel drivers. This is the same as the old musicclass
00962     *    option.
00963     * 4) The default class.
00964     */
00965    AST_LIST_LOCK(&mohclasses);
00966    if (!ast_strlen_zero(chan->musicclass))
00967       mohclass = get_mohbyname(chan->musicclass, 1);
00968    if (!mohclass && !ast_strlen_zero(mclass))
00969       mohclass = get_mohbyname(mclass, 1);
00970    if (!mohclass && !ast_strlen_zero(interpclass))
00971       mohclass = get_mohbyname(interpclass, 1);
00972    if (!mohclass) 
00973       mohclass = get_mohbyname("default", 1);
00974    if (mohclass)
00975       ast_atomic_fetchadd_int(&mohclass->inuse, +1);
00976    AST_LIST_UNLOCK(&mohclasses);
00977 
00978    if (!mohclass)
00979       return -1;
00980 
00981    ast_set_flag(chan, AST_FLAG_MOH);
00982    if (mohclass->total_files) {
00983       return ast_activate_generator(chan, &moh_file_stream, mohclass);
00984    } else
00985       return ast_activate_generator(chan, &mohgen, mohclass);
00986 }

static void local_ast_moh_stop ( struct ast_channel chan  )  [static]

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

00989 {
00990    ast_clear_flag(chan, AST_FLAG_MOH);
00991    ast_deactivate_generator(chan);
00992 
00993    if (chan->music_state) {
00994       if (chan->stream) {
00995          ast_closestream(chan->stream);
00996          chan->stream = NULL;
00997       }
00998    }
00999 }

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

Definition at line 594 of file res_musiconhold.c.

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

Referenced by load_module().

00595 {
00596    if (ast_moh_start(chan, data, NULL)) {
00597       ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
00598       return 0;
00599    }
00600    while (!ast_safe_sleep(chan, 10000));
00601    ast_moh_stop(chan);
00602    return -1;
00603 }

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

Definition at line 605 of file res_musiconhold.c.

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

Referenced by load_module().

00606 {
00607    int res;
00608    if (!data || !atoi(data)) {
00609       ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
00610       return -1;
00611    }
00612    if (ast_moh_start(chan, NULL, NULL)) {
00613       ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name);
00614       return 0;
00615    }
00616    res = ast_safe_sleep(chan, atoi(data) * 1000);
00617    ast_moh_stop(chan);
00618    return res;
00619 }

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

Definition at line 621 of file res_musiconhold.c.

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

Referenced by load_module().

00622 {
00623    if (ast_strlen_zero(data)) {
00624       ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
00625       return -1;
00626    }
00627    ast_string_field_set(chan, musicclass, data);
00628    return 0;
00629 }

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

Definition at line 631 of file res_musiconhold.c.

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

Referenced by load_module().

00632 {
00633    char *class = NULL;
00634    if (data && strlen(data))
00635       class = data;
00636    if (ast_moh_start(chan, class, NULL)) 
00637       ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name);
00638 
00639    return 0;
00640 }

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

Definition at line 642 of file res_musiconhold.c.

References ast_moh_stop().

Referenced by load_module().

00643 {
00644    ast_moh_stop(chan);
00645 
00646    return 0;
00647 }

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

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

00778 {
00779    if (!class->allowed_files) {
00780       if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray))))
00781          return -1;
00782       class->allowed_files = INITIAL_NUM_FILES;
00783    } else if (class->total_files == class->allowed_files) {
00784       if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) {
00785          class->allowed_files = 0;
00786          class->total_files = 0;
00787          return -1;
00788       }
00789       class->allowed_files *= 2;
00790    }
00791 
00792    if (!(class->filearray[class->total_files] = ast_strdup(filepath)))
00793       return -1;
00794 
00795    class->total_files++;
00796 
00797    return 0;
00798 }

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

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

00722 {
00723    struct mohdata *res;
00724    struct mohclass *class = params;
00725 
00726    if ((res = mohalloc(class))) {
00727       res->origwfmt = chan->writeformat;
00728       if (ast_set_write_format(chan, class->format)) {
00729          ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format));
00730          moh_release(NULL, res);
00731          res = NULL;
00732       }
00733       if (option_verbose > 2)
00734          ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name);
00735    }
00736    return res;
00737 }

static struct mohclass* moh_class_malloc ( void   )  [static]

Definition at line 1001 of file res_musiconhold.c.

References ast_calloc, AST_FORMAT_SLINEAR, and mohclass::format.

Referenced by load_moh_classes().

01002 {
01003    struct mohclass *class;
01004 
01005    if ((class = ast_calloc(1, sizeof(*class))))
01006       class->format = AST_FORMAT_SLINEAR;
01007 
01008    return class;
01009 }

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

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

01220 {
01221    struct mohclass *class;
01222 
01223    AST_LIST_LOCK(&mohclasses);
01224    AST_LIST_TRAVERSE(&mohclasses, class, list) {
01225       ast_cli(fd, "Class: %s\n", class->name);
01226       ast_cli(fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
01227       ast_cli(fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
01228       ast_cli(fd, "\tUse Count: %d\n", class->inuse);
01229       if (ast_test_flag(class, MOH_CUSTOM))
01230          ast_cli(fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
01231       if (strcasecmp(class->mode, "files"))
01232          ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format));
01233    }
01234    AST_LIST_UNLOCK(&mohclasses);
01235 
01236    return 0;
01237 }

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

Definition at line 1194 of file res_musiconhold.c.

References reload().

01195 {
01196    reload();
01197    return 0;
01198 }

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

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

00322 {
00323    struct moh_files_state *state;
00324    struct mohclass *class = params;
00325 
00326    if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) {
00327       chan->music_state = state;
00328       state->class = class;
00329       state->save_pos = -1;
00330    } else 
00331       state = chan->music_state;
00332 
00333    if (state) {
00334       if (state->class != class) {
00335          /* initialize */
00336          memset(state, 0, sizeof(*state));
00337          state->class = class;
00338          if (ast_test_flag(state->class, MOH_RANDOMIZE) && class->total_files)
00339             state->pos = ast_random() % class->total_files;
00340       }
00341 
00342       state->origwfmt = chan->writeformat;
00343 
00344       if (option_verbose > 2)
00345          ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->name, chan->name);
00346    }
00347    
00348    return chan->music_state;
00349 }

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

Definition at line 296 of file res_musiconhold.c.

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

00297 {
00298    struct moh_files_state *state = chan->music_state;
00299    struct ast_frame *f = NULL;
00300    int res = 0;
00301 
00302    state->sample_queue += samples;
00303 
00304    while (state->sample_queue > 0) {
00305       if ((f = moh_files_readframe(chan))) {
00306          state->samples += f->samples;
00307          res = ast_write(chan, f);
00308          state->sample_queue -= f->samples;
00309          ast_frfree(f);
00310          if (res < 0) {
00311             ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
00312             return -1;
00313          }
00314       } else
00315          return -1;  
00316    }
00317    return res;
00318 }

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

Definition at line 284 of file res_musiconhold.c.

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

Referenced by moh_files_generator().

00285 {
00286    struct ast_frame *f = NULL;
00287    
00288    if (!(chan->stream && (f = ast_readframe(chan->stream)))) {
00289       if (!ast_moh_files_next(chan))
00290          f = ast_readframe(chan->stream);
00291    }
00292 
00293    return f;
00294 }

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

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

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

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

Definition at line 739 of file res_musiconhold.c.

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

00740 {
00741    struct mohdata *moh = data;
00742    short buf[1280 + AST_FRIENDLY_OFFSET / 2];
00743    int res;
00744 
00745    if (!moh->parent->pid)
00746       return -1;
00747 
00748    len = ast_codec_get_len(moh->parent->format, samples);
00749 
00750    if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
00751       ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name);
00752       len = sizeof(buf) - AST_FRIENDLY_OFFSET;
00753    }
00754    res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
00755    if (res <= 0)
00756       return 0;
00757 
00758    moh->f.datalen = res;
00759    moh->f.data = buf + AST_FRIENDLY_OFFSET / 2;
00760    moh->f.samples = ast_codec_get_samples(&moh->f);
00761 
00762    if (ast_write(chan, &moh->f) < 0) {
00763       ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
00764       return -1;
00765    }
00766 
00767    return 0;
00768 }

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

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

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

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

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

00699 {
00700    struct mohdata *moh = data;
00701    int oldwfmt;
00702 
00703    AST_LIST_LOCK(&mohclasses);
00704    AST_LIST_REMOVE(&moh->parent->members, moh, list); 
00705    AST_LIST_UNLOCK(&mohclasses);
00706    
00707    close(moh->pipe[0]);
00708    close(moh->pipe[1]);
00709    oldwfmt = moh->origwfmt;
00710    if (moh->parent->delete && ast_atomic_dec_and_test(&moh->parent->inuse))
00711       ast_moh_destroy_one(moh->parent);
00712    free(moh);
00713    if (chan) {
00714       if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
00715          ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
00716       if (option_verbose > 2)
00717          ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
00718    }
00719 }

static int moh_scan_files ( struct mohclass class  )  [static]

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

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

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

Definition at line 665 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(), errno, mohclass::format, free, LOG_WARNING, moh, and mohdata::pipe.

Referenced by moh_alloc().

00666 {
00667    struct mohdata *moh;
00668    long flags; 
00669    
00670    if (!(moh = ast_calloc(1, sizeof(*moh))))
00671       return NULL;
00672    
00673    if (pipe(moh->pipe)) {
00674       ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
00675       free(moh);
00676       return NULL;
00677    }
00678 
00679    /* Make entirely non-blocking */
00680    flags = fcntl(moh->pipe[0], F_GETFL);
00681    fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
00682    flags = fcntl(moh->pipe[1], F_GETFL);
00683    fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
00684 
00685    moh->f.frametype = AST_FRAME_VOICE;
00686    moh->f.subclass = cl->format;
00687    moh->f.offset = AST_FRIENDLY_OFFSET;
00688 
00689    moh->parent = cl;
00690 
00691    AST_LIST_LOCK(&mohclasses);
00692    AST_LIST_INSERT_HEAD(&cl->members, moh, list);
00693    AST_LIST_UNLOCK(&mohclasses);
00694    
00695    return moh;
00696 }

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

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

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

static int reload ( void   )  [static]

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

01318 {
01319    if (init_classes(1))
01320       ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
01321 
01322    return 0;
01323 }

static int spawn_mp3 ( struct mohclass class  )  [static]

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

Referenced by monmp3thread().

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

static int unload_module ( void   )  [static]

Definition at line 1325 of file res_musiconhold.c.

01326 {
01327    return -1;
01328 }


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

Referenced by local_ast_moh_start().

struct ast_generator mohgen [static]

Definition at line 770 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 Mon Mar 31 07:42:26 2008 for Asterisk - the Open Source PBX by  doxygen 1.5.1