Mon Nov 24 15:34:49 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 "asterisk/dahdi_compat.h"

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

Referenced by moh_add_file().

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

Definition at line 168 of file res_musiconhold.c.

#define MAX_MP3S   256

Definition at line 170 of file res_musiconhold.c.

Referenced by spawn_mp3().

#define MOH_CUSTOM   (1 << 2)

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

Referenced by moh_register(), and spawn_mp3().

#define MOH_RANDOMIZE   (1 << 3)

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

Referenced by moh_register(), and spawn_mp3().

#define MPG_123   "/usr/bin/mpg123"

Definition at line 169 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 1185 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(), and unload_module().

01186 {
01187    struct mohclass *moh;
01188 
01189    if (option_verbose > 1)
01190       ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
01191 
01192    AST_LIST_LOCK(&mohclasses);
01193    while ((moh = AST_LIST_REMOVE_HEAD(&mohclasses, list))) {
01194       ast_moh_destroy_one(moh);
01195    }
01196    AST_LIST_UNLOCK(&mohclasses);
01197 }

static int ast_moh_destroy_one ( struct mohclass moh  )  [static]

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

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

static int ast_moh_files_next ( struct ast_channel chan  )  [static]

Definition at line 225 of file res_musiconhold.c.

References ast_closestream(), ast_fileexists(), ast_log(), ast_openstream_full(), ast_random(), 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().

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

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

Definition at line 175 of file res_musiconhold.c.

References AST_LIST_REMOVE_HEAD, and free.

Referenced by ast_moh_destroy_one(), and moh_register().

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

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

Definition at line 1205 of file res_musiconhold.c.

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

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

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

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

static int init_classes ( int  reload  )  [static]

Definition at line 1268 of file res_musiconhold.c.

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

Referenced by load_module(), and reload().

01269 {
01270    struct mohclass *moh;
01271     
01272    if (!load_moh_classes(reload))      /* Load classes from config */
01273       return 0;         /* Return if nothing is found */
01274 
01275    AST_LIST_LOCK(&mohclasses);
01276    AST_LIST_TRAVERSE_SAFE_BEGIN(&mohclasses, moh, list) {
01277       if (reload && moh->delete) {
01278          AST_LIST_REMOVE_CURRENT(&mohclasses, list);
01279          if (!moh->inuse)
01280             ast_moh_destroy_one(moh);
01281       }
01282    }
01283    AST_LIST_TRAVERSE_SAFE_END
01284    AST_LIST_UNLOCK(&mohclasses);
01285 
01286    return 1;
01287 }

static int load_module ( void   )  [static]

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

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

static int load_moh_classes ( int  reload  )  [static]

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

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

static void local_ast_moh_cleanup ( struct ast_channel chan  )  [static]

Definition at line 947 of file res_musiconhold.c.

References free, and ast_channel::music_state.

Referenced by load_module(), and reload().

00948 {
00949    if (chan->music_state) {
00950       free(chan->music_state);
00951       chan->music_state = NULL;
00952    }
00953 }

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

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

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

static void local_ast_moh_stop ( struct ast_channel chan  )  [static]

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

00994 {
00995    ast_clear_flag(chan, AST_FLAG_MOH);
00996    ast_deactivate_generator(chan);
00997 
00998    if (chan->music_state) {
00999       if (chan->stream) {
01000          ast_closestream(chan->stream);
01001          chan->stream = NULL;
01002       }
01003    }
01004 }

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

Definition at line 592 of file res_musiconhold.c.

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

Referenced by load_module().

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

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

Definition at line 603 of file res_musiconhold.c.

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

Referenced by load_module().

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

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

Definition at line 619 of file res_musiconhold.c.

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

Referenced by load_module().

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

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

Definition at line 629 of file res_musiconhold.c.

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

Referenced by load_module().

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

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

Definition at line 640 of file res_musiconhold.c.

References ast_moh_stop().

Referenced by load_module().

00641 {
00642    ast_moh_stop(chan);
00643 
00644    return 0;
00645 }

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

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

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

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

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

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

static struct mohclass* moh_class_malloc ( void   )  [static]

Definition at line 1006 of file res_musiconhold.c.

References ast_calloc, AST_FORMAT_SLINEAR, and mohclass::format.

Referenced by load_moh_classes().

01007 {
01008    struct mohclass *class;
01009 
01010    if ((class = ast_calloc(1, sizeof(*class))))
01011       class->format = AST_FORMAT_SLINEAR;
01012 
01013    return class;
01014 }

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

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

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

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

Definition at line 1199 of file res_musiconhold.c.

References reload().

01200 {
01201    reload();
01202    return 0;
01203 }

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

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

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

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

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

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

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

Definition at line 282 of file res_musiconhold.c.

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

Referenced by moh_files_generator().

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

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

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

00201 {
00202    struct moh_files_state *state;
00203 
00204    if (chan) {
00205       if ((state = chan->music_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       }
00221    }
00222 }

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

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

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

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

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

Referenced by load_moh_classes().

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

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

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

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

static int moh_scan_files ( struct mohclass class  )  [static]

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

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

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

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

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

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

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

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

static int reload ( void   )  [static]

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

01315 {
01316    if (init_classes(1))
01317       ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
01318 
01319    return 0;
01320 }

static int spawn_mp3 ( struct mohclass class  )  [static]

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

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

static int unload_module ( void   )  [static]

Definition at line 1322 of file res_musiconhold.c.

References ast_cli_unregister_multiple(), AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_log(), ast_moh_destroy(), ast_uninstall_music_functions(), ast_unregister_application(), cli_moh, and LOG_WARNING.

01323 {
01324    int res = 0;
01325    struct mohclass *class = NULL;
01326 
01327    AST_LIST_LOCK(&mohclasses);
01328    AST_LIST_TRAVERSE(&mohclasses, class, list) {
01329       if (class->inuse > 0) {
01330          res = -1;
01331          break;
01332       }
01333    }
01334    AST_LIST_UNLOCK(&mohclasses);
01335    if (res < 0) {
01336       ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n");
01337       return res;
01338    }
01339 
01340    ast_uninstall_music_functions();
01341    ast_moh_destroy();
01342    res = ast_unregister_application(app0);
01343    res |= ast_unregister_application(app1);
01344    res |= ast_unregister_application(app2);
01345    res |= ast_unregister_application(app3);
01346    res |= ast_unregister_application(app4);
01347    ast_cli_unregister_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry));
01348    return res;
01349 }


Variable Documentation

char* app0 = "MusicOnHold" [static]

Definition at line 75 of file res_musiconhold.c.

char* app1 = "WaitMusicOnHold" [static]

Definition at line 76 of file res_musiconhold.c.

char* app2 = "SetMusicOnHold" [static]

Definition at line 77 of file res_musiconhold.c.

char* app3 = "StartMusicOnHold" [static]

Definition at line 78 of file res_musiconhold.c.

char* app4 = "StopMusicOnHold" [static]

Definition at line 79 of file res_musiconhold.c.

struct ast_cli_entry cli_moh[] [static]

Definition at line 1254 of file res_musiconhold.c.

Referenced by load_module(), and unload_module().

struct ast_cli_entry cli_moh_classes_show_deprecated [static]

Initial value:

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

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

char* descrip0 [static]

Definition at line 87 of file res_musiconhold.c.

char* descrip1 [static]

Initial value:

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

Definition at line 94 of file res_musiconhold.c.

char* descrip2 [static]

Initial value:

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

Definition at line 99 of file res_musiconhold.c.

char* descrip3 [static]

Initial value:

 "StartMusicOnHold(class): "
"Starts playing music on hold, uses default music class for channel.\n"
"Starts playing music specified by class.  If omitted, the default\n"
"music source for the channel will be used.  Always returns 0.\n"

Definition at line 104 of file res_musiconhold.c.

char* descrip4 [static]

Initial value:

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

Definition at line 109 of file res_musiconhold.c.

struct ast_generator moh_file_stream [static]

Definition at line 349 of file res_musiconhold.c.

Referenced by local_ast_moh_start().

struct ast_generator mohgen [static]

Definition at line 768 of file res_musiconhold.c.

Referenced by local_ast_moh_start().

int respawn_time = 20 [static]

Definition at line 112 of file res_musiconhold.c.

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

Definition at line 81 of file res_musiconhold.c.

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

Definition at line 82 of file res_musiconhold.c.

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

Definition at line 83 of file res_musiconhold.c.

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

Definition at line 84 of file res_musiconhold.c.

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

Definition at line 85 of file res_musiconhold.c.


Generated on Mon Nov 24 15:34:49 2008 for Asterisk - the Open Source PBX by  doxygen 1.4.7