Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:49:15 2009

## Asterisk developer's documentation

# res_musiconhold.c File Reference

Routines implementing music on hold. More...

`#include <stdlib.h>`
`#include <errno.h>`
`#include <unistd.h>`
`#include <string.h>`
`#include <signal.h>`
`#include <stdio.h>`
`#include <sys/time.h>`
`#include <sys/signal.h>`
`#include <netinet/in.h>`
`#include <sys/stat.h>`
`#include <dirent.h>`
`#include <sys/ioctl.h>`
`#include "asterisk.h"`
`#include "asterisk/lock.h"`
`#include "asterisk/file.h"`
`#include "asterisk/logger.h"`
`#include "asterisk/channel.h"`
`#include "asterisk/pbx.h"`
`#include "asterisk/options.h"`
`#include "asterisk/module.h"`
`#include "asterisk/translate.h"`
`#include "asterisk/say.h"`
`#include "asterisk/musiconhold.h"`
`#include "asterisk/config.h"`
`#include "asterisk/utils.h"`
`#include "asterisk/cli.h"`

Include 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 | LOCAL_MPG_123 "/usr/local/bin/mpg123"
#define | MAX_MOHFILE_LEN 128
#define | MAX_MOHFILES 512
#define | MAX_MP3S 256
#define | MOH_CUSTOM (1 << 2)
#define | MOH_MS_INTERVAL 100
#define | MOH_QUIET (1 << 0)
#define | MOH_RANDOMIZE (1 << 3)
#define | MOH_SINGLE (1 << 1)
#define | MPG_123 "/usr/bin/mpg123"

## Functions

static void | ast_moh_destroy (void)
static int | ast_moh_files_next (struct ast_channel *chan)
static void | ast_moh_free_class (struct mohclass **class)
| AST_MUTEX_DEFINE_STATIC (moh_lock)
static int | cli_files_show (int fd, int argc, char *argv[])
char * | description (void)
| Provides a description of the module.
static struct mohclass * | get_mohbyname (char *name, int warn)
static int | init_classes (int reload)
char * | key ()
| Returns the ASTERISK_GPL_KEY.
int | load_module (void)
| Initialize the module.
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, char *class)
static void | local_ast_moh_stop (struct ast_channel *chan)
static int | moh0_exec (struct ast_channel *chan, void *data)
static int | moh1_exec (struct ast_channel *chan, void *data)
static int | moh2_exec (struct ast_channel *chan, void *data)
static int | moh3_exec (struct ast_channel *chan, void *data)
static int | moh4_exec (struct ast_channel *chan, void *data)
static void * | moh_alloc (struct ast_channel *chan, void *params)
static struct mohclass * | moh_class_malloc (void)
static int | moh_classes_show (int fd, int argc, char *argv[])
static int | moh_cli (int fd, int argc, char *argv[])
static void * | moh_files_alloc (struct ast_channel *chan, void *params)
static int | moh_files_generator (struct ast_channel *chan, void *data, int len, int samples)
static struct ast_frame * | moh_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_on_off (int on)
static int | moh_register (struct mohclass *moh, int reload)
static void | moh_release (struct ast_channel *chan, void *data)
static int | moh_scan_files (struct mohclass *class)
static struct mohdata * | mohalloc (struct mohclass *cl)
static void * | monmp3thread (void *data)
int | reload (void)
| Reload stuff.
static int | spawn_mp3 (struct mohclass *class)
int | unload_module (void)
| Cleanup all module structures, sockets, etc.
int | usecount (void)
| Provides a usecount.

## Variables

static char * | app0 = "MusicOnHold"
static char * | app1 = "WaitMusicOnHold"
static char * | app2 = "SetMusicOnHold"
static char * | app3 = "StartMusicOnHold"
static char * | app4 = "StopMusicOnHold"
static struct ast_cli_entry | cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL}
static struct ast_cli_entry | cli_moh_classes_show = { { "moh", "classes", "show"}, moh_classes_show, "List MOH classes", "Lists all MOH classes", NULL}
static struct ast_cli_entry | cli_moh_files_show = { { "moh", "files", "show"}, cli_files_show, "List MOH file-based classes", "Lists all loaded file-based MOH classes and their files", NULL}
static char * | descrip0
static char * | descrip1
static char * | descrip2
static char * | descrip3
static char * | descrip4
static struct ast_generator | moh_file_stream
static struct mohclass * | mohclasses
static struct ast_generator | mohgen
static int | respawn_time = 20
static char * | synopsis0 = "Play Music On Hold indefinitely"
static char * | synopsis1 = "Wait, playing Music On Hold"
static char * | synopsis2 = "Set default Music On Hold class"
static char * | synopsis3 = "Play Music On Hold"
static char * | synopsis4 = "Stop Playing Music On Hold"

## Detailed Description

Routines implementing music on hold.

- See also Music on Hold Configuration

Definition in file res_musiconhold.c.

## Define Documentation

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

Definition at line 157 of file res_musiconhold.c.

#define MAX_MOHFILE_LEN 128

Definition at line 71 of file res_musiconhold.c.

Referenced by moh_scan_files().

#define MAX_MOHFILES 512

Definition at line 70 of file res_musiconhold.c.

Referenced by moh_scan_files().

#define MAX_MP3S 256

Definition at line 159 of file res_musiconhold.c.

Referenced by spawn_mp3().

#define MOH_CUSTOM (1 << 2)

Definition at line 123 of file res_musiconhold.c.

Referenced by moh_classes_show(), moh_register(), and spawn_mp3().

#define MOH_MS_INTERVAL 100

Referenced by monmp3thread().

#define MOH_QUIET (1 << 0)

Definition at line 121 of file res_musiconhold.c.

Referenced by moh_register(), and spawn_mp3().

#define MOH_RANDOMIZE (1 << 3)

Definition at line 124 of file res_musiconhold.c.

Referenced by ast_moh_files_next(), load_moh_classes(), moh_files_alloc(), and moh_register().

#define MOH_SINGLE (1 << 1)

Definition at line 122 of file res_musiconhold.c.

Referenced by moh_register(), and spawn_mp3().

#define MPG_123 "/usr/bin/mpg123"

Definition at line 158 of file res_musiconhold.c.

## Function Documentation

static void ast_moh_destroy | ( | void |  | ) | `[static]`

Definition at line 1103 of file res_musiconhold.c.

References ast_log(), ast_moh_free_class(), ast_mutex_lock(), ast_mutex_unlock(), ast_verbose(), ast_wait_for_input(), LOG_DEBUG, moh, mohclass::next, option_verbose, mohclass::pid, mohclass::srcfd, and VERBOSE_PREFIX_2.

Referenced by load_module(), and moh_cli().

    01104 {
    01105    struct mohclass *moh, *tmp;
    01106    char buff[8192];
    01107    int bytes, tbytes=0, stime = 0, pid = 0;
    01108
    01109    if (option_verbose > 1)
    01110       ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
    01111    ast_mutex_lock(&moh_lock);
    01112    moh = mohclasses;
    01113
    01114    while (moh) {
    01115       if (moh->pid) {
    01116          ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
    01117          stime = time(NULL) + 2;
    01118          pid = moh->pid;
    01119          moh->pid = 0;
    01120          /* Back when this was just mpg123, SIGKILL was fine.  Now we need
    01121           * to give the process a reason and time enough to kill off its
    01122           * children. */
    01123          kill(pid, SIGHUP);
    01124          usleep(100000);
    01125          kill(pid, SIGTERM);
    01126          usleep(100000);
    01127          kill(pid, SIGKILL);
    01128          while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime) {
    01129             tbytes = tbytes + bytes;
    01130          }
    01131          ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
    01132          close(moh->srcfd);
    01133       }
    01134       tmp = moh;
    01135       moh = moh->next;
    01136       ast_moh_free_class(&tmp);
    01137    }
    01138    mohclasses = NULL;
    01139    ast_mutex_unlock(&moh_lock);
    01140 }

static int ast_moh_files_next | ( | struct ast_channel * | chan | ) | `[static]`

Definition at line 201 of file res_musiconhold.c.

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

Referenced by moh_files_readframe().

    00202 {
    00203    struct moh_files_state *state = chan->music_state;
    00204    int tries;
    00205
    00206    /* Discontinue a stream if it is running already */
    00207    if (chan->stream) {
    00208       ast_closestream(chan->stream);
    00209       chan->stream = NULL;
    00210    }
    00211
    00212    /* If a specific file has been saved, use it */
    00213    if (state->save_pos) {
    00214       state->pos = state->save_pos;
    00215       state->save_pos = 0;
    00216    } else if (ast_test_flag(state->class, MOH_RANDOMIZE)) {
    00217       /* Get a random file and ensure we can open it */
    00218       for (tries = 0; tries < 20; tries++) {
    00219          state->pos = rand() % state->class->total_files;
    00220          if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0)
    00221             break;
    00222       }
    00223       state->samples = 0;
    00224    } else {
    00225       /* This is easy, just increment our position and make sure we don't exceed the total file count */
    00226       state->pos++;
    00227       state->pos %= state->class->total_files;
    00228       state->samples = 0;
    00229    }
    00230
    00231    if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
    00232       ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
    00233       state->pos++;
    00234       state->pos %= state->class->total_files;
    00235       return -1;
    00236    }
    00237
    00238    if (option_debug)
    00239       ast_log(LOG_DEBUG, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]);
    00240
    00241    if (state->samples)
    00242       ast_seekstream(chan->stream, state->samples, SEEK_SET);
    00243
    00244    return 0;
    00245 }

static void ast_moh_free_class | ( | struct mohclass ** | class | ) | `[static]`

Definition at line 162 of file res_musiconhold.c.

References free, and mohdata::next.

Referenced by ast_moh_destroy(), and moh_register().

    00163 {
    00164    struct mohdata *members, *mtmp;
    00165
    00166    members = (*class)->members;
    00167    while(members) {
    00168       mtmp = members;
    00169       members = members->next;
    00170       free(mtmp);
    00171    }
    00172    if ((*class)->thread) {
    00173       pthread_cancel((*class)->thread);
    00174       (*class)->thread = 0;
    00175    }
    00176    free(*class);
    00177    *class = NULL;
    00178 }

AST_MUTEX_DEFINE_STATIC | ( | moh_lock |  | ) |

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

Definition at line 1169 of file res_musiconhold.c.

References ast_cli(), ast_mutex_lock(), and ast_mutex_unlock().

    01170 {
    01171    int i;
    01172    struct mohclass *class;
    01173
    01174    ast_mutex_lock(&moh_lock);
    01175    for (class = mohclasses; class; class = class->next) {
    01176       if (!class->total_files)
    01177          continue;
    01178
    01179       ast_cli(fd, "Class: %s\n", class->name);
    01180       for (i = 0; i < class->total_files; i++)
    01181          ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
    01182    }
    01183    ast_mutex_unlock(&moh_lock);
    01184
    01185    return 0;
    01186 }

char* description | ( | void |  | ) |

Provides a description of the module.

Returns:
  a short description of your module

Definition at line 1267 of file res_musiconhold.c.

    01268 {
    01269    return "Music On Hold Resource";
    01270 }

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

Definition at line 630 of file res_musiconhold.c.

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

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

    00631 {
    00632    struct mohclass *moh;
    00633    moh = mohclasses;
    00634    while (moh) {
    00635       if (!strcasecmp(name, moh->name))
    00636          return moh;
    00637       moh = moh->next;
    00638    }
    00639    if (warn)
    00640       ast_log(LOG_WARNING, "Music on Hold class '%s' not found\n", name);
    00641    return NULL;
    00642 }

static int init_classes | ( | int | reload | ) | `[static]`

Definition at line 1212 of file res_musiconhold.c.

References load_moh_classes(), moh, moh_scan_files(), mohclass::next, and mohclass::total_files.

Referenced by load_module(), and reload().

    01213 {
    01214    struct mohclass *moh;
    01215
    01216    if (!load_moh_classes(reload))      /* Load classes from config */
    01217       return 0;         /* Return if nothing is found */
    01218    moh = mohclasses;
    01219    while (moh) {
    01220       if (moh->total_files)
    01221          moh_scan_files(moh);
    01222       moh = moh->next;
    01223    }
    01224    return 1;
    01225 }

char* key | ( | void |  | ) |

Returns the ASTERISK_GPL_KEY.

This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:

     char *key(void) {
             return ASTERISK_GPL_KEY;
     }

Returns:
  ASTERISK_GPL_KEY

Definition at line 1285 of file res_musiconhold.c.

References ASTERISK_GPL_KEY.

    01286 {
    01287    return ASTERISK_GPL_KEY;
    01288 }

int load_module | ( | void |  | ) |

Initialize the module.

This function is called at module load time. Put all code in here that needs to set up your module's hardware, software, registrations, etc.

Returns:
  This function should return 0 on success and non-zero on failure. If the module is not loaded successfully, Asterisk will call its unload_module() function.

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.

Returns:
  int Always 0.

TE STUFF END

Definition at line 1227 of file res_musiconhold.c.

References ast_cli_register(), ast_install_music_functions(), ast_log(), ast_moh_destroy(), ast_register_application(), ast_register_atexit(), init_classes(), local_ast_moh_cleanup(), local_ast_moh_start(), local_ast_moh_stop(), LOG_WARNING, moh0_exec(), moh1_exec(), moh2_exec(), moh3_exec(), and moh4_exec().

    01228 {
    01229    int res;
    01230
    01231    res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
    01232    ast_register_atexit(ast_moh_destroy);
    01233    ast_cli_register(&cli_moh);
    01234    ast_cli_register(&cli_moh_files_show);
    01235    ast_cli_register(&cli_moh_classes_show);
    01236    if (!res)
    01237       res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
    01238    if (!res)
    01239       res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
    01240    if (!res)
    01241       res = ast_register_application(app3, moh3_exec, synopsis3, descrip3);
    01242    if (!res)
    01243       res = ast_register_application(app4, moh4_exec, synopsis4, descrip4);
    01244
    01245    if (!init_classes(0)) {    /* No music classes configured, so skip it */
    01246       ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold.\n");
    01247    } else {
    01248       ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
    01249    }
    01250
    01251    return 0;
    01252 }

static int load_moh_classes | ( | int | reload | ) | `[static]`

Definition at line 965 of file res_musiconhold.c.

References mohclass::args, ast_category_browse(), ast_config_destroy(), ast_config_load(), AST_FORMAT_SLINEAR, ast_getformatbyname(), ast_log(), ast_set2_flag, ast_strlen_zero(), ast_true(), ast_variable_browse(), cfg, dep_warning, free, get_mohbyname(), LOG_WARNING, moh_class_malloc(), MOH_RANDOMIZE, moh_register(), ast_variable::name, ast_variable::next, ast_variable::value, and var.

Referenced by init_classes(), and moh_cli().

    00966 {
    00967    struct ast_config *cfg;
    00968    struct ast_variable *var;
    00969    struct mohclass *class;
    00970    char *data;
    00971    char *args;
    00972    char *cat;
    00973    int numclasses = 0;
    00974    static int dep_warning = 0;
    00975
    00976    cfg = ast_config_load("musiconhold.conf");
    00977
    00978    if (!cfg)
    00979       return 0;
    00980
    00981    cat = ast_category_browse(cfg, NULL);
    00982    for (; cat; cat = ast_category_browse(cfg, cat)) {
    00983       if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) {
    00984          class = moh_class_malloc();
    00985          if (!class) {
    00986             ast_log(LOG_WARNING, "Out of memory!\n");
    00987             break;
    00988          }
    00989          ast_copy_string(class->name, cat, sizeof(class->name));
    00990          var = ast_variable_browse(cfg, cat);
    00991          while (var) {
    00992             if (!strcasecmp(var->name, "mode"))
    00993                ast_copy_string(class->mode, var->value, sizeof(class->mode));
    00994             else if (!strcasecmp(var->name, "directory"))
    00995                ast_copy_string(class->dir, var->value, sizeof(class->dir));
    00996             else if (!strcasecmp(var->name, "application"))
    00997                ast_copy_string(class->args, var->value, sizeof(class->args));
    00998             else if (!strcasecmp(var->name, "random"))
    00999                ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
    01000             else if (!strcasecmp(var->name, "format")) {
    01001                class->format = ast_getformatbyname(var->value);
    01002                if (!class->format) {
    01003                   ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
    01004                   class->format = AST_FORMAT_SLINEAR;
    01005                }
    01006             }
    01007                var = var->next;
    01008          }
    01009
    01010          if (ast_strlen_zero(class->dir)) {
    01011             if (!strcasecmp(class->mode, "custom")) {
    01012                strcpy(class->dir, "nodir");
    01013             } else {
    01014                ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
    01015                free(class);
    01016                continue;
    01017             }
    01018          }
    01019          if (ast_strlen_zero(class->mode)) {
    01020             ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
    01021             free(class);
    01022             continue;
    01023          }
    01024          if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
    01025             ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
    01026             free(class);
    01027             continue;
    01028          }
    01029
    01030          /* Don't leak a class when it's already registered */
    01031          moh_register(class, reload);
    01032
    01033          numclasses++;
    01034       }
    01035    }
    01036
    01037
    01038    /* Deprecated Old-School Configuration */
    01039    var = ast_variable_browse(cfg, "classes");
    01040    while (var) {
    01041       if (!dep_warning) {
    01042          ast_log(LOG_WARNING, "The old musiconhold.conf syntax has been deprecated!  Please refer to the sample configuration for information on the new syntax.\n");
    01043          dep_warning = 1;
    01044       }
    01045       data = strchr(var->value, ':');
    01046       if (data) {
    01047          *data++ = '\0';
    01048          args = strchr(data, ',');
    01049          if (args)
    01050             *args++ = '\0';
    01051          if (!(get_mohbyname(var->name, 0))) {
    01052             class = moh_class_malloc();
    01053             if (!class) {
    01054                ast_log(LOG_WARNING, "Out of memory!\n");
    01055                break;
    01056             }
    01057
    01058             ast_copy_string(class->name, var->name, sizeof(class->name));
    01059             ast_copy_string(class->dir, data, sizeof(class->dir));
    01060             ast_copy_string(class->mode, var->value, sizeof(class->mode));
    01061             if (args)
    01062                ast_copy_string(class->args, args, sizeof(class->args));
    01063
    01064             moh_register(class, reload);
    01065             numclasses++;
    01066          }
    01067       }
    01068       var = var->next;
    01069    }
    01070    var = ast_variable_browse(cfg, "moh_files");
    01071    while (var) {
    01072       if (!dep_warning) {
    01073          ast_log(LOG_WARNING, "The old musiconhold.conf syntax has been deprecated!  Please refer to the sample configuration for information on the new syntax.\n");
    01074          dep_warning = 1;
    01075       }
    01076       if (!(get_mohbyname(var->name, 0))) {
    01077          args = strchr(var->value, ',');
    01078          if (args)
    01079             *args++ = '\0';
    01080          class = moh_class_malloc();
    01081          if (!class) {
    01082             ast_log(LOG_WARNING, "Out of memory!\n");
    01083             break;
    01084          }
    01085
    01086          ast_copy_string(class->name, var->name, sizeof(class->name));
    01087          ast_copy_string(class->dir, var->value, sizeof(class->dir));
    01088          strcpy(class->mode, "files");
    01089          if (args)
    01090             ast_copy_string(class->args, args, sizeof(class->args));
    01091
    01092          moh_register(class, reload);
    01093          numclasses++;
    01094       }
    01095       var = var->next;
    01096    }
    01097
    01098    ast_config_destroy(cfg);
    01099
    01100    return numclasses;
    01101 }

static void local_ast_moh_cleanup | ( | struct ast_channel * | chan | ) | `[static]`

Definition at line 905 of file res_musiconhold.c.

References free, and ast_channel::music_state.

Referenced by load_module(), and reload().

    00906 {
    00907    if (chan->music_state) {
    00908       free(chan->music_state);
    00909       chan->music_state = NULL;
    00910    }
    00911 }

static int local_ast_moh_start | ( | struct ast_channel * | chan,
|  | char * | class |
| ) |  |  | `[static]`

Definition at line 913 of file res_musiconhold.c.

References ast_activate_generator(), AST_FLAG_MOH, ast_mutex_lock(), ast_mutex_unlock(), ast_set_flag, ast_strlen_zero(), get_mohbyname(), ast_channel::musicclass, and mohclass::total_files.

Referenced by load_module(), moh_on_off(), and reload().

    00914 {
    00915    struct mohclass *mohclass = NULL;
    00916
    00917    ast_mutex_lock(&moh_lock);
    00918    if (!ast_strlen_zero(class))
    00919       mohclass = get_mohbyname(class, 1);
    00920    if (!mohclass && !ast_strlen_zero(chan->musicclass))
    00921       mohclass = get_mohbyname(chan->musicclass, 1);
    00922    if (!mohclass)
    00923       mohclass = get_mohbyname("default", 1);
    00924    ast_mutex_unlock(&moh_lock);
    00925
    00926    if (!mohclass)
    00927       return -1;
    00928
    00929    ast_set_flag(chan, AST_FLAG_MOH);
    00930    if (mohclass->total_files) {
    00931       return ast_activate_generator(chan, &moh_file_stream, mohclass);
    00932    } else
    00933       return ast_activate_generator(chan, &mohgen, mohclass);
    00934 }

static void local_ast_moh_stop | ( | struct ast_channel * | chan | ) | `[static]`

Definition at line 936 of file res_musiconhold.c.

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

Referenced by load_module(), and reload().

    00937 {
    00938    ast_clear_flag(chan, AST_FLAG_MOH);
    00939    ast_deactivate_generator(chan);
    00940
    00941    if (chan->music_state) {
    00942       if (chan->stream) {
    00943          ast_closestream(chan->stream);
    00944          chan->stream = NULL;
    00945       }
    00946    }
    00947 }

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

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

    00576 {
    00577    if (ast_moh_start(chan, data)) {
    00578       ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
    00579       return -1;
    00580    }
    00581    while (!ast_safe_sleep(chan, 10000));
    00582    ast_moh_stop(chan);
    00583    return -1;
    00584 }

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

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

    00587 {
    00588    int res;
    00589    if (!data || !atoi(data)) {
    00590       ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
    00591       return -1;
    00592    }
    00593    if (ast_moh_start(chan, NULL)) {
    00594       ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name);
    00595       return -1;
    00596    }
    00597    res = ast_safe_sleep(chan, atoi(data) * 1000);
    00598    ast_moh_stop(chan);
    00599    return res;
    00600 }

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

Definition at line 602 of file res_musiconhold.c.

References ast_log(), ast_strlen_zero(), LOG_WARNING, and ast_channel::musicclass.

Referenced by load_module().

    00603 {
    00604    if (ast_strlen_zero(data)) {
    00605       ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
    00606       return -1;
    00607    }
    00608    strncpy(chan->musicclass, data, sizeof(chan->musicclass) - 1);
    00609    return 0;
    00610 }

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

Definition at line 612 of file res_musiconhold.c.

References ast_log(), ast_moh_start(), LOG_NOTICE, and ast_channel::name.

Referenced by load_module().

    00613 {
    00614    char *class = NULL;
    00615    if (data && strlen(data))
    00616       class = data;
    00617    if (ast_moh_start(chan, class))
    00618       ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name);
    00619
    00620    return 0;
    00621 }

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

Definition at line 623 of file res_musiconhold.c.

References ast_moh_stop().

Referenced by load_module().

    00624 {
    00625    ast_moh_stop(chan);
    00626
    00627    return 0;
    00628 }

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

Definition at line 702 of file res_musiconhold.c.

References ast_codec2str(), ast_log(), ast_set_write_format(), ast_verbose(), LOG_WARNING, moh_release(), mohalloc(), ast_channel::name, option_verbose, VERBOSE_PREFIX_3, and ast_channel::writeformat.

    00703 {
    00704    struct mohdata *res;
    00705    struct mohclass *class = params;
    00706
    00707    res = mohalloc(class);
    00708    if (res) {
    00709       res->origwfmt = chan->writeformat;
    00710       if (ast_set_write_format(chan, class->format)) {
    00711          ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format));
    00712          moh_release(NULL, res);
    00713          res = NULL;
    00714       }
    00715       if (option_verbose > 2)
    00716          ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name);
    00717    }
    00718    return res;
    00719 }

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

Definition at line 949 of file res_musiconhold.c.

References AST_FORMAT_SLINEAR, and malloc.

Referenced by load_moh_classes().

    00950 {
    00951    struct mohclass *class;
    00952
    00953    class = malloc(sizeof(struct mohclass));
    00954
    00955    if (!class)
    00956       return NULL;
    00957
    00958    memset(class, 0, sizeof(struct mohclass));
    00959
    00960    class->format = AST_FORMAT_SLINEAR;
    00961
    00962    return class;
    00963 }

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

Definition at line 1188 of file res_musiconhold.c.

References ast_cli(), ast_getformatname(), ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), ast_test_flag, and MOH_CUSTOM.

    01189 {
    01190    struct mohclass *class;
    01191
    01192    ast_mutex_lock(&moh_lock);
    01193    for (class = mohclasses; class; class = class->next) {
    01194       ast_cli(fd, "Class: %s\n", class->name);
    01195       ast_cli(fd, "\tMode: %s\n", ast_strlen_zero(class->mode) ? "<none>" : class->mode);
    01196       ast_cli(fd, "\tDirectory: %s\n", ast_strlen_zero(class->dir) ? "<none>" : class->dir);
    01197       if (ast_test_flag(class, MOH_CUSTOM))
    01198          ast_cli(fd, "\tApplication: %s\n", ast_strlen_zero(class->args) ? "<none>" : class->args);
    01199       ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format));
    01200    }
    01201    ast_mutex_unlock(&moh_lock);
    01202
    01203    return 0;
    01204 }

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

Definition at line 1157 of file res_musiconhold.c.

References ast_cli(), ast_moh_destroy(), load_moh_classes(), and moh_on_off().

    01158 {
    01159    int x;
    01160
    01161    moh_on_off(0);
    01162    ast_moh_destroy();
    01163    x = load_moh_classes(1);
    01164    moh_on_off(1);
    01165    ast_cli(fd, "\n%d class%s reloaded.\n", x, x == 1 ? "" : "es");
    01166    return 0;
    01167 }

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

Definition at line 285 of file res_musiconhold.c.

References ast_test_flag, ast_verbose(), moh_files_state::class, malloc, MOH_RANDOMIZE, ast_channel::music_state, ast_channel::name, option_verbose, moh_files_state::origwfmt, moh_files_state::pos, VERBOSE_PREFIX_3, and ast_channel::writeformat.

    00286 {
    00287    struct moh_files_state *state;
    00288    struct mohclass *class = params;
    00289    int allocated = 0;
    00290
    00291    if (!chan->music_state && (state = malloc(sizeof(struct moh_files_state)))) {
    00292       chan->music_state = state;
    00293       allocated = 1;
    00294    } else
    00295       state = chan->music_state;
    00296
    00297    if (state) {
    00298       if (allocated || state->class != class) {
    00299          /* initialize */
    00300          memset(state, 0, sizeof(struct moh_files_state));
    00301          state->class = class;
    00302          if (ast_test_flag(state->class, MOH_RANDOMIZE))
    00303             state->pos = rand() % class->total_files;
    00304       }
    00305
    00306       state->origwfmt = chan->writeformat;
    00307
    00308       if (option_verbose > 2)
    00309          ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->name, chan->name);
    00310    }
    00311
    00312    return chan->music_state;
    00313 }

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

Definition at line 260 of file res_musiconhold.c.

References ast_frfree(), ast_log(), ast_write(), 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.

    00261 {
    00262    struct moh_files_state *state = chan->music_state;
    00263    struct ast_frame *f = NULL;
    00264    int res = 0;
    00265
    00266    state->sample_queue += samples;
    00267
    00268    while (state->sample_queue > 0) {
    00269       if ((f = moh_files_readframe(chan))) {
    00270          state->samples += f->samples;
    00271          res = ast_write(chan, f);
    00272          state->sample_queue -= f->samples;
    00273          ast_frfree(f);
    00274          if (res < 0) {
    00275             ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
    00276             return -1;
    00277          }
    00278       } else
    00279          return -1;
    00280    }
    00281    return res;
    00282 }

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

Definition at line 248 of file res_musiconhold.c.

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

Referenced by moh_files_generator().

    00249 {
    00250    struct ast_frame *f = NULL;
    00251
    00252    if (!(chan->stream && (f = ast_readframe(chan->stream)))) {
    00253       if (!ast_moh_files_next(chan))
    00254          f = ast_readframe(chan->stream);
    00255    }
    00256
    00257    return f;
    00258 }

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

Definition at line 181 of file res_musiconhold.c.

References ast_closestream(), ast_log(), ast_set_write_format(), ast_verbose(), LOG_WARNING, 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.

    00182 {
    00183    struct moh_files_state *state = chan->music_state;
    00184
    00185    if (chan && state) {
    00186       if (chan->stream) {
    00187                         ast_closestream(chan->stream);
    00188                         chan->stream = NULL;
    00189                 }
    00190       if (option_verbose > 2)
    00191          ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
    00192
    00193       if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
    00194          ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt);
    00195       }
    00196       state->save_pos = state->pos;
    00197    }
    00198 }

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

Definition at line 721 of file res_musiconhold.c.

References ast_codec_get_len(), ast_codec_get_samples(), AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), ast_write(), ast_frame::data, ast_frame::datalen, mohclass::format, ast_frame::frametype, LOG_WARNING, ast_frame::mallocd, moh, ast_channel::name, ast_frame::offset, mohdata::parent, mohclass::pid, mohdata::pipe, ast_frame::samples, and ast_frame::subclass.

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

static void moh_on_off | ( | int | on | ) | `[static]`

Definition at line 1142 of file res_musiconhold.c.

References ast_channel_walk_locked(), ast_deactivate_generator(), AST_FLAG_MOH, ast_mutex_unlock(), ast_test_flag, local_ast_moh_start(), and ast_channel::lock.

Referenced by moh_cli().

    01143 {
    01144    struct ast_channel *chan = NULL;
    01145
    01146    while ( (chan = ast_channel_walk_locked(chan)) != NULL) {
    01147       if (ast_test_flag(chan, AST_FLAG_MOH)) {
    01148          if (on)
    01149             local_ast_moh_start(chan, NULL);
    01150          else
    01151             ast_deactivate_generator(chan);
    01152       }
    01153       ast_mutex_unlock(&chan->lock);
    01154    }
    01155 }

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

Definition at line 833 of file res_musiconhold.c.

References mohclass::args, ast_log(), ast_moh_free_class(), ast_mutex_lock(), ast_mutex_unlock(), ast_pthread_create, ast_set_flag, free, get_mohbyname(), LOG_DEBUG, LOG_WARNING, mohclass::mode, MOH_CUSTOM, MOH_QUIET, MOH_RANDOMIZE, moh_scan_files(), MOH_SINGLE, monmp3thread(), mohclass::name, mohclass::next, mohclass::pseudofd, mohclass::srcfd, mohclass::start, and mohclass::thread.

Referenced by load_moh_classes().

    00834 {
    00835 #ifdef ZAPATA_MOH
    00836    int x;
    00837 #endif
    00838    ast_mutex_lock(&moh_lock);
    00839    if (get_mohbyname(moh->name, 0)) {
    00840       if (reload) {
    00841          ast_log(LOG_DEBUG, "Music on Hold class '%s' left alone from initial load.\n", moh->name);
    00842       } else {
    00843          ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
    00844       }
    00845       free(moh);
    00846       ast_mutex_unlock(&moh_lock);
    00847       return -1;
    00848    }
    00849    ast_mutex_unlock(&moh_lock);
    00850
    00851    time(&moh->start);
    00852    moh->start -= respawn_time;
    00853
    00854    if (!strcasecmp(moh->mode, "files")) {
    00855       if (!moh_scan_files(moh)) {
    00856          ast_moh_free_class(&moh);
    00857          return -1;
    00858       }
    00859       if (strchr(moh->args, 'r'))
    00860          ast_set_flag(moh, MOH_RANDOMIZE);
    00861    } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) {
    00862
    00863       if (!strcasecmp(moh->mode, "custom"))
    00864          ast_set_flag(moh, MOH_CUSTOM);
    00865       else if (!strcasecmp(moh->mode, "mp3nb"))
    00866          ast_set_flag(moh, MOH_SINGLE);
    00867       else if (!strcasecmp(moh->mode, "quietmp3nb"))
    00868          ast_set_flag(moh, MOH_SINGLE | MOH_QUIET);
    00869       else if (!strcasecmp(moh->mode, "quietmp3"))
    00870          ast_set_flag(moh, MOH_QUIET);
    00871
    00872       moh->srcfd = -1;
    00873 #ifdef ZAPATA_MOH
    00874       /* Open /dev/zap/pseudo for timing...  Is
    00875          there a better, yet reliable way to do this? */
    00876       moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
    00877       if (moh->pseudofd < 0) {
    00878          ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
    00879       } else {
    00880          x = 320;
    00881          ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
    00882       }
    00883 #else
    00884       moh->pseudofd = -1;
    00885 #endif
    00886       if (ast_pthread_create(&moh->thread, NULL, monmp3thread, moh)) {
    00887          ast_log(LOG_WARNING, "Unable to create moh...\n");
    00888          if (moh->pseudofd > -1)
    00889             close(moh->pseudofd);
    00890          ast_moh_free_class(&moh);
    00891          return -1;
    00892       }
    00893    } else {
    00894       ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
    00895       ast_moh_free_class(&moh);
    00896       return -1;
    00897    }
    00898    ast_mutex_lock(&moh_lock);
    00899    moh->next = mohclasses;
    00900    mohclasses = moh;
    00901    ast_mutex_unlock(&moh_lock);
    00902    return 0;
    00903 }

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

Definition at line 670 of file res_musiconhold.c.

References ast_getformatname(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_set_write_format(), ast_verbose(), free, LOG_WARNING, mohclass::members, moh, ast_channel::name, mohdata::next, option_verbose, mohdata::origwfmt, mohdata::parent, mohdata::pipe, and VERBOSE_PREFIX_3.

Referenced by moh_alloc().

    00671 {
    00672    struct mohdata *moh = data, *prev, *cur;
    00673    int oldwfmt;
    00674    ast_mutex_lock(&moh_lock);
    00675    /* Unlink */
    00676    prev = NULL;
    00677    cur = moh->parent->members;
    00678    while (cur) {
    00679       if (cur == moh) {
    00680          if (prev)
    00681             prev->next = cur->next;
    00682          else
    00683             moh->parent->members = cur->next;
    00684          break;
    00685       }
    00686       prev = cur;
    00687       cur = cur->next;
    00688    }
    00689    ast_mutex_unlock(&moh_lock);
    00690    close(moh->pipe[0]);
    00691    close(moh->pipe[1]);
    00692    oldwfmt = moh->origwfmt;
    00693    free(moh);
    00694    if (chan) {
    00695       if (oldwfmt && ast_set_write_format(chan, oldwfmt))
    00696          ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
    00697       if (option_verbose > 2)
    00698          ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
    00699    }
    00700 }

static int moh_scan_files | ( | struct mohclass * | class | ) | `[static]`

Definition at line 771 of file res_musiconhold.c.

References ast_log(), LOG_WARNING, MAX_MOHFILE_LEN, and MAX_MOHFILES.

Referenced by init_classes(), and moh_register().

    00771                                                   {
    00772
    00773    DIR *files_DIR;
    00774    struct dirent *files_dirent;
    00775    char path[512];
    00776    char filepath[MAX_MOHFILE_LEN];
    00777    char *ext;
    00778    struct stat statbuf;
    00779    int dirnamelen;
    00780    int i;
    00781
    00782    files_DIR = opendir(class->dir);
    00783    if (!files_DIR) {
    00784       ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", class->dir);
    00785       return -1;
    00786    }
    00787
    00788    class->total_files = 0;
    00789    dirnamelen = strlen(class->dir) + 2;
    00790    getcwd(path, 512);
    00791    chdir(class->dir);
    00792    memset(class->filearray, 0, MAX_MOHFILES*MAX_MOHFILE_LEN);
    00793    while ((files_dirent = readdir(files_DIR))) {
    00794       if ((strlen(files_dirent->d_name) < 4) || ((strlen(files_dirent->d_name) + dirnamelen) >= MAX_MOHFILE_LEN))
    00795          continue;
    00796
    00797       /* Skip files that start with a dot */
    00798       if (files_dirent->d_name[0] == '.')
    00799          continue;
    00800
    00801       snprintf(filepath, MAX_MOHFILE_LEN, "%s/%s", class->dir, files_dirent->d_name);
    00802
    00803       if (stat(filepath, &statbuf))
    00804          continue;
    00805
    00806       if (!S_ISREG(statbuf.st_mode))
    00807          continue;
    00808
    00809       if ((ext = strrchr(filepath, '.'))) {
    00810          *ext = '\0';
    00811          ext++;
    00812       }
    00813
    00814       /* if the file is present in multiple formats, ensure we only put it into the list once */
    00815       for (i = 0; i < class->total_files; i++)
    00816          if (!strcmp(filepath, class->filearray[i]))
    00817             break;
    00818
    00819       if (i == class->total_files)
    00820          strcpy(class->filearray[class->total_files++], filepath);
    00821
    00822       /* If the new total files is equal to the maximum allowed, stop adding new ones */
    00823       if (class->total_files == MAX_MOHFILES)
    00824          break;
    00825
    00826    }
    00827
    00828    closedir(files_DIR);
    00829    chdir(path);
    00830    return class->total_files;
    00831 }

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

Definition at line 644 of file res_musiconhold.c.

References ast_log(), ast_mutex_lock(), ast_mutex_unlock(), free, LOG_WARNING, malloc, mohclass::members, moh, mohdata::next, mohdata::parent, and mohdata::pipe.

Referenced by moh_alloc().

    00645 {
    00646    struct mohdata *moh;
    00647    long flags;
    00648    moh = malloc(sizeof(struct mohdata));
    00649    if (!moh)
    00650       return NULL;
    00651    memset(moh, 0, sizeof(struct mohdata));
    00652    if (pipe(moh->pipe)) {
    00653       ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
    00654       free(moh);
    00655       return NULL;
    00656    }
    00657    /* Make entirely non-blocking */
    00658    flags = fcntl(moh->pipe[0], F_GETFL);
    00659    fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
    00660    flags = fcntl(moh->pipe[1], F_GETFL);
    00661    fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
    00662    moh->parent = cl;
    00663    ast_mutex_lock(&moh_lock);
    00664    moh->next = cl->members;
    00665    cl->members = moh;
    00666    ast_mutex_unlock(&moh_lock);
    00667    return moh;
    00668 }

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

Definition at line 489 of file res_musiconhold.c.

References ast_codec_get_len(), ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_tvadd(), LOG_DEBUG, LOG_NOTICE, LOG_WARNING, moh, MOH_MS_INTERVAL, mohdata::next, option_debug, mohdata::pipe, and spawn_mp3().

Referenced by moh_register().

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

int reload | ( | void |  | ) |

Reload stuff.

This function is where any reload routines take place. Re-read config files, change signalling, whatever is appropriate on a reload.

Returns:
  The return value is not used.

Definition at line 1254 of file res_musiconhold.c.

References ast_install_music_functions(), init_classes(), local_ast_moh_cleanup(), local_ast_moh_start(), and local_ast_moh_stop().

    01255 {
    01256    if (init_classes(1))
    01257       ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
    01258
    01259    return 0;
    01260 }

static int spawn_mp3 | ( | struct mohclass * | class | ) | `[static]`

Definition at line 322 of file res_musiconhold.c.

References ast_log(), ast_set_priority(), ast_strlen_zero(), ast_test_flag, LOCAL_MPG_123, LOG_WARNING, MAX_MP3S, MOH_CUSTOM, MOH_QUIET, MOH_SINGLE, MPG_123, and option_highpriority.

Referenced by monmp3thread().

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

int unload_module | ( | void |  | ) |

Cleanup all module structures, sockets, etc.

This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).

Returns:
  Zero on success, or non-zero on error.

Standard module functions ...

Definition at line 1262 of file res_musiconhold.c.

    01263 {
    01264    return -1;
    01265 }

int usecount | ( | void |  | ) |

Provides a usecount.

This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.

Returns:
  The module's usecount.

Definition at line 1272 of file res_musiconhold.c.

References STANDARD_USECOUNT.

    01273 {
    01274    /* Never allow Music On Hold to be unloaded
    01275       unresolve needed symbols in the dialer */
    01276 #if 0
    01277    int res;
    01278    STANDARD_USECOUNT(res);
    01279    return res;
    01280 #else
    01281    return 1;
    01282 #endif
    01283 }

## Variable Documentation

char* app0 = "MusicOnHold"`[static]`

Definition at line 73 of file res_musiconhold.c.

char* app1 = "WaitMusicOnHold"`[static]`

Definition at line 74 of file res_musiconhold.c.

char* app2 = "SetMusicOnHold"`[static]`

Definition at line 75 of file res_musiconhold.c.

char* app3 = "StartMusicOnHold"`[static]`

Definition at line 76 of file res_musiconhold.c.

char* app4 = "StopMusicOnHold"`[static]`

Definition at line 77 of file res_musiconhold.c.

struct ast_cli_entry cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL}`[static]`

Definition at line 1206 of file res_musiconhold.c.

struct ast_cli_entry cli_moh_classes_show = { { "moh", "classes", "show"}, moh_classes_show, "List MOH classes", "Lists all MOH classes", NULL}`[static]`

Definition at line 1208 of file res_musiconhold.c.

struct ast_cli_entry cli_moh_files_show = { { "moh", "files", "show"}, cli_files_show, "List MOH file-based classes", "Lists all loaded file-based MOH classes and their files", NULL}`[static]`

Definition at line 1210 of file res_musiconhold.c.

char* descrip0`[static]`

Definition at line 85 of file res_musiconhold.c.

char* descrip1`[static]`

Initial value:

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

Definition at line 92 of file res_musiconhold.c.

char* descrip2`[static]`

Initial value:

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

Definition at line 97 of file res_musiconhold.c.

char* descrip3`[static]`

Initial value:

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

Definition at line 102 of file res_musiconhold.c.

char* descrip4`[static]`

Initial value:

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

Definition at line 107 of file res_musiconhold.c.

struct ast_generator moh_file_stream`[static]`

Definition at line 315 of file res_musiconhold.c.

struct mohclass* mohclasses`[static]`

Definition at line 153 of file res_musiconhold.c.

struct ast_generator mohgen`[static]`

Definition at line 764 of file res_musiconhold.c.

int respawn_time = 20`[static]`

Definition at line 110 of file res_musiconhold.c.

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

Definition at line 79 of file res_musiconhold.c.

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

Definition at line 80 of file res_musiconhold.c.

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

Definition at line 81 of file res_musiconhold.c.

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

Definition at line 82 of file res_musiconhold.c.

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

Definition at line 83 of file res_musiconhold.c.