Wed Oct 28 11:46:18 2009

Asterisk developer's documentation


res_musiconhold.c File Reference

Routines implementing music on hold. More...

#include "asterisk.h"
#include <ctype.h>
#include <signal.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/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/app.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/astobj2.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_CACHERTCLASSES   (1 << 5)
#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 MOH_SORTALPHA   (1 << 4)
#define mohclass_ref(class)   (ao2_ref((class), +1), class)
#define mohclass_unref(class)   (ao2_ref((class), -1), (struct mohclass *) NULL)
#define MPG_123   "/usr/bin/mpg123"

Functions

static void __reg_module (void)
static void __unreg_module (void)
static void ast_moh_destroy (void)
static int ast_moh_files_next (struct ast_channel *chan)
static struct mohclassget_mohbydigit (char digit)
static struct mohclassget_mohbyname (const char *name, int warn)
static char * handle_cli_moh_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_moh_show_classes (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_moh_show_files (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int init_app_class (struct mohclass *class)
static int init_files_class (struct mohclass *class)
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 moh_add_file (struct mohclass *class, const char *filepath)
static void * moh_alloc (struct ast_channel *chan, void *params)
static int moh_class_cmp (void *obj, void *arg, int flags)
static void moh_class_destructor (void *obj)
static int moh_class_hash (const void *obj, const int flags)
static int moh_class_inuse (void *obj, void *arg, int flags)
static struct mohclassmoh_class_malloc (void)
static int moh_class_mark (void *obj, void *arg, int flags)
static int moh_classes_delete_marked (void *obj, void *arg, int flags)
static int moh_diff (struct mohclass *old, struct mohclass *new)
static int moh_digit_match (void *obj, void *arg, int flags)
static void * moh_files_alloc (struct ast_channel *chan, void *params)
static int moh_files_generator (struct ast_channel *chan, void *data, int len, int samples)
static struct ast_framemoh_files_readframe (struct ast_channel *chan)
static void moh_files_release (struct ast_channel *chan, void *data)
static int moh_generate (struct ast_channel *chan, void *data, int len, int samples)
static void moh_handle_digit (struct ast_channel *chan, char digit)
static int moh_register (struct mohclass *moh, int reload, int unref)
static void moh_release (struct ast_channel *chan, void *data)
static int moh_scan_files (struct mohclass *class)
static int moh_sort_compare (const void *i1, const void *i2)
static struct mohdatamohalloc (struct mohclass *cl)
static void * monmp3thread (void *data)
static int play_moh_exec (struct ast_channel *chan, void *data)
static int reload (void)
static int set_moh_exec (struct ast_channel *chan, void *data)
static int spawn_mp3 (struct mohclass *class)
static int start_moh_exec (struct ast_channel *chan, void *data)
static int stop_moh_exec (struct ast_channel *chan, void *data)
static int unload_module (void)
static int wait_moh_exec (struct ast_channel *chan, void *data)

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Music On Hold Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static const struct
ast_module_info
ast_module_info = &__mod_info
static struct ast_cli_entry cli_moh []
static struct ast_flags global_flags [1] = {{0}}
static struct ast_generator moh_file_stream
static struct ao2_containermohclasses
static struct ast_generator mohgen
static char * play_moh = "MusicOnHold"
static char * play_moh_desc
static char * play_moh_syn = "Play Music On Hold indefinitely"
static int respawn_time = 20
static char * set_moh = "SetMusicOnHold"
static char * set_moh_desc
static char * set_moh_syn = "Set default Music On Hold class"
static char * start_moh = "StartMusicOnHold"
static char * start_moh_desc
static char * start_moh_syn = "Play Music On Hold"
static char * stop_moh = "StopMusicOnHold"
static char * stop_moh_desc
static char * stop_moh_syn = "Stop Playing Music On Hold"
static char * wait_moh = "WaitMusicOnHold"
static char * wait_moh_desc
static char * wait_moh_syn = "Wait, 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 185 of file res_musiconhold.c.

#define MAX_MP3S   256

Definition at line 187 of file res_musiconhold.c.

Referenced by spawn_mp3().

#define MOH_CACHERTCLASSES   (1 << 5)

Should we use a separate instance of MOH for each user or not

Definition at line 141 of file res_musiconhold.c.

Referenced by load_moh_classes(), and local_ast_moh_start().

#define MOH_CUSTOM   (1 << 2)

#define MOH_MS_INTERVAL   100

Referenced by monmp3thread().

#define MOH_QUIET   (1 << 0)

Definition at line 135 of file res_musiconhold.c.

Referenced by init_app_class(), local_ast_moh_start(), and spawn_mp3().

#define MOH_RANDOMIZE   (1 << 3)

#define MOH_SINGLE   (1 << 1)

Definition at line 136 of file res_musiconhold.c.

Referenced by init_app_class(), local_ast_moh_start(), and spawn_mp3().

#define MOH_SORTALPHA   (1 << 4)

Definition at line 139 of file res_musiconhold.c.

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

#define mohclass_ref ( class   )     (ao2_ref((class), +1), class)

Definition at line 191 of file res_musiconhold.c.

Referenced by moh_files_alloc(), and mohalloc().

#define mohclass_unref ( class   )     (ao2_ref((class), -1), (struct mohclass *) NULL)

#define MPG_123   "/usr/bin/mpg123"

Definition at line 186 of file res_musiconhold.c.


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 1744 of file res_musiconhold.c.

static void __unreg_module ( void   )  [static]

Definition at line 1744 of file res_musiconhold.c.

static void ast_moh_destroy ( void   )  [static]

Definition at line 1540 of file res_musiconhold.c.

References ao2_callback(), ast_verb, OBJ_MULTIPLE, OBJ_NODATA, and OBJ_UNLINK.

Referenced by load_module(), and unload_module().

01541 {
01542    ast_verb(2, "Destroying musiconhold processes\n");
01543    ao2_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
01544 }

static int ast_moh_files_next ( struct ast_channel chan  )  [static]

Definition at line 222 of file res_musiconhold.c.

References ast_closestream(), ast_debug, ast_fileexists(), ast_log(), ast_openstream_full(), ast_random(), ast_seekstream(), ast_test_flag, moh_files_state::class, errno, mohclass::filearray, ast_channel::language, LOG_WARNING, MOH_RANDOMIZE, ast_channel::music_state, ast_channel::name, 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().

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

static struct mohclass* get_mohbydigit ( char  digit  )  [static, read]

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

Definition at line 352 of file res_musiconhold.c.

References ao2_callback(), and moh_digit_match().

Referenced by moh_handle_digit().

00353 {
00354    return ao2_callback(mohclasses, 0, moh_digit_match, &digit);
00355 }

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

Definition at line 738 of file res_musiconhold.c.

References ao2_find(), ast_copy_string(), ast_log(), mohclass::flags, LOG_DEBUG, moh, and mohclass::name.

Referenced by local_ast_moh_start(), and moh_register().

00739 {
00740    struct mohclass *moh = NULL;
00741    struct mohclass tmp_class = {
00742       .flags = 0,
00743    };
00744 
00745    ast_copy_string(tmp_class.name, name, sizeof(tmp_class.name));
00746 
00747    moh = ao2_find(mohclasses, &tmp_class, 0);
00748 
00749    if (!moh && warn) {
00750       ast_log(LOG_DEBUG, "Music on Hold class '%s' not found in memory\n", name);
00751    }
00752 
00753    return moh;
00754 }

static char* handle_cli_moh_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1546 of file res_musiconhold.c.

References ast_cli_args::argc, ast_cli_entry::args, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, reload, and ast_cli_entry::usage.

01547 {
01548    switch (cmd) {
01549    case CLI_INIT:
01550       e->command = "moh reload";
01551       e->usage =
01552          "Usage: moh reload\n"
01553          "       Reloads the MusicOnHold module.\n"
01554          "       Alias for 'module reload res_musiconhold.so'\n";
01555       return NULL;
01556    case CLI_GENERATE:
01557       return NULL;
01558    }
01559 
01560    if (a->argc != e->args)
01561       return CLI_SHOWUSAGE;
01562 
01563    reload();
01564 
01565    return CLI_SUCCESS;
01566 }

static char* handle_cli_moh_show_classes ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1606 of file res_musiconhold.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ast_cli_args::argc, ast_cli_entry::args, ast_cli(), ast_getformatname(), ast_test_flag, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, MOH_CUSTOM, mohclass_unref, S_OR, and ast_cli_entry::usage.

01607 {
01608    struct mohclass *class;
01609    struct ao2_iterator i;
01610 
01611    switch (cmd) {
01612    case CLI_INIT:
01613       e->command = "moh show classes";
01614       e->usage =
01615          "Usage: moh show classes\n"
01616          "       Lists all MusicOnHold classes.\n";
01617       return NULL;
01618    case CLI_GENERATE:
01619       return NULL;
01620    }
01621 
01622    if (a->argc != e->args)
01623       return CLI_SHOWUSAGE;
01624 
01625    i = ao2_iterator_init(mohclasses, 0);
01626    for (; (class = ao2_iterator_next(&i)); mohclass_unref(class)) {
01627       ast_cli(a->fd, "Class: %s\n", class->name);
01628       ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
01629       ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
01630       if (ast_test_flag(class, MOH_CUSTOM)) {
01631          ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
01632       }
01633       if (strcasecmp(class->mode, "files")) {
01634          ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(class->format));
01635       }
01636    }
01637    ao2_iterator_destroy(&i);
01638 
01639    return CLI_SUCCESS;
01640 }

static char* handle_cli_moh_show_files ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1568 of file res_musiconhold.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next(), ast_cli_args::argc, ast_cli_entry::args, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, mohclass_unref, and ast_cli_entry::usage.

01569 {
01570    struct mohclass *class;
01571    struct ao2_iterator i;
01572 
01573    switch (cmd) {
01574    case CLI_INIT:
01575       e->command = "moh show files";
01576       e->usage =
01577          "Usage: moh show files\n"
01578          "       Lists all loaded file-based MusicOnHold classes and their\n"
01579          "       files.\n";
01580       return NULL;
01581    case CLI_GENERATE:
01582       return NULL;
01583    }
01584 
01585    if (a->argc != e->args)
01586       return CLI_SHOWUSAGE;
01587 
01588    i = ao2_iterator_init(mohclasses, 0);
01589    for (; (class = ao2_iterator_next(&i)); mohclass_unref(class)) {
01590       int x;
01591 
01592       if (!class->total_files) {
01593          continue;
01594       }
01595 
01596       ast_cli(a->fd, "Class: %s\n", class->name);
01597       for (x = 0; x < class->total_files; x++) {
01598          ast_cli(a->fd, "\tFile: %s\n", class->filearray[x]);
01599       }
01600    }
01601    ao2_iterator_destroy(&i);
01602 
01603    return CLI_SUCCESS;
01604 }

static int init_app_class ( struct mohclass class  )  [static]

Definition at line 1035 of file res_musiconhold.c.

References ast_log(), ast_pthread_create_background, ast_set_flag, LOG_WARNING, MOH_CUSTOM, MOH_QUIET, MOH_SINGLE, and monmp3thread().

Referenced by moh_register().

01036 {
01037 #ifdef HAVE_DAHDI
01038    int x;
01039 #endif
01040 
01041    if (!strcasecmp(class->mode, "custom")) {
01042       ast_set_flag(class, MOH_CUSTOM);
01043    } else if (!strcasecmp(class->mode, "mp3nb")) {
01044       ast_set_flag(class, MOH_SINGLE);
01045    } else if (!strcasecmp(class->mode, "quietmp3nb")) {
01046       ast_set_flag(class, MOH_SINGLE | MOH_QUIET);
01047    } else if (!strcasecmp(class->mode, "quietmp3")) {
01048       ast_set_flag(class, MOH_QUIET);
01049    }
01050       
01051    class->srcfd = -1;
01052    class->pseudofd = -1;
01053 
01054 #ifdef HAVE_DAHDI
01055    /* Open /dev/zap/pseudo for timing...  Is
01056       there a better, yet reliable way to do this? */
01057    class->pseudofd = open("/dev/dahdi/pseudo", O_RDONLY);
01058    if (class->pseudofd < 0) {
01059       ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
01060    } else {
01061       x = 320;
01062       ioctl(class->pseudofd, DAHDI_SET_BLOCKSIZE, &x);
01063    }
01064 #endif
01065 
01066    if (ast_pthread_create_background(&class->thread, NULL, monmp3thread, class)) {
01067       ast_log(LOG_WARNING, "Unable to create moh thread...\n");
01068       if (class->pseudofd > -1) {
01069          close(class->pseudofd);
01070          class->pseudofd = -1;
01071       }
01072       return -1;
01073    }
01074 
01075    return 0;
01076 }

static int init_files_class ( struct mohclass class  )  [static]

Definition at line 990 of file res_musiconhold.c.

References ast_set_flag, ast_verbose(), MOH_RANDOMIZE, moh_scan_files(), option_verbose, and VERBOSE_PREFIX_3.

Referenced by moh_register().

00991 {
00992    int res;
00993 
00994    res = moh_scan_files(class);
00995 
00996    if (res < 0) {
00997       return -1;
00998    }
00999 
01000    if (!res) {
01001       if (option_verbose > 2) {
01002          ast_verbose(VERBOSE_PREFIX_3 "Files not found in %s for moh class:%s\n",
01003                class->dir, class->name);
01004       }
01005       return -1;
01006    }
01007 
01008    if (strchr(class->args, 'r')) {
01009       ast_set_flag(class, MOH_RANDOMIZE);
01010    }
01011 
01012    return 0;
01013 }

static int load_module ( void   )  [static]

Definition at line 1662 of file res_musiconhold.c.

References ao2_container_alloc(), ast_cli_register_multiple(), ast_install_music_functions(), ast_log(), AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_moh_destroy(), ast_register_application, ast_register_atexit(), load_moh_classes(), local_ast_moh_cleanup(), local_ast_moh_start(), local_ast_moh_stop(), LOG_WARNING, moh_class_cmp(), moh_class_hash(), play_moh_exec(), set_moh_exec(), start_moh_exec(), stop_moh_exec(), and wait_moh_exec().

01663 {
01664    int res;
01665 
01666    if (!(mohclasses = ao2_container_alloc(53, moh_class_hash, moh_class_cmp))) {
01667       return AST_MODULE_LOAD_DECLINE;
01668    }
01669 
01670    if (!load_moh_classes(0)) {   /* No music classes configured, so skip it */
01671       ast_log(LOG_WARNING, "No music on hold classes configured, "
01672             "disabling music on hold.\n");
01673    } else {
01674       ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop,
01675             local_ast_moh_cleanup);
01676    }
01677 
01678    res = ast_register_application(play_moh, play_moh_exec, play_moh_syn, play_moh_desc);
01679    ast_register_atexit(ast_moh_destroy);
01680    ast_cli_register_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry));
01681    if (!res)
01682       res = ast_register_application(wait_moh, wait_moh_exec, wait_moh_syn, wait_moh_desc);
01683    if (!res)
01684       res = ast_register_application(set_moh, set_moh_exec, set_moh_syn, set_moh_desc);
01685    if (!res)
01686       res = ast_register_application(start_moh, start_moh_exec, start_moh_syn, start_moh_desc);
01687    if (!res)
01688       res = ast_register_application(stop_moh, stop_moh_exec, stop_moh_syn, stop_moh_desc);
01689 
01690    return AST_MODULE_LOAD_SUCCESS;
01691 }

static int load_moh_classes ( int  reload  )  [static]

Definition at line 1439 of file res_musiconhold.c.

References ao2_callback(), ast_category_browse(), ast_clear_flag, ast_config_destroy(), ast_config_load, ast_copy_string(), AST_FLAGS_ALL, AST_FORMAT_SLINEAR, ast_getformatbyname(), ast_log(), ast_set2_flag, ast_set_flag, ast_strlen_zero(), ast_true(), ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, LOG_WARNING, MOH_CACHERTCLASSES, moh_class_malloc(), moh_class_mark(), moh_classes_delete_marked(), MOH_RANDOMIZE, moh_register(), MOH_SORTALPHA, mohclass_unref, ast_variable::name, ast_variable::next, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, ast_variable::value, and var.

Referenced by load_module().

01440 {
01441    struct ast_config *cfg;
01442    struct ast_variable *var;
01443    struct mohclass *class; 
01444    char *cat;
01445    int numclasses = 0;
01446    struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01447 
01448    cfg = ast_config_load("musiconhold.conf", config_flags);
01449 
01450    if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED)
01451       return 0;
01452 
01453    if (reload) {
01454       ao2_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL);
01455    }
01456    
01457    ast_clear_flag(global_flags, AST_FLAGS_ALL);
01458 
01459    cat = ast_category_browse(cfg, NULL);
01460    for (; cat; cat = ast_category_browse(cfg, cat)) {
01461       /* Setup common options from [general] section */
01462       if (!strcasecmp(cat, "general")) {
01463          for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
01464             if (!strcasecmp(var->name, "cachertclasses")) {
01465                ast_set2_flag(global_flags, ast_true(var->value), MOH_CACHERTCLASSES);
01466             } else {
01467                ast_log(LOG_WARNING, "Unknown option '%s' in [general] section of musiconhold.conf\n", var->name);
01468             }
01469          }
01470       }
01471       /* These names were deprecated in 1.4 and should not be used until after the next major release. */
01472       if (!strcasecmp(cat, "classes") || !strcasecmp(cat, "moh_files") || 
01473             !strcasecmp(cat, "general")) {
01474          continue;
01475       }
01476 
01477       if (!(class = moh_class_malloc())) {
01478          break;
01479       }
01480 
01481       ast_copy_string(class->name, cat, sizeof(class->name));  
01482       for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
01483          if (!strcasecmp(var->name, "mode"))
01484             ast_copy_string(class->mode, var->value, sizeof(class->mode)); 
01485          else if (!strcasecmp(var->name, "directory"))
01486             ast_copy_string(class->dir, var->value, sizeof(class->dir));
01487          else if (!strcasecmp(var->name, "application"))
01488             ast_copy_string(class->args, var->value, sizeof(class->args));
01489          else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value)))
01490             class->digit = *var->value;
01491          else if (!strcasecmp(var->name, "random"))
01492             ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
01493          else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "random"))
01494             ast_set_flag(class, MOH_RANDOMIZE);
01495          else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) 
01496             ast_set_flag(class, MOH_SORTALPHA);
01497          else if (!strcasecmp(var->name, "format")) {
01498             class->format = ast_getformatbyname(var->value);
01499             if (!class->format) {
01500                ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
01501                class->format = AST_FORMAT_SLINEAR;
01502             }
01503          }
01504       }
01505 
01506       if (ast_strlen_zero(class->dir)) {
01507          if (!strcasecmp(class->mode, "custom")) {
01508             strcpy(class->dir, "nodir");
01509          } else {
01510             ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
01511             class = mohclass_unref(class);
01512             continue;
01513          }
01514       }
01515       if (ast_strlen_zero(class->mode)) {
01516          ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
01517          class = mohclass_unref(class);
01518          continue;
01519       }
01520       if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
01521          ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
01522          class = mohclass_unref(class);
01523          continue;
01524       }
01525 
01526       /* Don't leak a class when it's already registered */
01527       if (!moh_register(class, reload, 1)) {
01528          numclasses++;
01529       }
01530    }
01531 
01532    ast_config_destroy(cfg);
01533 
01534    ao2_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, 
01535          moh_classes_delete_marked, NULL);
01536 
01537    return numclasses;
01538 }

static void local_ast_moh_cleanup ( struct ast_channel chan  )  [static]

Definition at line 1127 of file res_musiconhold.c.

References ast_free, and ast_channel::music_state.

Referenced by load_module().

01128 {
01129    struct moh_files_state *state = chan->music_state;
01130 
01131    if (state) {
01132       ast_free(chan->music_state);
01133       chan->music_state = NULL;
01134    }
01135 }

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

Definition at line 1150 of file res_musiconhold.c.

References mohclass::args, ast_activate_generator(), ast_check_realtime(), ast_copy_string(), AST_FLAG_MOH, AST_FORMAT_SLINEAR, ast_getformatbyname(), ast_load_realtime(), ast_log(), ast_pthread_create_background, ast_set2_flag, ast_set_flag, ast_strlen_zero(), ast_test_flag, ast_true(), ast_variables_destroy(), moh_files_state::class, mohclass::digit, mohclass::dir, mohclass::format, get_mohbyname(), LOG_NOTICE, LOG_WARNING, mohclass::mode, MOH_CACHERTCLASSES, moh_class_malloc(), MOH_CUSTOM, MOH_QUIET, MOH_RANDOMIZE, moh_register(), moh_scan_files(), MOH_SINGLE, MOH_SORTALPHA, mohclass_unref, monmp3thread(), ast_channel::music_state, ast_channel::musicclass, mohclass::name, ast_variable::name, ast_variable::next, mohclass::pseudofd, mohclass::realtime, mohclass::srcfd, mohclass::start, mohclass::thread, mohclass::total_files, ast_variable::value, and var.

Referenced by load_module().

01151 {
01152    struct mohclass *mohclass = NULL;
01153    struct moh_files_state *state = chan->music_state;
01154    struct ast_variable *var = NULL;
01155    int res;
01156    int realtime_possible = ast_check_realtime("musiconhold");
01157 
01158    /* The following is the order of preference for which class to use:
01159     * 1) The channels explicitly set musicclass, which should *only* be
01160     *    set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
01161     * 2) The mclass argument. If a channel is calling ast_moh_start() as the
01162     *    result of receiving a HOLD control frame, this should be the
01163     *    payload that came with the frame.
01164     * 3) The interpclass argument. This would be from the mohinterpret
01165     *    option from channel drivers. This is the same as the old musicclass
01166     *    option.
01167     * 4) The default class.
01168     */
01169    if (!ast_strlen_zero(chan->musicclass)) {
01170       mohclass = get_mohbyname(chan->musicclass, 1);
01171       if (!mohclass && realtime_possible) {
01172          var = ast_load_realtime("musiconhold", "name", chan->musicclass, NULL);
01173       }
01174    }
01175    if (!mohclass && !var && !ast_strlen_zero(mclass)) {
01176       mohclass = get_mohbyname(mclass, 1);
01177       if (!mohclass && realtime_possible) {
01178          var = ast_load_realtime("musiconhold", "name", mclass, NULL);
01179       }
01180    }
01181    if (!mohclass && !var && !ast_strlen_zero(interpclass)) {
01182       mohclass = get_mohbyname(interpclass, 1);
01183       if (!mohclass && realtime_possible) {
01184          var = ast_load_realtime("musiconhold", "name", interpclass, NULL);
01185       }
01186    }
01187 
01188    if (!mohclass && !var) {
01189       mohclass = get_mohbyname("default", 1);
01190       if (!mohclass && realtime_possible) {
01191          var = ast_load_realtime("musiconhold", "name", "default", NULL);
01192       }
01193    }
01194 
01195    /* If no moh class found in memory, then check RT. Note that the logic used
01196     * above guarantees that if var is non-NULL, then mohclass must be NULL.
01197     */
01198    if (var) {
01199       struct ast_variable *tmp = NULL;
01200 
01201       if ((mohclass = moh_class_malloc())) {
01202          mohclass->realtime = 1;
01203          for (tmp = var; tmp; tmp = tmp->next) {
01204             if (!strcasecmp(tmp->name, "name"))
01205                ast_copy_string(mohclass->name, tmp->value, sizeof(mohclass->name));
01206             else if (!strcasecmp(tmp->name, "mode"))
01207                ast_copy_string(mohclass->mode, tmp->value, sizeof(mohclass->mode)); 
01208             else if (!strcasecmp(tmp->name, "directory"))
01209                ast_copy_string(mohclass->dir, tmp->value, sizeof(mohclass->dir));
01210             else if (!strcasecmp(tmp->name, "application"))
01211                ast_copy_string(mohclass->args, tmp->value, sizeof(mohclass->args));
01212             else if (!strcasecmp(tmp->name, "digit") && (isdigit(*tmp->value) || strchr("*#", *tmp->value)))
01213                mohclass->digit = *tmp->value;
01214             else if (!strcasecmp(tmp->name, "random"))
01215                ast_set2_flag(mohclass, ast_true(tmp->value), MOH_RANDOMIZE);
01216             else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "random"))
01217                ast_set_flag(mohclass, MOH_RANDOMIZE);
01218             else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "alpha")) 
01219                ast_set_flag(mohclass, MOH_SORTALPHA);
01220             else if (!strcasecmp(tmp->name, "format")) {
01221                mohclass->format = ast_getformatbyname(tmp->value);
01222                if (!mohclass->format) {
01223                   ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", tmp->value);
01224                   mohclass->format = AST_FORMAT_SLINEAR;
01225                }
01226             }
01227          }
01228          ast_variables_destroy(var);
01229          if (ast_strlen_zero(mohclass->dir)) {
01230             if (!strcasecmp(mohclass->mode, "custom")) {
01231                strcpy(mohclass->dir, "nodir");
01232             } else {
01233                ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", mohclass->name);
01234                mohclass = mohclass_unref(mohclass);
01235                return -1;
01236             }
01237          }
01238          if (ast_strlen_zero(mohclass->mode)) {
01239             ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", mohclass->name);
01240             mohclass = mohclass_unref(mohclass);
01241             return -1;
01242          }
01243          if (ast_strlen_zero(mohclass->args) && !strcasecmp(mohclass->mode, "custom")) {
01244             ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", mohclass->name);
01245             mohclass = mohclass_unref(mohclass);
01246             return -1;
01247          }
01248 
01249          if (ast_test_flag(global_flags, MOH_CACHERTCLASSES)) {
01250             /* CACHERTCLASSES enabled, let's add this class to default tree */
01251             if (state && state->class) {
01252                /* Class already exist for this channel */
01253                ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name);
01254                if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) {
01255                   /* we found RT class with the same name, seems like we should continue playing existing one */
01256                   mohclass = mohclass_unref(mohclass);
01257                   mohclass = state->class;
01258                }
01259             }
01260             /* We don't want moh_register to unref the mohclass because we do it at the end of this function as well.
01261              * If we allowed moh_register to unref the mohclass,too, then the count would be off by one. The result would
01262              * be that the destructor would be called when the generator on the channel is deactivated. The container then
01263              * has a pointer to a freed mohclass, so any operations involving the mohclass container would result in reading
01264              * invalid memory.
01265              */
01266             moh_register(mohclass, 0, 0);
01267          } else {
01268             /* We don't register RT moh class, so let's init it manualy */
01269 
01270             time(&mohclass->start);
01271             mohclass->start -= respawn_time;
01272    
01273             if (!strcasecmp(mohclass->mode, "files")) {
01274                if (!moh_scan_files(mohclass)) {
01275                   mohclass = mohclass_unref(mohclass);
01276                   return -1;
01277                }
01278                if (strchr(mohclass->args, 'r'))
01279                   ast_set_flag(mohclass, MOH_RANDOMIZE);
01280             } else if (!strcasecmp(mohclass->mode, "mp3") || !strcasecmp(mohclass->mode, "mp3nb") || !strcasecmp(mohclass->mode, "quietmp3") || !strcasecmp(mohclass->mode, "quietmp3nb") || !strcasecmp(mohclass->mode, "httpmp3") || !strcasecmp(mohclass->mode, "custom")) {
01281 
01282                if (!strcasecmp(mohclass->mode, "custom"))
01283                   ast_set_flag(mohclass, MOH_CUSTOM);
01284                else if (!strcasecmp(mohclass->mode, "mp3nb"))
01285                   ast_set_flag(mohclass, MOH_SINGLE);
01286                else if (!strcasecmp(mohclass->mode, "quietmp3nb"))
01287                   ast_set_flag(mohclass, MOH_SINGLE | MOH_QUIET);
01288                else if (!strcasecmp(mohclass->mode, "quietmp3"))
01289                   ast_set_flag(mohclass, MOH_QUIET);
01290          
01291                mohclass->srcfd = -1;
01292 #ifdef HAVE_DAHDI
01293                /* Open /dev/dahdi/pseudo for timing...  Is
01294                   there a better, yet reliable way to do this? */
01295                mohclass->pseudofd = open("/dev/dahdi/pseudo", O_RDONLY);
01296                if (mohclass->pseudofd < 0) {
01297                   ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
01298                } else {
01299                   int x = 320;
01300                   ioctl(mohclass->pseudofd, DAHDI_SET_BLOCKSIZE, &x);
01301                }
01302 #else
01303                mohclass->pseudofd = -1;
01304 #endif
01305                /* Let's check if this channel already had a moh class before */
01306                if (state && state->class) {
01307                   /* Class already exist for this channel */
01308                   ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name);
01309                   if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) {
01310                      /* we found RT class with the same name, seems like we should continue playing existing one */
01311                      mohclass = mohclass_unref(mohclass);
01312                      mohclass = state->class;
01313                   }
01314                } else {
01315                   if (ast_pthread_create_background(&mohclass->thread, NULL, monmp3thread, mohclass)) {
01316                      ast_log(LOG_WARNING, "Unable to create moh...\n");
01317                      if (mohclass->pseudofd > -1) {
01318                         close(mohclass->pseudofd);
01319                         mohclass->pseudofd = -1;
01320                      }
01321                      mohclass = mohclass_unref(mohclass);
01322                      return -1;
01323                   }
01324                }
01325             } else {
01326                ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mohclass->mode);
01327                mohclass = mohclass_unref(mohclass);
01328                return -1;
01329             }
01330          }
01331       } else {
01332          ast_variables_destroy(var);
01333       }
01334    }
01335 
01336    if (!mohclass) {
01337       return -1;
01338    }
01339 
01340    ast_set_flag(chan, AST_FLAG_MOH);
01341 
01342    if (mohclass->total_files) {
01343       res = ast_activate_generator(chan, &moh_file_stream, mohclass);
01344    } else {
01345       res = ast_activate_generator(chan, &mohgen, mohclass);
01346    }
01347 
01348    mohclass = mohclass_unref(mohclass);
01349 
01350    return res;
01351 }

static void local_ast_moh_stop ( struct ast_channel chan  )  [static]

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

01354 {
01355    struct moh_files_state *state = chan->music_state;
01356    ast_clear_flag(chan, AST_FLAG_MOH);
01357    ast_deactivate_generator(chan);
01358 
01359    if (state) {
01360       if (chan->stream) {
01361          ast_closestream(chan->stream);
01362          chan->stream = NULL;
01363       }
01364    }
01365 }

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

Definition at line 882 of file res_musiconhold.c.

References ast_calloc, ast_realloc, ast_strdup, and INITIAL_NUM_FILES.

Referenced by moh_scan_files().

00883 {
00884    if (!class->allowed_files) {
00885       if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray))))
00886          return -1;
00887       class->allowed_files = INITIAL_NUM_FILES;
00888    } else if (class->total_files == class->allowed_files) {
00889       if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) {
00890          class->allowed_files = 0;
00891          class->total_files = 0;
00892          return -1;
00893       }
00894       class->allowed_files *= 2;
00895    }
00896 
00897    if (!(class->filearray[class->total_files] = ast_strdup(filepath)))
00898       return -1;
00899 
00900    class->total_files++;
00901 
00902    return 0;
00903 }

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

Definition at line 818 of file res_musiconhold.c.

References ast_calloc, ast_codec2str(), ast_log(), ast_set_write_format(), ast_verb, moh_files_state::class, mohclass::format, LOG_WARNING, moh_release(), mohalloc(), ast_channel::music_state, mohclass::name, ast_channel::name, mohdata::origwfmt, and ast_channel::writeformat.

00819 {
00820    struct mohdata *res;
00821    struct mohclass *class = params;
00822    struct moh_files_state *state;
00823 
00824    /* Initiating music_state for current channel. Channel should know name of moh class */
00825    if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) {
00826       chan->music_state = state;
00827       state->class = class;
00828    } else
00829       state = chan->music_state;
00830    if (state && state->class != class) {
00831       memset(state, 0, sizeof(*state));
00832       state->class = class;
00833    }
00834 
00835    if ((res = mohalloc(class))) {
00836       res->origwfmt = chan->writeformat;
00837       if (ast_set_write_format(chan, class->format)) {
00838          ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format));
00839          moh_release(NULL, res);
00840          res = NULL;
00841       }
00842       ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name);
00843    }
00844    return res;
00845 }

static int moh_class_cmp ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1655 of file res_musiconhold.c.

References CMP_MATCH, and CMP_STOP.

Referenced by load_module().

01656 {
01657    struct mohclass *class = obj, *class2 = arg;
01658 
01659    return strcasecmp(class->name, class2->name) ? 0 : CMP_MATCH | CMP_STOP;
01660 }

static void moh_class_destructor ( void *  obj  )  [static]

Definition at line 1367 of file res_musiconhold.c.

References ast_debug, AST_LIST_REMOVE_HEAD, ast_log(), AST_PTHREADT_NULL, ast_wait_for_input(), buff, free, LOG_DEBUG, and mohclass::pid.

Referenced by moh_class_malloc().

01368 {
01369    struct mohclass *class = obj;
01370    struct mohdata *member;
01371 
01372    ast_debug(1, "Destroying MOH class '%s'\n", class->name);
01373 
01374    if (class->pid > 1) {
01375       char buff[8192];
01376       int bytes, tbytes = 0, stime = 0, pid = 0;
01377 
01378       ast_log(LOG_DEBUG, "killing %d!\n", class->pid);
01379 
01380       stime = time(NULL) + 2;
01381       pid = class->pid;
01382       class->pid = 0;
01383 
01384       /* Back when this was just mpg123, SIGKILL was fine.  Now we need
01385        * to give the process a reason and time enough to kill off its
01386        * children. */
01387       killpg(pid, SIGHUP);
01388       usleep(100000);
01389       killpg(pid, SIGTERM);
01390       usleep(100000);
01391       killpg(pid, SIGKILL);
01392 
01393       while ((ast_wait_for_input(class->srcfd, 100) > 0) && 
01394             (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) {
01395          tbytes = tbytes + bytes;
01396       }
01397 
01398       ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
01399 
01400       close(class->srcfd);
01401    }
01402 
01403    while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) {
01404       free(member);
01405    }
01406 
01407    if (class->thread) {
01408       pthread_cancel(class->thread);
01409       pthread_join(class->thread, NULL);
01410       class->thread = AST_PTHREADT_NULL;
01411    }
01412 
01413    if (class->filearray) {
01414       int i;
01415       for (i = 0; i < class->total_files; i++) {
01416          free(class->filearray[i]);
01417       }
01418       free(class->filearray);
01419       class->filearray = NULL;
01420    }
01421 }

static int moh_class_hash ( const void *  obj,
const int  flags 
) [static]

Definition at line 1648 of file res_musiconhold.c.

References ast_str_case_hash().

Referenced by load_module().

01649 {
01650    const struct mohclass *class = obj;
01651 
01652    return ast_str_case_hash(class->name);
01653 }

static int moh_class_inuse ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1703 of file res_musiconhold.c.

References AST_LIST_EMPTY, CMP_MATCH, and CMP_STOP.

Referenced by unload_module().

01704 {
01705    struct mohclass *class = obj;
01706 
01707    return AST_LIST_EMPTY(&class->members) ? 0 : CMP_MATCH | CMP_STOP;
01708 }

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

Definition at line 1139 of file res_musiconhold.c.

References ao2_alloc(), AST_FORMAT_SLINEAR, mohclass::format, and moh_class_destructor().

Referenced by load_moh_classes(), and local_ast_moh_start().

01140 {
01141    struct mohclass *class;
01142 
01143    if ((class = ao2_alloc(sizeof(*class), moh_class_destructor))) {
01144       class->format = AST_FORMAT_SLINEAR;
01145    }
01146 
01147    return class;
01148 }

static int moh_class_mark ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1423 of file res_musiconhold.c.

Referenced by load_moh_classes().

01424 {
01425    struct mohclass *class = obj;
01426 
01427    class->delete = 1;
01428 
01429    return 0;
01430 }

static int moh_classes_delete_marked ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 1432 of file res_musiconhold.c.

References CMP_MATCH.

Referenced by load_moh_classes().

01433 {
01434    struct mohclass *class = obj;
01435 
01436    return class->delete ? CMP_MATCH : 0;
01437 }

static int moh_diff ( struct mohclass old,
struct mohclass new 
) [static]

Definition at line 1016 of file res_musiconhold.c.

References mohclass::args, mohclass::dir, mohclass::flags, and mohclass::mode.

Referenced by moh_register().

01017 {
01018    if (!old || !new) {
01019       return -1;
01020    }
01021 
01022    if (strcmp(old->dir, new->dir)) {
01023       return -1;
01024    } else if (strcmp(old->mode, new->mode)) {
01025       return -1;
01026    } else if (strcmp(old->args, new->args)) {
01027       return -1;
01028    } else if (old->flags != new->flags) {
01029       return -1;
01030    }
01031 
01032    return 0;
01033 }

static int moh_digit_match ( void *  obj,
void *  arg,
int  flags 
) [static]

Definition at line 343 of file res_musiconhold.c.

References CMP_MATCH, CMP_STOP, and mohclass::digit.

Referenced by get_mohbydigit().

00344 {
00345    char *digit = arg;
00346    struct mohclass *class = obj;
00347 
00348    return (*digit == class->digit) ? CMP_MATCH | CMP_STOP : 0;
00349 }

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

Definition at line 313 of file res_musiconhold.c.

References ast_calloc, ast_random(), ast_test_flag, ast_verb, moh_files_state::class, MOH_RANDOMIZE, mohclass_ref, ast_channel::music_state, ast_channel::name, moh_files_state::origwfmt, moh_files_state::pos, and ast_channel::writeformat.

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

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

Definition at line 289 of file res_musiconhold.c.

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

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

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

Definition at line 277 of file res_musiconhold.c.

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

Referenced by moh_files_generator().

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

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

Definition at line 194 of file res_musiconhold.c.

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

00195 {
00196    struct moh_files_state *state;
00197 
00198    if (!chan || !chan->music_state) {
00199       return;
00200    }
00201 
00202    state = chan->music_state;
00203 
00204    if (chan->stream) {
00205       ast_closestream(chan->stream);
00206       chan->stream = NULL;
00207    }
00208    
00209    if (option_verbose > 2) {
00210       ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
00211    }
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 
00217    state->save_pos = state->pos;
00218 
00219    mohclass_unref(state->class);
00220 }

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

Definition at line 847 of file res_musiconhold.c.

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

00848 {
00849    struct mohdata *moh = data;
00850    short buf[1280 + AST_FRIENDLY_OFFSET / 2];
00851    int res;
00852 
00853    len = ast_codec_get_len(moh->parent->format, samples);
00854 
00855    if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
00856       ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name);
00857       len = sizeof(buf) - AST_FRIENDLY_OFFSET;
00858    }
00859    res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
00860    if (res <= 0)
00861       return 0;
00862 
00863    moh->f.datalen = res;
00864    moh->f.data = buf + AST_FRIENDLY_OFFSET / 2;
00865    moh->f.samples = ast_codec_get_samples(&moh->f);
00866 
00867    if (ast_write(chan, &moh->f) < 0) {
00868       ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
00869       return -1;
00870    }
00871 
00872    return 0;
00873 }

static void moh_handle_digit ( struct ast_channel chan,
char  digit 
) [static]

Definition at line 357 of file res_musiconhold.c.

References ast_moh_start(), ast_moh_stop(), ast_strdupa, ast_string_field_set, get_mohbydigit(), mohclass_unref, and musicclass.

00358 {
00359    struct mohclass *class;
00360    const char *classname = NULL;
00361 
00362    if ((class = get_mohbydigit(digit))) {
00363       classname = ast_strdupa(class->name);
00364       class = mohclass_unref(class);
00365       ast_string_field_set(chan,musicclass,classname);
00366       ast_moh_stop(chan);
00367       ast_moh_start(chan, classname, NULL);
00368    }
00369 }

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

Note:
This function owns the reference it gets to moh

Definition at line 1081 of file res_musiconhold.c.

References ao2_link(), ast_log(), mohclass::delete, get_mohbyname(), init_app_class(), init_files_class(), LOG_WARNING, mohclass::mode, moh_diff(), mohclass_unref, mohclass::name, and mohclass::start.

Referenced by load_moh_classes(), and local_ast_moh_start().

01082 {
01083    struct mohclass *mohclass = NULL;
01084 
01085    if ((mohclass = get_mohbyname(moh->name, 0)) && !moh_diff(mohclass, moh)) {
01086       if (!mohclass->delete) {
01087          ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
01088          mohclass = mohclass_unref(mohclass);
01089          if (unref) {
01090             moh = mohclass_unref(moh);
01091          }
01092          return -1;
01093       }
01094       mohclass = mohclass_unref(mohclass);
01095    }
01096 
01097    time(&moh->start);
01098    moh->start -= respawn_time;
01099    
01100    if (!strcasecmp(moh->mode, "files")) {
01101       if (init_files_class(moh)) {
01102          moh = mohclass_unref(moh);
01103          return -1;
01104       }
01105    } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || 
01106          !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || 
01107          !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) {
01108       if (init_app_class(moh)) {
01109          moh = mohclass_unref(moh);
01110          return -1;
01111       }
01112    } else {
01113       ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
01114       moh = mohclass_unref(moh);
01115       return -1;
01116    }
01117 
01118    ao2_link(mohclasses, moh);
01119 
01120    if (unref) {
01121       moh = mohclass_unref(moh);
01122    }
01123    
01124    return 0;
01125 }

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

Definition at line 789 of file res_musiconhold.c.

References ao2_lock(), ao2_unlock(), ast_free, ast_getformatname(), AST_LIST_REMOVE, ast_log(), ast_set_write_format(), ast_verb, LOG_WARNING, mohclass::members, moh, mohclass_unref, ast_channel::name, mohdata::origwfmt, mohdata::parent, and mohdata::pipe.

Referenced by moh_alloc().

00790 {
00791    struct mohdata *moh = data;
00792    struct mohclass *class = moh->parent;
00793    int oldwfmt;
00794 
00795    ao2_lock(class);
00796    AST_LIST_REMOVE(&moh->parent->members, moh, list); 
00797    ao2_unlock(class);
00798    
00799    close(moh->pipe[0]);
00800    close(moh->pipe[1]);
00801 
00802    oldwfmt = moh->origwfmt;
00803 
00804    moh->parent = class = mohclass_unref(class);
00805 
00806    ast_free(moh);
00807 
00808    if (chan) {
00809       if (oldwfmt && ast_set_write_format(chan, oldwfmt)) {
00810          ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n",
00811                chan->name, ast_getformatname(oldwfmt));
00812       }
00813 
00814       ast_verb(3, "Stopped music on hold on %s\n", chan->name);
00815    }
00816 }

static int moh_scan_files ( struct mohclass class  )  [static]

Definition at line 915 of file res_musiconhold.c.

References ast_free, ast_log(), ast_test_flag, errno, ext, LOG_WARNING, moh_add_file(), moh_sort_compare(), and MOH_SORTALPHA.

Referenced by init_files_class(), and local_ast_moh_start().

00915                                                   {
00916 
00917    DIR *files_DIR;
00918    struct dirent *files_dirent;
00919    char path[PATH_MAX];
00920    char filepath[PATH_MAX];
00921    char *ext;
00922    struct stat statbuf;
00923    int dirnamelen;
00924    int i;
00925 
00926    files_DIR = opendir(class->dir);
00927    if (!files_DIR) {
00928       ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", class->dir);
00929       return -1;
00930    }
00931 
00932    for (i = 0; i < class->total_files; i++)
00933       ast_free(class->filearray[i]);
00934 
00935    class->total_files = 0;
00936    dirnamelen = strlen(class->dir) + 2;
00937    if (!getcwd(path, sizeof(path))) {
00938       ast_log(LOG_WARNING, "getcwd() failed: %s\n", strerror(errno));
00939       return -1;
00940    }
00941    if (chdir(class->dir) < 0) {
00942       ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
00943       return -1;
00944    }
00945    while ((files_dirent = readdir(files_DIR))) {
00946       /* The file name must be at least long enough to have the file type extension */
00947       if ((strlen(files_dirent->d_name) < 4))
00948          continue;
00949 
00950       /* Skip files that starts with a dot */
00951       if (files_dirent->d_name[0] == '.')
00952          continue;
00953 
00954       /* Skip files without extensions... they are not audio */
00955       if (!strchr(files_dirent->d_name, '.'))
00956          continue;
00957 
00958       snprintf(filepath, sizeof(filepath), "%s/%s", class->dir, files_dirent->d_name);
00959 
00960       if (stat(filepath, &statbuf))
00961          continue;
00962 
00963       if (!S_ISREG(statbuf.st_mode))
00964          continue;
00965 
00966       if ((ext = strrchr(filepath, '.')))
00967          *ext = '\0';
00968 
00969       /* if the file is present in multiple formats, ensure we only put it into the list once */
00970       for (i = 0; i < class->total_files; i++)
00971          if (!strcmp(filepath, class->filearray[i]))
00972             break;
00973 
00974       if (i == class->total_files) {
00975          if (moh_add_file(class, filepath))
00976             break;
00977       }
00978    }
00979 
00980    closedir(files_DIR);
00981    if (chdir(path) < 0) {
00982       ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
00983       return -1;
00984    }
00985    if (ast_test_flag(class, MOH_SORTALPHA))
00986       qsort(&class->filearray[0], class->total_files, sizeof(char *), moh_sort_compare);
00987    return class->total_files;
00988 }

static int moh_sort_compare ( const void *  i1,
const void *  i2 
) [static]

Definition at line 905 of file res_musiconhold.c.

Referenced by moh_scan_files().

00906 {
00907    char *s1, *s2;
00908 
00909    s1 = ((char **)i1)[0];
00910    s2 = ((char **)i2)[0];
00911 
00912    return strcasecmp(s1, s2);
00913 }

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

Definition at line 756 of file res_musiconhold.c.

References ao2_lock(), ao2_unlock(), ast_calloc, AST_FRAME_VOICE, ast_free, AST_FRIENDLY_OFFSET, AST_LIST_INSERT_HEAD, ast_log(), errno, mohdata::f, mohclass::flags, mohclass::format, ast_frame::frametype, LOG_WARNING, mohclass::members, moh, mohclass_ref, ast_frame::offset, mohdata::parent, mohdata::pipe, and ast_frame::subclass.

Referenced by moh_alloc().

00757 {
00758    struct mohdata *moh;
00759    long flags; 
00760    
00761    if (!(moh = ast_calloc(1, sizeof(*moh))))
00762       return NULL;
00763    
00764    if (pipe(moh->pipe)) {
00765       ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
00766       ast_free(moh);
00767       return NULL;
00768    }
00769 
00770    /* Make entirely non-blocking */
00771    flags = fcntl(moh->pipe[0], F_GETFL);
00772    fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
00773    flags = fcntl(moh->pipe[1], F_GETFL);
00774    fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
00775 
00776    moh->f.frametype = AST_FRAME_VOICE;
00777    moh->f.subclass = cl->format;
00778    moh->f.offset = AST_FRIENDLY_OFFSET;
00779 
00780    moh->parent = mohclass_ref(cl);
00781 
00782    ao2_lock(cl);
00783    AST_LIST_INSERT_HEAD(&cl->members, moh, list);
00784    ao2_unlock(cl);
00785    
00786    return moh;
00787 }

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

Definition at line 545 of file res_musiconhold.c.

References ao2_lock(), ao2_unlock(), ast_codec_get_len(), ast_debug, AST_LIST_EMPTY, AST_LIST_TRAVERSE, ast_log(), ast_samp2tv(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), buf, len(), LOG_NOTICE, LOG_WARNING, moh, MOH_MS_INTERVAL, mohdata::pipe, and spawn_mp3().

Referenced by init_app_class(), and local_ast_moh_start().

00546 {
00547 #define  MOH_MS_INTERVAL      100
00548 
00549    struct mohclass *class = data;
00550    struct mohdata *moh;
00551    char buf[8192];
00552    short sbuf[8192];
00553    int res, res2;
00554    int len;
00555    struct timeval tv, tv_tmp;
00556 
00557    tv.tv_sec = 0;
00558    tv.tv_usec = 0;
00559    for(;/* ever */;) {
00560       pthread_testcancel();
00561       /* Spawn mp3 player if it's not there */
00562       if (class->srcfd < 0) {
00563          if ((class->srcfd = spawn_mp3(class)) < 0) {
00564             ast_log(LOG_WARNING, "Unable to spawn mp3player\n");
00565             /* Try again later */
00566             sleep(500);
00567             pthread_testcancel();
00568          }
00569       }
00570       if (class->pseudofd > -1) {
00571 #ifdef SOLARIS
00572          thr_yield();
00573 #endif
00574          /* Pause some amount of time */
00575          res = read(class->pseudofd, buf, sizeof(buf));
00576          pthread_testcancel();
00577       } else {
00578          long delta;
00579          /* Reliable sleep */
00580          tv_tmp = ast_tvnow();
00581          if (ast_tvzero(tv))
00582             tv = tv_tmp;
00583          delta = ast_tvdiff_ms(tv_tmp, tv);
00584          if (delta < MOH_MS_INTERVAL) {   /* too early */
00585             tv = ast_tvadd(tv, ast_samp2tv(MOH_MS_INTERVAL, 1000));  /* next deadline */
00586             usleep(1000 * (MOH_MS_INTERVAL - delta));
00587             pthread_testcancel();
00588          } else {
00589             ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
00590             tv = tv_tmp;
00591          }
00592          res = 8 * MOH_MS_INTERVAL; /* 8 samples per millisecond */
00593       }
00594       if ((strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir")) && AST_LIST_EMPTY(&class->members))
00595          continue;
00596       /* Read mp3 audio */
00597       len = ast_codec_get_len(class->format, res);
00598 
00599       if ((res2 = read(class->srcfd, sbuf, len)) != len) {
00600          if (!res2) {
00601             close(class->srcfd);
00602             class->srcfd = -1;
00603             pthread_testcancel();
00604             if (class->pid > 1) {
00605                killpg(class->pid, SIGHUP);
00606                usleep(100000);
00607                killpg(class->pid, SIGTERM);
00608                usleep(100000);
00609                killpg(class->pid, SIGKILL);
00610                class->pid = 0;
00611             }
00612          } else {
00613             ast_debug(1, "Read %d bytes of audio while expecting %d\n", res2, len);
00614          }
00615          continue;
00616       }
00617 
00618       pthread_testcancel();
00619 
00620       ao2_lock(class);
00621       AST_LIST_TRAVERSE(&class->members, moh, list) {
00622          /* Write data */
00623          if ((res = write(moh->pipe[1], sbuf, res2)) != res2) {
00624             ast_debug(1, "Only wrote %d of %d bytes to pipe\n", res, res2);
00625          }
00626       }
00627       ao2_unlock(class);
00628    }
00629    return NULL;
00630 }

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

Definition at line 632 of file res_musiconhold.c.

References mohclass::args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_moh_start(), ast_moh_stop(), ast_safe_sleep(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), LOG_WARNING, ast_channel::name, parse(), and S_OR.

Referenced by load_module().

00633 {
00634    char *parse;
00635    char *class;
00636    int timeout = -1;
00637    int res;
00638    AST_DECLARE_APP_ARGS(args,
00639       AST_APP_ARG(class);
00640       AST_APP_ARG(duration);
00641    );
00642 
00643    parse = ast_strdupa(data);
00644 
00645    AST_STANDARD_APP_ARGS(args, parse);
00646 
00647    if (!ast_strlen_zero(args.duration)) {
00648       if (sscanf(args.duration, "%30d", &timeout) == 1) {
00649          timeout *= 1000;
00650       } else {
00651          ast_log(LOG_WARNING, "Invalid MusicOnHold duration '%s'. Will wait indefinitely.\n", args.duration);
00652       }
00653    }
00654 
00655    class = S_OR(args.class, NULL);
00656    if (ast_moh_start(chan, class, NULL)) {
00657       ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, chan->name);
00658       return 0;
00659    }
00660 
00661    if (timeout > 0)
00662       res = ast_safe_sleep(chan, timeout);
00663    else {
00664       while (!(res = ast_safe_sleep(chan, 10000)));
00665    }
00666 
00667    ast_moh_stop(chan);
00668 
00669    return res;
00670 }

static int reload ( void   )  [static]

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

Definition at line 695 of file res_musiconhold.c.

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

Referenced by load_module().

00696 {
00697    static int deprecation_warning = 0;
00698 
00699    if (!deprecation_warning) {
00700       deprecation_warning = 1;
00701       ast_log(LOG_WARNING, "SetMusicOnHold application is deprecated and will be removed. Use Set(CHANNEL(musicclass)=...) instead\n");
00702    }
00703 
00704    if (ast_strlen_zero(data)) {
00705       ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
00706       return -1;
00707    }
00708    ast_string_field_set(chan, musicclass, data);
00709    return 0;
00710 }

static int spawn_mp3 ( struct mohclass class  )  [static]

Definition at line 379 of file res_musiconhold.c.

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

00380 {
00381    int fds[2];
00382    int files = 0;
00383    char fns[MAX_MP3S][80];
00384    char *argv[MAX_MP3S + 50];
00385    char xargs[256];
00386    char *argptr;
00387    int argc = 0;
00388    DIR *dir = NULL;
00389    struct dirent *de;
00390    sigset_t signal_set, old_set;
00391 
00392    
00393    if (!strcasecmp(class->dir, "nodir")) {
00394       files = 1;
00395    } else {
00396       dir = opendir(class->dir);
00397       if (!dir && strncasecmp(class->dir, "http://", 7)) {
00398          ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
00399          return -1;
00400       }
00401    }
00402 
00403    if (!ast_test_flag(class, MOH_CUSTOM)) {
00404       argv[argc++] = "mpg123";
00405       argv[argc++] = "-q";
00406       argv[argc++] = "-s";
00407       argv[argc++] = "--mono";
00408       argv[argc++] = "-r";
00409       argv[argc++] = "8000";
00410       
00411       if (!ast_test_flag(class, MOH_SINGLE)) {
00412          argv[argc++] = "-b";
00413          argv[argc++] = "2048";
00414       }
00415       
00416       argv[argc++] = "-f";
00417       
00418       if (ast_test_flag(class, MOH_QUIET))
00419          argv[argc++] = "4096";
00420       else
00421          argv[argc++] = "8192";
00422       
00423       /* Look for extra arguments and add them to the list */
00424       ast_copy_string(xargs, class->args, sizeof(xargs));
00425       argptr = xargs;
00426       while (!ast_strlen_zero(argptr)) {
00427          argv[argc++] = argptr;
00428          strsep(&argptr, ",");
00429       }
00430    } else  {
00431       /* Format arguments for argv vector */
00432       ast_copy_string(xargs, class->args, sizeof(xargs));
00433       argptr = xargs;
00434       while (!ast_strlen_zero(argptr)) {
00435          argv[argc++] = argptr;
00436          strsep(&argptr, " ");
00437       }
00438    }
00439 
00440    if (!strncasecmp(class->dir, "http://", 7)) {
00441       ast_copy_string(fns[files], class->dir, sizeof(fns[files]));
00442       argv[argc++] = fns[files];
00443       files++;
00444    } else if (dir) {
00445       while ((de = readdir(dir)) && (files < MAX_MP3S)) {
00446          if ((strlen(de->d_name) > 3) && 
00447              ((ast_test_flag(class, MOH_CUSTOM) && 
00448                (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 
00449                 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) ||
00450               !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
00451             ast_copy_string(fns[files], de->d_name, sizeof(fns[files]));
00452             argv[argc++] = fns[files];
00453             files++;
00454          }
00455       }
00456    }
00457    argv[argc] = NULL;
00458    if (dir) {
00459       closedir(dir);
00460    }
00461    if (pipe(fds)) {  
00462       ast_log(LOG_WARNING, "Pipe failed\n");
00463       return -1;
00464    }
00465    if (!files) {
00466       ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
00467       close(fds[0]);
00468       close(fds[1]);
00469       return -1;
00470    }
00471    if (!strncasecmp(class->dir, "http://", 7) && time(NULL) - class->start < respawn_time) {
00472       sleep(respawn_time - (time(NULL) - class->start));
00473    }
00474 
00475    /* Block signals during the fork() */
00476    sigfillset(&signal_set);
00477    pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
00478 
00479    time(&class->start);
00480    class->pid = fork();
00481    if (class->pid < 0) {
00482       close(fds[0]);
00483       close(fds[1]);
00484       ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
00485       return -1;
00486    }
00487    if (!class->pid) {
00488       /* Child */
00489       int x;
00490 #ifdef HAVE_CAP
00491       cap_t cap;
00492 #endif
00493       if (strcasecmp(class->dir, "nodir") && chdir(class->dir) < 0) {
00494          ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
00495          _exit(1);
00496       }
00497 
00498       if (ast_opt_high_priority)
00499          ast_set_priority(0);
00500 
00501       /* Reset ignored signals back to default */
00502       signal(SIGPIPE, SIG_DFL);
00503       pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
00504 
00505 #ifdef HAVE_CAP
00506       cap = cap_from_text("cap_net_admin-eip");
00507 
00508       if (cap_set_proc(cap)) {
00509          ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
00510       }
00511       cap_free(cap);
00512 #endif
00513       close(fds[0]);
00514       /* Stdout goes to pipe */
00515       dup2(fds[1], STDOUT_FILENO);
00516       /* Close unused file descriptors */
00517       for (x=3;x<8192;x++) {
00518          if (-1 != fcntl(x, F_GETFL)) {
00519             close(x);
00520          }
00521       }
00522       setpgid(0, getpid());
00523 
00524       if (ast_test_flag(class, MOH_CUSTOM)) {
00525          execv(argv[0], argv);
00526       } else {
00527          /* Default install is /usr/local/bin */
00528          execv(LOCAL_MPG_123, argv);
00529          /* Many places have it in /usr/bin */
00530          execv(MPG_123, argv);
00531          /* Check PATH as a last-ditch effort */
00532          execvp("mpg123", argv);
00533       }
00534       ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
00535       close(fds[1]);
00536       _exit(1);
00537    } else {
00538       /* Parent */
00539       pthread_sigmask(SIG_SETMASK, &old_set, NULL);
00540       close(fds[1]);
00541    }
00542    return fds[0];
00543 }

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

Definition at line 712 of file res_musiconhold.c.

References mohclass::args, AST_APP_ARG, AST_DECLARE_APP_ARGS, ast_log(), ast_moh_start(), AST_STANDARD_APP_ARGS, ast_strdupa, LOG_WARNING, ast_channel::name, parse(), and S_OR.

Referenced by load_module().

00713 {
00714    char *parse;
00715    char *class;
00716    AST_DECLARE_APP_ARGS(args,
00717       AST_APP_ARG(class);
00718    );
00719 
00720    parse = ast_strdupa(data);
00721 
00722    AST_STANDARD_APP_ARGS(args, parse);
00723 
00724    class = S_OR(args.class, NULL);
00725    if (ast_moh_start(chan, class, NULL)) 
00726       ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, chan->name);
00727 
00728    return 0;
00729 }

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

Definition at line 731 of file res_musiconhold.c.

References ast_moh_stop().

Referenced by load_module().

00732 {
00733    ast_moh_stop(chan);
00734 
00735    return 0;
00736 }

static int unload_module ( void   )  [static]

Definition at line 1710 of file res_musiconhold.c.

References ao2_callback(), ast_cli_unregister_multiple(), ast_log(), ast_moh_destroy(), ast_uninstall_music_functions(), ast_unregister_application(), LOG_WARNING, moh_class_inuse(), and mohclass_unref.

01711 {
01712    int res = 0;
01713    struct mohclass *class = NULL;
01714 
01715    /* XXX This check shouldn't be required if module ref counting was being used
01716     * properly ... */
01717    if ((class = ao2_callback(mohclasses, 0, moh_class_inuse, NULL))) {
01718       class = mohclass_unref(class);
01719       res = -1;
01720    }
01721 
01722    if (res < 0) {
01723       ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n");
01724       return res;
01725    }
01726 
01727    ast_uninstall_music_functions();
01728 
01729    ast_moh_destroy();
01730    res = ast_unregister_application(play_moh);
01731    res |= ast_unregister_application(wait_moh);
01732    res |= ast_unregister_application(set_moh);
01733    res |= ast_unregister_application(start_moh);
01734    res |= ast_unregister_application(stop_moh);
01735    ast_cli_unregister_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry));
01736 
01737    return res;
01738 }

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

Definition at line 672 of file res_musiconhold.c.

References ast_log(), ast_moh_start(), ast_moh_stop(), ast_safe_sleep(), LOG_WARNING, and ast_channel::name.

Referenced by load_module().

00673 {
00674    static int deprecation_warning = 0;
00675    int res;
00676 
00677    if (!deprecation_warning) {
00678       deprecation_warning = 1;
00679       ast_log(LOG_WARNING, "WaitMusicOnHold application is deprecated and will be removed. Use MusicOnHold with duration parameter instead\n");
00680    }
00681 
00682    if (!data || !atoi(data)) {
00683       ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
00684       return -1;
00685    }
00686    if (ast_moh_start(chan, NULL, NULL)) {
00687       ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name);
00688       return 0;
00689    }
00690    res = ast_safe_sleep(chan, atoi(data) * 1000);
00691    ast_moh_stop(chan);
00692    return res;
00693 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Music On Hold Resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 1744 of file res_musiconhold.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1744 of file res_musiconhold.c.

struct ast_cli_entry cli_moh[] [static]

Initial value:

 {
   AST_CLI_DEFINE(handle_cli_moh_reload,       "Reload MusicOnHold"),
   AST_CLI_DEFINE(handle_cli_moh_show_classes, "List MusicOnHold classes"),
   AST_CLI_DEFINE(handle_cli_moh_show_files,   "List MusicOnHold file-based classes")
}

Definition at line 1642 of file res_musiconhold.c.

struct ast_flags global_flags[1] = {{0}} [static]

global MOH_ flags

Definition at line 143 of file res_musiconhold.c.

struct ast_generator moh_file_stream [static]

Definition at line 371 of file res_musiconhold.c.

struct ao2_container* mohclasses [static]

Definition at line 183 of file res_musiconhold.c.

struct ast_generator mohgen [static]

Definition at line 875 of file res_musiconhold.c.

char* play_moh = "MusicOnHold" [static]

Definition at line 75 of file res_musiconhold.c.

char* play_moh_desc [static]

Definition at line 87 of file res_musiconhold.c.

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

Definition at line 81 of file res_musiconhold.c.

int respawn_time = 20 [static]

Definition at line 123 of file res_musiconhold.c.

char* set_moh = "SetMusicOnHold" [static]

Definition at line 77 of file res_musiconhold.c.

char* set_moh_desc [static]

Definition at line 105 of file res_musiconhold.c.

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

Definition at line 83 of file res_musiconhold.c.

char* start_moh = "StartMusicOnHold" [static]

Definition at line 78 of file res_musiconhold.c.

char* start_moh_desc [static]

Initial value:

 "  StartMusicOnHold(class):\n"
"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 115 of file res_musiconhold.c.

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

Definition at line 84 of file res_musiconhold.c.

char* stop_moh = "StopMusicOnHold" [static]

Definition at line 79 of file res_musiconhold.c.

char* stop_moh_desc [static]

Initial value:

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

Definition at line 120 of file res_musiconhold.c.

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

Definition at line 85 of file res_musiconhold.c.

char* wait_moh = "WaitMusicOnHold" [static]

Definition at line 76 of file res_musiconhold.c.

char* wait_moh_desc [static]

Definition at line 95 of file res_musiconhold.c.

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

Definition at line 82 of file res_musiconhold.c.


Generated on Wed Oct 28 11:46:18 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6