Wed Jan 8 2020 09:50:19

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 "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/manager.h"
#include "asterisk/paths.h"
#include "asterisk/astobj2.h"
#include "asterisk/timing.h"
#include "asterisk/time.h"
#include "asterisk/poll-compat.h"

Go to the source code of this file.

Data Structures

struct  moh_files_state
 
struct  mohclass
 
struct  mohdata
 

Macros

#define DONT_UNREF   0
 
#define get_mohbyname(a, b, c)   _get_mohbyname(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__)
 
#define HANDLE_REF   1
 
#define INITIAL_NUM_FILES   8
 
#define LOCAL_MPG_123   "/usr/local/bin/mpg123"
 
#define MAX_MP3S   256
 
#define MOH_CACHERTCLASSES   (1 << 5)
 
#define moh_class_malloc()   _moh_class_malloc(__FILE__,__LINE__,__PRETTY_FUNCTION__)
 
#define MOH_CUSTOM   (1 << 2)
 
#define MOH_MS_INTERVAL   100
 
#define MOH_NOTDELETED   (1 << 30)
 
#define MOH_QUIET   (1 << 0)
 
#define MOH_RANDOMIZE   (1 << 3)
 
#define moh_register(a, b, c)   _moh_register(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__)
 
#define MOH_SINGLE   (1 << 1)
 
#define MOH_SORTALPHA   (1 << 4)
 
#define mohclass_ref(class, string)   (ao2_t_ref((class), +1, (string)), class)
 
#define mohclass_unref(class, string)   ({ ao2_t_ref((class), -1, (string)); (struct mohclass *) NULL; })
 
#define MPG_123   "/usr/bin/mpg123"
 

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
static struct mohclass_get_mohbyname (const char *name, int warn, int flags, const char *file, int lineno, const char *funcname)
 
static struct mohclass_moh_class_malloc (const char *file, int line, const char *funcname)
 
static int _moh_register (struct mohclass *moh, int reload, int unref, const char *file, int line, const char *funcname)
 
static void ast_moh_destroy (void)
 
static int ast_moh_files_next (struct ast_channel *chan)
 
static struct mohclassget_mohbydigit (char digit)
 
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 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 void moh_release (struct ast_channel *chan, void *data)
 
static void moh_rescan_files (void)
 
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, const char *data)
 
static int reload (void)
 
static int set_moh_exec (struct ast_channel *chan, const char *data)
 
static int spawn_mp3 (struct mohclass *class)
 
static int start_moh_exec (struct ast_channel *chan, const char *data)
 
static int stop_moh_exec (struct ast_channel *chan, const char *data)
 
static int unload_module (void)
 
static int wait_moh_exec (struct ast_channel *chan, const char *data)
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, }
 
static 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 const char play_moh [] = "MusicOnHold"
 
static int respawn_time = 20
 
static const char set_moh [] = "SetMusicOnHold"
 
static const char start_moh [] = "StartMusicOnHold"
 
static const char stop_moh [] = "StopMusicOnHold"
 
static const char wait_moh [] = "WaitMusicOnHold"
 

Detailed Description

Routines implementing music on hold.

Author
Mark Spencer marks.nosp@m.ter@.nosp@m.digiu.nosp@m.m.co.nosp@m.m

Definition in file res_musiconhold.c.

Macro Definition Documentation

#define DONT_UNREF   0

Definition at line 72 of file res_musiconhold.c.

Referenced by local_ast_moh_start().

#define get_mohbyname (   a,
  b,
 
)    _get_mohbyname(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__)

Definition at line 838 of file res_musiconhold.c.

Referenced by local_ast_moh_start().

#define HANDLE_REF   1

Definition at line 71 of file res_musiconhold.c.

Referenced by load_moh_classes().

#define INITIAL_NUM_FILES   8

Definition at line 70 of file res_musiconhold.c.

Referenced by moh_add_file().

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

Definition at line 221 of file res_musiconhold.c.

Referenced by spawn_mp3().

#define MAX_MP3S   256

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

Referenced by load_moh_classes(), and local_ast_moh_start().

#define moh_class_malloc ( )    _moh_class_malloc(__FILE__,__LINE__,__PRETTY_FUNCTION__)

Definition at line 1294 of file res_musiconhold.c.

Referenced by load_moh_classes(), and local_ast_moh_start().

#define MOH_CUSTOM   (1 << 2)
#define MOH_MS_INTERVAL   100

Referenced by monmp3thread().

#define MOH_NOTDELETED   (1 << 30)

Find only records that aren't deleted?

Definition at line 177 of file res_musiconhold.c.

Referenced by _moh_register(), and moh_class_cmp().

#define MOH_QUIET   (1 << 0)

Definition at line 168 of file res_musiconhold.c.

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

#define MOH_RANDOMIZE   (1 << 3)
#define moh_register (   a,
  b,
 
)    _moh_register(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__)
Note
This function owns the reference it gets to moh if unref is true

Definition at line 1219 of file res_musiconhold.c.

Referenced by load_moh_classes(), and local_ast_moh_start().

#define MOH_SINGLE   (1 << 1)

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

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

#define mohclass_ref (   class,
  string 
)    (ao2_t_ref((class), +1, (string)), class)

Definition at line 227 of file res_musiconhold.c.

Referenced by local_ast_moh_start(), moh_alloc(), moh_files_alloc(), and mohalloc().

#define MPG_123   "/usr/bin/mpg123"

Definition at line 222 of file res_musiconhold.c.

Referenced by spawn_mp3().

Function Documentation

static void __reg_module ( void  )
static

Definition at line 1980 of file res_musiconhold.c.

static void __unreg_module ( void  )
static

Definition at line 1980 of file res_musiconhold.c.

static struct mohclass* _get_mohbyname ( const char *  name,
int  warn,
int  flags,
const char *  file,
int  lineno,
const char *  funcname 
)
static

Definition at line 840 of file res_musiconhold.c.

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

Referenced by _moh_register().

841 {
842  struct mohclass *moh = NULL;
843  struct mohclass tmp_class = {
844  .flags = 0,
845  };
846 
847  ast_copy_string(tmp_class.name, name, sizeof(tmp_class.name));
848 
849 #ifdef REF_DEBUG
850  moh = __ao2_find_debug(mohclasses, &tmp_class, flags, "get_mohbyname", (char *) file, lineno, funcname);
851 #else
852  moh = __ao2_find(mohclasses, &tmp_class, flags);
853 #endif
854 
855  if (!moh && warn) {
856  ast_log(LOG_DEBUG, "Music on Hold class '%s' not found in memory\n", name);
857  }
858 
859  return moh;
860 }
static struct ao2_container * mohclasses
char name[MAX_MUSICCLASS]
void * __ao2_find(struct ao2_container *c, void *arg, enum search_flags flags)
Definition: astobj2.c:810
#define LOG_DEBUG
Definition: logger.h:122
unsigned int flags
static char moh[80]
Definition: chan_agent.c:209
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static const char name[]
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
void * __ao2_find_debug(struct ao2_container *c, void *arg, enum search_flags flags, char *tag, char *file, int line, const char *funcname)
Definition: astobj2.c:805
static struct mohclass* _moh_class_malloc ( const char *  file,
int  line,
const char *  funcname 
)
static

Definition at line 1296 of file res_musiconhold.c.

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

1297 {
1298  struct mohclass *class;
1299 
1300  if ((class =
1301 #ifdef REF_DEBUG
1302  __ao2_alloc_debug(sizeof(*class), moh_class_destructor, "Allocating new moh class", file, line, funcname, 1)
1303 #elif defined(__AST_DEBUG_MALLOC)
1304  __ao2_alloc_debug(sizeof(*class), moh_class_destructor, "Allocating new moh class", file, line, funcname, 0)
1305 #else
1306  ao2_alloc(sizeof(*class), moh_class_destructor)
1307 #endif
1308  )) {
1309  class->format = AST_FORMAT_SLINEAR;
1310  class->srcfd = -1;
1311  }
1312 
1313  return class;
1314 }
#define __AST_DEBUG_MALLOC
Definition: astmm.h:36
void * __ao2_alloc_debug(const size_t data_size, ao2_destructor_fn destructor_fn, char *tag, const char *file, int line, const char *funcname, int ref_debug)
Definition: astobj2.c:335
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:430
format_t format
#define AST_FORMAT_SLINEAR
Definition: frame.h:254
static void moh_class_destructor(void *obj)
static int _moh_register ( struct mohclass moh,
int  reload,
int  unref,
const char *  file,
int  line,
const char *  funcname 
)
static

Definition at line 1220 of file res_musiconhold.c.

References _get_mohbyname(), ao2_t_link, ast_log(), init_app_class(), init_files_class(), LOG_WARNING, mohclass::mode, moh_diff(), MOH_NOTDELETED, mohclass_unref, mohclass::name, respawn_time, and mohclass::start.

1221 {
1222  struct mohclass *mohclass = NULL;
1223 
1224  mohclass = _get_mohbyname(moh->name, 0, MOH_NOTDELETED, file, line, funcname);
1225 
1226  if (mohclass && !moh_diff(mohclass, moh)) {
1227  ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
1228  mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name");
1229  if (unref) {
1230  moh = mohclass_unref(moh, "unreffing potential new moh class (it is a duplicate)");
1231  }
1232  return -1;
1233  } else if (mohclass) {
1234  /* Found a class, but it's different from the one being registered */
1235  mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name");
1236  }
1237 
1238  time(&moh->start);
1239  moh->start -= respawn_time;
1240 
1241  if (!strcasecmp(moh->mode, "files")) {
1242  if (init_files_class(moh)) {
1243  if (unref) {
1244  moh = mohclass_unref(moh, "unreffing potential new moh class (init_files_class failed)");
1245  }
1246  return -1;
1247  }
1248  } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") ||
1249  !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") ||
1250  !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) {
1251  if (init_app_class(moh)) {
1252  if (unref) {
1253  moh = mohclass_unref(moh, "unreffing potential new moh class (init_app_class_failed)");
1254  }
1255  return -1;
1256  }
1257  } else {
1258  ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
1259  if (unref) {
1260  moh = mohclass_unref(moh, "unreffing potential new moh class (unknown mode)");
1261  }
1262  return -1;
1263  }
1264 
1265  ao2_t_link(mohclasses, moh, "Adding class to container");
1266 
1267  if (unref) {
1268  moh = mohclass_unref(moh, "Unreffing new moh class because we just added it to the container");
1269  }
1270 
1271  return 0;
1272 }
static struct ao2_container * mohclasses
char name[MAX_MUSICCLASS]
#define MOH_NOTDELETED
static int init_files_class(struct mohclass *class)
#define LOG_WARNING
Definition: logger.h:144
static int init_app_class(struct mohclass *class)
#define ao2_t_link(arg1, arg2, arg3)
Add an object to a container.
Definition: astobj2.h:784
static struct mohclass * _get_mohbyname(const char *name, int warn, int flags, const char *file, int lineno, const char *funcname)
static int moh_diff(struct mohclass *old, struct mohclass *new)
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
time_t start
static int respawn_time
#define mohclass_unref(class, string)
char mode[80]
static void ast_moh_destroy ( void  )
static

Definition at line 1768 of file res_musiconhold.c.

References ao2_ref, ao2_t_callback, ast_verb, OBJ_MULTIPLE, OBJ_NODATA, and OBJ_UNLINK.

Referenced by load_module(), and unload_module().

1769 {
1770  ast_verb(2, "Destroying musiconhold processes\n");
1771  if (mohclasses) {
1772  ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "Destroy callback");
1773  ao2_ref(mohclasses, -1);
1774  mohclasses = NULL;
1775  }
1776 }
static struct ao2_container * mohclasses
#define ast_verb(level,...)
Definition: logger.h:243
#define ao2_ref(o, delta)
Definition: astobj2.h:472
#define ao2_t_callback(c, flags, cb_fn, arg, tag)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Definition: astobj2.h:909
static int ast_moh_files_next ( struct ast_channel chan)
static

Definition at line 279 of file res_musiconhold.c.

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

280 {
281  struct moh_files_state *state = chan->music_state;
282  int tries;
283 
284  /* Discontinue a stream if it is running already */
285  if (chan->stream) {
286  ast_closestream(chan->stream);
287  chan->stream = NULL;
288  }
289 
290  if (!state->class->total_files) {
291  ast_log(LOG_WARNING, "No files available for class '%s'\n", state->class->name);
292  return -1;
293  }
294 
295  if (state->pos == 0 && ast_strlen_zero(state->save_pos_filename)) {
296  /* First time so lets play the file. */
297  state->save_pos = -1;
298  } else if (state->save_pos >= 0 && state->save_pos < state->class->total_files && !strcmp(state->class->filearray[state->save_pos], state->save_pos_filename)) {
299  /* If a specific file has been saved confirm it still exists and that it is still valid */
300  state->pos = state->save_pos;
301  state->save_pos = -1;
302  } else if (ast_test_flag(state->class, MOH_RANDOMIZE)) {
303  /* Get a random file and ensure we can open it */
304  for (tries = 0; tries < 20; tries++) {
305  state->pos = ast_random() % state->class->total_files;
306  if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0) {
307  break;
308  }
309  }
310  state->save_pos = -1;
311  state->samples = 0;
312  } else {
313  /* This is easy, just increment our position and make sure we don't exceed the total file count */
314  state->pos++;
315  state->pos %= state->class->total_files;
316  state->save_pos = -1;
317  state->samples = 0;
318  }
319 
320  for (tries = 0; tries < state->class->total_files; ++tries) {
321  if (ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
322  break;
323  }
324 
325  ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
326  state->pos++;
327  state->pos %= state->class->total_files;
328  }
329 
330  if (tries == state->class->total_files) {
331  return -1;
332  }
333 
334  /* Record the pointer to the filename for position resuming later */
335  ast_copy_string(state->save_pos_filename, state->class->filearray[state->pos], sizeof(state->save_pos_filename));
336 
337  ast_debug(1, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]);
338 
339  if (state->samples) {
340  size_t loc;
341  /* seek *SHOULD* be good since it's from a known location */
342  ast_seekstream(chan->stream, state->samples, SEEK_SET);
343  /* if the seek failed then recover because if there is not a valid read,
344  * moh_files_generate will return -1 and MOH will stop */
345  loc = ast_tellstream(chan->stream);
346  if (state->samples > loc && loc) {
347  /* seek one sample from the end for one guaranteed valid read */
348  ast_seekstream(chan->stream, 1, SEEK_END);
349  }
350  }
351 
352  return 0;
353 }
void * music_state
Definition: channel.h:745
char name[MAX_MUSICCLASS]
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define LOG_WARNING
Definition: logger.h:144
struct mohclass * class
struct ast_filestream * ast_openstream_full(struct ast_channel *chan, const char *filename, const char *preflang, int asis)
Opens stream for use in seeking, playing.
Definition: file.c:641
off_t ast_tellstream(struct ast_filestream *fs)
Tell where we are in a stream.
Definition: file.c:889
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
char save_pos_filename[PATH_MAX]
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
long int ast_random(void)
Definition: utils.c:1640
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
Seeks into stream.
Definition: file.c:879
int errno
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:904
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:919
char ** filearray
struct ast_filestream * stream
Definition: channel.h:757
#define MOH_RANDOMIZE
const ast_string_field language
Definition: channel.h:787
static struct mohclass* get_mohbydigit ( char  digit)
static
Note
This function should be called with the mohclasses list locked

Definition at line 450 of file res_musiconhold.c.

References ao2_t_callback, and moh_digit_match().

Referenced by moh_handle_digit().

451 {
452  return ao2_t_callback(mohclasses, 0, moh_digit_match, &digit, "digit callback");
453 }
static struct ao2_container * mohclasses
static int moh_digit_match(void *obj, void *arg, int flags)
#define ao2_t_callback(c, flags, cb_fn, arg, tag)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Definition: astobj2.h:909
static char* handle_cli_moh_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

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

1779 {
1780  switch (cmd) {
1781  case CLI_INIT:
1782  e->command = "moh reload";
1783  e->usage =
1784  "Usage: moh reload\n"
1785  " Reloads the MusicOnHold module.\n"
1786  " Alias for 'module reload res_musiconhold.so'\n";
1787  return NULL;
1788  case CLI_GENERATE:
1789  return NULL;
1790  }
1791 
1792  if (a->argc != e->args)
1793  return CLI_SHOWUSAGE;
1794 
1795  reload();
1796 
1797  return CLI_SUCCESS;
1798 }
static int reload(void)
const int argc
Definition: cli.h:154
Definition: cli.h:146
int args
This gets set in ast_cli_register()
Definition: cli.h:179
#define CLI_SHOWUSAGE
Definition: cli.h:44
char * command
Definition: cli.h:180
const char * usage
Definition: cli.h:171
#define CLI_SUCCESS
Definition: cli.h:43
static char* handle_cli_moh_show_classes ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1838 of file res_musiconhold.c.

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

1839 {
1840  struct mohclass *class;
1841  struct ao2_iterator i;
1842 
1843  switch (cmd) {
1844  case CLI_INIT:
1845  e->command = "moh show classes";
1846  e->usage =
1847  "Usage: moh show classes\n"
1848  " Lists all MusicOnHold classes.\n";
1849  return NULL;
1850  case CLI_GENERATE:
1851  return NULL;
1852  }
1853 
1854  if (a->argc != e->args)
1855  return CLI_SHOWUSAGE;
1856 
1857  i = ao2_iterator_init(mohclasses, 0);
1858  for (; (class = ao2_t_iterator_next(&i, "Show classes iterator")); mohclass_unref(class, "Unref iterator in moh show classes")) {
1859  ast_cli(a->fd, "Class: %s\n", class->name);
1860  ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
1861  ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
1862  if (ast_test_flag(class, MOH_CUSTOM)) {
1863  ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
1864  }
1865  if (strcasecmp(class->mode, "files")) {
1866  ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(class->format));
1867  }
1868  }
1870 
1871  return CLI_SUCCESS;
1872 }
static struct ao2_container * mohclasses
#define ast_test_flag(p, flag)
Definition: utils.h:63
const int argc
Definition: cli.h:154
#define ao2_t_iterator_next(arg1, arg2)
Definition: astobj2.h:1125
Definition: cli.h:146
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
Create an iterator for a container.
Definition: astobj2.c:818
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
int args
This gets set in ast_cli_register()
Definition: cli.h:179
const int fd
Definition: cli.h:153
char * ast_getformatname(format_t format)
Get the name of a format.
Definition: frame.c:578
#define CLI_SHOWUSAGE
Definition: cli.h:44
char * command
Definition: cli.h:180
void ao2_iterator_destroy(struct ao2_iterator *i)
Destroy a container iterator.
Definition: astobj2.c:833
const char * usage
Definition: cli.h:171
#define MOH_CUSTOM
#define CLI_SUCCESS
Definition: cli.h:43
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1053
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
#define mohclass_unref(class, string)
static char* handle_cli_moh_show_files ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1800 of file res_musiconhold.c.

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

1801 {
1802  struct mohclass *class;
1803  struct ao2_iterator i;
1804 
1805  switch (cmd) {
1806  case CLI_INIT:
1807  e->command = "moh show files";
1808  e->usage =
1809  "Usage: moh show files\n"
1810  " Lists all loaded file-based MusicOnHold classes and their\n"
1811  " files.\n";
1812  return NULL;
1813  case CLI_GENERATE:
1814  return NULL;
1815  }
1816 
1817  if (a->argc != e->args)
1818  return CLI_SHOWUSAGE;
1819 
1820  i = ao2_iterator_init(mohclasses, 0);
1821  for (; (class = ao2_t_iterator_next(&i, "Show files iterator")); mohclass_unref(class, "Unref iterator in moh show files")) {
1822  int x;
1823 
1824  if (!class->total_files) {
1825  continue;
1826  }
1827 
1828  ast_cli(a->fd, "Class: %s\n", class->name);
1829  for (x = 0; x < class->total_files; x++) {
1830  ast_cli(a->fd, "\tFile: %s\n", class->filearray[x]);
1831  }
1832  }
1834 
1835  return CLI_SUCCESS;
1836 }
static struct ao2_container * mohclasses
const int argc
Definition: cli.h:154
#define ao2_t_iterator_next(arg1, arg2)
Definition: astobj2.h:1125
Definition: cli.h:146
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
Create an iterator for a container.
Definition: astobj2.c:818
void ast_cli(int fd, const char *fmt,...)
Definition: cli.c:105
int args
This gets set in ast_cli_register()
Definition: cli.h:179
const int fd
Definition: cli.h:153
#define CLI_SHOWUSAGE
Definition: cli.h:44
char * command
Definition: cli.h:180
void ao2_iterator_destroy(struct ao2_iterator *i)
Destroy a container iterator.
Definition: astobj2.c:833
const char * usage
Definition: cli.h:171
#define CLI_SUCCESS
Definition: cli.h:43
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1053
#define mohclass_unref(class, string)
static int init_app_class ( struct mohclass class)
static

Definition at line 1180 of file res_musiconhold.c.

References ast_log(), ast_pthread_create_background, ast_set_flag, ast_timer_close(), ast_timer_open(), ast_timer_set_rate(), errno, LOG_WARNING, MOH_CUSTOM, MOH_QUIET, MOH_SINGLE, and monmp3thread().

Referenced by _moh_register().

1181 {
1182  if (!strcasecmp(class->mode, "custom")) {
1183  ast_set_flag(class, MOH_CUSTOM);
1184  } else if (!strcasecmp(class->mode, "mp3nb")) {
1185  ast_set_flag(class, MOH_SINGLE);
1186  } else if (!strcasecmp(class->mode, "quietmp3nb")) {
1187  ast_set_flag(class, MOH_SINGLE | MOH_QUIET);
1188  } else if (!strcasecmp(class->mode, "quietmp3")) {
1189  ast_set_flag(class, MOH_QUIET);
1190  }
1191 
1192  class->srcfd = -1;
1193 
1194  if (!(class->timer = ast_timer_open())) {
1195  ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno));
1196  return -1;
1197  }
1198  if (class->timer && ast_timer_set_rate(class->timer, 25)) {
1199  ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno));
1200  ast_timer_close(class->timer);
1201  class->timer = NULL;
1202  }
1203 
1204  if (ast_pthread_create_background(&class->thread, NULL, monmp3thread, class)) {
1205  ast_log(LOG_WARNING, "Unable to create moh thread...\n");
1206  if (class->timer) {
1207  ast_timer_close(class->timer);
1208  class->timer = NULL;
1209  }
1210  return -1;
1211  }
1212 
1213  return 0;
1214 }
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:144
void ast_timer_close(struct ast_timer *handle)
Close an opened timing handle.
Definition: timing.c:150
struct ast_timer * ast_timer_open(void)
Open a timer.
Definition: timing.c:123
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:426
#define MOH_QUIET
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int errno
int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
Set the timing tick rate.
Definition: timing.c:163
struct ast_timer * timer
#define MOH_CUSTOM
pthread_t thread
char mode[80]
static void * monmp3thread(void *data)
#define MOH_SINGLE
static int init_files_class ( struct mohclass class)
static

Definition at line 1124 of file res_musiconhold.c.

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

Referenced by _moh_register().

1125 {
1126  int res;
1127 
1128  res = moh_scan_files(class);
1129 
1130  if (res < 0) {
1131  return -1;
1132  }
1133 
1134  if (!res) {
1135  if (option_verbose > 2) {
1136  ast_verbose(VERBOSE_PREFIX_3 "Files not found in %s for moh class:%s\n",
1137  class->dir, class->name);
1138  }
1139  return -1;
1140  }
1141 
1142  return 0;
1143 }
char name[MAX_MUSICCLASS]
#define VERBOSE_PREFIX_3
Definition: logger.h:43
void ast_verbose(const char *fmt,...)
Definition: logger.c:1568
int option_verbose
Definition: asterisk.c:181
static int moh_scan_files(struct mohclass *class)
char dir[256]
static int load_module ( void  )
static

Definition at line 1896 of file res_musiconhold.c.

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

1897 {
1898  int res;
1899 
1900  if (!(mohclasses = ao2_t_container_alloc(53, moh_class_hash, moh_class_cmp, "Moh class container"))) {
1901  return AST_MODULE_LOAD_DECLINE;
1902  }
1903 
1904  if (!load_moh_classes(0) && ast_check_realtime("musiconhold") == 0) { /* No music classes configured, so skip it */
1905  ast_log(LOG_WARNING, "No music on hold classes configured, "
1906  "disabling music on hold.\n");
1907  } else {
1910  }
1911 
1915  if (!res)
1917  if (!res)
1919  if (!res)
1921  if (!res)
1923 
1924  return AST_MODULE_LOAD_SUCCESS;
1925 }
static int stop_moh_exec(struct ast_channel *chan, const char *data)
static struct ao2_container * mohclasses
static int wait_moh_exec(struct ast_channel *chan, const char *data)
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static const char stop_moh[]
static const char set_moh[]
static int start_moh_exec(struct ast_channel *chan, const char *data)
static int load_moh_classes(int reload)
#define LOG_WARNING
Definition: logger.h:144
static struct ast_cli_entry cli_moh[]
#define ao2_t_container_alloc(arg1, arg2, arg3, arg4)
Allocate and initialize a container with the desired number of buckets.
Definition: astobj2.h:733
static void ast_moh_destroy(void)
static void local_ast_moh_cleanup(struct ast_channel *chan)
static void local_ast_moh_stop(struct ast_channel *chan)
static int set_moh_exec(struct ast_channel *chan, const char *data)
int ast_register_atexit(void(*func)(void))
Register a function to be executed before Asterisk exits.
Definition: asterisk.c:998
static const char start_moh[]
static int play_moh_exec(struct ast_channel *chan, const char *data)
static int moh_class_cmp(void *obj, void *arg, int flags)
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
void ast_install_music_functions(int(*start_ptr)(struct ast_channel *, const char *, const char *), void(*stop_ptr)(struct ast_channel *), void(*cleanup_ptr)(struct ast_channel *))
Definition: channel.c:8023
static int moh_class_hash(const void *obj, const int flags)
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
Definition: cli.c:2167
static const char wait_moh[]
static const char play_moh[]
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:437
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: config.c:2587
static int load_moh_classes ( int  reload)
static

Definition at line 1658 of file res_musiconhold.c.

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

Referenced by load_module(), and reload().

1659 {
1660  struct ast_config *cfg;
1661  struct ast_variable *var;
1662  struct mohclass *class;
1663  char *cat;
1664  int numclasses = 0;
1665  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1666 
1667  cfg = ast_config_load("musiconhold.conf", config_flags);
1668 
1670  if (ast_check_realtime("musiconhold") && reload) {
1671  ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
1673  }
1674  return 0;
1675  }
1676  if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
1677  moh_rescan_files();
1678  return 0;
1679  }
1680 
1681  if (reload) {
1682  ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
1683  }
1684 
1686 
1687  cat = ast_category_browse(cfg, NULL);
1688  for (; cat; cat = ast_category_browse(cfg, cat)) {
1689  /* Setup common options from [general] section */
1690  if (!strcasecmp(cat, "general")) {
1691  for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1692  if (!strcasecmp(var->name, "cachertclasses")) {
1694  } else {
1695  ast_log(LOG_WARNING, "Unknown option '%s' in [general] section of musiconhold.conf\n", var->name);
1696  }
1697  }
1698  }
1699  /* These names were deprecated in 1.4 and should not be used until after the next major release. */
1700  if (!strcasecmp(cat, "classes") || !strcasecmp(cat, "moh_files") ||
1701  !strcasecmp(cat, "general")) {
1702  continue;
1703  }
1704 
1705  if (!(class = moh_class_malloc())) {
1706  break;
1707  }
1708 
1709  ast_copy_string(class->name, cat, sizeof(class->name));
1710  for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1711  if (!strcasecmp(var->name, "mode"))
1712  ast_copy_string(class->mode, var->value, sizeof(class->mode));
1713  else if (!strcasecmp(var->name, "directory"))
1714  ast_copy_string(class->dir, var->value, sizeof(class->dir));
1715  else if (!strcasecmp(var->name, "application"))
1716  ast_copy_string(class->args, var->value, sizeof(class->args));
1717  else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value)))
1718  class->digit = *var->value;
1719  else if (!strcasecmp(var->name, "random"))
1720  ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
1721  else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "random"))
1722  ast_set_flag(class, MOH_RANDOMIZE);
1723  else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha"))
1724  ast_set_flag(class, MOH_SORTALPHA);
1725  else if (!strcasecmp(var->name, "format")) {
1726  class->format = ast_getformatbyname(var->value);
1727  if (!class->format) {
1728  ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
1729  class->format = AST_FORMAT_SLINEAR;
1730  }
1731  }
1732  }
1733 
1734  if (ast_strlen_zero(class->dir)) {
1735  if (!strcasecmp(class->mode, "custom")) {
1736  strcpy(class->dir, "nodir");
1737  } else {
1738  ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
1739  class = mohclass_unref(class, "unreffing potential mohclass (no directory)");
1740  continue;
1741  }
1742  }
1743  if (ast_strlen_zero(class->mode)) {
1744  ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
1745  class = mohclass_unref(class, "unreffing potential mohclass (no mode)");
1746  continue;
1747  }
1748  if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
1749  ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
1750  class = mohclass_unref(class, "unreffing potential mohclass (no app for custom mode)");
1751  continue;
1752  }
1753 
1754  /* Don't leak a class when it's already registered */
1755  if (!moh_register(class, reload, HANDLE_REF)) {
1756  numclasses++;
1757  }
1758  }
1759 
1760  ast_config_destroy(cfg);
1761 
1763  moh_classes_delete_marked, NULL, "Purge marked classes");
1764 
1765  return numclasses;
1766 }
static struct ao2_container * mohclasses
#define HANDLE_REF
static int moh_classes_delete_marked(void *obj, void *arg, int flags)
#define moh_register(a, b, c)
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94
static int reload(void)
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:144
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Goes through variables.
Definition: config.c:597
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
#define var
Definition: ast_expr2f.c:606
for(;;)
Definition: ast_expr2.c:2460
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: config.c:1037
#define CONFIG_STATUS_FILEMISSING
Definition: config.h:50
static void moh_rescan_files(void)
const char * value
Definition: config.h:79
static const char app[]
Definition: app_adsiprog.c:49
#define MOH_CACHERTCLASSES
#define ast_config_load(filename, flags)
Load a config file.
Definition: config.h:170
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
char * ast_category_browse(struct ast_config *config, const char *prev)
Goes through categories.
Definition: config.c:810
#define MOH_SORTALPHA
const char * name
Definition: config.h:77
format_t ast_getformatbyname(const char *name)
Gets a format from a name.
Definition: frame.c:641
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is &quot;true&quot;. This function checks to see whether a string passed to it is an indication of an &quot;true&quot; value. It checks to see if the string is &quot;yes&quot;, &quot;true&quot;, &quot;y&quot;, &quot;t&quot;, &quot;on&quot; or &quot;1&quot;.
Definition: utils.c:1533
#define ao2_t_callback(c, flags, cb_fn, arg, tag)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Definition: astobj2.h:909
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define AST_FLAGS_ALL
Definition: utils.h:196
Structure used to handle boolean flags.
Definition: utils.h:200
#define ast_clear_flag(p, flag)
Definition: utils.h:77
static struct ast_flags global_flags[1]
static int moh_class_mark(void *obj, void *arg, int flags)
#define AST_FORMAT_SLINEAR
Definition: frame.h:254
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
#define mohclass_unref(class, string)
struct ast_variable * next
Definition: config.h:82
#define CONFIG_STATUS_FILEINVALID
Definition: config.h:52
#define moh_class_malloc()
#define MOH_RANDOMIZE
#define CONFIG_STATUS_FILEUNCHANGED
Definition: config.h:51
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: config.c:2587
static void local_ast_moh_cleanup ( struct ast_channel chan)
static

Definition at line 1274 of file res_musiconhold.c.

References ast_free, ast_log(), ast_module_unref(), moh_files_state::class, LOG_WARNING, mohclass_unref, ast_channel::music_state, and ast_module_info::self.

Referenced by load_module(), and reload().

1275 {
1276  struct moh_files_state *state = chan->music_state;
1277 
1278  if (state) {
1279  if (state->class) {
1280  /* This should never happen. We likely just leaked some resource. */
1281  state->class =
1282  mohclass_unref(state->class, "Uh Oh. Cleaning up MOH with an active class");
1283  ast_log(LOG_WARNING, "Uh Oh. Cleaning up MOH with an active class\n");
1284  }
1285  ast_free(chan->music_state);
1286  chan->music_state = NULL;
1287  /* Only held a module reference if we had a music state */
1289  }
1290 }
void * music_state
Definition: channel.h:745
void ast_module_unref(struct ast_module *)
Definition: loader.c:1312
#define LOG_WARNING
Definition: logger.h:144
struct mohclass * class
struct ast_module * self
Definition: module.h:227
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_free(a)
Definition: astmm.h:97
#define mohclass_unref(class, string)
static int local_ast_moh_start ( struct ast_channel chan,
const char *  mclass,
const char *  interpclass 
)
static

Definition at line 1316 of file res_musiconhold.c.

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

Referenced by load_module(), and reload().

1317 {
1318  struct mohclass *mohclass = NULL;
1319  struct moh_files_state *state = chan->music_state;
1320  struct ast_variable *var = NULL;
1321  int res = 0;
1322  int realtime_possible = ast_check_realtime("musiconhold");
1323 
1324  /* The following is the order of preference for which class to use:
1325  * 1) The channels explicitly set musicclass, which should *only* be
1326  * set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
1327  * 2) The mclass argument. If a channel is calling ast_moh_start() as the
1328  * result of receiving a HOLD control frame, this should be the
1329  * payload that came with the frame.
1330  * 3) The interpclass argument. This would be from the mohinterpret
1331  * option from channel drivers. This is the same as the old musicclass
1332  * option.
1333  * 4) The default class.
1334  */
1335  if (!ast_strlen_zero(chan->musicclass)) {
1336  mohclass = get_mohbyname(chan->musicclass, 1, 0);
1337  if (!mohclass && realtime_possible) {
1338  var = ast_load_realtime("musiconhold", "name", chan->musicclass, SENTINEL);
1339  }
1340  }
1341  if (!mohclass && !var && !ast_strlen_zero(mclass)) {
1342  mohclass = get_mohbyname(mclass, 1, 0);
1343  if (!mohclass && realtime_possible) {
1344  var = ast_load_realtime("musiconhold", "name", mclass, SENTINEL);
1345  }
1346  }
1347  if (!mohclass && !var && !ast_strlen_zero(interpclass)) {
1348  mohclass = get_mohbyname(interpclass, 1, 0);
1349  if (!mohclass && realtime_possible) {
1350  var = ast_load_realtime("musiconhold", "name", interpclass, SENTINEL);
1351  }
1352  }
1353 
1354  if (!mohclass && !var) {
1355  mohclass = get_mohbyname("default", 1, 0);
1356  if (!mohclass && realtime_possible) {
1357  var = ast_load_realtime("musiconhold", "name", "default", SENTINEL);
1358  }
1359  }
1360 
1361  /* If no moh class found in memory, then check RT. Note that the logic used
1362  * above guarantees that if var is non-NULL, then mohclass must be NULL.
1363  */
1364  if (var) {
1365  struct ast_variable *tmp = NULL;
1366 
1367  if ((mohclass = moh_class_malloc())) {
1368  mohclass->realtime = 1;
1369  for (tmp = var; tmp; tmp = tmp->next) {
1370  if (!strcasecmp(tmp->name, "name"))
1371  ast_copy_string(mohclass->name, tmp->value, sizeof(mohclass->name));
1372  else if (!strcasecmp(tmp->name, "mode"))
1373  ast_copy_string(mohclass->mode, tmp->value, sizeof(mohclass->mode));
1374  else if (!strcasecmp(tmp->name, "directory"))
1375  ast_copy_string(mohclass->dir, tmp->value, sizeof(mohclass->dir));
1376  else if (!strcasecmp(tmp->name, "application"))
1377  ast_copy_string(mohclass->args, tmp->value, sizeof(mohclass->args));
1378  else if (!strcasecmp(tmp->name, "digit") && (isdigit(*tmp->value) || strchr("*#", *tmp->value)))
1379  mohclass->digit = *tmp->value;
1380  else if (!strcasecmp(tmp->name, "random"))
1381  ast_set2_flag(mohclass, ast_true(tmp->value), MOH_RANDOMIZE);
1382  else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "random"))
1383  ast_set_flag(mohclass, MOH_RANDOMIZE);
1384  else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "alpha"))
1385  ast_set_flag(mohclass, MOH_SORTALPHA);
1386  else if (!strcasecmp(tmp->name, "format")) {
1387  mohclass->format = ast_getformatbyname(tmp->value);
1388  if (!mohclass->format) {
1389  ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", tmp->value);
1390  mohclass->format = AST_FORMAT_SLINEAR;
1391  }
1392  }
1393  }
1394  ast_variables_destroy(var);
1395  if (ast_strlen_zero(mohclass->dir)) {
1396  if (!strcasecmp(mohclass->mode, "custom")) {
1397  strcpy(mohclass->dir, "nodir");
1398  } else {
1399  ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", mohclass->name);
1400  mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no directory specified)");
1401  return -1;
1402  }
1403  }
1404  if (ast_strlen_zero(mohclass->mode)) {
1405  ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", mohclass->name);
1406  mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no mode specified)");
1407  return -1;
1408  }
1409  if (ast_strlen_zero(mohclass->args) && !strcasecmp(mohclass->mode, "custom")) {
1410  ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", mohclass->name);
1411  mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no app specified for custom mode");
1412  return -1;
1413  }
1414 
1416  /* CACHERTCLASSES enabled, let's add this class to default tree */
1417  if (state && state->class) {
1418  /* Class already exist for this channel */
1419  ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name);
1420  }
1421  /* We don't want moh_register to unref the mohclass because we do it at the end of this function as well.
1422  * If we allowed moh_register to unref the mohclass,too, then the count would be off by one. The result would
1423  * be that the destructor would be called when the generator on the channel is deactivated. The container then
1424  * has a pointer to a freed mohclass, so any operations involving the mohclass container would result in reading
1425  * invalid memory.
1426  */
1427  if (moh_register(mohclass, 0, DONT_UNREF) == -1) {
1428  mohclass = mohclass_unref(mohclass, "unreffing mohclass failed to register");
1429  return -1;
1430  }
1431  } else {
1432  /* We don't register RT moh class, so let's init it manualy */
1433 
1434  time(&mohclass->start);
1435  mohclass->start -= respawn_time;
1436 
1437  if (!strcasecmp(mohclass->mode, "files")) {
1438  if (!moh_scan_files(mohclass)) {
1439  mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)");
1440  return -1;
1441  }
1442  if (strchr(mohclass->args, 'r'))
1443  ast_set_flag(mohclass, MOH_RANDOMIZE);
1444  } 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")) {
1445 
1446  if (!strcasecmp(mohclass->mode, "custom"))
1447  ast_set_flag(mohclass, MOH_CUSTOM);
1448  else if (!strcasecmp(mohclass->mode, "mp3nb"))
1449  ast_set_flag(mohclass, MOH_SINGLE);
1450  else if (!strcasecmp(mohclass->mode, "quietmp3nb"))
1451  ast_set_flag(mohclass, MOH_SINGLE | MOH_QUIET);
1452  else if (!strcasecmp(mohclass->mode, "quietmp3"))
1453  ast_set_flag(mohclass, MOH_QUIET);
1454 
1455  mohclass->srcfd = -1;
1456  if (!(mohclass->timer = ast_timer_open())) {
1457  ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno));
1458  }
1459  if (mohclass->timer && ast_timer_set_rate(mohclass->timer, 25)) {
1460  ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno));
1461  ast_timer_close(mohclass->timer);
1462  mohclass->timer = NULL;
1463  }
1464 
1465  /* Let's check if this channel already had a moh class before */
1466  if (state && state->class) {
1467  /* Class already exist for this channel */
1468  ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name);
1469  if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) {
1470  /* we found RT class with the same name, seems like we should continue playing existing one */
1471  mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has one)");
1472  mohclass = mohclass_ref(state->class, "using existing class from state");
1473  }
1474  } else {
1475  if (ast_pthread_create_background(&mohclass->thread, NULL, monmp3thread, mohclass)) {
1476  ast_log(LOG_WARNING, "Unable to create moh...\n");
1477  if (mohclass->timer) {
1478  ast_timer_close(mohclass->timer);
1479  mohclass->timer = NULL;
1480  }
1481  mohclass = mohclass_unref(mohclass, "Unreffing potential mohclass (failed to create background thread)");
1482  return -1;
1483  }
1484  }
1485  } else {
1486  ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mohclass->mode);
1487  mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (unknown mode)");
1488  return -1;
1489  }
1490  }
1491  } else {
1492  ast_variables_destroy(var);
1493  var = NULL;
1494  }
1495  }
1496 
1497  if (!mohclass) {
1498  return -1;
1499  }
1500 
1501  /* If we are using a cached realtime class with files, re-scan the files */
1502  if (!var && ast_test_flag(global_flags, MOH_CACHERTCLASSES) && mohclass->realtime && !strcasecmp(mohclass->mode, "files")) {
1503  if (!moh_scan_files(mohclass)) {
1504  mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)");
1505  return -1;
1506  }
1507  }
1508 
1509  ast_manager_event(chan, EVENT_FLAG_CALL, "MusicOnHold",
1510  "State: Start\r\n"
1511  "Channel: %s\r\n"
1512  "UniqueID: %s\r\n"
1513  "Class: %s\r\n",
1514  chan->name, chan->uniqueid,
1515  mohclass->name);
1516 
1517  ast_set_flag(chan, AST_FLAG_MOH);
1518 
1519  if (!state || !state->class || strcmp(mohclass->name, state->class->name)) {
1520  if (mohclass->total_files) {
1521  res = ast_activate_generator(chan, &moh_file_stream, mohclass);
1522  } else {
1523  res = ast_activate_generator(chan, &mohgen, mohclass);
1524  }
1525  }
1526 
1527  mohclass = mohclass_unref(mohclass, "unreffing local reference to mohclass in local_ast_moh_start");
1528 
1529  return res;
1530 }
void * music_state
Definition: channel.h:745
char name[MAX_MUSICCLASS]
const ast_string_field uniqueid
Definition: channel.h:787
#define moh_register(a, b, c)
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94
#define ast_test_flag(p, flag)
Definition: utils.h:63
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
Definition: channel.c:3148
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:144
struct mohclass * class
Structure for variables, used for configurations and for channel variables.
Definition: config.h:75
#define var
Definition: ast_expr2f.c:606
#define EVENT_FLAG_CALL
Definition: manager.h:72
void ast_timer_close(struct ast_timer *handle)
Close an opened timing handle.
Definition: timing.c:150
struct ast_timer * ast_timer_open(void)
Open a timer.
Definition: timing.c:123
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
Definition: config.c:2548
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: config.c:586
static int moh_scan_files(struct mohclass *class)
#define mohclass_ref(class, string)
char dir[256]
#define ast_manager_event(chan, category, event, contents,...)
Definition: manager.h:221
unsigned int realtime
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:426
#define SENTINEL
Definition: compiler.h:75
const char * value
Definition: config.h:79
#define MOH_CACHERTCLASSES
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define MOH_QUIET
#define MOH_SORTALPHA
const char * name
Definition: config.h:77
format_t ast_getformatbyname(const char *name)
Gets a format from a name.
Definition: frame.c:641
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is &quot;true&quot;. This function checks to see whether a string passed to it is an indication of an &quot;true&quot; value. It checks to see if the string is &quot;yes&quot;, &quot;true&quot;, &quot;y&quot;, &quot;t&quot;, &quot;on&quot; or &quot;1&quot;.
Definition: utils.c:1533
const ast_string_field name
Definition: channel.h:787
static struct ast_generator moh_file_stream
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
int errno
time_t start
static int respawn_time
int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
Set the timing tick rate.
Definition: timing.c:163
struct ast_timer * timer
format_t format
static struct ast_flags global_flags[1]
#define MOH_CUSTOM
#define AST_FORMAT_SLINEAR
Definition: frame.h:254
pthread_t thread
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
char args[256]
const ast_string_field musicclass
Definition: channel.h:787
#define mohclass_unref(class, string)
struct ast_variable * next
Definition: config.h:82
char mode[80]
static struct ast_generator mohgen
static void * monmp3thread(void *data)
#define MOH_SINGLE
#define moh_class_malloc()
#define MOH_RANDOMIZE
#define DONT_UNREF
#define get_mohbyname(a, b, c)
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: config.c:2587
static void local_ast_moh_stop ( struct ast_channel chan)
static

Definition at line 1532 of file res_musiconhold.c.

References ast_channel_lock, ast_channel_unlock, ast_clear_flag, ast_closestream(), ast_deactivate_generator(), AST_FLAG_MOH, ast_manager_event, EVENT_FLAG_CALL, ast_channel::music_state, ast_channel::name, ast_channel::stream, and ast_channel::uniqueid.

Referenced by load_module(), and reload().

1533 {
1536 
1537  ast_channel_lock(chan);
1538  if (chan->music_state) {
1539  if (chan->stream) {
1540  ast_closestream(chan->stream);
1541  chan->stream = NULL;
1542  }
1543  }
1544 
1545  ast_manager_event(chan, EVENT_FLAG_CALL, "MusicOnHold",
1546  "State: Stop\r\n"
1547  "Channel: %s\r\n"
1548  "UniqueID: %s\r\n",
1549  chan->name, chan->uniqueid);
1550  ast_channel_unlock(chan);
1551 }
void * music_state
Definition: channel.h:745
#define ast_channel_lock(chan)
Definition: channel.h:2466
const ast_string_field uniqueid
Definition: channel.h:787
#define EVENT_FLAG_CALL
Definition: manager.h:72
#define ast_manager_event(chan, category, event, contents,...)
Definition: manager.h:221
const ast_string_field name
Definition: channel.h:787
#define ast_channel_unlock(chan)
Definition: channel.h:2467
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:904
#define ast_clear_flag(p, flag)
Definition: utils.h:77
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:3107
struct ast_filestream * stream
Definition: channel.h:757
static int moh_add_file ( struct mohclass class,
const char *  filepath 
)
static

Definition at line 1001 of file res_musiconhold.c.

References ast_calloc, ast_realloc, ast_strdup, and INITIAL_NUM_FILES.

Referenced by moh_scan_files().

1002 {
1003  if (!class->allowed_files) {
1004  class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray));
1005  if (!class->filearray) {
1006  return -1;
1007  }
1008  class->allowed_files = INITIAL_NUM_FILES;
1009  } else if (class->total_files == class->allowed_files) {
1010  char **new_array;
1011 
1012  new_array = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2);
1013  if (!new_array) {
1014  return -1;
1015  }
1016  class->filearray = new_array;
1017  class->allowed_files *= 2;
1018  }
1019 
1020  class->filearray[class->total_files] = ast_strdup(filepath);
1021  if (!class->filearray[class->total_files]) {
1022  return -1;
1023  }
1024 
1025  class->total_files++;
1026 
1027  return 0;
1028 }
#define ast_strdup(a)
Definition: astmm.h:109
#define INITIAL_NUM_FILES
#define ast_calloc(a, b)
Definition: astmm.h:82
#define ast_realloc(a, b)
Definition: astmm.h:103
char ** filearray
static void* moh_alloc ( struct ast_channel chan,
void *  params 
)
static

Definition at line 930 of file res_musiconhold.c.

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

931 {
932  struct mohdata *res;
933  struct mohclass *class = params;
934  struct moh_files_state *state;
935 
936  /* Initiating music_state for current channel. Channel should know name of moh class */
937  if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) {
938  chan->music_state = state;
940  } else {
941  state = chan->music_state;
942  if (!state) {
943  return NULL;
944  }
945  if (state->class) {
946  mohclass_unref(state->class, "Uh Oh. Restarting MOH with an active class");
947  ast_log(LOG_WARNING, "Uh Oh. Restarting MOH with an active class\n");
948  }
949  memset(state, 0, sizeof(*state));
950  }
951 
952  if ((res = mohalloc(class))) {
953  res->origwfmt = chan->writeformat;
954  if (ast_set_write_format(chan, class->format)) {
955  ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format));
956  moh_release(NULL, res);
957  res = NULL;
958  } else {
959  state->class = mohclass_ref(class, "Placing reference into state container");
960  }
961  ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name);
962  }
963  return res;
964 }
void * music_state
Definition: channel.h:745
static void moh_release(struct ast_channel *chan, void *data)
enum sip_cc_notify_state state
Definition: chan_sip.c:842
char name[MAX_MUSICCLASS]
format_t writeformat
Definition: channel.h:854
#define LOG_WARNING
Definition: logger.h:144
struct mohclass * class
format_t origwfmt
#define ast_verb(level,...)
Definition: logger.h:243
static struct mohdata * mohalloc(struct mohclass *cl)
#define mohclass_ref(class, string)
int ast_set_write_format(struct ast_channel *chan, format_t format)
Sets write format on channel chan Set write format for channel to whichever component of &quot;format&quot; is ...
Definition: channel.c:5307
struct ast_module * self
Definition: module.h:227
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
format_t format
#define ast_calloc(a, b)
Definition: astmm.h:82
#define mohclass_unref(class, string)
char * ast_codec2str(format_t codec)
Get a name from a format Gets a name from a format.
Definition: frame.c:660
struct ast_module * ast_module_ref(struct ast_module *)
Definition: loader.c:1300
static int moh_class_cmp ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 1887 of file res_musiconhold.c.

References CMP_MATCH, CMP_STOP, and MOH_NOTDELETED.

Referenced by load_module().

1888 {
1889  struct mohclass *class = obj, *class2 = arg;
1890 
1891  return strcasecmp(class->name, class2->name) ? 0 :
1892  (flags & MOH_NOTDELETED) && (class->delete || class2->delete) ? 0 :
1893  CMP_MATCH | CMP_STOP;
1894 }
#define MOH_NOTDELETED
static void moh_class_destructor ( void *  obj)
static

Definition at line 1553 of file res_musiconhold.c.

References ao2_lock, ao2_unlock, ast_debug, ast_free, AST_LIST_REMOVE_HEAD, ast_log(), AST_PTHREADT_NULL, ast_timer_close(), ast_wait_for_input(), buff, errno, LOG_DEBUG, LOG_WARNING, and mohclass::pid.

Referenced by _moh_class_malloc().

1554 {
1555  struct mohclass *class = obj;
1556  struct mohdata *member;
1557  pthread_t tid = 0;
1558 
1559  ast_debug(1, "Destroying MOH class '%s'\n", class->name);
1560 
1561  ao2_lock(class);
1562  while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) {
1563  ast_free(member);
1564  }
1565  ao2_unlock(class);
1566 
1567  /* Kill the thread first, so it cannot restart the child process while the
1568  * class is being destroyed */
1569  if (class->thread != AST_PTHREADT_NULL && class->thread != 0) {
1570  tid = class->thread;
1571  class->thread = AST_PTHREADT_NULL;
1572  pthread_cancel(tid);
1573  /* We'll collect the exit status later, after we ensure all the readers
1574  * are dead. */
1575  }
1576 
1577  if (class->pid > 1) {
1578  char buff[8192];
1579  int bytes, tbytes = 0, stime = 0, pid = 0;
1580 
1581  ast_log(LOG_DEBUG, "killing %d!\n", class->pid);
1582 
1583  stime = time(NULL) + 2;
1584  pid = class->pid;
1585  class->pid = 0;
1586 
1587  /* Back when this was just mpg123, SIGKILL was fine. Now we need
1588  * to give the process a reason and time enough to kill off its
1589  * children. */
1590  do {
1591  if (killpg(pid, SIGHUP) < 0) {
1592  ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno));
1593  }
1594  usleep(100000);
1595  if (killpg(pid, SIGTERM) < 0) {
1596  if (errno == ESRCH) {
1597  break;
1598  }
1599  ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno));
1600  }
1601  usleep(100000);
1602  if (killpg(pid, SIGKILL) < 0) {
1603  if (errno == ESRCH) {
1604  break;
1605  }
1606  ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno));
1607  }
1608  } while (0);
1609 
1610  while ((ast_wait_for_input(class->srcfd, 100) > 0) &&
1611  (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) {
1612  tbytes = tbytes + bytes;
1613  }
1614 
1615  ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
1616 
1617  close(class->srcfd);
1618  class->srcfd = -1;
1619  }
1620 
1621  if (class->filearray) {
1622  int i;
1623  for (i = 0; i < class->total_files; i++) {
1624  ast_free(class->filearray[i]);
1625  }
1626  ast_free(class->filearray);
1627  class->filearray = NULL;
1628  }
1629 
1630  if (class->timer) {
1631  ast_timer_close(class->timer);
1632  class->timer = NULL;
1633  }
1634 
1635  /* Finally, collect the exit status of the monitor thread */
1636  if (tid > 0) {
1637  pthread_join(tid, NULL);
1638  }
1639 
1640 }
struct mohdata::@336 list
#define LOG_WARNING
Definition: logger.h:144
void ast_timer_close(struct ast_timer *handle)
Close an opened timing handle.
Definition: timing.c:150
#define ao2_unlock(a)
Definition: astobj2.h:497
#define LOG_DEBUG
Definition: logger.h:122
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define AST_PTHREADT_NULL
Definition: lock.h:65
#define ao2_lock(a)
Definition: astobj2.h:488
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int errno
#define ast_free(a)
Definition: astmm.h:97
static unsigned char * buff
Definition: chan_unistim.c:232
int ast_wait_for_input(int fd, int ms)
Definition: utils.c:1255
static int moh_class_hash ( const void *  obj,
const int  flags 
)
static

Definition at line 1880 of file res_musiconhold.c.

References ast_str_case_hash().

Referenced by load_module().

1881 {
1882  const struct mohclass *class = obj;
1883 
1884  return ast_str_case_hash(class->name);
1885 }
static force_inline int attribute_pure ast_str_case_hash(const char *str)
Compute a hash value on a case-insensitive string.
Definition: strings.h:989
static int moh_class_inuse ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 1937 of file res_musiconhold.c.

References AST_LIST_EMPTY, CMP_MATCH, and CMP_STOP.

Referenced by unload_module().

1938 {
1939  struct mohclass *class = obj;
1940 
1941  return AST_LIST_EMPTY(&class->members) ? 0 : CMP_MATCH | CMP_STOP;
1942 }
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
static int moh_class_mark ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 1642 of file res_musiconhold.c.

References mohclass::delete.

Referenced by load_moh_classes().

1643 {
1644  struct mohclass *class = obj;
1645 
1646  class->delete = 1;
1647 
1648  return 0;
1649 }
unsigned int delete
static int moh_classes_delete_marked ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 1651 of file res_musiconhold.c.

References CMP_MATCH, and mohclass::delete.

Referenced by load_moh_classes().

1652 {
1653  struct mohclass *class = obj;
1654 
1655  return class->delete ? CMP_MATCH : 0;
1656 }
unsigned int delete
static int moh_diff ( struct mohclass old,
struct mohclass new 
)
static

Definition at line 1161 of file res_musiconhold.c.

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

Referenced by _moh_register().

1162 {
1163  if (!old || !new) {
1164  return -1;
1165  }
1166 
1167  if (strcmp(old->dir, new->dir)) {
1168  return -1;
1169  } else if (strcmp(old->mode, new->mode)) {
1170  return -1;
1171  } else if (strcmp(old->args, new->args)) {
1172  return -1;
1173  } else if (old->flags != new->flags) {
1174  return -1;
1175  }
1176 
1177  return 0;
1178 }
char dir[256]
unsigned int flags
char args[256]
char mode[80]
static int moh_digit_match ( void *  obj,
void *  arg,
int  flags 
)
static

Definition at line 441 of file res_musiconhold.c.

References CMP_MATCH, CMP_STOP, and mohclass::digit.

Referenced by get_mohbydigit().

442 {
443  char *digit = arg;
444  struct mohclass *class = obj;
445 
446  return (*digit == class->digit) ? CMP_MATCH | CMP_STOP : 0;
447 }
static void* moh_files_alloc ( struct ast_channel chan,
void *  params 
)
static

Definition at line 402 of file res_musiconhold.c.

References ast_calloc, ast_copy_string(), ast_log(), ast_module_ref(), ast_random(), ast_test_flag, ast_verb, moh_files_state::class, LOG_WARNING, MOH_RANDOMIZE, mohclass_ref, mohclass_unref, ast_channel::music_state, moh_files_state::name, ast_channel::name, moh_files_state::origwfmt, moh_files_state::pos, moh_files_state::save_total, ast_module_info::self, state, and ast_channel::writeformat.

403 {
404  struct moh_files_state *state;
405  struct mohclass *class = params;
406 
407  if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) {
408  chan->music_state = state;
410  } else {
411  state = chan->music_state;
412  if (!state) {
413  return NULL;
414  }
415  if (state->class) {
416  mohclass_unref(state->class, "Uh Oh. Restarting MOH with an active class");
417  ast_log(LOG_WARNING, "Uh Oh. Restarting MOH with an active class\n");
418  }
419  }
420 
421  /* Resume MOH from where we left off last time or start from scratch? */
422  if (state->save_total != class->total_files || strcmp(state->name, class->name) != 0) {
423  /* Start MOH from scratch. */
424  memset(state, 0, sizeof(*state));
425  if (ast_test_flag(class, MOH_RANDOMIZE) && class->total_files) {
426  state->pos = ast_random() % class->total_files;
427  }
428  }
429 
430  state->class = mohclass_ref(class, "Reffing music class for channel");
431  state->origwfmt = chan->writeformat;
432  /* For comparison on restart of MOH (see above) */
433  ast_copy_string(state->name, class->name, sizeof(state->name));
434  state->save_total = class->total_files;
435 
436  ast_verb(3, "Started music on hold, class '%s', on %s\n", class->name, chan->name);
437 
438  return chan->music_state;
439 }
void * music_state
Definition: channel.h:745
enum sip_cc_notify_state state
Definition: chan_sip.c:842
format_t writeformat
Definition: channel.h:854
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define LOG_WARNING
Definition: logger.h:144
struct mohclass * class
#define ast_verb(level,...)
Definition: logger.h:243
#define mohclass_ref(class, string)
struct ast_module * self
Definition: module.h:227
long int ast_random(void)
Definition: utils.c:1640
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_calloc(a, b)
Definition: astmm.h:82
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
#define mohclass_unref(class, string)
char name[MAX_MUSICCLASS]
#define MOH_RANDOMIZE
struct ast_module * ast_module_ref(struct ast_module *)
Definition: loader.c:1300
static int moh_files_generator ( struct ast_channel chan,
void *  data,
int  len,
int  samples 
)
static

Definition at line 367 of file res_musiconhold.c.

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

368 {
369  struct moh_files_state *state = chan->music_state;
370  struct ast_frame *f = NULL;
371  int res = 0;
372 
373  state->sample_queue += samples;
374 
375  while (state->sample_queue > 0) {
376  ast_channel_lock(chan);
377  f = moh_files_readframe(chan);
378 
379  /* We need to be sure that we unlock
380  * the channel prior to calling
381  * ast_write. Otherwise, the recursive locking
382  * that occurs can cause deadlocks when using
383  * indirect channels, like local channels
384  */
385  ast_channel_unlock(chan);
386  if (!f) {
387  return -1;
388  }
389 
390  state->samples += f->samples;
391  state->sample_queue -= f->samples;
392  res = ast_write(chan, f);
393  ast_frfree(f);
394  if (res < 0) {
395  ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
396  return -1;
397  }
398  }
399  return res;
400 }
void * music_state
Definition: channel.h:745
#define ast_channel_lock(chan)
Definition: channel.h:2466
static struct ast_frame * moh_files_readframe(struct ast_channel *chan)
#define LOG_WARNING
Definition: logger.h:144
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_channel_unlock(chan)
Definition: channel.h:2467
int errno
static struct ast_format f[]
Definition: format_g726.c:181
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition: channel.c:4916
Data structure associated with a single frame of data.
Definition: frame.h:142
#define ast_frfree(fr)
Definition: frame.h:583
int samples
Definition: frame.h:150
static struct ast_frame* moh_files_readframe ( struct ast_channel chan)
static

Definition at line 355 of file res_musiconhold.c.

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

Referenced by moh_files_generator().

356 {
357  struct ast_frame *f = NULL;
358 
359  if (!(chan->stream && (f = ast_readframe(chan->stream)))) {
360  if (!ast_moh_files_next(chan))
361  f = ast_readframe(chan->stream);
362  }
363 
364  return f;
365 }
struct ast_frame * ast_readframe(struct ast_filestream *s)
Read a frame from a filestream.
Definition: file.c:737
static struct ast_format f[]
Definition: format_g726.c:181
Data structure associated with a single frame of data.
Definition: frame.h:142
struct ast_filestream * stream
Definition: channel.h:757
static int ast_moh_files_next(struct ast_channel *chan)
static void moh_files_release ( struct ast_channel chan,
void *  data 
)
static

Definition at line 251 of file res_musiconhold.c.

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

252 {
253  struct moh_files_state *state;
254 
255  if (!chan || !chan->music_state) {
256  return;
257  }
258 
259  state = chan->music_state;
260 
261  if (chan->stream) {
262  ast_closestream(chan->stream);
263  chan->stream = NULL;
264  }
265 
266  if (option_verbose > 2) {
267  ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
268  }
269 
270  if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
271  ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%s'\n", chan->name, ast_getformatname(state->origwfmt));
272  }
273 
274  state->save_pos = state->pos;
275 
276  state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator");
277 }
void * music_state
Definition: channel.h:745
enum sip_cc_notify_state state
Definition: chan_sip.c:842
#define VERBOSE_PREFIX_3
Definition: logger.h:43
#define LOG_WARNING
Definition: logger.h:144
struct mohclass * class
void ast_verbose(const char *fmt,...)
Definition: logger.c:1568
int option_verbose
Definition: asterisk.c:181
int ast_set_write_format(struct ast_channel *chan, format_t format)
Sets write format on channel chan Set write format for channel to whichever component of &quot;format&quot; is ...
Definition: channel.c:5307
char * ast_getformatname(format_t format)
Get the name of a format.
Definition: frame.c:578
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:904
#define mohclass_unref(class, string)
struct ast_filestream * stream
Definition: channel.h:757
static int moh_generate ( struct ast_channel chan,
void *  data,
int  len,
int  samples 
)
static

Definition at line 966 of file res_musiconhold.c.

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

967 {
968  struct mohdata *moh = data;
969  short buf[1280 + AST_FRIENDLY_OFFSET / 2];
970  int res;
971 
972  len = ast_codec_get_len(moh->parent->format, samples);
973 
974  if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
975  ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name);
976  len = sizeof(buf) - AST_FRIENDLY_OFFSET;
977  }
978  res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
979  if (res <= 0)
980  return 0;
981 
982  moh->f.datalen = res;
983  moh->f.data.ptr = buf + AST_FRIENDLY_OFFSET / 2;
984  moh->f.samples = ast_codec_get_samples(&moh->f);
985 
986  if (ast_write(chan, &moh->f) < 0) {
987  ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
988  return -1;
989  }
990 
991  return 0;
992 }
void * ptr
Definition: frame.h:160
#define LOG_WARNING
Definition: logger.h:144
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
Definition: frame.h:204
int datalen
Definition: frame.h:148
static char moh[80]
Definition: chan_agent.c:209
int pipe[2]
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int errno
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Definition: channel.c:4916
format_t format
struct ast_frame f
int ast_codec_get_samples(struct ast_frame *f)
Returns the number of samples contained in the frame.
Definition: frame.c:1470
struct mohclass * parent
union ast_frame::@172 data
int ast_codec_get_len(format_t format, int samples)
Returns the number of bytes for the number of samples of the given format.
Definition: frame.c:1532
int samples
Definition: frame.h:150
static void moh_handle_digit ( struct ast_channel chan,
char  digit 
)
static

Definition at line 455 of file res_musiconhold.c.

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

456 {
457  struct mohclass *class;
458  const char *classname = NULL;
459 
460  if ((class = get_mohbydigit(digit))) {
461  classname = ast_strdupa(class->name);
462  class = mohclass_unref(class, "Unreffing ao2_find from finding by digit");
463  ast_string_field_set(chan,musicclass,classname);
464  ast_moh_stop(chan);
465  ast_moh_start(chan, classname, NULL);
466  }
467 }
static char musicclass[MAX_MUSICCLASS]
Definition: chan_mgcp.c:155
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:8051
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:8040
#define ao2_find(arg1, arg2, arg3)
Definition: astobj2.h:964
#define mohclass_unref(class, string)
static struct mohclass * get_mohbydigit(char digit)
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:344
static void moh_release ( struct ast_channel chan,
void *  data 
)
static

Definition at line 895 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, moh_files_state::class, LOG_WARNING, mohclass::members, moh, mohclass_unref, ast_channel::music_state, ast_channel::name, mohdata::origwfmt, mohdata::parent, mohdata::pipe, and state.

Referenced by moh_alloc().

896 {
897  struct mohdata *moh = data;
898  struct mohclass *class = moh->parent;
899  format_t oldwfmt;
900 
901  ao2_lock(class);
902  AST_LIST_REMOVE(&moh->parent->members, moh, list);
903  ao2_unlock(class);
904 
905  close(moh->pipe[0]);
906  close(moh->pipe[1]);
907 
908  oldwfmt = moh->origwfmt;
909 
910  moh->parent = class = mohclass_unref(class, "unreffing moh->parent upon deactivation of generator");
911 
912  ast_free(moh);
913 
914  if (chan) {
915  struct moh_files_state *state;
916 
917  state = chan->music_state;
918  if (state && state->class) {
919  state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator");
920  }
921  if (oldwfmt && ast_set_write_format(chan, oldwfmt)) {
922  ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n",
923  chan->name, ast_getformatname(oldwfmt));
924  }
925 
926  ast_verb(3, "Stopped music on hold on %s\n", chan->name);
927  }
928 }
void * music_state
Definition: channel.h:745
enum sip_cc_notify_state state
Definition: chan_sip.c:842
#define LOG_WARNING
Definition: logger.h:144
struct mohclass * class
format_t origwfmt
#define ao2_unlock(a)
Definition: astobj2.h:497
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:841
#define ast_verb(level,...)
Definition: logger.h:243
struct mohclass::@334 members
int ast_set_write_format(struct ast_channel *chan, format_t format)
Sets write format on channel chan Set write format for channel to whichever component of &quot;format&quot; is ...
Definition: channel.c:5307
#define ao2_lock(a)
Definition: astobj2.h:488
static char moh[80]
Definition: chan_agent.c:209
char * ast_getformatname(format_t format)
Get the name of a format.
Definition: frame.c:578
static struct ast_generator generator
Definition: app_fax.c:361
int64_t format_t
Definition: frame_defs.h:32
int pipe[2]
const ast_string_field name
Definition: channel.h:787
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_free(a)
Definition: astmm.h:97
#define mohclass_unref(class, string)
struct mohclass * parent
static void moh_rescan_files ( void  )
static

Definition at line 1145 of file res_musiconhold.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_iterator_next, ao2_ref, mohclass::mode, and moh_scan_files().

Referenced by load_moh_classes().

1145  {
1146  struct ao2_iterator i;
1147  struct mohclass *c;
1148 
1149  i = ao2_iterator_init(mohclasses, 0);
1150 
1151  while ((c = ao2_iterator_next(&i))) {
1152  if (!strcasecmp(c->mode, "files")) {
1153  moh_scan_files(c);
1154  }
1155  ao2_ref(c, -1);
1156  }
1157 
1159 }
static struct ao2_container * mohclasses
#define ao2_iterator_next(arg1)
Definition: astobj2.h:1126
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags)
Create an iterator for a container.
Definition: astobj2.c:818
static int moh_scan_files(struct mohclass *class)
#define ao2_ref(o, delta)
Definition: astobj2.h:472
void ao2_iterator_destroy(struct ao2_iterator *i)
Destroy a container iterator.
Definition: astobj2.c:833
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1053
char mode[80]
static int moh_scan_files ( struct mohclass class)
static

Definition at line 1040 of file res_musiconhold.c.

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

Referenced by init_files_class(), local_ast_moh_start(), and moh_rescan_files().

1040  {
1041 
1042  DIR *files_DIR;
1043  struct dirent *files_dirent;
1044  char dir_path[PATH_MAX];
1045  char path[PATH_MAX];
1046  char filepath[PATH_MAX];
1047  char *ext;
1048  struct stat statbuf;
1049  int i;
1050 
1051  if (class->dir[0] != '/') {
1052  ast_copy_string(dir_path, ast_config_AST_DATA_DIR, sizeof(dir_path));
1053  strncat(dir_path, "/", sizeof(dir_path) - 1);
1054  strncat(dir_path, class->dir, sizeof(dir_path) - 1);
1055  } else {
1056  ast_copy_string(dir_path, class->dir, sizeof(dir_path));
1057  }
1058  ast_debug(4, "Scanning '%s' for files for class '%s'\n", dir_path, class->name);
1059  files_DIR = opendir(dir_path);
1060  if (!files_DIR) {
1061  ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", dir_path);
1062  return -1;
1063  }
1064 
1065  for (i = 0; i < class->total_files; i++)
1066  ast_free(class->filearray[i]);
1067 
1068  class->total_files = 0;
1069  if (!getcwd(path, sizeof(path))) {
1070  ast_log(LOG_WARNING, "getcwd() failed: %s\n", strerror(errno));
1071  closedir(files_DIR);
1072  return -1;
1073  }
1074  if (chdir(dir_path) < 0) {
1075  ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
1076  closedir(files_DIR);
1077  return -1;
1078  }
1079  while ((files_dirent = readdir(files_DIR))) {
1080  /* The file name must be at least long enough to have the file type extension */
1081  if ((strlen(files_dirent->d_name) < 4))
1082  continue;
1083 
1084  /* Skip files that starts with a dot */
1085  if (files_dirent->d_name[0] == '.')
1086  continue;
1087 
1088  /* Skip files without extensions... they are not audio */
1089  if (!strchr(files_dirent->d_name, '.'))
1090  continue;
1091 
1092  snprintf(filepath, sizeof(filepath), "%s/%s", dir_path, files_dirent->d_name);
1093 
1094  if (stat(filepath, &statbuf))
1095  continue;
1096 
1097  if (!S_ISREG(statbuf.st_mode))
1098  continue;
1099 
1100  if ((ext = strrchr(filepath, '.')))
1101  *ext = '\0';
1102 
1103  /* if the file is present in multiple formats, ensure we only put it into the list once */
1104  for (i = 0; i < class->total_files; i++)
1105  if (!strcmp(filepath, class->filearray[i]))
1106  break;
1107 
1108  if (i == class->total_files) {
1109  if (moh_add_file(class, filepath))
1110  break;
1111  }
1112  }
1113 
1114  closedir(files_DIR);
1115  if (chdir(path) < 0) {
1116  ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
1117  return -1;
1118  }
1119  if (ast_test_flag(class, MOH_SORTALPHA))
1120  qsort(&class->filearray[0], class->total_files, sizeof(char *), moh_sort_compare);
1121  return class->total_files;
1122 }
char name[MAX_MUSICCLASS]
static int moh_sort_compare(const void *i1, const void *i2)
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define LOG_WARNING
Definition: logger.h:144
const char * ext
Definition: http.c:112
char dir[256]
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define MOH_SORTALPHA
const char * ast_config_AST_DATA_DIR
Definition: asterisk.c:262
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int errno
#define ast_free(a)
Definition: astmm.h:97
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
static int moh_add_file(struct mohclass *class, const char *filepath)
char ** filearray
static int moh_sort_compare ( const void *  i1,
const void *  i2 
)
static

Definition at line 1030 of file res_musiconhold.c.

Referenced by moh_scan_files().

1031 {
1032  char *s1, *s2;
1033 
1034  s1 = ((char **)i1)[0];
1035  s2 = ((char **)i2)[0];
1036 
1037  return strcasecmp(s1, s2);
1038 }
static struct mohdata* mohalloc ( struct mohclass cl)
static

Definition at line 862 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(), ast_frame_subclass::codec, errno, mohdata::f, mohclass::flags, mohclass::format, ast_frame::frametype, LOG_WARNING, mohclass::members, moh, mohclass_ref, ast_frame::offset, mohdata::parent, mohdata::pipe, and ast_frame::subclass.

Referenced by moh_alloc().

863 {
864  struct mohdata *moh;
865  long flags;
866 
867  if (!(moh = ast_calloc(1, sizeof(*moh))))
868  return NULL;
869 
870  if (pipe(moh->pipe)) {
871  ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
872  ast_free(moh);
873  return NULL;
874  }
875 
876  /* Make entirely non-blocking */
877  flags = fcntl(moh->pipe[0], F_GETFL);
878  fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
879  flags = fcntl(moh->pipe[1], F_GETFL);
880  fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
881 
882  moh->f.frametype = AST_FRAME_VOICE;
883  moh->f.subclass.codec = cl->format;
885 
886  moh->parent = mohclass_ref(cl, "Reffing music class for mohdata parent");
887 
888  ao2_lock(cl);
889  AST_LIST_INSERT_HEAD(&cl->members, moh, list);
890  ao2_unlock(cl);
891 
892  return moh;
893 }
union ast_frame_subclass subclass
Definition: frame.h:146
int offset
Definition: frame.h:156
struct mohdata::@336 list
#define LOG_WARNING
Definition: logger.h:144
#define ao2_unlock(a)
Definition: astobj2.h:497
format_t codec
Definition: frame.h:137
struct mohclass::@334 members
#define mohclass_ref(class, string)
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
Definition: frame.h:204
#define ao2_lock(a)
Definition: astobj2.h:488
static char moh[80]
Definition: chan_agent.c:209
int pipe[2]
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:696
int errno
#define ast_free(a)
Definition: astmm.h:97
format_t format
struct ast_frame f
#define ast_calloc(a, b)
Definition: astmm.h:82
enum ast_frame_type frametype
Definition: frame.h:144
struct mohclass * parent
static void* monmp3thread ( void *  data)
static

Definition at line 618 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_poll, ast_samp2tv(), ast_timer_ack(), ast_timer_fd(), ast_tvadd(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), errno, len(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, moh, MOH_MS_INTERVAL, mohdata::pipe, and spawn_mp3().

Referenced by init_app_class(), and local_ast_moh_start().

619 {
620 #define MOH_MS_INTERVAL 100
621 
622  struct mohclass *class = data;
623  struct mohdata *moh;
624  short sbuf[8192];
625  int res = 0, res2;
626  int len;
627  struct timeval deadline, tv_tmp;
628 
629  deadline.tv_sec = 0;
630  deadline.tv_usec = 0;
631  for(;/* ever */;) {
632  pthread_testcancel();
633  /* Spawn mp3 player if it's not there */
634  if (class->srcfd < 0) {
635  if ((class->srcfd = spawn_mp3(class)) < 0) {
636  ast_log(LOG_WARNING, "Unable to spawn mp3player\n");
637  /* Try again later */
638  sleep(500);
639  continue;
640  }
641  }
642  if (class->timer) {
643  struct pollfd pfd = { .fd = ast_timer_fd(class->timer), .events = POLLIN | POLLPRI, };
644 
645 #ifdef SOLARIS
646  thr_yield();
647 #endif
648  /* Pause some amount of time */
649  if (ast_poll(&pfd, 1, -1) > 0) {
650  if (ast_timer_ack(class->timer, 1) < 0) {
651  ast_log(LOG_ERROR, "Failed to acknowledge timer for mp3player\n");
652  return NULL;
653  }
654  res = 320;
655  } else {
656  ast_log(LOG_WARNING, "poll() failed: %s\n", strerror(errno));
657  res = 0;
658  }
659  pthread_testcancel();
660  } else {
661  long delta;
662  /* Reliable sleep */
663  tv_tmp = ast_tvnow();
664  if (ast_tvzero(deadline))
665  deadline = tv_tmp;
666  delta = ast_tvdiff_ms(tv_tmp, deadline);
667  if (delta < MOH_MS_INTERVAL) { /* too early */
668  deadline = ast_tvadd(deadline, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */
669  usleep(1000 * (MOH_MS_INTERVAL - delta));
670  pthread_testcancel();
671  } else {
672  ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
673  deadline = tv_tmp;
674  }
675  res = 8 * MOH_MS_INTERVAL; /* 8 samples per millisecond */
676  }
677  if ((strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir")) && AST_LIST_EMPTY(&class->members))
678  continue;
679  /* Read mp3 audio */
680  len = ast_codec_get_len(class->format, res);
681 
682  if ((res2 = read(class->srcfd, sbuf, len)) != len) {
683  if (!res2) {
684  close(class->srcfd);
685  class->srcfd = -1;
686  pthread_testcancel();
687  if (class->pid > 1) {
688  do {
689  if (killpg(class->pid, SIGHUP) < 0) {
690  if (errno == ESRCH) {
691  break;
692  }
693  ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno));
694  }
695  usleep(100000);
696  if (killpg(class->pid, SIGTERM) < 0) {
697  if (errno == ESRCH) {
698  break;
699  }
700  ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno));
701  }
702  usleep(100000);
703  if (killpg(class->pid, SIGKILL) < 0) {
704  if (errno == ESRCH) {
705  break;
706  }
707  ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno));
708  }
709  } while (0);
710  class->pid = 0;
711  }
712  } else {
713  ast_debug(1, "Read %d bytes of audio while expecting %d\n", res2, len);
714  }
715  continue;
716  }
717 
718  pthread_testcancel();
719 
720  ao2_lock(class);
721  AST_LIST_TRAVERSE(&class->members, moh, list) {
722  /* Write data */
723  if ((res = write(moh->pipe[1], sbuf, res2)) != res2) {
724  ast_debug(1, "Only wrote %d of %d bytes to pipe\n", res, res2);
725  }
726  }
727  ao2_unlock(class);
728  }
729  return NULL;
730 }
#define LOG_WARNING
Definition: logger.h:144
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:100
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:142
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
#define ao2_unlock(a)
Definition: astobj2.h:497
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:90
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define ast_poll(a, b, c)
Definition: poll-compat.h:88
#define ao2_lock(a)
Definition: astobj2.h:488
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
Definition: time.h:191
#define MOH_MS_INTERVAL
static char moh[80]
Definition: chan_agent.c:209
int ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
Acknowledge a timer event.
Definition: timing.c:172
#define LOG_ERROR
Definition: logger.h:155
int pipe[2]
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: utils.c:1587
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define LOG_NOTICE
Definition: logger.h:133
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
int errno
int ast_timer_fd(const struct ast_timer *handle)
Get a poll()-able file descriptor for a timer.
Definition: timing.c:158
int ast_codec_get_len(format_t format, int samples)
Returns the number of bytes for the number of samples of the given format.
Definition: frame.c:1532
static int spawn_mp3(struct mohclass *class)
static int play_moh_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 732 of file res_musiconhold.c.

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

Referenced by load_module().

733 {
734  char *parse;
735  char *class;
736  int timeout = -1;
737  int res;
739  AST_APP_ARG(class);
740  AST_APP_ARG(duration);
741  );
742 
743  parse = ast_strdupa(data);
744 
745  AST_STANDARD_APP_ARGS(args, parse);
746 
747  if (!ast_strlen_zero(args.duration)) {
748  if (sscanf(args.duration, "%30d", &timeout) == 1) {
749  timeout *= 1000;
750  } else {
751  ast_log(LOG_WARNING, "Invalid MusicOnHold duration '%s'. Will wait indefinitely.\n", args.duration);
752  }
753  }
754 
755  class = S_OR(args.class, NULL);
756  if (ast_moh_start(chan, class, NULL)) {
757  ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, chan->name);
758  return 0;
759  }
760 
761  if (timeout > 0)
762  res = ast_safe_sleep(chan, timeout);
763  else {
764  while (!(res = ast_safe_sleep(chan, 10000)));
765  }
766 
767  ast_moh_stop(chan);
768 
769  return res;
770 }
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1916
#define LOG_WARNING
Definition: logger.h:144
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:8051
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
static struct @350 args
const ast_string_field name
Definition: channel.h:787
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:8040
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1858
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
static int reload ( void  )
static

Definition at line 1927 of file res_musiconhold.c.

References ast_install_music_functions(), AST_MODULE_LOAD_SUCCESS, load_moh_classes(), local_ast_moh_cleanup(), local_ast_moh_start(), and local_ast_moh_stop().

Referenced by handle_cli_moh_reload().

1928 {
1929  if (load_moh_classes(1)) {
1932  }
1933 
1934  return AST_MODULE_LOAD_SUCCESS;
1935 }
static int load_moh_classes(int reload)
static void local_ast_moh_cleanup(struct ast_channel *chan)
static void local_ast_moh_stop(struct ast_channel *chan)
static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
void ast_install_music_functions(int(*start_ptr)(struct ast_channel *, const char *, const char *), void(*stop_ptr)(struct ast_channel *), void(*cleanup_ptr)(struct ast_channel *))
Definition: channel.c:8023
static int set_moh_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 795 of file res_musiconhold.c.

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

Referenced by load_module().

796 {
797  static int deprecation_warning = 0;
798 
799  if (!deprecation_warning) {
800  deprecation_warning = 1;
801  ast_log(LOG_WARNING, "SetMusicOnHold application is deprecated and will be removed. Use Set(CHANNEL(musicclass)=...) instead\n");
802  }
803 
804  if (ast_strlen_zero(data)) {
805  ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
806  return -1;
807  }
808  ast_string_field_set(chan, musicclass, data);
809  return 0;
810 }
static char musicclass[MAX_MUSICCLASS]
Definition: chan_mgcp.c:155
#define LOG_WARNING
Definition: logger.h:144
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
Definition: stringfields.h:344
static int spawn_mp3 ( struct mohclass class)
static

Definition at line 477 of file res_musiconhold.c.

References ast_close_fds_above_n(), ast_copy_string(), ast_log(), ast_opt_high_priority, ast_safe_fork(), ast_set_priority(), ast_strlen_zero(), ast_test_flag, mohclass::dir, errno, LOCAL_MPG_123, LOG_WARNING, MAX_MP3S, MOH_CUSTOM, MOH_QUIET, MOH_SINGLE, MPG_123, and strsep().

Referenced by monmp3thread().

478 {
479  int fds[2];
480  int files = 0;
481  char fns[MAX_MP3S][80];
482  char *argv[MAX_MP3S + 50];
483  char xargs[256];
484  char *argptr;
485  int argc = 0;
486  DIR *dir = NULL;
487  struct dirent *de;
488 
489 
490  if (!strcasecmp(class->dir, "nodir")) {
491  files = 1;
492  } else {
493  dir = opendir(class->dir);
494  if (!dir && strncasecmp(class->dir, "http://", 7)) {
495  ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
496  return -1;
497  }
498  }
499 
500  if (!ast_test_flag(class, MOH_CUSTOM)) {
501  argv[argc++] = "mpg123";
502  argv[argc++] = "-q";
503  argv[argc++] = "-s";
504  argv[argc++] = "--mono";
505  argv[argc++] = "-r";
506  argv[argc++] = "8000";
507 
508  if (!ast_test_flag(class, MOH_SINGLE)) {
509  argv[argc++] = "-b";
510  argv[argc++] = "2048";
511  }
512 
513  argv[argc++] = "-f";
514 
515  if (ast_test_flag(class, MOH_QUIET))
516  argv[argc++] = "4096";
517  else
518  argv[argc++] = "8192";
519 
520  /* Look for extra arguments and add them to the list */
521  ast_copy_string(xargs, class->args, sizeof(xargs));
522  argptr = xargs;
523  while (!ast_strlen_zero(argptr)) {
524  argv[argc++] = argptr;
525  strsep(&argptr, ",");
526  }
527  } else {
528  /* Format arguments for argv vector */
529  ast_copy_string(xargs, class->args, sizeof(xargs));
530  argptr = xargs;
531  while (!ast_strlen_zero(argptr)) {
532  argv[argc++] = argptr;
533  strsep(&argptr, " ");
534  }
535  }
536 
537  if (!strncasecmp(class->dir, "http://", 7)) {
538  ast_copy_string(fns[files], class->dir, sizeof(fns[files]));
539  argv[argc++] = fns[files];
540  files++;
541  } else if (dir) {
542  while ((de = readdir(dir)) && (files < MAX_MP3S)) {
543  if ((strlen(de->d_name) > 3) &&
544  ((ast_test_flag(class, MOH_CUSTOM) &&
545  (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") ||
546  !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) ||
547  !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
548  ast_copy_string(fns[files], de->d_name, sizeof(fns[files]));
549  argv[argc++] = fns[files];
550  files++;
551  }
552  }
553  }
554  argv[argc] = NULL;
555  if (dir) {
556  closedir(dir);
557  }
558  if (pipe(fds)) {
559  ast_log(LOG_WARNING, "Pipe failed\n");
560  return -1;
561  }
562  if (!files) {
563  ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
564  close(fds[0]);
565  close(fds[1]);
566  return -1;
567  }
568  if (!strncasecmp(class->dir, "http://", 7) && time(NULL) - class->start < respawn_time) {
569  sleep(respawn_time - (time(NULL) - class->start));
570  }
571 
572  time(&class->start);
573  class->pid = ast_safe_fork(0);
574  if (class->pid < 0) {
575  close(fds[0]);
576  close(fds[1]);
577  ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
578  return -1;
579  }
580  if (!class->pid) {
582  ast_set_priority(0);
583 
584  close(fds[0]);
585  /* Stdout goes to pipe */
586  dup2(fds[1], STDOUT_FILENO);
587 
588  /* Close everything else */
589  ast_close_fds_above_n(STDERR_FILENO);
590 
591  /* Child */
592  if (strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir") && chdir(class->dir) < 0) {
593  ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
594  _exit(1);
595  }
596  setpgid(0, getpid());
597  if (ast_test_flag(class, MOH_CUSTOM)) {
598  execv(argv[0], argv);
599  } else {
600  /* Default install is /usr/local/bin */
601  execv(LOCAL_MPG_123, argv);
602  /* Many places have it in /usr/bin */
603  execv(MPG_123, argv);
604  /* Check PATH as a last-ditch effort */
605  execvp("mpg123", argv);
606  }
607  /* Can't use logger, since log FDs are closed */
608  fprintf(stderr, "MOH: exec failed: %s\n", strerror(errno));
609  close(fds[1]);
610  _exit(1);
611  } else {
612  /* Parent */
613  close(fds[1]);
614  }
615  return fds[0];
616 }
char * strsep(char **str, const char *delims)
int ast_safe_fork(int stop_reaper)
Common routine to safely fork without a chance of a signal handler firing badly in the child...
Definition: app.c:2242
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define LOG_WARNING
Definition: logger.h:144
#define MPG_123
char dir[256]
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define MOH_QUIET
int ast_set_priority(int)
We set ourselves to a high priority, that we might pre-empt everything else. If your PBX has heavy ac...
Definition: asterisk.c:1650
#define MAX_MP3S
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
int errno
void ast_close_fds_above_n(int n)
Common routine for child processes, to close all fds prior to exec(2)
Definition: app.c:2237
time_t start
static int respawn_time
#define MOH_CUSTOM
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
char args[256]
#define MOH_SINGLE
#define ast_opt_high_priority
Definition: options.h:108
#define LOCAL_MPG_123
static int start_moh_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 812 of file res_musiconhold.c.

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

Referenced by load_module().

813 {
814  char *parse;
815  char *class;
817  AST_APP_ARG(class);
818  );
819 
820  parse = ast_strdupa(data);
821 
822  AST_STANDARD_APP_ARGS(args, parse);
823 
824  class = S_OR(args.class, NULL);
825  if (ast_moh_start(chan, class, NULL))
826  ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, chan->name);
827 
828  return 0;
829 }
#define LOG_WARNING
Definition: logger.h:144
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
static struct @350 args
const ast_string_field name
Definition: channel.h:787
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:8040
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1858
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:77
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
static int stop_moh_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 831 of file res_musiconhold.c.

References ast_moh_stop().

Referenced by load_module().

832 {
833  ast_moh_stop(chan);
834 
835  return 0;
836 }
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:8051
static int unload_module ( void  )
static

Definition at line 1944 of file res_musiconhold.c.

References ao2_t_callback, ARRAY_LEN, ast_cli_unregister_multiple(), ast_log(), ast_moh_destroy(), ast_uninstall_music_functions(), ast_unregister_application(), ast_unregister_atexit(), LOG_WARNING, moh_class_inuse(), and mohclass_unref.

1945 {
1946  int res = 0;
1947  struct mohclass *class = NULL;
1948 
1949  /* XXX This check shouldn't be required if module ref counting was being used
1950  * properly ... */
1951  if ((class = ao2_t_callback(mohclasses, 0, moh_class_inuse, NULL, "Module unload callback"))) {
1952  class = mohclass_unref(class, "unref of class from module unload callback");
1953  res = -1;
1954  }
1955 
1956  if (res < 0) {
1957  ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n");
1958  return res;
1959  }
1960 
1962 
1963  ast_moh_destroy();
1971 
1972  return res;
1973 }
static struct ao2_container * mohclasses
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static const char stop_moh[]
static const char set_moh[]
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: cli.c:2177
#define LOG_WARNING
Definition: logger.h:144
static struct ast_cli_entry cli_moh[]
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx.c:7705
static void ast_moh_destroy(void)
void ast_uninstall_music_functions(void)
Definition: channel.c:8032
void ast_unregister_atexit(void(*func)(void))
Unregister a function registered with ast_register_atexit().
Definition: asterisk.c:1008
static int moh_class_inuse(void *obj, void *arg, int flags)
static const char start_moh[]
#define ao2_t_callback(c, flags, cb_fn, arg, tag)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
Definition: astobj2.h:909
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207
static const char wait_moh[]
#define mohclass_unref(class, string)
static const char play_moh[]
static int wait_moh_exec ( struct ast_channel chan,
const char *  data 
)
static

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

773 {
774  static int deprecation_warning = 0;
775  int res;
776 
777  if (!deprecation_warning) {
778  deprecation_warning = 1;
779  ast_log(LOG_WARNING, "WaitMusicOnHold application is deprecated and will be removed. Use MusicOnHold with duration parameter instead\n");
780  }
781 
782  if (!data || !atoi(data)) {
783  ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
784  return -1;
785  }
786  if (ast_moh_start(chan, NULL, NULL)) {
787  ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name);
788  return 0;
789  }
790  res = ast_safe_sleep(chan, atoi(data) * 1000);
791  ast_moh_stop(chan);
792  return res;
793 }
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1916
#define LOG_WARNING
Definition: logger.h:144
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:8051
const ast_string_field name
Definition: channel.h:787
int ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
Turn on music on hold on a given channel.
Definition: channel.c:8040
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
Definition: logger.c:1207

Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, }
static

Definition at line 1980 of file res_musiconhold.c.

Definition at line 1980 of file res_musiconhold.c.

struct ast_cli_entry cli_moh[]
static
Initial value:
= {
AST_CLI_DEFINE(handle_cli_moh_reload, "Reload MusicOnHold"),
AST_CLI_DEFINE(handle_cli_moh_show_classes, "List MusicOnHold classes"),
AST_CLI_DEFINE(handle_cli_moh_show_files, "List MusicOnHold file-based classes")
}
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:191
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 char * handle_cli_moh_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)

Definition at line 1874 of file res_musiconhold.c.

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

global MOH_ flags

Definition at line 179 of file res_musiconhold.c.

struct ast_generator moh_file_stream
static

Definition at line 469 of file res_musiconhold.c.

struct ao2_container* mohclasses
static

Definition at line 219 of file res_musiconhold.c.

struct ast_generator mohgen
static

Definition at line 994 of file res_musiconhold.c.

const char play_moh[] = "MusicOnHold"
static

Definition at line 147 of file res_musiconhold.c.

int respawn_time = 20
static

Definition at line 153 of file res_musiconhold.c.

Referenced by _moh_register(), and local_ast_moh_start().

const char set_moh[] = "SetMusicOnHold"
static

Definition at line 149 of file res_musiconhold.c.

const char start_moh[] = "StartMusicOnHold"
static

Definition at line 150 of file res_musiconhold.c.

const char stop_moh[] = "StopMusicOnHold"
static

Definition at line 151 of file res_musiconhold.c.

const char wait_moh[] = "WaitMusicOnHold"
static

Definition at line 148 of file res_musiconhold.c.