Thu Jul 9 13:41:30 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 <dahdi/user.h>
#include <sys/capability.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"

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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, }
static const struct ast_module_infoast_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)

Definition at line 137 of file res_musiconhold.c.

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

#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)

Definition at line 138 of file res_musiconhold.c.

Referenced by ast_moh_files_next(), init_files_class(), load_moh_classes(), local_ast_moh_start(), and moh_files_alloc().

#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(), and local_ast_moh_start().

#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)

Definition at line 192 of file res_musiconhold.c.

Referenced by handle_cli_moh_show_classes(), handle_cli_moh_show_files(), local_ast_moh_start(), moh_files_release(), moh_handle_digit(), moh_register(), moh_release(), and unload_module().

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

static void __unreg_module ( void   )  [static]

Definition at line 1741 of file res_musiconhold.c.

static void ast_moh_destroy ( void   )  [static]

Definition at line 1537 of file res_musiconhold.c.

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

Referenced by load_module(), and unload_module().

01538 {
01539    ast_verb(2, "Destroying musiconhold processes\n");
01540    ao2_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL);
01541 }

static int ast_moh_files_next ( struct ast_channel chan  )  [static]

Definition at line 222 of file res_musiconhold.c.

References ast_closestream(), ast_fileexists(), ast_log(), ast_openstream_full(), ast_random(), ast_test_flag, chan, moh_files_state::class, errno, mohclass::filearray, ast_channel::language, 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().

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]

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]

Definition at line 742 of file res_musiconhold.c.

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

Referenced by local_ast_moh_start(), and moh_register().

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

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

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

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

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

Definition at line 1603 of file res_musiconhold.c.

References 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, mohclasses, S_OR, and ast_cli_entry::usage.

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

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

Definition at line 1565 of file res_musiconhold.c.

References 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, mohclasses, and ast_cli_entry::usage.

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

static int init_app_class ( struct mohclass class  )  [static]

Definition at line 1039 of file res_musiconhold.c.

References ast_log(), ast_pthread_create_background, ast_set_flag, LOG_WARNING, mohclass::mode, MOH_CUSTOM, MOH_QUIET, MOH_SINGLE, monmp3thread(), mohclass::pseudofd, and mohclass::thread.

Referenced by moh_register().

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

static int init_files_class ( struct mohclass class  )  [static]

Definition at line 994 of file res_musiconhold.c.

References mohclass::args, ast_set_flag, ast_verbose(), mohclass::dir, MOH_RANDOMIZE, moh_scan_files(), mohclass::name, option_verbose, and VERBOSE_PREFIX_3.

Referenced by moh_register().

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

static int load_module ( void   )  [static]

Definition at line 1659 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(), cli_moh, load_moh_classes(), local_ast_moh_cleanup(), local_ast_moh_start(), local_ast_moh_stop(), LOG_WARNING, moh_class_cmp(), moh_class_hash(), mohclasses, play_moh_exec(), set_moh_exec(), start_moh_exec(), stop_moh_exec(), and wait_moh_exec().

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

static int load_moh_classes ( int  reload  )  [static]

Definition at line 1436 of file res_musiconhold.c.

References ao2_callback(), ast_category_browse(), ast_clear_flag, ast_config_load, ast_copy_string(), AST_FLAGS_ALL, AST_FORMAT_SLINEAR, ast_getformatbyname(), ast_log(), ast_set2_flag, ast_set_flag, ast_true(), ast_variable_browse(), CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEUNCHANGED, global_flags, LOG_WARNING, MOH_CACHERTCLASSES, moh_class_malloc(), moh_class_mark(), MOH_RANDOMIZE, MOH_SORTALPHA, mohclasses, OBJ_NODATA, and var.

Referenced by load_module().

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

static void local_ast_moh_cleanup ( struct ast_channel chan  )  [static]

Definition at line 1131 of file res_musiconhold.c.

References ast_free, chan, and ast_channel::music_state.

Referenced by load_module().

01132 {
01133    struct moh_files_state *state = chan->music_state;
01134 
01135    if (state) {
01136       ast_free(chan->music_state);
01137       chan->music_state = NULL;
01138    }
01139 }

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

Definition at line 1154 of file res_musiconhold.c.

References mohclass::args, ast_check_realtime(), ast_copy_string(), 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(), chan, moh_files_state::class, mohclass::digit, mohclass::dir, mohclass::format, get_mohbyname(), global_flags, 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, mohclass::pseudofd, mohclass::realtime, mohclass::srcfd, mohclass::start, mohclass::thread, and var.

Referenced by load_module().

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

static void local_ast_moh_stop ( struct ast_channel chan  )  [static]

Definition at line 1350 of file res_musiconhold.c.

References ast_clear_flag, ast_closestream(), ast_deactivate_generator(), AST_FLAG_MOH, chan, ast_channel::music_state, and ast_channel::stream.

Referenced by load_module().

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

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

Definition at line 886 of file res_musiconhold.c.

References mohclass::allowed_files, ast_calloc, ast_realloc, ast_strdup, mohclass::filearray, INITIAL_NUM_FILES, and mohclass::total_files.

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

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

Definition at line 822 of file res_musiconhold.c.

References ast_calloc, ast_codec2str(), ast_log(), ast_set_write_format(), ast_verb, chan, 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.

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

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

Definition at line 1652 of file res_musiconhold.c.

References CMP_MATCH, and CMP_STOP.

Referenced by load_module().

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

static void moh_class_destructor ( void *  obj  )  [static]

Definition at line 1364 of file res_musiconhold.c.

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

Referenced by moh_class_malloc().

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

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

Definition at line 1645 of file res_musiconhold.c.

References ast_str_case_hash().

Referenced by load_module().

01646 {
01647    const struct mohclass *class = obj;
01648 
01649    return ast_str_case_hash(class->name);
01650 }

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

Definition at line 1700 of file res_musiconhold.c.

References AST_LIST_EMPTY, CMP_MATCH, and CMP_STOP.

Referenced by unload_module().

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

static struct mohclass* moh_class_malloc ( void   )  [static]

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

01144 {
01145    struct mohclass *class;
01146 
01147    if ((class = ao2_alloc(sizeof(*class), moh_class_destructor))) {
01148       class->format = AST_FORMAT_SLINEAR;
01149    }
01150 
01151    return class;
01152 }

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

Definition at line 1420 of file res_musiconhold.c.

Referenced by load_moh_classes().

01421 {
01422    struct mohclass *class = obj;
01423 
01424    class->delete = 1;
01425 
01426    return 0;
01427 }

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

Definition at line 1429 of file res_musiconhold.c.

References CMP_MATCH.

01430 {
01431    struct mohclass *class = obj;
01432 
01433    return class->delete ? CMP_MATCH : 0;
01434 }

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

Definition at line 1020 of file res_musiconhold.c.

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

Referenced by moh_register().

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

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, chan, MOH_RANDOMIZE, mohclass_ref, ast_channel::music_state, ast_channel::name, 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(), chan, errno, f, LOG_WARNING, moh_files_readframe(), ast_channel::music_state, ast_channel::name, moh_files_state::sample_queue, 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]

Definition at line 277 of file res_musiconhold.c.

References ast_moh_files_next(), ast_readframe(), chan, 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(), chan, 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 851 of file res_musiconhold.c.

References ast_codec_get_len(), ast_codec_get_samples(), AST_FRIENDLY_OFFSET, ast_log(), ast_write(), buf, chan, errno, LOG_WARNING, moh, and ast_channel::name.

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

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, chan, get_mohbydigit(), and mohclass_unref.

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    }
00366 
00367    if (!class) {
00368       return;
00369    }
00370 
00371    ast_moh_stop(chan);
00372    ast_moh_start(chan, classname, NULL);
00373 }

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

References ao2_link(), ast_log(), mohclass::delete, get_mohbyname(), init_app_class(), init_files_class(), LOG_WARNING, moh, moh_diff(), mohclass_unref, and mohclasses.

Referenced by local_ast_moh_start().

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

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

Definition at line 793 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, chan, LOG_WARNING, moh, mohclass_unref, and ast_channel::name.

Referenced by moh_alloc().

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

static int moh_scan_files ( struct mohclass class  )  [static]

Definition at line 919 of file res_musiconhold.c.

References ast_free, ast_log(), mohclass::dir, errno, ext, mohclass::filearray, LOG_WARNING, and mohclass::total_files.

Referenced by init_files_class(), and local_ast_moh_start().

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

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

Definition at line 909 of file res_musiconhold.c.

00910 {
00911    char *s1, *s2;
00912 
00913    s1 = ((char **)i1)[0];
00914    s2 = ((char **)i2)[0];
00915 
00916    return strcasecmp(s1, s2);
00917 }

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

Definition at line 760 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, mohclass::format, LOG_WARNING, mohclass::members, moh, mohclass_ref, and mohdata::pipe.

Referenced by moh_alloc().

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

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

Definition at line 549 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(), mohclass::list, LOG_NOTICE, LOG_WARNING, moh, MOH_MS_INTERVAL, and spawn_mp3().

Referenced by init_app_class(), and local_ast_moh_start().

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

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

Definition at line 636 of file res_musiconhold.c.

References 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(), chan, LOG_WARNING, ast_channel::name, parse(), and S_OR.

Referenced by load_module().

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

static int reload ( void   )  [static]

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

Definition at line 699 of file res_musiconhold.c.

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

Referenced by load_module().

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

static int spawn_mp3 ( struct mohclass class  )  [static]

Definition at line 383 of file res_musiconhold.c.

References mohclass::args, 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, mohclass::pid, mohclass::start, and strsep().

Referenced by monmp3thread().

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

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

Definition at line 716 of file res_musiconhold.c.

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

Referenced by load_module().

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

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

Definition at line 735 of file res_musiconhold.c.

References ast_moh_stop(), and chan.

Referenced by load_module().

00736 {
00737    ast_moh_stop(chan);
00738 
00739    return 0;
00740 }

static int unload_module ( void   )  [static]

Definition at line 1707 of file res_musiconhold.c.

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

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

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

Definition at line 676 of file res_musiconhold.c.

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

Referenced by load_module().

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


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 = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 1741 of file res_musiconhold.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 1741 of file res_musiconhold.c.

struct ast_cli_entry cli_moh[] [static]

Initial value:

 {
   { .handler =  handle_cli_moh_reload , .summary =  "Reload MusicOnHold" ,__VA_ARGS__ },
   { .handler =  handle_cli_moh_show_classes , .summary =  "List MusicOnHold classes" ,__VA_ARGS__ },
   { .handler =  handle_cli_moh_show_files , .summary =  "List MusicOnHold file-based classes" ,__VA_ARGS__ }
}

Definition at line 1639 of file res_musiconhold.c.

Referenced by load_module(), and unload_module().

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

struct ao2_container* mohclasses [static]

Definition at line 183 of file res_musiconhold.c.

Referenced by ast_moh_destroy(), get_mohbyname(), handle_cli_moh_show_classes(), handle_cli_moh_show_files(), load_module(), load_moh_classes(), moh_register(), and unload_module().

struct ast_generator mohgen [static]

Definition at line 879 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 Thu Jul 9 13:41:30 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7