Asterisk - The Open Source Telephony Project  GIT-master-1f78ee9
Data Structures | Macros | Enumerations | Functions | Variables
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 <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/stasis.h"
#include "asterisk/stasis_channels.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_ANNOUNCEMENT   (1 << 6)
 
#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_PREFERCHANNELCLASS   (1 << 7)
 
#define MOH_QUIET   (1 << 0)
 
#define MOH_RANDOMIZE   (1 << 3)
 
#define MOH_RANDSTART   (MOH_RANDOMIZE | MOH_SORTALPHA)
 
#define MOH_REALTIME   (1 << 31)
 
#define moh_register(moh, reload, unref)   _moh_register(moh, reload, unref, __FILE__, __LINE__, __PRETTY_FUNCTION__)
 
#define MOH_SINGLE   (1 << 1)
 
#define MOH_SORTALPHA   (1 << 4)
 
#define MOH_SORTMODE   (3 << 3)
 
#define moh_unregister(a)   _moh_unregister(a,__FILE__,__LINE__,__PRETTY_FUNCTION__)
 
#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"
 

Enumerations

enum  kill_methods { KILL_METHOD_PROCESS_GROUP = 0, KILL_METHOD_PROCESS }
 

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 int _moh_unregister (struct mohclass *moh, const char *file, int line, const char *funcname)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static void ast_moh_destroy (void)
 
static int ast_moh_files_next (struct ast_channel *chan)
 
static char * complete_mohclass_realtime (const char *line, const char *word, int pos, int state)
 Support routing for 'moh unregister class' CLI This is in charge of generating all strings that match a prefix in the given position. As many functions of this kind, each invokation has O(state) time complexity so be careful in using it. More...
 
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 char * handle_cli_moh_unregister_class (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 killer (pid_t pid, int signum, enum kill_methods kill_method)
 
static void killpid (int pid, size_t delay, enum kill_methods kill_method)
 
static int load_module (void)
 Load the module. More...
 
static int load_moh_classes (int reload)
 
static struct ast_variableload_realtime_musiconhold (const char *name)
 
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 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 void moh_files_write_format_change (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_parse_options (struct ast_variable *var, struct mohclass *mohclass)
 
static void moh_post_start (struct ast_channel *chan, const char *moh_class_name)
 
static void moh_post_stop (struct ast_channel *chan)
 
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 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 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)
 

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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_cli_entry cli_moh []
 
static struct ast_flags global_flags [1] = {{0}}
 
static struct ast_generator moh_file_stream
 
static struct ao2_containermohclasses
 
static struct ast_generator mohgen
 
static const char play_moh [] = "MusicOnHold"
 
static int respawn_time = 20
 
static const char start_moh [] = "StartMusicOnHold"
 
static const char stop_moh [] = "StopMusicOnHold"
 

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

◆ DONT_UNREF

#define DONT_UNREF   0

Definition at line 78 of file res_musiconhold.c.

Referenced by local_ast_moh_start().

◆ get_mohbyname

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

Definition at line 919 of file res_musiconhold.c.

Referenced by local_ast_moh_start().

◆ HANDLE_REF

#define HANDLE_REF   1

Definition at line 77 of file res_musiconhold.c.

Referenced by load_moh_classes().

◆ INITIAL_NUM_FILES

#define INITIAL_NUM_FILES   8

Definition at line 76 of file res_musiconhold.c.

◆ LOCAL_MPG_123

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

Definition at line 208 of file res_musiconhold.c.

Referenced by spawn_mp3().

◆ MAX_MP3S

#define MAX_MP3S   256

Definition at line 210 of file res_musiconhold.c.

Referenced by spawn_mp3().

◆ MOH_ANNOUNCEMENT

#define MOH_ANNOUNCEMENT   (1 << 6)

Do we play announcement files between songs on this channel?

Definition at line 153 of file res_musiconhold.c.

Referenced by ast_moh_files_next(), handle_cli_moh_show_classes(), and moh_parse_options().

◆ MOH_CACHERTCLASSES

#define MOH_CACHERTCLASSES   (1 << 5)

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

Definition at line 152 of file res_musiconhold.c.

Referenced by load_moh_classes(), and local_ast_moh_start().

◆ moh_class_malloc

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

Definition at line 1495 of file res_musiconhold.c.

Referenced by load_moh_classes(), and local_ast_moh_start().

◆ MOH_CUSTOM

#define MOH_CUSTOM   (1 << 2)

◆ MOH_MS_INTERVAL

#define MOH_MS_INTERVAL   100

Referenced by monmp3thread().

◆ MOH_NOTDELETED

#define MOH_NOTDELETED   (1 << 30)

Find only records that aren't deleted?

Definition at line 157 of file res_musiconhold.c.

Referenced by _moh_register(), and moh_class_cmp().

◆ MOH_PREFERCHANNELCLASS

#define MOH_PREFERCHANNELCLASS   (1 << 7)

Should queue moh override channel moh

Definition at line 154 of file res_musiconhold.c.

Referenced by load_moh_classes(), and local_ast_moh_start().

◆ MOH_QUIET

#define MOH_QUIET   (1 << 0)

Definition at line 144 of file res_musiconhold.c.

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

◆ MOH_RANDOMIZE

#define MOH_RANDOMIZE   (1 << 3)

◆ MOH_RANDSTART

#define MOH_RANDSTART   (MOH_RANDOMIZE | MOH_SORTALPHA)

Sorted but start at random position

Definition at line 149 of file res_musiconhold.c.

Referenced by moh_parse_options().

◆ MOH_REALTIME

#define MOH_REALTIME   (1 << 31)

Find only records that are realtime

Definition at line 158 of file res_musiconhold.c.

Referenced by load_moh_classes(), and moh_class_mark().

◆ moh_register

#define moh_register (   moh,
  reload,
  unref 
)    _moh_register(moh, reload, unref, __FILE__, __LINE__, __PRETTY_FUNCTION__)
Note
This function owns the reference it gets to moh if unref is true

Definition at line 1328 of file res_musiconhold.c.

Referenced by load_moh_classes(), and local_ast_moh_start().

◆ MOH_SINGLE

#define MOH_SINGLE   (1 << 1)

Definition at line 145 of file res_musiconhold.c.

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

◆ MOH_SORTALPHA

#define MOH_SORTALPHA   (1 << 4)

Definition at line 148 of file res_musiconhold.c.

Referenced by moh_parse_options(), and moh_scan_files().

◆ MOH_SORTMODE

#define MOH_SORTMODE   (3 << 3)

Definition at line 150 of file res_musiconhold.c.

Referenced by ast_moh_files_next().

◆ moh_unregister

#define moh_unregister (   a)    _moh_unregister(a,__FILE__,__LINE__,__PRETTY_FUNCTION__)

Definition at line 1390 of file res_musiconhold.c.

Referenced by handle_cli_moh_unregister_class().

◆ mohclass_ref

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

Definition at line 215 of file res_musiconhold.c.

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

◆ mohclass_unref

#define mohclass_unref (   class,
  string 
)    ({ ao2_t_ref((class), -1, (string)); (struct mohclass *) NULL; })

◆ MPG_123

#define MPG_123   "/usr/bin/mpg123"

Definition at line 209 of file res_musiconhold.c.

Referenced by spawn_mp3().

Enumeration Type Documentation

◆ kill_methods

Enumerator
KILL_METHOD_PROCESS_GROUP 
KILL_METHOD_PROCESS 

Definition at line 162 of file res_musiconhold.c.

Function Documentation

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 2168 of file res_musiconhold.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 2168 of file res_musiconhold.c.

◆ _get_mohbyname()

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

Definition at line 921 of file res_musiconhold.c.

References __ao2_find(), ast_copy_string(), ast_log, mohclass::flags, LOG_WARNING, mohclass::name, and NULL.

Referenced by _moh_register().

922 {
923  struct mohclass *moh = NULL;
924  struct mohclass tmp_class = {
925  .flags = 0,
926  };
927 
928  ast_copy_string(tmp_class.name, name, sizeof(tmp_class.name));
929 
930  moh = __ao2_find(mohclasses, &tmp_class, flags,
931  "get_mohbyname", file, lineno, funcname);
932 
933  if (!moh && warn) {
934  ast_log(LOG_WARNING, "Music on Hold class '%s' not found in memory. Verify your configuration.\n", name);
935  }
936 
937  return moh;
938 }
static struct ao2_container * mohclasses
char name[MAX_MUSICCLASS]
void * __ao2_find(struct ao2_container *c, const void *arg, enum search_flags flags, const char *tag, const char *file, int line, const char *func)
#define LOG_WARNING
Definition: logger.h:274
#define NULL
Definition: resample.c:96
#define ast_log
Definition: astobj2.c:42
unsigned int flags
static const char name[]
Definition: cdr_mysql.c:74
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401

◆ _moh_class_malloc()

static struct mohclass* _moh_class_malloc ( const char *  file,
int  line,
const char *  funcname 
)
static

Definition at line 1497 of file res_musiconhold.c.

References __ao2_alloc(), AO2_ALLOC_OPT_LOCK_MUTEX, ao2_bump, ast_format_slin, AST_VECTOR_INIT, moh_files_state::class, mohclass::files, and moh_class_destructor().

1498 {
1499  struct mohclass *class;
1500 
1502  "Allocating new moh class", file, line, funcname);
1503  if (class) {
1504  class->format = ao2_bump(ast_format_slin);
1505  class->srcfd = -1;
1506  class->kill_delay = 100000;
1507  AST_VECTOR_INIT(&class->files, 0);
1508  }
1509 
1510  return class;
1511 }
void * __ao2_alloc(size_t data_size, ao2_destructor_fn destructor_fn, unsigned int options, const char *tag, const char *file, int line, const char *func) attribute_warn_unused_result
Definition: astobj2.c:765
#define ao2_bump(obj)
Definition: astobj2.h:491
#define AST_VECTOR_INIT(vec, size)
Initialize a vector.
Definition: vector.h:113
static void moh_class_destructor(void *obj)
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41

◆ _moh_register()

static int _moh_register ( struct mohclass moh,
int  reload,
int  unref,
const char *  file,
int  line,
const char *  funcname 
)
static

Definition at line 1329 of file res_musiconhold.c.

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

1330 {
1331  struct mohclass *mohclass = NULL;
1332 
1333  mohclass = _get_mohbyname(moh->name, 0, MOH_NOTDELETED, file, line, funcname);
1334 
1335  if (mohclass && !moh_diff(mohclass, moh)) {
1336  ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
1337  mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name");
1338  if (unref) {
1339  moh = mohclass_unref(moh, "unreffing potential new moh class (it is a duplicate)");
1340  }
1341  return -1;
1342  } else if (mohclass) {
1343  /* Found a class, but it's different from the one being registered */
1344  mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name");
1345  }
1346 
1347  time(&moh->start);
1348  moh->start -= respawn_time;
1349 
1350  if (!strcasecmp(moh->mode, "files")) {
1351  if (init_files_class(moh)) {
1352  if (unref) {
1353  moh = mohclass_unref(moh, "unreffing potential new moh class (init_files_class failed)");
1354  }
1355  return -1;
1356  }
1357  } else if (!strcasecmp(moh->mode, "playlist")) {
1358  if (!AST_VECTOR_SIZE(&moh->files)) {
1359  if (unref) {
1360  moh = mohclass_unref(moh, "unreffing potential new moh class (no playlist entries)");
1361  }
1362  return -1;
1363  }
1364  } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") ||
1365  !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") ||
1366  !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) {
1367  if (init_app_class(moh)) {
1368  if (unref) {
1369  moh = mohclass_unref(moh, "unreffing potential new moh class (init_app_class_failed)");
1370  }
1371  return -1;
1372  }
1373  } else {
1374  ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
1375  if (unref) {
1376  moh = mohclass_unref(moh, "unreffing potential new moh class (unknown mode)");
1377  }
1378  return -1;
1379  }
1380 
1381  ao2_t_link(mohclasses, moh, "Adding class to container");
1382 
1383  if (unref) {
1384  moh = mohclass_unref(moh, "Unreffing new moh class because we just added it to the container");
1385  }
1386 
1387  return 0;
1388 }
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:274
static int init_app_class(struct mohclass *class)
#define ao2_t_link(container, obj, tag)
Add an object to a container.
Definition: astobj2.h:1547
#define NULL
Definition: resample.c:96
struct ast_vector_string files
#define ast_log
Definition: astobj2.c:42
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)
time_t start
static int respawn_time
#define mohclass_unref(class, string)
char mode[80]
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ _moh_unregister()

static int _moh_unregister ( struct mohclass moh,
const char *  file,
int  line,
const char *  funcname 
)
static

Definition at line 1391 of file res_musiconhold.c.

References ao2_t_unlink.

1392 {
1393  ao2_t_unlink(mohclasses, moh, "Removing class from container");
1394  return 0;
1395 }
static struct ao2_container * mohclasses
#define ao2_t_unlink(container, obj, tag)
Remove an object from a container.
Definition: astobj2.h:1596

◆ AST_MODULE_SELF_SYM()

struct ast_module* AST_MODULE_SELF_SYM ( void  )

Definition at line 2168 of file res_musiconhold.c.

◆ ast_moh_destroy()

static void ast_moh_destroy ( void  )
static

Definition at line 1941 of file res_musiconhold.c.

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

Referenced by load_module(), and unload_module().

1942 {
1943  ast_verb(2, "Destroying musiconhold processes\n");
1944  if (mohclasses) {
1945  ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "Destroy callback");
1946  ao2_ref(mohclasses, -1);
1947  mohclasses = NULL;
1948  }
1949 }
static struct ao2_container * mohclasses
#define NULL
Definition: resample.c:96
#define ast_verb(level,...)
Definition: logger.h:455
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#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:1714

◆ ast_moh_files_next()

static int ast_moh_files_next ( struct ast_channel chan)
static

Definition at line 313 of file res_musiconhold.c.

References moh_files_state::announcement, mohclass::announcement, ast_channel_language(), ast_channel_music_state(), ast_channel_name(), ast_channel_stream(), ast_channel_stream_set(), 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, AST_VECTOR_GET, AST_VECTOR_SIZE, moh_files_state::class, errno, mohclass::files, LOG_WARNING, MOH_ANNOUNCEMENT, MOH_RANDOMIZE, MOH_SORTMODE, mohclass::name, NULL, moh_files_state::pos, moh_files_state::samples, moh_files_state::save_pos, and moh_files_state::save_pos_filename.

Referenced by moh_files_readframe().

314 {
316  int tries;
317  size_t file_count;
318 
319  /* Discontinue a stream if it is running already */
320  if (ast_channel_stream(chan)) {
323  }
324 
325  if (ast_test_flag(state->class, MOH_ANNOUNCEMENT) && state->announcement == 0) {
326  state->announcement = 1;
327  if (ast_openstream_full(chan, state->class->announcement, ast_channel_language(chan), 1)) {
328  ast_debug(1, "%s Opened announcement '%s'\n", ast_channel_name(chan), state->class->announcement);
329  return 0;
330  }
331  } else {
332  state->announcement = 0;
333  }
334 
335  file_count = AST_VECTOR_SIZE(&state->class->files);
336  if (!file_count) {
337  ast_log(LOG_WARNING, "No files available for class '%s'\n", state->class->name);
338  return -1;
339  }
340 
341  if (state->pos == 0 && ast_strlen_zero(state->save_pos_filename)) {
342  /* First time so lets play the file. */
343  state->save_pos = -1;
344  } else if (state->save_pos >= 0 && state->save_pos < file_count && !strcmp(AST_VECTOR_GET(&state->class->files, state->save_pos), state->save_pos_filename)) {
345  /* If a specific file has been saved confirm it still exists and that it is still valid */
346  state->pos = state->save_pos;
347  state->save_pos = -1;
348  } else if (ast_test_flag(state->class, MOH_SORTMODE) == MOH_RANDOMIZE) {
349  /* Get a random file and ensure we can open it */
350  for (tries = 0; tries < 20; tries++) {
351  state->pos = ast_random() % file_count;
352  if (ast_fileexists(AST_VECTOR_GET(&state->class->files, state->pos), NULL, NULL) > 0) {
353  break;
354  }
355  }
356  state->save_pos = -1;
357  state->samples = 0;
358  } else {
359  /* This is easy, just increment our position and make sure we don't exceed the total file count */
360  state->pos++;
361  state->pos %= file_count;
362  state->save_pos = -1;
363  state->samples = 0;
364  }
365 
366  for (tries = 0; tries < file_count; ++tries) {
367  if (ast_openstream_full(chan, AST_VECTOR_GET(&state->class->files, state->pos), ast_channel_language(chan), 1)) {
368  break;
369  }
370 
371  ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", AST_VECTOR_GET(&state->class->files, state->pos), strerror(errno));
372  state->pos++;
373  state->pos %= file_count;
374  }
375 
376  if (tries == file_count) {
377  return -1;
378  }
379 
380  /* Record the pointer to the filename for position resuming later */
381  ast_copy_string(state->save_pos_filename, AST_VECTOR_GET(&state->class->files, state->pos), sizeof(state->save_pos_filename));
382 
383  ast_debug(1, "%s Opened file %d '%s'\n", ast_channel_name(chan), state->pos, state->save_pos_filename);
384 
385  if (state->samples) {
386  size_t loc;
387  /* seek *SHOULD* be good since it's from a known location */
388  ast_seekstream(ast_channel_stream(chan), state->samples, SEEK_SET);
389  /* if the seek failed then recover because if there is not a valid read,
390  * moh_files_generate will return -1 and MOH will stop */
391  loc = ast_tellstream(ast_channel_stream(chan));
392  if (state->samples > loc && loc) {
393  /* seek one sample from the end for one guaranteed valid read */
394  ast_seekstream(ast_channel_stream(chan), 1, SEEK_END);
395  }
396  }
397 
398  return 0;
399 }
char name[MAX_MUSICCLASS]
char announcement[256]
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define LOG_WARNING
Definition: logger.h:274
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:760
#define NULL
Definition: resample.c:96
struct ast_vector_string files
off_t ast_tellstream(struct ast_filestream *fs)
Tell where we are in a stream.
Definition: file.c:1048
void ast_channel_stream_set(struct ast_channel *chan, struct ast_filestream *value)
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
char save_pos_filename[PATH_MAX]
#define MOH_SORTMODE
long int ast_random(void)
Definition: main/utils.c:1934
#define MOH_ANNOUNCEMENT
int errno
int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
Seeks into stream.
Definition: file.c:1038
#define ast_strlen_zero(a)
Definition: muted.c:73
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:1068
struct ast_filestream * ast_channel_stream(const struct ast_channel *chan)
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:678
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
const char * ast_channel_name(const struct ast_channel *chan)
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:1086
void * ast_channel_music_state(const struct ast_channel *chan)
const char * ast_channel_language(const struct ast_channel *chan)
#define MOH_RANDOMIZE
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ complete_mohclass_realtime()

static char* complete_mohclass_realtime ( const char *  line,
const char *  word,
int  pos,
int  state 
)
static

Support routing for 'moh unregister class' CLI This is in charge of generating all strings that match a prefix in the given position. As many functions of this kind, each invokation has O(state) time complexity so be careful in using it.

Definition at line 1422 of file res_musiconhold.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_t_iterator_next, ast_strdup, c, mohclass_unref, mohclass::name, NULL, and mohclass::realtime.

Referenced by handle_cli_moh_unregister_class().

1423 {
1424  int which=0;
1425  struct mohclass *cur;
1426  char *c = NULL;
1427  int wordlen = strlen(word);
1428  struct ao2_iterator i;
1429 
1430  if (pos != 3) {
1431  return NULL;
1432  }
1433 
1434  i = ao2_iterator_init(mohclasses, 0);
1435  while ((cur = ao2_t_iterator_next(&i, "iterate thru mohclasses"))) {
1436  if (cur->realtime && !strncasecmp(cur->name, word, wordlen) && ++which > state) {
1437  c = ast_strdup(cur->name);
1438  mohclass_unref(cur, "drop ref in iterator loop break");
1439  break;
1440  }
1441  mohclass_unref(cur, "drop ref in iterator loop");
1442  }
1444 
1445  return c;
1446 }
static struct ao2_container * mohclasses
char name[MAX_MUSICCLASS]
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
static struct test_val c
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define NULL
Definition: resample.c:96
unsigned int realtime
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
#define mohclass_unref(class, string)
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
short word

◆ get_mohbydigit()

static struct mohclass* get_mohbydigit ( char  digit)
static
Note
This function should be called with the mohclasses list locked

Definition at line 542 of file res_musiconhold.c.

References ao2_t_callback, and moh_digit_match().

Referenced by moh_handle_digit().

543 {
544  return ao2_t_callback(mohclasses, 0, moh_digit_match, &digit, "digit callback");
545 }
static struct ao2_container * mohclasses
char digit
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:1714

◆ handle_cli_moh_reload()

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

Definition at line 1951 of file res_musiconhold.c.

References ast_cli_args::argc, ast_cli_entry::args, ast_module_reload(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, NULL, and ast_cli_entry::usage.

1952 {
1953  switch (cmd) {
1954  case CLI_INIT:
1955  e->command = "moh reload";
1956  e->usage =
1957  "Usage: moh reload\n"
1958  " Reloads the MusicOnHold module.\n"
1959  " Alias for 'module reload res_musiconhold.so'\n";
1960  return NULL;
1961  case CLI_GENERATE:
1962  return NULL;
1963  }
1964 
1965  if (a->argc != e->args)
1966  return CLI_SHOWUSAGE;
1967 
1968  /* The module loader will prevent concurrent reloads from occurring, so we delegate */
1969  ast_module_reload("res_musiconhold");
1970 
1971  return CLI_SUCCESS;
1972 }
enum ast_module_reload_result ast_module_reload(const char *name)
Reload asterisk modules.
Definition: loader.c:1560
const int argc
Definition: cli.h:160
Definition: cli.h:152
#define NULL
Definition: resample.c:96
int args
This gets set in ast_cli_register()
Definition: cli.h:185
#define CLI_SHOWUSAGE
Definition: cli.h:45
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44

◆ handle_cli_moh_show_classes()

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

Definition at line 2012 of file res_musiconhold.c.

References mohclass::announcement, ao2_iterator_destroy(), ao2_iterator_init(), ao2_t_iterator_next, ast_cli_args::argc, mohclass::args, ast_cli_entry::args, ast_cli(), ast_format_get_name(), ast_test_flag, moh_files_state::class, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, mohclass::dir, ast_cli_args::fd, mohclass::format, mohclass::kill_delay, mohclass::kill_method, KILL_METHOD_PROCESS, mohclass::mode, MOH_ANNOUNCEMENT, MOH_CUSTOM, mohclass_unref, mohclass::name, NULL, S_OR, and ast_cli_entry::usage.

2013 {
2014  struct mohclass *class;
2015  struct ao2_iterator i;
2016 
2017  switch (cmd) {
2018  case CLI_INIT:
2019  e->command = "moh show classes";
2020  e->usage =
2021  "Usage: moh show classes\n"
2022  " Lists all MusicOnHold classes.\n";
2023  return NULL;
2024  case CLI_GENERATE:
2025  return NULL;
2026  }
2027 
2028  if (a->argc != e->args)
2029  return CLI_SHOWUSAGE;
2030 
2031  i = ao2_iterator_init(mohclasses, 0);
2032  for (; (class = ao2_t_iterator_next(&i, "Show classes iterator")); mohclass_unref(class, "Unref iterator in moh show classes")) {
2033  ast_cli(a->fd, "Class: %s\n", class->name);
2034  ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
2035  ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
2036  if (ast_test_flag(class, MOH_ANNOUNCEMENT)) {
2037  ast_cli(a->fd, "\tAnnouncement: %s\n", S_OR(class->announcement, "<none>"));
2038  }
2039  if (ast_test_flag(class, MOH_CUSTOM)) {
2040  ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
2041  ast_cli(a->fd, "\tKill Escalation Delay: %zu ms\n", class->kill_delay / 1000);
2042  ast_cli(a->fd, "\tKill Method: %s\n",
2043  class->kill_method == KILL_METHOD_PROCESS ? "process" : "process_group");
2044  }
2045  if (strcasecmp(class->mode, "files")) {
2046  ast_cli(a->fd, "\tFormat: %s\n", ast_format_get_name(class->format));
2047  }
2048  }
2050 
2051  return CLI_SUCCESS;
2052 }
static struct ao2_container * mohclasses
#define ast_test_flag(p, flag)
Definition: utils.h:63
const int argc
Definition: cli.h:160
Definition: cli.h:152
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
int args
This gets set in ast_cli_register()
Definition: cli.h:185
const int fd
Definition: cli.h:159
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
#define MOH_ANNOUNCEMENT
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
#define MOH_CUSTOM
#define CLI_SUCCESS
Definition: cli.h:44
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
#define mohclass_unref(class, string)
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.

◆ handle_cli_moh_show_files()

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

Definition at line 1974 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_VECTOR_GET, AST_VECTOR_SIZE, moh_files_state::class, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, mohclass::files, mohclass_unref, mohclass::name, NULL, and ast_cli_entry::usage.

1975 {
1976  struct mohclass *class;
1977  struct ao2_iterator i;
1978 
1979  switch (cmd) {
1980  case CLI_INIT:
1981  e->command = "moh show files";
1982  e->usage =
1983  "Usage: moh show files\n"
1984  " Lists all loaded file-based MusicOnHold classes and their\n"
1985  " files.\n";
1986  return NULL;
1987  case CLI_GENERATE:
1988  return NULL;
1989  }
1990 
1991  if (a->argc != e->args)
1992  return CLI_SHOWUSAGE;
1993 
1994  i = ao2_iterator_init(mohclasses, 0);
1995  for (; (class = ao2_t_iterator_next(&i, "Show files iterator")); mohclass_unref(class, "Unref iterator in moh show files")) {
1996  int x;
1997 
1998  if (!AST_VECTOR_SIZE(&class->files)) {
1999  continue;
2000  }
2001 
2002  ast_cli(a->fd, "Class: %s\n", class->name);
2003  for (x = 0; x < AST_VECTOR_SIZE(&class->files); x++) {
2004  ast_cli(a->fd, "\tFile: %s\n", AST_VECTOR_GET(&class->files, x));
2005  }
2006  }
2008 
2009  return CLI_SUCCESS;
2010 }
static struct ao2_container * mohclasses
const int argc
Definition: cli.h:160
Definition: cli.h:152
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
int args
This gets set in ast_cli_register()
Definition: cli.h:185
const int fd
Definition: cli.h:159
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:678
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
#define mohclass_unref(class, string)
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ handle_cli_moh_unregister_class()

static char* handle_cli_moh_unregister_class ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
)
static

Definition at line 1448 of file res_musiconhold.c.

References ao2_iterator_destroy(), ao2_iterator_init(), ao2_t_iterator_next, ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_mohclass_realtime(), ast_cli_args::fd, len(), ast_cli_args::line, moh_class_destructor(), moh_unregister, mohclass_unref, ast_cli_args::n, mohclass::name, NULL, ast_cli_args::pos, mohclass::realtime, ast_cli_entry::usage, and ast_cli_args::word.

1449 {
1450  struct mohclass *cur;
1451  int len;
1452  int found = 0;
1453  struct ao2_iterator i;
1454 
1455  switch (cmd) {
1456  case CLI_INIT:
1457  e->command = "moh unregister class";
1458  e->usage =
1459  "Usage: moh unregister class <class>\n"
1460  " Unregisters a realtime moh class.\n";
1461  return NULL;
1462  case CLI_GENERATE:
1463  return complete_mohclass_realtime(a->line, a->word, a->pos, a->n);
1464  }
1465 
1466  if (a->argc != 4)
1467  return CLI_SHOWUSAGE;
1468 
1469  len = strlen(a->argv[3]);
1470 
1471  i = ao2_iterator_init(mohclasses, 0);
1472  while ((cur = ao2_t_iterator_next(&i, "iterate thru mohclasses"))) {
1473  if (cur->realtime && len == strlen(cur->name) && !strncasecmp(cur->name, a->argv[3], len)) {
1474  found = 1;
1475  break;
1476  }
1477  mohclass_unref(cur, "drop ref in iterator loop");
1478  }
1480 
1481  if (found) {
1482  moh_unregister(cur);
1483  mohclass_unref(cur, "drop ref after unregister");
1484  } else {
1485  ast_cli(a->fd, "No such realtime moh class '%s'\n", a->argv[3]);
1486  }
1487 
1488  return CLI_SUCCESS;
1489 }
static struct ao2_container * mohclasses
char name[MAX_MUSICCLASS]
const int argc
Definition: cli.h:160
Definition: cli.h:152
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
#define NULL
Definition: resample.c:96
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
const char * line
Definition: cli.h:162
unsigned int realtime
const int fd
Definition: cli.h:159
const int n
Definition: cli.h:165
const char *const * argv
Definition: cli.h:161
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define ao2_t_iterator_next(iter, tag)
Definition: astobj2.h:1931
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define moh_unregister(a)
char * command
Definition: cli.h:186
const char * word
Definition: cli.h:163
const char * usage
Definition: cli.h:177
#define CLI_SUCCESS
Definition: cli.h:44
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
const int pos
Definition: cli.h:164
#define mohclass_unref(class, string)
static char * complete_mohclass_realtime(const char *line, const char *word, int pos, int state)
Support routing for &#39;moh unregister class&#39; CLI This is in charge of generating all strings that match...
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.

◆ init_app_class()

static int init_app_class ( struct mohclass class)
static

Definition at line 1289 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(), moh_files_state::class, errno, LOG_WARNING, mohclass::mode, MOH_CUSTOM, MOH_QUIET, MOH_SINGLE, monmp3thread(), NULL, mohclass::thread, and mohclass::timer.

Referenced by _moh_register().

1290 {
1291  if (!strcasecmp(class->mode, "custom")) {
1292  ast_set_flag(class, MOH_CUSTOM);
1293  } else if (!strcasecmp(class->mode, "mp3nb")) {
1294  ast_set_flag(class, MOH_SINGLE);
1295  } else if (!strcasecmp(class->mode, "quietmp3nb")) {
1296  ast_set_flag(class, MOH_SINGLE | MOH_QUIET);
1297  } else if (!strcasecmp(class->mode, "quietmp3")) {
1298  ast_set_flag(class, MOH_QUIET);
1299  }
1300 
1301  class->srcfd = -1;
1302 
1303  if (!(class->timer = ast_timer_open())) {
1304  ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno));
1305  return -1;
1306  }
1307  if (class->timer && ast_timer_set_rate(class->timer, 25)) {
1308  ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno));
1309  ast_timer_close(class->timer);
1310  class->timer = NULL;
1311  }
1312 
1313  if (ast_pthread_create_background(&class->thread, NULL, monmp3thread, class)) {
1314  ast_log(LOG_WARNING, "Unable to create moh thread...\n");
1315  if (class->timer) {
1316  ast_timer_close(class->timer);
1317  class->timer = NULL;
1318  }
1319  return -1;
1320  }
1321 
1322  return 0;
1323 }
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:274
void ast_timer_close(struct ast_timer *handle)
Close an opened timing handle.
Definition: timing.c:154
struct ast_timer * ast_timer_open(void)
Open a timer.
Definition: timing.c:122
#define NULL
Definition: resample.c:96
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:507
#define ast_log
Definition: astobj2.c:42
#define MOH_QUIET
int errno
int ast_timer_set_rate(const struct ast_timer *handle, unsigned int rate)
Set the timing tick rate.
Definition: timing.c:166
struct ast_timer * timer
#define MOH_CUSTOM
pthread_t thread
char mode[80]
static void * monmp3thread(void *data)
#define MOH_SINGLE

◆ init_files_class()

static int init_files_class ( struct mohclass class)
static

Definition at line 1235 of file res_musiconhold.c.

References ast_verb, moh_files_state::class, mohclass::dir, moh_scan_files(), and mohclass::name.

Referenced by _moh_register().

1236 {
1237  int res;
1238 
1239  res = moh_scan_files(class);
1240 
1241  if (res < 0) {
1242  return -1;
1243  }
1244 
1245  if (!res) {
1246  ast_verb(3, "Files not found in %s for moh class:%s\n",
1247  class->dir, class->name);
1248  return -1;
1249  }
1250 
1251  return 0;
1252 }
char name[MAX_MUSICCLASS]
static int moh_scan_files(struct mohclass *class)
#define ast_verb(level,...)
Definition: logger.h:455
char dir[256]

◆ killer()

static int killer ( pid_t  pid,
int  signum,
enum kill_methods  kill_method 
)
static

Definition at line 710 of file res_musiconhold.c.

References KILL_METHOD_PROCESS, and KILL_METHOD_PROCESS_GROUP.

Referenced by killpid().

711 {
712  switch (kill_method) {
714  return killpg(pid, signum);
715  case KILL_METHOD_PROCESS:
716  return kill(pid, signum);
717  }
718 
719  return -1;
720 }

◆ killpid()

static void killpid ( int  pid,
size_t  delay,
enum kill_methods  kill_method 
)
static

Definition at line 722 of file res_musiconhold.c.

References ast_debug, ast_log, errno, KILL_METHOD_PROCESS_GROUP, killer(), and LOG_WARNING.

Referenced by moh_class_destructor(), and monmp3thread().

723 {
724  if (killer(pid, SIGHUP, kill_method) < 0) {
725  if (errno == ESRCH) {
726  return;
727  }
728  ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process '%d'?!!: %s\n", pid, strerror(errno));
729  } else {
730  ast_debug(1, "Sent HUP to pid %d%s\n", pid,
731  kill_method == KILL_METHOD_PROCESS_GROUP ? " and all children" : " only");
732  }
733  usleep(delay);
734  if (killer(pid, SIGTERM, kill_method) < 0) {
735  if (errno == ESRCH) {
736  return;
737  }
738  ast_log(LOG_WARNING, "Unable to terminate MOH process '%d'?!!: %s\n", pid, strerror(errno));
739  } else {
740  ast_debug(1, "Sent TERM to pid %d%s\n", pid,
741  kill_method == KILL_METHOD_PROCESS_GROUP ? " and all children" : " only");
742  }
743  usleep(delay);
744  if (killer(pid, SIGKILL, kill_method) < 0) {
745  if (errno == ESRCH) {
746  return;
747  }
748  ast_log(LOG_WARNING, "Unable to kill MOH process '%d'?!!: %s\n", pid, strerror(errno));
749  } else {
750  ast_debug(1, "Sent KILL to pid %d%s\n", pid,
751  kill_method == KILL_METHOD_PROCESS_GROUP ? " and all children" : " only");
752  }
753 }
#define LOG_WARNING
Definition: logger.h:274
static int killer(pid_t pid, int signum, enum kill_methods kill_method)
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
int errno

◆ load_module()

static int load_module ( void  )
static

Load the module.

Module loading including tests for configuration or dependencies. This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE, or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails tests return AST_MODULE_LOAD_FAILURE. If the module can not load the configuration file or other non-critical problem return AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.

Definition at line 2087 of file res_musiconhold.c.

References AO2_ALLOC_OPT_LOCK_MUTEX, ao2_t_container_alloc_hash, 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(), NULL, play_moh, play_moh_exec(), start_moh, start_moh_exec(), stop_moh, and stop_moh_exec().

Referenced by unload_module().

2088 {
2089  int res;
2090 
2092  moh_class_hash, NULL, moh_class_cmp, "Moh class container");
2093  if (!mohclasses) {
2094  return AST_MODULE_LOAD_DECLINE;
2095  }
2096 
2097  if (!load_moh_classes(0) && ast_check_realtime("musiconhold") == 0) { /* No music classes configured, so skip it */
2098  ast_log(LOG_WARNING, "No music on hold classes configured, "
2099  "disabling music on hold.\n");
2100  } else {
2103  }
2104 
2108  if (!res)
2110  if (!res)
2112 
2113  return AST_MODULE_LOAD_SUCCESS;
2114 }
static int stop_moh_exec(struct ast_channel *chan, const char *data)
static struct ao2_container * mohclasses
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static const char stop_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:274
static struct ast_cli_entry cli_moh[]
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3363
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
#define NULL
Definition: resample.c:96
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)
#define ast_log
Definition: astobj2.c:42
int ast_register_atexit(void(*func)(void))
Register a function to be executed before Asterisk exits.
Definition: clicompat.c:13
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)
static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
#define ao2_t_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn, tag)
Allocate and initialize a hash container with the desired number of buckets.
Definition: astobj2.h:1308
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:7689
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static int moh_class_hash(const void *obj, const int flags)
static const char play_moh[]
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:626

◆ load_moh_classes()

static int load_moh_classes ( int  reload)
static

Definition at line 1847 of file res_musiconhold.c.

References ao2_t_callback, mohclass::args, ast_category_browse(), ast_check_realtime(), ast_clear_flag, ast_config_destroy(), ast_config_load, ast_copy_string(), AST_FLAGS_ALL, ast_log, ast_set2_flag, ast_strlen_zero, ast_true(), ast_variable_browse(), moh_files_state::class, CONFIG_FLAG_FILEUNCHANGED, CONFIG_STATUS_FILEINVALID, CONFIG_STATUS_FILEMISSING, CONFIG_STATUS_FILEUNCHANGED, mohclass::dir, HANDLE_REF, LOG_WARNING, mohclass::mode, MOH_CACHERTCLASSES, moh_class_malloc, moh_class_mark(), moh_classes_delete_marked(), moh_parse_options(), MOH_PREFERCHANNELCLASS, MOH_REALTIME, moh_register, moh_rescan_files(), mohclass_unref, ast_variable::name, mohclass::name, ast_variable::next, NULL, OBJ_MULTIPLE, OBJ_NODATA, OBJ_UNLINK, ast_variable::value, and var.

Referenced by load_module(), and reload().

1848 {
1849  struct ast_config *cfg;
1850  struct ast_variable *var;
1851  struct mohclass *class;
1852  char *cat;
1853  int numclasses = 0;
1854  struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1855 
1856  cfg = ast_config_load("musiconhold.conf", config_flags);
1857 
1858  if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
1859  if (ast_check_realtime("musiconhold") && reload) {
1860  ao2_t_callback(mohclasses, OBJ_NODATA | MOH_REALTIME, moh_class_mark, NULL, "Mark realtime classes for deletion");
1862  }
1863  moh_rescan_files();
1864  return 0;
1865  }
1866 
1868  if (ast_check_realtime("musiconhold") && reload) {
1869  ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
1871  }
1872  return 0;
1873  }
1874 
1875  if (reload) {
1876  ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
1877  }
1878 
1881 
1882  cat = ast_category_browse(cfg, NULL);
1883  for (; cat; cat = ast_category_browse(cfg, cat)) {
1884  /* Setup common options from [general] section */
1885  if (!strcasecmp(cat, "general")) {
1886  for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1887  if (!strcasecmp(var->name, "cachertclasses")) {
1889  } else if (!strcasecmp(var->name, "preferchannelclass")) {
1891  } else {
1892  ast_log(LOG_WARNING, "Unknown option '%s' in [general] section of musiconhold.conf\n", var->name);
1893  }
1894  }
1895  continue;
1896  }
1897 
1898  if (!(class = moh_class_malloc())) {
1899  break;
1900  }
1901 
1902  moh_parse_options(ast_variable_browse(cfg, cat), class);
1903  /* For compatibility with the past, we overwrite any name=name
1904  * with the context [name]. */
1905  ast_copy_string(class->name, cat, sizeof(class->name));
1906 
1907  if (ast_strlen_zero(class->dir)) {
1908  if (!strcasecmp(class->mode, "custom") || !strcasecmp(class->mode, "playlist")) {
1909  strcpy(class->dir, "nodir");
1910  } else {
1911  ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
1912  class = mohclass_unref(class, "unreffing potential mohclass (no directory)");
1913  continue;
1914  }
1915  }
1916  if (ast_strlen_zero(class->mode)) {
1917  ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
1918  class = mohclass_unref(class, "unreffing potential mohclass (no mode)");
1919  continue;
1920  }
1921  if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
1922  ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
1923  class = mohclass_unref(class, "unreffing potential mohclass (no app for custom mode)");
1924  continue;
1925  }
1926 
1927  /* Don't leak a class when it's already registered */
1928  if (!moh_register(class, reload, HANDLE_REF)) {
1929  numclasses++;
1930  }
1931  }
1932 
1933  ast_config_destroy(cfg);
1934 
1936  moh_classes_delete_marked, NULL, "Purge marked classes");
1937 
1938  return numclasses;
1939 }
static struct ao2_container * mohclasses
struct ast_variable * next
#define HANDLE_REF
static int moh_classes_delete_marked(void *obj, void *arg, int flags)
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
Definition: extconf.c:1216
#define moh_register(moh, reload, unref)
static int reload(void)
#define LOG_WARNING
Definition: logger.h:274
#define CONFIG_STATUS_FILEINVALID
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3363
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
Definition: extconf.c:3328
#define NULL
Definition: resample.c:96
static void moh_rescan_files(void)
#define ast_log
Definition: astobj2.c:42
#define ast_config_load(filename, flags)
Load a config file.
#define MOH_CACHERTCLASSES
void ast_config_destroy(struct ast_config *config)
Destroys a config.
Definition: extconf.c:1290
#define MOH_PREFERCHANNELCLASS
#define CONFIG_STATUS_FILEUNCHANGED
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1821
#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:1714
#define ast_strlen_zero(a)
Definition: muted.c:73
#define AST_FLAGS_ALL
Definition: utils.h:196
#define MOH_REALTIME
static void moh_parse_options(struct ast_variable *var, struct mohclass *mohclass)
Structure used to handle boolean flags.
Definition: utils.h:199
#define ast_clear_flag(p, flag)
Definition: utils.h:77
static struct ast_flags global_flags[1]
#define CONFIG_STATUS_FILEMISSING
static int moh_class_mark(void *obj, void *arg, int flags)
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define mohclass_unref(class, string)
static const char app[]
Definition: app_mysql.c:62
#define moh_class_malloc()

◆ load_realtime_musiconhold()

static struct ast_variable* load_realtime_musiconhold ( const char *  name)
static

Definition at line 1513 of file res_musiconhold.c.

References ast_load_realtime(), ast_log, ast_strings_equal(), ast_variable_find_in_list(), ast_variable_list_append, ast_variable_new, ast_variables_destroy(), LOG_WARNING, ast_variable::name, ast_variable::next, NULL, SENTINEL, ast_variable::value, and var.

Referenced by local_ast_moh_start().

1514 {
1515  struct ast_variable *var = ast_load_realtime("musiconhold", "name", name, SENTINEL);
1516 
1517  if (var) {
1518  const char *mode = ast_variable_find_in_list(var, "mode");
1519  if (ast_strings_equal(mode, "playlist")) {
1520  struct ast_variable *entries = ast_load_realtime("musiconhold_entry", "name", name, SENTINEL);
1521  struct ast_variable *cur = entries;
1522  size_t entry_count = 0;
1523  for (; cur; cur = cur->next) {
1524  if (!strcmp(cur->name, "entry")) {
1525  struct ast_variable *dup = ast_variable_new(cur->name, cur->value, "");
1526  if (dup) {
1527  entry_count++;
1528  ast_variable_list_append(&var, dup);
1529  }
1530  }
1531  }
1532  ast_variables_destroy(entries);
1533 
1534  if (entry_count == 0) {
1535  /* Behave as though this class doesn't exist */
1536  ast_variables_destroy(var);
1537  var = NULL;
1538  }
1539  }
1540  }
1541 
1542  if (!var) {
1544  "Music on Hold class '%s' not found in memory/database. "
1545  "Verify your configuration.\n",
1546  name);
1547  }
1548  return var;
1549 }
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Definition: main/config.c:3339
struct ast_variable * next
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
#define LOG_WARNING
Definition: logger.h:274
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
#define NULL
Definition: resample.c:96
#define ast_log
Definition: astobj2.c:42
#define SENTINEL
Definition: compiler.h:87
const char * ast_variable_find_in_list(const struct ast_variable *list, const char *variable)
Gets the value of a variable from a variable list by name.
Definition: main/config.c:830
#define ast_variable_new(name, value, filename)
int ast_strings_equal(const char *str1, const char *str2)
Compare strings for equality checking for NULL.
Definition: strings.c:239
static const char name[]
Definition: cdr_mysql.c:74
#define ast_variable_list_append(head, new_var)

◆ local_ast_moh_cleanup()

static void local_ast_moh_cleanup ( struct ast_channel chan)
static

Definition at line 1397 of file res_musiconhold.c.

References ao2_cleanup, ast_channel_music_state(), ast_channel_music_state_set(), ast_free, ast_log, ast_module_unref, moh_files_state::class, LOG_WARNING, mohclass_unref, moh_files_state::mohwfmt, NULL, moh_files_state::origwfmt, and ast_module_info::self.

Referenced by load_module(), and reload().

1398 {
1400 
1401  if (state) {
1403  if (state->class) {
1404  /* This should never happen. We likely just leaked some resource. */
1405  state->class =
1406  mohclass_unref(state->class, "Uh Oh. Cleaning up MOH with an active class");
1407  ast_log(LOG_WARNING, "Uh Oh. Cleaning up MOH with an active class\n");
1408  }
1409  ao2_cleanup(state->origwfmt);
1410  ao2_cleanup(state->mohwfmt);
1411  ast_free(state);
1412  /* Only held a module reference if we had a music state */
1414  }
1415 }
#define LOG_WARNING
Definition: logger.h:274
struct mohclass * class
struct ast_format * origwfmt
void ast_channel_music_state_set(struct ast_channel *chan, void *value)
#define NULL
Definition: resample.c:96
#define ast_module_unref(mod)
Release a reference to the module.
Definition: module.h:469
#define ast_log
Definition: astobj2.c:42
struct ast_module * self
Definition: module.h:342
#define ast_free(a)
Definition: astmm.h:182
struct ast_format * mohwfmt
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void * ast_channel_music_state(const struct ast_channel *chan)
#define mohclass_unref(class, string)

◆ local_ast_moh_start()

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

Definition at line 1551 of file res_musiconhold.c.

References mohclass::args, ARRAY_LEN, ast_activate_generator(), ast_channel_flags(), ast_channel_lock, ast_channel_music_state(), ast_channel_musicclass(), ast_channel_unlock, ast_check_realtime(), AST_FLAG_MOH, ast_log, ast_pthread_create_background, ast_set_flag, ast_strlen_zero, ast_test_flag, ast_timer_close(), ast_timer_open(), ast_timer_set_rate(), ast_variables_destroy(), AST_VECTOR_SIZE, moh_files_state::class, mohclass::dir, DONT_UNREF, errno, mohclass::files, get_mohbyname, load_realtime_musiconhold(), LOG_NOTICE, LOG_WARNING, mohclass::mode, MOH_CACHERTCLASSES, moh_class_malloc, MOH_CUSTOM, moh_parse_options(), MOH_PREFERCHANNELCLASS, MOH_QUIET, MOH_RANDOMIZE, moh_register, moh_scan_files(), MOH_SINGLE, mohclass_ref, mohclass_unref, monmp3thread(), mohclass::name, NULL, mohclass::realtime, respawn_time, mohclass::srcfd, mohclass::start, mohclass::thread, mohclass::timer, and var.

Referenced by load_module(), and reload().

1552 {
1553  struct mohclass *mohclass = NULL;
1555  struct ast_variable *var = NULL;
1556  int res = 0;
1557  int i;
1558  int realtime_possible = ast_check_realtime("musiconhold");
1559  int warn_if_not_in_memory = !realtime_possible;
1560  const char *classes[] = {NULL, NULL, interpclass, "default"};
1561 
1563  classes[0] = ast_channel_musicclass(chan);
1564  classes[1] = mclass;
1565  } else {
1566  classes[0] = mclass;
1567  classes[1] = ast_channel_musicclass(chan);
1568  }
1569 
1570  /* The following is the order of preference for which class to use:
1571  * 1) The channels explicitly set musicclass, which should *only* be
1572  * set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
1573  * Unless preferchannelclass in musiconhold.conf is false
1574  * 2) The mclass argument. If a channel is calling ast_moh_start() as the
1575  * result of receiving a HOLD control frame, this should be the
1576  * payload that came with the frame.
1577  * 3) The channels explicitly set musicclass, which should *only* be
1578  * set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
1579  * 4) The interpclass argument. This would be from the mohinterpret
1580  * option from channel drivers. This is the same as the old musicclass
1581  * option.
1582  * 5) The default class.
1583  */
1584 
1585  for (i = 0; i < ARRAY_LEN(classes); ++i) {
1586  if (!ast_strlen_zero(classes[i])) {
1587  mohclass = get_mohbyname(classes[i], warn_if_not_in_memory, 0);
1588  if (!mohclass && realtime_possible) {
1589  var = load_realtime_musiconhold(classes[i]);
1590  }
1591  if (mohclass || var) {
1592  break;
1593  }
1594  }
1595  }
1596 
1597  /* If no moh class found in memory, then check RT. Note that the logic used
1598  * above guarantees that if var is non-NULL, then mohclass must be NULL.
1599  */
1600  if (var) {
1601  if ((mohclass = moh_class_malloc())) {
1602  mohclass->realtime = 1;
1603 
1604  moh_parse_options(var, mohclass);
1605  ast_variables_destroy(var);
1606 
1607  if (ast_strlen_zero(mohclass->dir)) {
1608  if (!strcasecmp(mohclass->mode, "custom") || !strcasecmp(mohclass->mode, "playlist")) {
1609  strcpy(mohclass->dir, "nodir");
1610  } else {
1611  ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", mohclass->name);
1612  mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no directory specified)");
1613  return -1;
1614  }
1615  }
1616  if (ast_strlen_zero(mohclass->mode)) {
1617  ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", mohclass->name);
1618  mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no mode specified)");
1619  return -1;
1620  }
1621  if (ast_strlen_zero(mohclass->args) && !strcasecmp(mohclass->mode, "custom")) {
1622  ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", mohclass->name);
1623  mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no app specified for custom mode");
1624  return -1;
1625  }
1626 
1628  /* CACHERTCLASSES enabled, let's add this class to default tree */
1629  if (state && state->class) {
1630  /* Class already exist for this channel */
1631  ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name);
1632  }
1633  /* We don't want moh_register to unref the mohclass because we do it at the end of this function as well.
1634  * If we allowed moh_register to unref the mohclass,too, then the count would be off by one. The result would
1635  * be that the destructor would be called when the generator on the channel is deactivated. The container then
1636  * has a pointer to a freed mohclass, so any operations involving the mohclass container would result in reading
1637  * invalid memory.
1638  */
1639  if (moh_register(mohclass, 0, DONT_UNREF) == -1) {
1640  mohclass = mohclass_unref(mohclass, "unreffing mohclass failed to register");
1641  return -1;
1642  }
1643  } else {
1644  /* We don't register RT moh class, so let's init it manualy */
1645 
1646  time(&mohclass->start);
1647  mohclass->start -= respawn_time;
1648 
1649  if (!strcasecmp(mohclass->mode, "files")) {
1650  if (!moh_scan_files(mohclass)) {
1651  mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)");
1652  return -1;
1653  }
1654  if (strchr(mohclass->args, 'r')) {
1655  static int deprecation_warning = 0;
1656  if (!deprecation_warning) {
1657  ast_log(LOG_WARNING, "Music on hold 'application=r' setting is deprecated in 14. Please use 'sort=random' instead.\n");
1658  deprecation_warning = 1;
1659  }
1660  ast_set_flag(mohclass, MOH_RANDOMIZE);
1661  }
1662  } else if (!strcasecmp(mohclass->mode, "playlist")) {
1663  if (!AST_VECTOR_SIZE(&mohclass->files)) {
1664  mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no playlist entries)");
1665  return -1;
1666  }
1667  } 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")) {
1668 
1669  if (!strcasecmp(mohclass->mode, "custom"))
1670  ast_set_flag(mohclass, MOH_CUSTOM);
1671  else if (!strcasecmp(mohclass->mode, "mp3nb"))
1672  ast_set_flag(mohclass, MOH_SINGLE);
1673  else if (!strcasecmp(mohclass->mode, "quietmp3nb"))
1674  ast_set_flag(mohclass, MOH_SINGLE | MOH_QUIET);
1675  else if (!strcasecmp(mohclass->mode, "quietmp3"))
1676  ast_set_flag(mohclass, MOH_QUIET);
1677 
1678  mohclass->srcfd = -1;
1679  if (!(mohclass->timer = ast_timer_open())) {
1680  ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno));
1681  }
1682  if (mohclass->timer && ast_timer_set_rate(mohclass->timer, 25)) {
1683  ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno));
1684  ast_timer_close(mohclass->timer);
1685  mohclass->timer = NULL;
1686  }
1687 
1688  /* Let's check if this channel already had a moh class before */
1689  if (state && state->class) {
1690  /* Class already exist for this channel */
1691  ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name);
1692  if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) {
1693  /* we found RT class with the same name, seems like we should continue playing existing one */
1694  mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has one)");
1695  mohclass = mohclass_ref(state->class, "using existing class from state");
1696  }
1697  } else {
1698  if (ast_pthread_create_background(&mohclass->thread, NULL, monmp3thread, mohclass)) {
1699  ast_log(LOG_WARNING, "Unable to create moh...\n");
1700  if (mohclass->timer) {
1701  ast_timer_close(mohclass->timer);
1702  mohclass->timer = NULL;
1703  }
1704  mohclass = mohclass_unref(mohclass, "Unreffing potential mohclass (failed to create background thread)");
1705  return -1;
1706  }
1707  }
1708  } else {
1709  ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mohclass->mode);
1710  mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (unknown mode)");
1711  return -1;
1712  }
1713  }
1714  } else {
1715  ast_variables_destroy(var);
1716  var = NULL;
1717  }
1718  }
1719 
1720  if (!mohclass) {
1721  return -1;
1722  }
1723 
1724  /* If we are using a cached realtime class with files, re-scan the files */
1725  if (!var && ast_test_flag(global_flags, MOH_CACHERTCLASSES) && mohclass->realtime && !strcasecmp(mohclass->mode, "files")) {
1726  if (!moh_scan_files(mohclass)) {
1727  mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)");
1728  return -1;
1729  }
1730  }
1731 
1732  if (!state || !state->class || strcmp(mohclass->name, state->class->name)) {
1733  if (AST_VECTOR_SIZE(&mohclass->files)) {
1734  res = ast_activate_generator(chan, &moh_file_stream, mohclass);
1735  } else {
1736  res = ast_activate_generator(chan, &mohgen, mohclass);
1737  }
1738  }
1739  if (!res) {
1740  ast_channel_lock(chan);
1741  ast_channel_latest_musicclass_set(chan, mohclass->name);
1743  ast_channel_unlock(chan);
1744  }
1745 
1746  mohclass = mohclass_unref(mohclass, "unreffing local reference to mohclass in local_ast_moh_start");
1747 
1748  return res;
1749 }
#define ast_channel_lock(chan)
Definition: channel.h:2837
char name[MAX_MUSICCLASS]
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1263
#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:2926
#define moh_register(moh, reload, unref)
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:274
struct mohclass * class
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Definition: main/config.c:3363
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
void ast_timer_close(struct ast_timer *handle)
Close an opened timing handle.
Definition: timing.c:154
struct ast_timer * ast_timer_open(void)
Open a timer.
Definition: timing.c:122
#define NULL
Definition: resample.c:96
static int moh_scan_files(struct mohclass *class)
#define mohclass_ref(class, string)
struct ast_vector_string files
char dir[256]
unsigned int realtime
#define ast_pthread_create_background(a, b, c, d)
Definition: utils.h:507
#define ast_log
Definition: astobj2.c:42
#define MOH_CACHERTCLASSES
#define MOH_QUIET
#define MOH_PREFERCHANNELCLASS
int errno
static struct ast_generator moh_file_stream
#define LOG_NOTICE
Definition: logger.h:263
#define ast_strlen_zero(a)
Definition: muted.c:73
#define ast_channel_unlock(chan)
Definition: channel.h:2838
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:166
struct ast_timer * timer
static void moh_parse_options(struct ast_variable *var, struct mohclass *mohclass)
static struct ast_flags global_flags[1]
#define MOH_CUSTOM
pthread_t thread
char args[256]
static struct ast_variable * load_realtime_musiconhold(const char *name)
void * ast_channel_music_state(const struct ast_channel *chan)
#define mohclass_unref(class, string)
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
char mode[80]
static struct ast_generator mohgen
static void * monmp3thread(void *data)
#define MOH_SINGLE
#define moh_class_malloc()
#define MOH_RANDOMIZE
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
#define DONT_UNREF
#define get_mohbyname(a, b, c)
const char * ast_channel_musicclass(const struct ast_channel *chan)

◆ local_ast_moh_stop()

static void local_ast_moh_stop ( struct ast_channel chan)
static

Definition at line 1751 of file res_musiconhold.c.

References ast_channel_flags(), ast_channel_lock, ast_channel_music_state(), ast_channel_stream(), ast_channel_stream_set(), ast_channel_unlock, ast_clear_flag, ast_closestream(), ast_deactivate_generator(), AST_FLAG_MOH, and NULL.

Referenced by load_module(), and reload().

1752 {
1754 
1755  ast_channel_lock(chan);
1757  if (ast_channel_music_state(chan)) {
1758  if (ast_channel_stream(chan)) {
1761  }
1762  }
1763  ast_channel_unlock(chan);
1764 }
#define ast_channel_lock(chan)
Definition: channel.h:2837
#define NULL
Definition: resample.c:96
void ast_channel_stream_set(struct ast_channel *chan, struct ast_filestream *value)
#define ast_channel_unlock(chan)
Definition: channel.h:2838
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:1068
struct ast_filestream * ast_channel_stream(const struct ast_channel *chan)
#define ast_clear_flag(p, flag)
Definition: utils.h:77
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:2868
void * ast_channel_music_state(const struct ast_channel *chan)
struct ast_flags * ast_channel_flags(struct ast_channel *chan)

◆ moh_alloc()

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

Definition at line 1003 of file res_musiconhold.c.

References ao2_bump, ao2_cleanup, ast_calloc, ast_channel_music_state(), ast_channel_music_state_set(), ast_channel_name(), ast_channel_writeformat(), ast_format_get_name(), ast_log, ast_module_ref, ast_set_write_format(), moh_files_state::class, mohclass::format, LOG_WARNING, moh_post_start(), moh_release(), mohalloc(), mohclass_ref, mohclass_unref, moh_files_state::mohwfmt, mohclass::name, NULL, moh_files_state::origwfmt, mohdata::origwfmt, ast_module_info::self, and state.

1004 {
1005  struct mohdata *res;
1006  struct mohclass *class = params;
1007  struct moh_files_state *state;
1008 
1009  /* Initiating music_state for current channel. Channel should know name of moh class */
1010  state = ast_channel_music_state(chan);
1011  if (!state && (state = ast_calloc(1, sizeof(*state)))) {
1012  ast_channel_music_state_set(chan, state);
1014  } else {
1015  if (!state) {
1016  return NULL;
1017  }
1018  if (state->class) {
1019  mohclass_unref(state->class, "Uh Oh. Restarting MOH with an active class");
1020  ast_log(LOG_WARNING, "Uh Oh. Restarting MOH with an active class\n");
1021  }
1022  ao2_cleanup(state->origwfmt);
1023  ao2_cleanup(state->mohwfmt);
1024  memset(state, 0, sizeof(*state));
1025  }
1026 
1027  if ((res = mohalloc(class))) {
1029  if (ast_set_write_format(chan, class->format)) {
1030  ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", ast_channel_name(chan),
1032  moh_release(NULL, res);
1033  res = NULL;
1034  } else {
1035  state->class = mohclass_ref(class, "Placing reference into state container");
1036  moh_post_start(chan, class->name);
1037  }
1038  }
1039  return res;
1040 }
static void moh_release(struct ast_channel *chan, void *data)
enum sip_cc_notify_state state
Definition: chan_sip.c:956
char name[MAX_MUSICCLASS]
static void moh_post_start(struct ast_channel *chan, const char *moh_class_name)
#define LOG_WARNING
Definition: logger.h:274
struct mohclass * class
struct ast_format * origwfmt
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
void ast_channel_music_state_set(struct ast_channel *chan, void *value)
#define NULL
Definition: resample.c:96
static struct mohdata * mohalloc(struct mohclass *cl)
#define mohclass_ref(class, string)
#define ao2_bump(obj)
Definition: astobj2.h:491
#define ast_log
Definition: astobj2.c:42
struct ast_module * self
Definition: module.h:342
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5765
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
struct ast_format * mohwfmt
struct ast_format * format
struct ast_format * origwfmt
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
const char * ast_channel_name(const struct ast_channel *chan)
void * ast_channel_music_state(const struct ast_channel *chan)
#define mohclass_unref(class, string)
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:443

◆ moh_class_cmp()

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

Definition at line 2068 of file res_musiconhold.c.

References moh_files_state::class, CMP_MATCH, CMP_STOP, mohclass::delete, MOH_NOTDELETED, and mohclass::name.

Referenced by load_module().

2069 {
2070  struct mohclass *class = obj, *class2 = arg;
2071 
2072  return strcasecmp(class->name, class2->name) ? 0 :
2073  (flags & MOH_NOTDELETED) && (class->delete || class2->delete) ? 0 :
2074  CMP_MATCH | CMP_STOP;
2075 }
#define MOH_NOTDELETED

◆ moh_class_destructor()

static void moh_class_destructor ( void *  obj)
static

Definition at line 1766 of file res_musiconhold.c.

References ao2_cleanup, ao2_lock, ao2_unlock, ast_debug, ast_free, AST_LIST_REMOVE_HEAD, AST_PTHREADT_NULL, ast_timer_close(), AST_VECTOR_FREE, AST_VECTOR_RESET, ast_wait_for_input(), buff, moh_files_state::class, mohclass::files, mohclass::format, mohclass::kill_delay, mohclass::kill_method, killpid(), mohdata::list, mohclass::members, mohclass::name, NULL, mohclass::pid, mohclass::srcfd, mohclass::thread, and mohclass::timer.

Referenced by _moh_class_malloc(), and handle_cli_moh_unregister_class().

1767 {
1768  struct mohclass *class = obj;
1769  struct mohdata *member;
1770  pthread_t tid = 0;
1771 
1772  ast_debug(1, "Destroying MOH class '%s'\n", class->name);
1773 
1774  ao2_lock(class);
1775  while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) {
1776  ast_free(member);
1777  }
1778  ao2_unlock(class);
1779 
1780  /* Kill the thread first, so it cannot restart the child process while the
1781  * class is being destroyed */
1782  if (class->thread != AST_PTHREADT_NULL && class->thread != 0) {
1783  tid = class->thread;
1784  class->thread = AST_PTHREADT_NULL;
1785  pthread_cancel(tid);
1786  /* We'll collect the exit status later, after we ensure all the readers
1787  * are dead. */
1788  }
1789 
1790  if (class->pid > 1) {
1791  char buff[8192];
1792  int bytes, tbytes = 0, stime = 0;
1793 
1794  ast_debug(1, "killing %d!\n", class->pid);
1795 
1796  stime = time(NULL) + 2;
1797  killpid(class->pid, class->kill_delay, class->kill_method);
1798 
1799  while ((ast_wait_for_input(class->srcfd, 100) > 0) &&
1800  (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) {
1801  tbytes = tbytes + bytes;
1802  }
1803 
1804  ast_debug(1, "mpg123 pid %d and child died after %d bytes read\n",
1805  class->pid, tbytes);
1806 
1807  class->pid = 0;
1808  close(class->srcfd);
1809  class->srcfd = -1;
1810  }
1811 
1812  AST_VECTOR_RESET(&class->files, ast_free);
1813  AST_VECTOR_FREE(&class->files);
1814 
1815  if (class->timer) {
1816  ast_timer_close(class->timer);
1817  class->timer = NULL;
1818  }
1819 
1820  ao2_cleanup(class->format);
1821 
1822  /* Finally, collect the exit status of the monitor thread */
1823  if (tid > 0) {
1824  pthread_join(tid, NULL);
1825  }
1826 
1827 }
#define AST_VECTOR_FREE(vec)
Deallocates this vector.
Definition: vector.h:174
void ast_timer_close(struct ast_timer *handle)
Close an opened timing handle.
Definition: timing.c:154
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define AST_PTHREADT_NULL
Definition: lock.h:66
static void killpid(int pid, size_t delay, enum kill_methods kill_method)
#define ao2_lock(a)
Definition: astobj2.h:718
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:832
#define ast_free(a)
Definition: astmm.h:182
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition: vector.h:627
struct mohdata::@456 list
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static unsigned char * buff
Definition: chan_unistim.c:259
int ast_wait_for_input(int fd, int ms)
Definition: main/utils.c:1389

◆ moh_class_hash()

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

Definition at line 2061 of file res_musiconhold.c.

References ast_str_case_hash(), moh_files_state::class, and mohclass::name.

Referenced by load_module().

2062 {
2063  const struct mohclass *class = obj;
2064 
2065  return ast_str_case_hash(class->name);
2066 }
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:1250

◆ moh_class_inuse()

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

Definition at line 2126 of file res_musiconhold.c.

References AST_LIST_EMPTY, moh_files_state::class, CMP_MATCH, CMP_STOP, and mohclass::members.

Referenced by unload_module().

2127 {
2128  struct mohclass *class = obj;
2129 
2130  return AST_LIST_EMPTY(&class->members) ? 0 : CMP_MATCH | CMP_STOP;
2131 }
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449

◆ moh_class_mark()

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

Definition at line 1829 of file res_musiconhold.c.

References moh_files_state::class, mohclass::delete, MOH_REALTIME, and mohclass::realtime.

Referenced by load_moh_classes().

1830 {
1831  struct mohclass *class = obj;
1832 
1833  if ( ((flags & MOH_REALTIME) && class->realtime) || !(flags & MOH_REALTIME) ) {
1834  class->delete = 1;
1835  }
1836 
1837  return 0;
1838 }
unsigned int delete
#define MOH_REALTIME

◆ moh_classes_delete_marked()

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

Definition at line 1840 of file res_musiconhold.c.

References CMP_MATCH, and mohclass::delete.

Referenced by load_moh_classes().

1841 {
1842  struct mohclass *class = obj;
1843 
1844  return class->delete ? CMP_MATCH : 0;
1845 }
unsigned int delete

◆ moh_diff()

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

Definition at line 1270 of file res_musiconhold.c.

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

Referenced by _moh_register().

1271 {
1272  if (!old || !new) {
1273  return -1;
1274  }
1275 
1276  if (strcmp(old->dir, new->dir)) {
1277  return -1;
1278  } else if (strcmp(old->mode, new->mode)) {
1279  return -1;
1280  } else if (strcmp(old->args, new->args)) {
1281  return -1;
1282  } else if (old->flags != new->flags) {
1283  return -1;
1284  }
1285 
1286  return 0;
1287 }
char dir[256]
unsigned int flags
char args[256]
char mode[80]

◆ moh_digit_match()

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

Definition at line 533 of file res_musiconhold.c.

References moh_files_state::class, CMP_MATCH, CMP_STOP, digit, and mohclass::digit.

Referenced by get_mohbydigit().

534 {
535  char *digit = arg;
536  struct mohclass *class = obj;
537 
538  return (*digit == class->digit) ? CMP_MATCH | CMP_STOP : 0;
539 }
char digit

◆ moh_files_alloc()

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

Definition at line 487 of file res_musiconhold.c.

References ao2_cleanup, ao2_replace, ast_calloc, ast_channel_music_state(), ast_channel_music_state_set(), ast_channel_writeformat(), ast_copy_string(), ast_log, ast_module_ref, ast_random(), ast_test_flag, AST_VECTOR_SIZE, moh_files_state::class, mohclass::files, LOG_WARNING, moh_post_start(), MOH_RANDOMIZE, mohclass_ref, mohclass_unref, moh_files_state::mohwfmt, moh_files_state::name, mohclass::name, NULL, moh_files_state::origwfmt, moh_files_state::pos, moh_files_state::save_total, ast_module_info::self, and state.

488 {
489  struct moh_files_state *state;
490  struct mohclass *class = params;
491  size_t file_count;
492 
493  state = ast_channel_music_state(chan);
494  if (!state && (state = ast_calloc(1, sizeof(*state)))) {
495  ast_channel_music_state_set(chan, state);
497  } else {
498  if (!state) {
499  return NULL;
500  }
501  if (state->class) {
502  mohclass_unref(state->class, "Uh Oh. Restarting MOH with an active class");
503  ast_log(LOG_WARNING, "Uh Oh. Restarting MOH with an active class\n");
504  }
505  }
506 
507  file_count = AST_VECTOR_SIZE(&class->files);
508 
509  /* Resume MOH from where we left off last time or start from scratch? */
510  if (state->save_total != file_count || strcmp(state->name, class->name) != 0) {
511  /* Start MOH from scratch. */
512  ao2_cleanup(state->origwfmt);
513  ao2_cleanup(state->mohwfmt);
514  memset(state, 0, sizeof(*state));
515  if (ast_test_flag(class, MOH_RANDOMIZE) && file_count) {
516  state->pos = ast_random() % file_count;
517  }
518  }
519 
520  state->class = mohclass_ref(class, "Reffing music class for channel");
521  /* it's possible state is not a new allocation, don't leak old refs */
524  /* For comparison on restart of MOH (see above) */
525  ast_copy_string(state->name, class->name, sizeof(state->name));
526  state->save_total = file_count;
527 
528  moh_post_start(chan, class->name);
529 
530  return state;
531 }
enum sip_cc_notify_state state
Definition: chan_sip.c:956
static void moh_post_start(struct ast_channel *chan, const char *moh_class_name)
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define LOG_WARNING
Definition: logger.h:274
struct mohclass * class
struct ast_format * origwfmt
void ast_channel_music_state_set(struct ast_channel *chan, void *value)
#define NULL
Definition: resample.c:96
#define mohclass_ref(class, string)
#define ast_log
Definition: astobj2.c:42
struct ast_module * self
Definition: module.h:342
long int ast_random(void)
Definition: main/utils.c:1934
const ast_string_field name
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
struct ast_format * mohwfmt
#define ao2_replace(dst, src)
Definition: astobj2.h:517
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
void * ast_channel_music_state(const struct ast_channel *chan)
#define mohclass_unref(class, string)
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)
char name[MAX_MUSICCLASS]
#define MOH_RANDOMIZE
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
#define ast_module_ref(mod)
Hold a reference to the module.
Definition: module.h:443

◆ moh_files_generator()

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

Definition at line 449 of file res_musiconhold.c.

References ao2_replace, ast_channel_lock, ast_channel_music_state(), ast_channel_name(), ast_channel_unlock, ast_format_cmp(), AST_FORMAT_CMP_NOT_EQUAL, ast_frfree, ast_log, ast_write(), errno, ast_frame_subclass::format, LOG_WARNING, moh_files_readframe(), moh_files_state::mohwfmt, NULL, moh_files_state::sample_queue, moh_files_state::samples, ast_frame::samples, and ast_frame::subclass.

450 {
452  struct ast_frame *f = NULL;
453  int res = 0;
454 
455  state->sample_queue += samples;
456 
457  while (state->sample_queue > 0) {
458  ast_channel_lock(chan);
459  f = moh_files_readframe(chan);
460 
461  /* We need to be sure that we unlock
462  * the channel prior to calling
463  * ast_write. Otherwise, the recursive locking
464  * that occurs can cause deadlocks when using
465  * indirect channels, like local channels
466  */
467  ast_channel_unlock(chan);
468  if (!f) {
469  return -1;
470  }
471 
472  state->samples += f->samples;
473  state->sample_queue -= f->samples;
475  ao2_replace(state->mohwfmt, f->subclass.format);
476  }
477  res = ast_write(chan, f);
478  ast_frfree(f);
479  if (res < 0) {
480  ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno));
481  return -1;
482  }
483  }
484  return res;
485 }
#define ast_channel_lock(chan)
Definition: channel.h:2837
static struct ast_frame * moh_files_readframe(struct ast_channel *chan)
#define LOG_WARNING
Definition: logger.h:274
#define NULL
Definition: resample.c:96
struct ast_frame_subclass subclass
#define ast_log
Definition: astobj2.c:42
enum ast_format_cmp_res ast_format_cmp(const struct ast_format *format1, const struct ast_format *format2)
Compare two formats.
Definition: format.c:201
int errno
#define ast_channel_unlock(chan)
Definition: channel.h:2838
struct ast_format * mohwfmt
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:5068
#define ao2_replace(dst, src)
Definition: astobj2.h:517
const char * ast_channel_name(const struct ast_channel *chan)
void * ast_channel_music_state(const struct ast_channel *chan)
#define ast_frfree(fr)
Data structure associated with a single frame of data.
struct ast_format * format

◆ moh_files_readframe()

static struct ast_frame* moh_files_readframe ( struct ast_channel chan)
static

Definition at line 401 of file res_musiconhold.c.

References ast_channel_stream(), ast_moh_files_next(), and ast_readframe().

Referenced by moh_files_generator().

402 {
403  struct ast_frame *f;
404 
406  if (!f) {
407  /* Either there was no file stream setup or we reached EOF. */
408  if (!ast_moh_files_next(chan)) {
409  /*
410  * Either we resetup the previously saved file stream position
411  * or we started a new file stream.
412  */
414  if (!f) {
415  /*
416  * We can get here if we were very unlucky because the
417  * resetup file stream was saved at EOF when MOH was
418  * previously stopped.
419  */
420  if (!ast_moh_files_next(chan)) {
422  }
423  }
424  }
425  }
426 
427  return f;
428 }
struct ast_frame * ast_readframe(struct ast_filestream *s)
Read a frame from a filestream.
Definition: file.c:899
struct ast_filestream * ast_channel_stream(const struct ast_channel *chan)
Data structure associated with a single frame of data.
static int ast_moh_files_next(struct ast_channel *chan)

◆ moh_files_release()

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

Definition at line 281 of file res_musiconhold.c.

References moh_files_state::announcement, ao2_cleanup, ao2_ref, ast_channel_music_state(), ast_channel_name(), ast_channel_stream(), ast_channel_stream_set(), ast_closestream(), ast_format_get_name(), ast_log, ast_set_write_format(), moh_files_state::class, LOG_WARNING, moh_post_stop(), mohclass_unref, moh_files_state::mohwfmt, NULL, moh_files_state::origwfmt, moh_files_state::pos, moh_files_state::save_pos, and state.

282 {
283  struct moh_files_state *state;
284 
285  if (!chan || !ast_channel_music_state(chan)) {
286  return;
287  }
288 
289  state = ast_channel_music_state(chan);
290 
291  if (ast_channel_stream(chan)) {
294  }
295 
296  moh_post_stop(chan);
297 
298  ao2_ref(state->mohwfmt, -1);
299  state->mohwfmt = NULL; /* make sure to clear this format before restoring the original format */
300  if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
301  ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%s'\n", ast_channel_name(chan),
302  ast_format_get_name(state->origwfmt));
303  }
304  ao2_cleanup(state->origwfmt);
305  state->origwfmt = NULL;
306 
307  state->save_pos = state->pos;
308  state->announcement = 0;
309 
310  state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator");
311 }
enum sip_cc_notify_state state
Definition: chan_sip.c:956
static void moh_post_stop(struct ast_channel *chan)
#define LOG_WARNING
Definition: logger.h:274
struct mohclass * class
struct ast_format * origwfmt
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
#define NULL
Definition: resample.c:96
void ast_channel_stream_set(struct ast_channel *chan, struct ast_filestream *value)
#define ast_log
Definition: astobj2.c:42
#define ao2_ref(o, delta)
Definition: astobj2.h:464
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5765
struct ast_format * mohwfmt
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:1068
struct ast_filestream * ast_channel_stream(const struct ast_channel *chan)
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
const char * ast_channel_name(const struct ast_channel *chan)
void * ast_channel_music_state(const struct ast_channel *chan)
#define mohclass_unref(class, string)

◆ moh_files_write_format_change()

static void moh_files_write_format_change ( struct ast_channel chan,
void *  data 
)
static

Definition at line 430 of file res_musiconhold.c.

References ao2_bump, ao2_replace, ast_channel_music_state(), ast_channel_writeformat(), ast_set_write_format(), moh_files_state::mohwfmt, NULL, moh_files_state::origwfmt, and tmp().

431 {
433 
434  /* In order to prevent a recursive call to this function as a result
435  * of setting the moh write format back on the channel. Clear
436  * the moh write format before setting the write format on the channel.*/
437  if (state->origwfmt) {
438  struct ast_format *tmp;
439 
440  tmp = ao2_bump(ast_channel_writeformat(chan));
441  ao2_replace(state->origwfmt, NULL);
442  if (state->mohwfmt) {
443  ast_set_write_format(chan, state->mohwfmt);
444  }
445  state->origwfmt = tmp;
446  }
447 }
static int tmp()
Definition: bt_open.c:389
struct ast_format * origwfmt
Definition of a media format.
Definition: format.c:43
#define NULL
Definition: resample.c:96
#define ao2_bump(obj)
Definition: astobj2.h:491
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5765
struct ast_format * mohwfmt
#define ao2_replace(dst, src)
Definition: astobj2.h:517
void * ast_channel_music_state(const struct ast_channel *chan)
struct ast_format * ast_channel_writeformat(struct ast_channel *chan)

◆ moh_generate()

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

Definition at line 1042 of file res_musiconhold.c.

References ast_channel_name(), ast_codec_samples_count(), ast_format_determine_length(), AST_FRIENDLY_OFFSET, ast_log, ast_write(), buf, ast_frame::data, ast_frame::datalen, errno, mohdata::f, mohclass::format, LOG_WARNING, mohdata::parent, mohdata::pipe, ast_frame::ptr, and ast_frame::samples.

1043 {
1044  struct mohdata *moh = data;
1045  short buf[1280 + AST_FRIENDLY_OFFSET / 2];
1046  int res;
1047 
1048  len = ast_format_determine_length(moh->parent->format, samples);
1049 
1050  if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
1051  ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, ast_channel_name(chan));
1052  len = sizeof(buf) - AST_FRIENDLY_OFFSET;
1053  }
1054  res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
1055  if (res <= 0)
1056  return 0;
1057 
1058  moh->f.datalen = res;
1059  moh->f.data.ptr = buf + AST_FRIENDLY_OFFSET / 2;
1060  moh->f.samples = ast_codec_samples_count(&moh->f);
1061 
1062  if (ast_write(chan, &moh->f) < 0) {
1063  ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno));
1064  return -1;
1065  }
1066 
1067  return 0;
1068 }
char buf[BUFSIZE]
Definition: eagi_proxy.c:66
#define LOG_WARNING
Definition: logger.h:274
union ast_frame::@255 data
#define ast_log
Definition: astobj2.c:42
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
unsigned int ast_codec_samples_count(struct ast_frame *frame)
Get the number of samples contained within a frame.
Definition: codec.c:378
unsigned int ast_format_determine_length(const struct ast_format *format, unsigned int samples)
Get the length (in milliseconds) for the format with a given number of samples.
Definition: format.c:384
int pipe[2]
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int errno
struct ast_format * format
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:5068
struct ast_frame f
const char * ast_channel_name(const struct ast_channel *chan)
struct mohclass * parent

◆ moh_handle_digit()

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

Definition at line 547 of file res_musiconhold.c.

References ast_moh_start(), ast_moh_stop(), ast_strdupa, moh_files_state::class, get_mohbydigit(), mohclass_unref, mohclass::name, and NULL.

548 {
549  struct mohclass *class;
550  const char *classname = NULL;
551 
552  if ((class = get_mohbydigit(digit))) {
553  classname = ast_strdupa(class->name);
554  class = mohclass_unref(class, "Unreffing ao2_find from finding by digit");
555  ast_channel_musicclass_set(chan, classname);
556  ast_moh_stop(chan);
557  ast_moh_start(chan, classname, NULL);
558  }
559 }
char digit
#define NULL
Definition: resample.c:96
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7715
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
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:7705
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
#define mohclass_unref(class, string)
static struct mohclass * get_mohbydigit(char digit)

◆ moh_parse_options()

static void moh_parse_options ( struct ast_variable var,
struct mohclass mohclass 
)
static

Definition at line 1077 of file res_musiconhold.c.

References mohclass::announcement, ao2_bump, ao2_cleanup, mohclass::args, ast_begins_with(), ast_copy_string(), ast_format_cache_get, ast_format_slin, ast_log, ast_set2_flag, ast_set_flag, ast_strdup, ast_strlen_zero, ast_true(), AST_VECTOR_APPEND, AST_VECTOR_COMPACT, mohclass::digit, mohclass::dir, mohclass::files, mohclass::format, mohclass::kill_delay, mohclass::kill_method, KILL_METHOD_PROCESS, KILL_METHOD_PROCESS_GROUP, LOG_ERROR, LOG_WARNING, mohclass::mode, MOH_ANNOUNCEMENT, MOH_RANDOMIZE, MOH_RANDSTART, MOH_SORTALPHA, ast_variable::name, mohclass::name, ast_variable::next, ast_variable::value, and var.

Referenced by load_moh_classes(), and local_ast_moh_start().

1078 {
1079  for (; var; var = var->next) {
1080  if (!strcasecmp(var->name, "name")) {
1081  ast_copy_string(mohclass->name, var->value, sizeof(mohclass->name));
1082  } else if (!strcasecmp(var->name, "mode")) {
1083  ast_copy_string(mohclass->mode, var->value, sizeof(mohclass->mode));
1084  } else if (!strcasecmp(var->name, "entry")) {
1085  if (ast_begins_with(var->value, "/") || ast_begins_with(var->value, "http://") || ast_begins_with(var->value, "https://")) {
1086  char *dup = ast_strdup(var->value);
1087  if (!dup) {
1088  continue;
1089  }
1090 
1091  if (ast_begins_with(dup, "/")) {
1092  char *last_pos_dot = strrchr(dup, '.');
1093  char *last_pos_slash = strrchr(dup, '/');
1094  if (last_pos_dot && last_pos_dot > last_pos_slash) {
1095  ast_log(LOG_WARNING, "The playlist entry '%s' may include an extension, which could prevent it from playing.\n",
1096  dup);
1097  }
1098  }
1099  AST_VECTOR_APPEND(&mohclass->files, dup);
1100  } else {
1101  ast_log(LOG_ERROR, "Playlist entries must be a URL or absolute path, '%s' provided.\n", var->value);
1102  }
1103  } else if (!strcasecmp(var->name, "directory")) {
1104  ast_copy_string(mohclass->dir, var->value, sizeof(mohclass->dir));
1105  } else if (!strcasecmp(var->name, "application")) {
1106  ast_copy_string(mohclass->args, var->value, sizeof(mohclass->args));
1107  } else if (!strcasecmp(var->name, "announcement")) {
1108  ast_copy_string(mohclass->announcement, var->value, sizeof(mohclass->announcement));
1109  ast_set_flag(mohclass, MOH_ANNOUNCEMENT);
1110  } else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value))) {
1111  mohclass->digit = *var->value;
1112  } else if (!strcasecmp(var->name, "random")) {
1113  static int deprecation_warning = 0;
1114  if (!deprecation_warning) {
1115  ast_log(LOG_WARNING, "Music on hold 'random' setting is deprecated in 14. Please use 'sort=random' instead.\n");
1116  deprecation_warning = 1;
1117  }
1118  ast_set2_flag(mohclass, ast_true(var->value), MOH_RANDOMIZE);
1119  } else if (!strcasecmp(var->name, "sort")) {
1120  if (!strcasecmp(var->value, "random")) {
1121  ast_set_flag(mohclass, MOH_RANDOMIZE);
1122  } else if (!strcasecmp(var->value, "alpha")) {
1123  ast_set_flag(mohclass, MOH_SORTALPHA);
1124  } else if (!strcasecmp(var->value, "randstart")) {
1125  ast_set_flag(mohclass, MOH_RANDSTART);
1126  }
1127  } else if (!strcasecmp(var->name, "format") && !ast_strlen_zero(var->value)) {
1128  ao2_cleanup(mohclass->format);
1129  mohclass->format = ast_format_cache_get(var->value);
1130  if (!mohclass->format) {
1131  ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
1132  mohclass->format = ao2_bump(ast_format_slin);
1133  }
1134  } else if (!strcasecmp(var->name, "kill_escalation_delay")) {
1135  if (sscanf(var->value, "%zu", &mohclass->kill_delay) == 1) {
1136  mohclass->kill_delay *= 1000;
1137  } else {
1138  ast_log(LOG_WARNING, "kill_escalation_delay '%s' is invalid. Setting to 100ms\n", var->value);
1139  mohclass->kill_delay = 100000;
1140  }
1141  } else if (!strcasecmp(var->name, "kill_method")) {
1142  if (!strcasecmp(var->value, "process")) {
1143  mohclass->kill_method = KILL_METHOD_PROCESS;
1144  } else if (!strcasecmp(var->value, "process_group")) {
1146  } else {
1147  ast_log(LOG_WARNING, "kill_method '%s' is invalid. Setting to 'process_group'\n", var->value);
1149  }
1150  }
1151  }
1152 
1153  AST_VECTOR_COMPACT(&mohclass->files);
1154 }
struct ast_variable * next
char name[MAX_MUSICCLASS]
char announcement[256]
#define ast_set2_flag(p, value, flag)
Definition: utils.h:94
#define ast_set_flag(p, flag)
Definition: utils.h:70
#define LOG_WARNING
Definition: logger.h:274
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define var
Definition: ast_expr2f.c:614
#define AST_VECTOR_COMPACT(vec)
Resize a vector so that its capacity is the same as its size.
Definition: vector.h:640
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
#define MOH_RANDSTART
struct ast_vector_string files
#define ast_format_cache_get(name)
Definition: format_cache.h:286
char dir[256]
#define ao2_bump(obj)
Definition: astobj2.h:491
#define ast_log
Definition: astobj2.c:42
#define MOH_SORTALPHA
#define LOG_ERROR
Definition: logger.h:285
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1821
#define MOH_ANNOUNCEMENT
#define ast_strlen_zero(a)
Definition: muted.c:73
struct ast_format * format
enum kill_methods kill_method
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
char args[256]
size_t kill_delay
static int force_inline attribute_pure ast_begins_with(const char *str, const char *prefix)
Definition: strings.h:94
char mode[80]
struct ast_format * ast_format_slin
Built-in cached signed linear 8kHz format.
Definition: format_cache.c:41
#define MOH_RANDOMIZE

◆ moh_post_start()

static void moh_post_start ( struct ast_channel chan,
const char *  moh_class_name 
)
static

Definition at line 239 of file res_musiconhold.c.

References ao2_cleanup, ast_assert, ast_channel_blob_create_from_cache(), ast_channel_moh_start_type(), ast_channel_name(), ast_channel_topic(), ast_channel_uniqueid(), ast_json_pack(), ast_json_unref(), ast_verb, NULL, stasis_message_data(), and stasis_publish().

Referenced by moh_alloc(), and moh_files_alloc().

240 {
241  struct stasis_message *message;
242  struct ast_json *json_object;
243 
244  ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n",
245  moh_class_name, ast_channel_name(chan));
246 
247  json_object = ast_json_pack("{s: s}", "class", moh_class_name);
248  if (!json_object) {
249  return;
250  }
251 
253  ast_channel_moh_start_type(), json_object);
254  if (message) {
255  /* A channel snapshot must have been in the cache. */
256  ast_assert(((struct ast_channel_blob *) stasis_message_data(message))->snapshot != NULL);
257 
258  stasis_publish(ast_channel_topic(chan), message);
259  }
260  ao2_cleanup(message);
261  ast_json_unref(json_object);
262 }
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
Definition: json.c:591
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
Definition: json.c:73
struct stasis_message_type * ast_channel_moh_start_type(void)
Message type for starting music on hold on a channel.
#define ast_assert(a)
Definition: utils.h:650
#define NULL
Definition: resample.c:96
#define ast_verb(level,...)
Definition: logger.h:455
Blob of data associated with a channel.
const char * ast_channel_uniqueid(const struct ast_channel *chan)
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1507
struct stasis_message * ast_channel_blob_create_from_cache(const char *uniqueid, struct stasis_message_type *type, struct ast_json *blob)
Create a ast_channel_blob message, pulling channel state from the cache.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
const char * ast_channel_name(const struct ast_channel *chan)
Abstract JSON element (object, array, string, int, ...).

◆ moh_post_stop()

static void moh_post_stop ( struct ast_channel chan)
static

Definition at line 264 of file res_musiconhold.c.

References ao2_cleanup, ast_assert, ast_channel_blob_create_from_cache(), ast_channel_moh_stop_type(), ast_channel_name(), ast_channel_topic(), ast_channel_uniqueid(), ast_verb, NULL, stasis_message_data(), and stasis_publish().

Referenced by moh_files_release(), and moh_release().

265 {
266  struct stasis_message *message;
267 
268  ast_verb(3, "Stopped music on hold on %s\n", ast_channel_name(chan));
269 
272  if (message) {
273  /* A channel snapshot must have been in the cache. */
274  ast_assert(((struct ast_channel_blob *) stasis_message_data(message))->snapshot != NULL);
275 
276  stasis_publish(ast_channel_topic(chan), message);
277  }
278  ao2_cleanup(message);
279 }
#define ast_assert(a)
Definition: utils.h:650
#define NULL
Definition: resample.c:96
#define ast_verb(level,...)
Definition: logger.h:455
Blob of data associated with a channel.
const char * ast_channel_uniqueid(const struct ast_channel *chan)
struct stasis_topic * ast_channel_topic(struct ast_channel *chan)
A topic which publishes the events for a particular channel.
void * stasis_message_data(const struct stasis_message *msg)
Get the data contained in a message.
void stasis_publish(struct stasis_topic *topic, struct stasis_message *message)
Publish a message to a topic&#39;s subscribers.
Definition: stasis.c:1507
struct stasis_message * ast_channel_blob_create_from_cache(const char *uniqueid, struct stasis_message_type *type, struct ast_json *blob)
Create a ast_channel_blob message, pulling channel state from the cache.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
const char * ast_channel_name(const struct ast_channel *chan)
struct stasis_message_type * ast_channel_moh_stop_type(void)
Message type for stopping music on hold on a channel.

◆ moh_release()

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

Definition at line 966 of file res_musiconhold.c.

References ao2_cleanup, ao2_lock, ao2_unlock, ast_channel_music_state(), ast_channel_name(), ast_format_get_name(), ast_free, AST_LIST_REMOVE, ast_log, ast_set_write_format(), moh_files_state::class, LOG_WARNING, mohclass::members, moh_post_stop(), mohclass_unref, mohdata::origwfmt, mohdata::parent, mohdata::pipe, and state.

Referenced by moh_alloc().

967 {
968  struct mohdata *moh = data;
969  struct mohclass *class = moh->parent;
970  struct ast_format *oldwfmt;
971 
972  ao2_lock(class);
973  AST_LIST_REMOVE(&moh->parent->members, moh, list);
974  ao2_unlock(class);
975 
976  close(moh->pipe[0]);
977  close(moh->pipe[1]);
978 
979  oldwfmt = moh->origwfmt;
980 
981  moh->parent = class = mohclass_unref(class, "unreffing moh->parent upon deactivation of generator");
982 
983  ast_free(moh);
984 
985  if (chan) {
986  struct moh_files_state *state;
987 
988  state = ast_channel_music_state(chan);
989  if (state && state->class) {
990  state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator");
991  }
992  if (oldwfmt && ast_set_write_format(chan, oldwfmt)) {
993  ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n",
994  ast_channel_name(chan), ast_format_get_name(oldwfmt));
995  }
996 
997  moh_post_stop(chan);
998  }
999 
1000  ao2_cleanup(oldwfmt);
1001 }
enum sip_cc_notify_state state
Definition: chan_sip.c:956
static void moh_post_stop(struct ast_channel *chan)
#define LOG_WARNING
Definition: logger.h:274
struct mohclass * class
Definition of a media format.
Definition: format.c:43
#define ao2_unlock(a)
Definition: astobj2.h:730
const char * ast_format_get_name(const struct ast_format *format)
Get the name associated with a format.
Definition: format.c:334
struct mohclass::@454 members
#define AST_LIST_REMOVE(head, elm, field)
Removes a specific entry from a list.
Definition: linkedlists.h:855
#define ast_log
Definition: astobj2.c:42
#define ao2_lock(a)
Definition: astobj2.h:718
int ast_set_write_format(struct ast_channel *chan, struct ast_format *format)
Sets write format on channel chan.
Definition: channel.c:5765
static struct ast_generator generator
Definition: app_fax.c:359
int pipe[2]
#define ast_free(a)
Definition: astmm.h:182
struct ast_format * origwfmt
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
const char * ast_channel_name(const struct ast_channel *chan)
void * ast_channel_music_state(const struct ast_channel *chan)
#define mohclass_unref(class, string)
struct mohclass * parent

◆ moh_rescan_files()

static void moh_rescan_files ( void  )
static

Definition at line 1254 of file res_musiconhold.c.

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

Referenced by load_moh_classes().

1254  {
1255  struct ao2_iterator i;
1256  struct mohclass *c;
1257 
1258  i = ao2_iterator_init(mohclasses, 0);
1259 
1260  while ((c = ao2_iterator_next(&i))) {
1261  if (!strcasecmp(c->mode, "files")) {
1262  moh_scan_files(c);
1263  }
1264  ao2_ref(c, -1);
1265  }
1266 
1268 }
static struct ao2_container * mohclasses
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
static struct test_val c
static int moh_scan_files(struct mohclass *class)
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_iterator_next(iter)
Definition: astobj2.h:1933
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1841
char mode[80]
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.

◆ moh_scan_files()

static int moh_scan_files ( struct mohclass class)
static

Definition at line 1156 of file res_musiconhold.c.

References ast_config_AST_DATA_DIR, ast_copy_string(), ast_debug, ast_free, ast_log, ast_strdup, ast_test_flag, AST_VECTOR_ADD_SORTED, AST_VECTOR_APPEND, AST_VECTOR_COMPACT, AST_VECTOR_GET_CMP, AST_VECTOR_RESET, AST_VECTOR_SIZE, moh_files_state::class, mohclass::dir, ext, mohclass::files, LOG_WARNING, MOH_SORTALPHA, mohclass::name, and PATH_MAX.

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

1156  {
1157 
1158  DIR *files_DIR;
1159  struct dirent *files_dirent;
1160  char dir_path[PATH_MAX - sizeof(class->dir)];
1161  char filepath[PATH_MAX];
1162  char *ext;
1163  struct stat statbuf;
1164  int res;
1165 
1166  if (class->dir[0] != '/') {
1167  snprintf(dir_path, sizeof(dir_path), "%s/%s", ast_config_AST_DATA_DIR, class->dir);
1168  } else {
1169  ast_copy_string(dir_path, class->dir, sizeof(dir_path));
1170  }
1171  ast_debug(4, "Scanning '%s' for files for class '%s'\n", dir_path, class->name);
1172  files_DIR = opendir(dir_path);
1173  if (!files_DIR) {
1174  ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", dir_path);
1175  return -1;
1176  }
1177 
1178  AST_VECTOR_RESET(&class->files, ast_free);
1179 
1180  while ((files_dirent = readdir(files_DIR))) {
1181  char *filepath_copy;
1182 
1183  /* The file name must be at least long enough to have the file type extension */
1184  if ((strlen(files_dirent->d_name) < 4))
1185  continue;
1186 
1187  /* Skip files that starts with a dot */
1188  if (files_dirent->d_name[0] == '.')
1189  continue;
1190 
1191  /* Skip files without extensions... they are not audio */
1192  if (!strchr(files_dirent->d_name, '.'))
1193  continue;
1194 
1195  snprintf(filepath, sizeof(filepath), "%s/%s", dir_path, files_dirent->d_name);
1196 
1197  if (stat(filepath, &statbuf))
1198  continue;
1199 
1200  if (!S_ISREG(statbuf.st_mode))
1201  continue;
1202 
1203  if ((ext = strrchr(filepath, '.')))
1204  *ext = '\0';
1205 
1206  /* if the file is present in multiple formats, ensure we only put it into the list once */
1207  if (AST_VECTOR_GET_CMP(&class->files, &filepath[0], !strcmp)) {
1208  continue;
1209  }
1210 
1211  filepath_copy = ast_strdup(filepath);
1212  if (!filepath_copy) {
1213  break;
1214  }
1215 
1216  if (ast_test_flag(class, MOH_SORTALPHA)) {
1217  res = AST_VECTOR_ADD_SORTED(&class->files, filepath_copy, strcasecmp);
1218  } else {
1219  res = AST_VECTOR_APPEND(&class->files, filepath_copy);
1220  }
1221 
1222  if (res) {
1223  ast_free(filepath_copy);
1224  break;
1225  }
1226  }
1227 
1228  closedir(files_DIR);
1229 
1230  AST_VECTOR_COMPACT(&class->files);
1231 
1232  return AST_VECTOR_SIZE(&class->files);
1233 }
char name[MAX_MUSICCLASS]
#define AST_VECTOR_ADD_SORTED(vec, elem, cmp)
Add an element into a sorted vector.
Definition: vector.h:371
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define LOG_WARNING
Definition: logger.h:274
#define AST_VECTOR_APPEND(vec, elem)
Append an element to a vector, growing the vector if needed.
Definition: vector.h:256
#define AST_VECTOR_COMPACT(vec)
Resize a vector so that its capacity is the same as its size.
Definition: vector.h:640
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
const char * ext
Definition: http.c:147
struct ast_vector_string files
char dir[256]
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
#define MOH_SORTALPHA
const char * ast_config_AST_DATA_DIR
Definition: options.c:155
#define ast_free(a)
Definition: astmm.h:182
#define AST_VECTOR_RESET(vec, cleanup)
Reset vector.
Definition: vector.h:627
#define AST_VECTOR_GET_CMP(vec, value, cmp)
Get an element from a vector that matches the given comparison.
Definition: vector.h:729
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
#define PATH_MAX
Definition: asterisk.h:40
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ mohalloc()

static struct mohdata* mohalloc ( struct mohclass cl)
static

Definition at line 940 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_pipe_nonblock, errno, mohdata::f, ast_frame_subclass::format, mohclass::format, ast_frame::frametype, mohdata::list, LOG_WARNING, mohclass::members, mohclass_ref, NULL, ast_frame::offset, mohdata::parent, mohdata::pipe, and ast_frame::subclass.

Referenced by moh_alloc().

941 {
942  struct mohdata *moh;
943 
944  if (!(moh = ast_calloc(1, sizeof(*moh))))
945  return NULL;
946 
947  if (ast_pipe_nonblock(moh->pipe)) {
948  ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
949  ast_free(moh);
950  return NULL;
951  }
952 
953  moh->f.frametype = AST_FRAME_VOICE;
954  moh->f.subclass.format = cl->format;
956 
957  moh->parent = mohclass_ref(cl, "Reffing music class for mohdata parent");
958 
959  ao2_lock(cl);
960  AST_LIST_INSERT_HEAD(&cl->members, moh, list);
961  ao2_unlock(cl);
962 
963  return moh;
964 }
#define ast_pipe_nonblock(filedes)
Create a non-blocking pipe.
Definition: utils.h:1000
#define LOG_WARNING
Definition: logger.h:274
#define ao2_unlock(a)
Definition: astobj2.h:730
#define NULL
Definition: resample.c:96
struct mohclass::@454 members
#define mohclass_ref(class, string)
struct ast_frame_subclass subclass
#define ast_log
Definition: astobj2.c:42
#define AST_FRIENDLY_OFFSET
Offset into a frame&#39;s data buffer.
#define ao2_lock(a)
Definition: astobj2.h:718
int pipe[2]
int errno
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
Definition: linkedlists.h:710
#define ast_free(a)
Definition: astmm.h:182
#define ast_calloc(num, len)
A wrapper for calloc()
Definition: astmm.h:204
struct ast_format * format
struct ast_frame f
struct mohdata::@456 list
enum ast_frame_type frametype
struct ast_format * format
struct mohclass * parent

◆ monmp3thread()

static void* monmp3thread ( void *  data)
static

Definition at line 755 of file res_musiconhold.c.

References ao2_lock, ao2_unlock, ast_debug, ast_format_determine_length(), ast_format_get_sample_rate(), 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(), moh_files_state::class, mohclass::dir, errno, mohclass::format, mohclass::kill_delay, mohclass::kill_method, killpid(), len(), LOG_ERROR, LOG_NOTICE, LOG_WARNING, mohclass::members, MOH_MS_INTERVAL, NULL, mohclass::pid, mohdata::pipe, spawn_mp3(), mohclass::srcfd, and mohclass::timer.

Referenced by init_app_class(), and local_ast_moh_start().

756 {
757 #define MOH_MS_INTERVAL 100
758 
759  struct mohclass *class = data;
760  struct mohdata *moh;
761  short sbuf[8192];
762  int res = 0, res2;
763  int len;
764  struct timeval deadline, tv_tmp;
765 
766  deadline.tv_sec = 0;
767  deadline.tv_usec = 0;
768  for(;/* ever */;) {
769  pthread_testcancel();
770  /* Spawn mp3 player if it's not there */
771  if (class->srcfd < 0) {
772  if ((class->srcfd = spawn_mp3(class)) < 0) {
773  ast_log(LOG_WARNING, "Unable to spawn mp3player\n");
774  /* Try again later */
775  sleep(500);
776  continue;
777  }
778  }
779  if (class->timer) {
780  struct pollfd pfd = { .fd = ast_timer_fd(class->timer), .events = POLLIN | POLLPRI, };
781 
782 #ifdef SOLARIS
783  thr_yield();
784 #endif
785  /* Pause some amount of time */
786  if (ast_poll(&pfd, 1, -1) > 0) {
787  if (ast_timer_ack(class->timer, 1) < 0) {
788  ast_log(LOG_ERROR, "Failed to acknowledge timer for mp3player\n");
789  return NULL;
790  }
791  /* 25 samples per second => 40ms framerate => 320 samples */
792  res = 320; /* 320/40 = 8 samples/ms */
793  } else {
794  ast_log(LOG_WARNING, "poll() failed: %s\n", strerror(errno));
795  res = 0;
796  }
797  pthread_testcancel();
798  } else {
799  long delta;
800  /* Reliable sleep */
801  tv_tmp = ast_tvnow();
802  if (ast_tvzero(deadline))
803  deadline = tv_tmp;
804  delta = ast_tvdiff_ms(tv_tmp, deadline);
805  if (delta < MOH_MS_INTERVAL) { /* too early */
806  deadline = ast_tvadd(deadline, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */
807  usleep(1000 * (MOH_MS_INTERVAL - delta));
808  pthread_testcancel();
809  } else {
810  ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
811  deadline = tv_tmp;
812  }
813  /* 10 samples per second (MOH_MS_INTERVAL) => 100ms framerate => 800 samples */
814  res = 8 * MOH_MS_INTERVAL; /* 800/100 = 8 samples/ms */
815  }
816  /* For non-8000Hz formats, we need to alter the resolution */
817  res = res * ast_format_get_sample_rate(class->format) / 8000;
818 
819  if ((strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir")) && AST_LIST_EMPTY(&class->members))
820  continue;
821  /* Read mp3 audio */
822  len = ast_format_determine_length(class->format, res);
823 
824  if ((res2 = read(class->srcfd, sbuf, len)) != len) {
825  if (!res2) {
826  close(class->srcfd);
827  class->srcfd = -1;
828  pthread_testcancel();
829  if (class->pid > 1) {
830  killpid(class->pid, class->kill_delay, class->kill_method);
831  class->pid = 0;
832  }
833  } else {
834  ast_debug(1, "Read %d bytes of audio while expecting %d\n", res2, len);
835  }
836  continue;
837  }
838 
839  pthread_testcancel();
840 
841  ao2_lock(class);
842  AST_LIST_TRAVERSE(&class->members, moh, list) {
843  /* Write data */
844  if ((res = write(moh->pipe[1], sbuf, res2)) != res2) {
845  ast_debug(1, "Only wrote %d of %d bytes to pipe\n", res, res2);
846  }
847  }
848  ao2_unlock(class);
849  }
850  return NULL;
851 }
#define LOG_WARNING
Definition: logger.h:274
int ast_tvzero(const struct timeval t)
Returns true if the argument is 0,0.
Definition: time.h:108
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Definition: time.h:150
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
#define ao2_unlock(a)
Definition: astobj2.h:730
int64_t ast_tvdiff_ms(struct timeval end, struct timeval start)
Computes the difference (in milliseconds) between two struct timeval instances.
Definition: time.h:98
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:444
#define ast_log
Definition: astobj2.c:42
#define ast_poll(a, b, c)
Definition: poll-compat.h:88
static void killpid(int pid, size_t delay, enum kill_methods kill_method)
#define ao2_lock(a)
Definition: astobj2.h:718
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:238
#define MOH_MS_INTERVAL
int ast_timer_ack(const struct ast_timer *handle, unsigned int quantity)
Acknowledge a timer event.
Definition: timing.c:171
#define LOG_ERROR
Definition: logger.h:285
unsigned int ast_format_determine_length(const struct ast_format *format, unsigned int samples)
Get the length (in milliseconds) for the format with a given number of samples.
Definition: format.c:384
int pipe[2]
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
int errno
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
Definition: extconf.c:2283
#define LOG_NOTICE
Definition: logger.h:263
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:490
int ast_timer_fd(const struct ast_timer *handle)
Get a poll()-able file descriptor for a timer.
Definition: timing.c:161
unsigned int ast_format_get_sample_rate(const struct ast_format *format)
Get the sample rate of a media format.
Definition: format.c:379
static int spawn_mp3(struct mohclass *class)

◆ play_moh_exec()

static int play_moh_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 853 of file res_musiconhold.c.

References args, AST_APP_ARG, ast_channel_name(), 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, parse(), S_OR, and timeout.

Referenced by load_module().

854 {
855  char *parse;
856  char *class;
857  int timeout = -1;
858  int res;
860  AST_APP_ARG(class);
861  AST_APP_ARG(duration);
862  );
863 
864  parse = ast_strdupa(data);
865 
866  AST_STANDARD_APP_ARGS(args, parse);
867 
868  if (!ast_strlen_zero(args.duration)) {
869  if (sscanf(args.duration, "%30d", &timeout) == 1) {
870  timeout *= 1000;
871  } else {
872  ast_log(LOG_WARNING, "Invalid MusicOnHold duration '%s'. Will wait indefinitely.\n", args.duration);
873  }
874  }
875 
876  class = S_OR(args.class, NULL);
877  if (ast_moh_start(chan, class, NULL)) {
878  ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, ast_channel_name(chan));
879  return 0;
880  }
881 
882  if (timeout > 0)
883  res = ast_safe_sleep(chan, timeout);
884  else {
885  while (!(res = ast_safe_sleep(chan, 10000)));
886  }
887 
888  ast_moh_stop(chan);
889 
890  return res;
891 }
int ast_safe_sleep(struct ast_channel *chan, int ms)
Wait for a specified amount of time, looking for hangups.
Definition: channel.c:1554
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
static int timeout
Definition: cdr_mysql.c:86
const char * args
#define NULL
Definition: resample.c:96
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7715
#define ast_log
Definition: astobj2.c:42
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
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:7705
#define ast_strlen_zero(a)
Definition: muted.c:73
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const char * ast_channel_name(const struct ast_channel *chan)
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ reload()

static int reload ( void  )
static

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

2117 {
2118  if (load_moh_classes(1)) {
2121  }
2122 
2123  return AST_MODULE_LOAD_SUCCESS;
2124 }
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:7689

◆ spawn_mp3()

static int spawn_mp3 ( struct mohclass class)
static

Definition at line 569 of file res_musiconhold.c.

References mohclass::args, 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, moh_files_state::class, mohclass::dir, errno, LOCAL_MPG_123, LOG_WARNING, MAX_MP3S, MOH_CUSTOM, MOH_QUIET, MOH_SINGLE, MPG_123, NULL, mohclass::pid, respawn_time, mohclass::start, and strsep().

Referenced by monmp3thread().

570 {
571  int fds[2];
572  int files = 0;
573  char fns[MAX_MP3S][80];
574  char *argv[MAX_MP3S + 50];
575  char xargs[256];
576  char *argptr;
577  int argc = 0;
578  DIR *dir = NULL;
579  struct dirent *de;
580 
581 
582  if (!strcasecmp(class->dir, "nodir")) {
583  files = 1;
584  } else {
585  dir = opendir(class->dir);
586  if (!dir && strncasecmp(class->dir, "http://", 7)) {
587  ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
588  return -1;
589  }
590  }
591 
592  if (!ast_test_flag(class, MOH_CUSTOM)) {
593  argv[argc++] = "mpg123";
594  argv[argc++] = "-q";
595  argv[argc++] = "-s";
596  argv[argc++] = "--mono";
597  argv[argc++] = "-r";
598  argv[argc++] = "8000";
599 
600  if (!ast_test_flag(class, MOH_SINGLE)) {
601  argv[argc++] = "-b";
602  argv[argc++] = "2048";
603  }
604 
605  argv[argc++] = "-f";
606 
607  if (ast_test_flag(class, MOH_QUIET))
608  argv[argc++] = "4096";
609  else
610  argv[argc++] = "8192";
611 
612  /* Look for extra arguments and add them to the list */
613  ast_copy_string(xargs, class->args, sizeof(xargs));
614  argptr = xargs;
615  while (!ast_strlen_zero(argptr)) {
616  argv[argc++] = argptr;
617  strsep(&argptr, ",");
618  }
619  } else {
620  /* Format arguments for argv vector */
621  ast_copy_string(xargs, class->args, sizeof(xargs));
622  argptr = xargs;
623  while (!ast_strlen_zero(argptr)) {
624  argv[argc++] = argptr;
625  strsep(&argptr, " ");
626  }
627  }
628 
629  if (!strncasecmp(class->dir, "http://", 7)) {
630  ast_copy_string(fns[files], class->dir, sizeof(fns[files]));
631  argv[argc++] = fns[files];
632  files++;
633  } else if (dir) {
634  while ((de = readdir(dir)) && (files < MAX_MP3S)) {
635  if ((strlen(de->d_name) > 3) &&
636  ((ast_test_flag(class, MOH_CUSTOM) &&
637  (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") ||
638  !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) ||
639  !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
640  ast_copy_string(fns[files], de->d_name, sizeof(fns[files]));
641  argv[argc++] = fns[files];
642  files++;
643  }
644  }
645  }
646  argv[argc] = NULL;
647  if (dir) {
648  closedir(dir);
649  }
650  if (pipe(fds)) {
651  ast_log(LOG_WARNING, "Pipe failed\n");
652  return -1;
653  }
654  if (!files) {
655  ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
656  close(fds[0]);
657  close(fds[1]);
658  return -1;
659  }
660  if (!strncasecmp(class->dir, "http://", 7) && time(NULL) - class->start < respawn_time) {
661  sleep(respawn_time - (time(NULL) - class->start));
662  }
663 
664  time(&class->start);
665  class->pid = ast_safe_fork(0);
666  if (class->pid < 0) {
667  close(fds[0]);
668  close(fds[1]);
669  ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
670  return -1;
671  }
672  if (!class->pid) {
674  ast_set_priority(0);
675 
676  close(fds[0]);
677  /* Stdout goes to pipe */
678  dup2(fds[1], STDOUT_FILENO);
679 
680  /* Close everything else */
681  ast_close_fds_above_n(STDERR_FILENO);
682 
683  /* Child */
684  if (strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir") && chdir(class->dir) < 0) {
685  ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
686  _exit(1);
687  }
688  setpgid(0, getpid());
689  if (ast_test_flag(class, MOH_CUSTOM)) {
690  execv(argv[0], argv);
691  } else {
692  /* Default install is /usr/local/bin */
693  execv(LOCAL_MPG_123, argv);
694  /* Many places have it in /usr/bin */
695  execv(MPG_123, argv);
696  /* Check PATH as a last-ditch effort */
697  execvp("mpg123", argv);
698  }
699  /* Can't use logger, since log FDs are closed */
700  fprintf(stderr, "MOH: exec failed: %s\n", strerror(errno));
701  close(fds[1]);
702  _exit(1);
703  } else {
704  /* Parent */
705  close(fds[1]);
706  }
707  return fds[0];
708 }
#define ast_test_flag(p, flag)
Definition: utils.h:63
#define LOG_WARNING
Definition: logger.h:274
void ast_close_fds_above_n(int n)
Common routine for child processes, to close all fds prior to exec(2)
Definition: main/app.c:2965
#define MPG_123
#define NULL
Definition: resample.c:96
char dir[256]
#define ast_log
Definition: astobj2.c:42
#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:1799
#define MAX_MP3S
int errno
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: main/app.c:2970
#define ast_strlen_zero(a)
Definition: muted.c:73
time_t start
static int respawn_time
#define MOH_CUSTOM
char * strsep(char **str, const char *delims)
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:401
char args[256]
#define MOH_SINGLE
#define ast_opt_high_priority
Definition: options.h:110
#define LOCAL_MPG_123

◆ start_moh_exec()

static int start_moh_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 893 of file res_musiconhold.c.

References args, AST_APP_ARG, ast_channel_name(), AST_DECLARE_APP_ARGS, ast_log, ast_moh_start(), AST_STANDARD_APP_ARGS, ast_strdupa, LOG_WARNING, parse(), and S_OR.

Referenced by load_module().

894 {
895  char *parse;
896  char *class;
898  AST_APP_ARG(class);
899  );
900 
901  parse = ast_strdupa(data);
902 
903  AST_STANDARD_APP_ARGS(args, parse);
904 
905  class = S_OR(args.class, NULL);
906  if (ast_moh_start(chan, class, NULL))
907  ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, ast_channel_name(chan));
908 
909  return 0;
910 }
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
const char * args
#define NULL
Definition: resample.c:96
#define ast_log
Definition: astobj2.c:42
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
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:7705
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
Definition: strings.h:79
const char * ast_channel_name(const struct ast_channel *chan)
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define AST_APP_ARG(name)
Define an application argument.

◆ stop_moh_exec()

static int stop_moh_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 912 of file res_musiconhold.c.

References ast_moh_stop().

Referenced by load_module().

913 {
914  ast_moh_stop(chan);
915 
916  return 0;
917 }
void ast_moh_stop(struct ast_channel *chan)
Turn off music on hold on a given channel.
Definition: channel.c:7715

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 2133 of file res_musiconhold.c.

References ao2_t_callback, ARRAY_LEN, ast_cli_unregister_multiple(), ast_log, AST_MODFLAG_LOAD_ORDER, AST_MODPRI_CHANNEL_DEPEND, AST_MODULE_INFO(), AST_MODULE_SUPPORT_CORE, ast_moh_destroy(), ast_uninstall_music_functions(), ast_unregister_application(), ast_unregister_atexit(), ASTERISK_GPL_KEY, load_module(), LOG_WARNING, moh_class_inuse(), mohclass_unref, NULL, play_moh, reload(), start_moh, and stop_moh.

2134 {
2135  int res = 0;
2136  struct mohclass *class = NULL;
2137 
2138  /* XXX This check shouldn't be required if module ref counting was being used
2139  * properly ... */
2140  if ((class = ao2_t_callback(mohclasses, 0, moh_class_inuse, NULL, "Module unload callback"))) {
2141  class = mohclass_unref(class, "unref of class from module unload callback");
2142  res = -1;
2143  }
2144 
2145  if (res < 0) {
2146  ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n");
2147  return res;
2148  }
2149 
2151 
2152  ast_moh_destroy();
2158 
2159  return res;
2160 }
static struct ao2_container * mohclasses
#define ARRAY_LEN(a)
Definition: isdn_lib.c:42
static const char stop_moh[]
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define LOG_WARNING
Definition: logger.h:274
static struct ast_cli_entry cli_moh[]
#define NULL
Definition: resample.c:96
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx_app.c:392
static void ast_moh_destroy(void)
void ast_uninstall_music_functions(void)
Definition: channel.c:7698
#define ast_log
Definition: astobj2.c:42
void ast_unregister_atexit(void(*func)(void))
Unregister a function registered with ast_register_atexit().
Definition: asterisk.c:1022
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:1714
#define mohclass_unref(class, string)
static const char play_moh[]

Variable Documentation

◆ __mod_info

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 = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload, .load_pri = AST_MODPRI_CHANNEL_DEPEND, }
static

Definition at line 2168 of file res_musiconhold.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 2168 of file res_musiconhold.c.

◆ cli_moh

struct ast_cli_entry cli_moh[]
static

Definition at line 2054 of file res_musiconhold.c.

◆ global_flags

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

global MOH_ flags

Definition at line 160 of file res_musiconhold.c.

◆ moh_file_stream

struct ast_generator moh_file_stream
static

Definition at line 561 of file res_musiconhold.c.

◆ mohclasses

struct ao2_container* mohclasses
static

Definition at line 206 of file res_musiconhold.c.

◆ mohgen

struct ast_generator mohgen
static

Definition at line 1070 of file res_musiconhold.c.

◆ play_moh

const char play_moh[] = "MusicOnHold"
static

Definition at line 123 of file res_musiconhold.c.

Referenced by load_module(), and unload_module().

◆ respawn_time

int respawn_time = 20
static

Definition at line 127 of file res_musiconhold.c.

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

◆ start_moh

const char start_moh[] = "StartMusicOnHold"
static

Definition at line 124 of file res_musiconhold.c.

Referenced by load_module(), and unload_module().

◆ stop_moh

const char stop_moh[] = "StopMusicOnHold"
static

Definition at line 125 of file res_musiconhold.c.

Referenced by load_module(), and unload_module().