Fri Sep 25 19:28:43 2009

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)

#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 1171 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().

01172 {
01173    struct mohclass *moh;
01174 
01175    if (option_verbose > 1)
01176       ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
01177 
01178    AST_LIST_LOCK(&mohclasses);
01179    while ((moh = AST_LIST_REMOVE_HEAD(&mohclasses, list))) {
01180       ast_moh_destroy_one(moh);
01181    }
01182    AST_LIST_UNLOCK(&mohclasses);
01183 }

static int ast_moh_destroy_one ( struct mohclass moh  )  [static]

Definition at line 1141 of file res_musiconhold.c.

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

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

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

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_seekstream(), ast_test_flag, moh_files_state::class, errno, mohclass::filearray, LOG_DEBUG, LOG_WARNING, MOH_RANDOMIZE, ast_channel::music_state, mohclass::name, option_debug, moh_files_state::pos, moh_files_state::samples, moh_files_state::save_pos, ast_channel::stream, and mohclass::total_files.

Referenced by moh_files_readframe().

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 (!state->class->total_files) {
00235       ast_log(LOG_WARNING, "No files available for class '%s'\n", state->class->name);
00236       return -1;
00237    }
00238 
00239    /* If a specific file has been saved, use it */
00240    if (state->save_pos >= 0) {
00241       state->pos = state->save_pos;
00242       state->save_pos = -1;
00243    } else if (ast_test_flag(state->class, MOH_RANDOMIZE)) {
00244       /* Get a random file and ensure we can open it */
00245       for (tries = 0; tries < 20; tries++) {
00246          state->pos = rand() % state->class->total_files;
00247          if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0)
00248             break;
00249       }
00250       state->samples = 0;
00251    } else {
00252       /* This is easy, just increment our position and make sure we don't exceed the total file count */
00253       state->pos++;
00254       state->pos %= state->class->total_files;
00255       state->samples = 0;
00256    }
00257 
00258    if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
00259       ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
00260       state->pos++;
00261       state->pos %= state->class->total_files;
00262       return -1;
00263    }
00264 
00265    if (option_debug)
00266       ast_log(LOG_DEBUG, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]);
00267 
00268    if (state->samples)
00269       ast_seekstream(chan->stream, state->samples, SEEK_SET);
00270 
00271    return 0;
00272 }

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

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

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

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

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

Definition at line 641 of file res_musiconhold.c.

References AST_LIST_TRAVERSE, ast_log(), LOG_WARNING, moh, and mohclass::name.

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

00642 {
00643    struct mohclass *moh = NULL;
00644 
00645    AST_LIST_TRAVERSE(&mohclasses, moh, list) {
00646       if (!strcasecmp(name, moh->name))
00647          break;
00648    }
00649 
00650    if (!moh && warn)
00651       ast_log(LOG_WARNING, "Music on Hold class '%s' not found\n", name);
00652 
00653    return moh;
00654 }

static int init_classes ( int  reload  )  [static]

Definition at line 1254 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(), mohclass::delete, mohclass::inuse, load_moh_classes(), LOG_WARNING, moh, moh_scan_files(), mohclass::name, and mohclass::total_files.

Referenced by load_module(), and reload().

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

static int load_module ( void   )  [static]

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

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

static int load_moh_classes ( int  reload  )  [static]

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

Referenced by init_classes().

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

static void local_ast_moh_cleanup ( struct ast_channel chan  )  [static]

Definition at line 933 of file res_musiconhold.c.

References free, and ast_channel::music_state.

Referenced by load_module(), and reload().

00934 {
00935    if (chan->music_state) {
00936       free(chan->music_state);
00937       chan->music_state = NULL;
00938    }
00939 }

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

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

Referenced by load_module(), and reload().

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

static void local_ast_moh_stop ( struct ast_channel chan  )  [static]

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

00980 {
00981    ast_clear_flag(chan, AST_FLAG_MOH);
00982    ast_deactivate_generator(chan);
00983 
00984    if (chan->music_state) {
00985       if (chan->stream) {
00986          ast_closestream(chan->stream);
00987          chan->stream = NULL;
00988       }
00989    }
00990 }

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

Definition at line 585 of file res_musiconhold.c.

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

Referenced by load_module().

00586 {
00587    if (ast_moh_start(chan, data, NULL)) {
00588       ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
00589       return 0;
00590    }
00591    while (!ast_safe_sleep(chan, 10000));
00592    ast_moh_stop(chan);
00593    return -1;
00594 }

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

Definition at line 596 of file res_musiconhold.c.

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

Referenced by load_module().

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

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

Definition at line 612 of file res_musiconhold.c.

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

Referenced by load_module().

00613 {
00614    if (ast_strlen_zero(data)) {
00615       ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
00616       return -1;
00617    }
00618    ast_string_field_set(chan, musicclass, data);
00619    return 0;
00620 }

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

Definition at line 622 of file res_musiconhold.c.

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

Referenced by load_module().

00623 {
00624    char *class = NULL;
00625    if (data && strlen(data))
00626       class = data;
00627    if (ast_moh_start(chan, class, NULL)) 
00628       ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name);
00629 
00630    return 0;
00631 }

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

Definition at line 633 of file res_musiconhold.c.

References ast_moh_stop().

Referenced by load_module().

00634 {
00635    ast_moh_stop(chan);
00636 
00637    return 0;
00638 }

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

Definition at line 768 of file res_musiconhold.c.

References ast_calloc, ast_realloc, ast_strdup, and INITIAL_NUM_FILES.

Referenced by moh_scan_files().

00769 {
00770    if (!class->allowed_files) {
00771       if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray))))
00772          return -1;
00773       class->allowed_files = INITIAL_NUM_FILES;
00774    } else if (class->total_files == class->allowed_files) {
00775       if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) {
00776          class->allowed_files = 0;
00777          class->total_files = 0;
00778          return -1;
00779       }
00780       class->allowed_files *= 2;
00781    }
00782 
00783    if (!(class->filearray[class->total_files] = ast_strdup(filepath)))
00784       return -1;
00785 
00786    class->total_files++;
00787 
00788    return 0;
00789 }

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

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

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

static struct mohclass* moh_class_malloc ( void   )  [static, read]

Definition at line 992 of file res_musiconhold.c.

References ast_calloc, AST_FORMAT_SLINEAR, and mohclass::format.

Referenced by load_moh_classes().

00993 {
00994    struct mohclass *class;
00995 
00996    if ((class = ast_calloc(1, sizeof(*class))))
00997       class->format = AST_FORMAT_SLINEAR;
00998 
00999    return class;
01000 }

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

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

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

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

Definition at line 1185 of file res_musiconhold.c.

References reload().

01186 {
01187    reload();
01188    return 0;
01189 }

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

Definition at line 312 of file res_musiconhold.c.

References ast_calloc, ast_random(), ast_test_flag, ast_verbose(), moh_files_state::class, MOH_RANDOMIZE, ast_channel::music_state, option_verbose, moh_files_state::origwfmt, moh_files_state::pos, moh_files_state::save_pos, VERBOSE_PREFIX_3, and ast_channel::writeformat.

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

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

Definition at line 287 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, ast_frame::samples, and moh_files_state::samples.

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

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

Definition at line 275 of file res_musiconhold.c.

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

Referenced by moh_files_generator().

00276 {
00277    struct ast_frame *f = NULL;
00278    
00279    if (!(chan->stream && (f = ast_readframe(chan->stream)))) {
00280       if (!ast_moh_files_next(chan))
00281          f = ast_readframe(chan->stream);
00282    }
00283 
00284    return f;
00285 }

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 (ast_atomic_dec_and_test(&state->class->inuse) && state->class->delete)
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 730 of file res_musiconhold.c.

References ast_codec_get_len(), ast_codec_get_samples(), AST_FRIENDLY_OFFSET, ast_log(), ast_write(), ast_frame::data, ast_frame::datalen, errno, mohdata::f, mohclass::format, LOG_WARNING, moh, mohdata::parent, mohclass::pid, mohdata::pipe, and ast_frame::samples.

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

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

Definition at line 857 of file res_musiconhold.c.

References mohclass::args, 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, mohclass::mode, MOH_CUSTOM, MOH_QUIET, MOH_RANDOMIZE, moh_scan_files(), MOH_SINGLE, monmp3thread(), mohclass::name, mohclass::pseudofd, mohclass::srcfd, mohclass::start, and mohclass::thread.

Referenced by load_moh_classes().

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

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

Definition at line 689 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(), mohclass::delete, free, mohclass::inuse, LOG_WARNING, moh, option_verbose, mohdata::origwfmt, mohdata::parent, mohdata::pipe, and VERBOSE_PREFIX_3.

Referenced by moh_alloc().

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

static int moh_scan_files ( struct mohclass class  )  [static]

Definition at line 791 of file res_musiconhold.c.

References ast_log(), ext, free, LOG_WARNING, and moh_add_file().

Referenced by init_classes(), and moh_register().

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

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

Definition at line 656 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, mohdata::f, mohclass::flags, mohclass::format, ast_frame::frametype, free, LOG_WARNING, moh, ast_frame::offset, mohdata::parent, mohdata::pipe, and ast_frame::subclass.

Referenced by moh_alloc().

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

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

Definition at line 500 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_DEBUG, LOG_NOTICE, LOG_WARNING, moh, MOH_MS_INTERVAL, option_debug, mohdata::pipe, and spawn_mp3().

Referenced by moh_register().

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

static int reload ( void   )  [static]

static int spawn_mp3 ( struct mohclass class  )  [static]

Definition at line 349 of file res_musiconhold.c.

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

Referenced by monmp3thread().

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

static int unload_module ( void   )  [static]

Definition at line 1316 of file res_musiconhold.c.

01317 {
01318    return -1;
01319 }


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

Initial value:

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

Definition at line 1230 of file res_musiconhold.c.

Initial value:

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

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

struct ast_generator mohgen [static]

Definition at line 761 of file res_musiconhold.c.

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 Sep 25 19:28:43 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.5