2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2010, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Routines implementing music on hold
23 * \author Mark Spencer <markster@digium.com>
26 /*! \li \ref res_musiconhold.c uses the configuration file \ref musiconhold.conf
27 * \addtogroup configuration_file Configuration Files
31 * \page musiconhold.conf musiconhold.conf
32 * \verbinclude musiconhold.conf.sample
36 <conflict>win32</conflict>
37 <support_level>core</support_level>
42 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
47 #include <sys/signal.h>
48 #include <netinet/in.h>
56 #include "asterisk/lock.h"
57 #include "asterisk/file.h"
58 #include "asterisk/channel.h"
59 #include "asterisk/pbx.h"
60 #include "asterisk/app.h"
61 #include "asterisk/module.h"
62 #include "asterisk/translate.h"
63 #include "asterisk/say.h"
64 #include "asterisk/musiconhold.h"
65 #include "asterisk/config.h"
66 #include "asterisk/utils.h"
67 #include "asterisk/cli.h"
68 #include "asterisk/stringfields.h"
69 #include "asterisk/linkedlists.h"
70 #include "asterisk/stasis.h"
71 #include "asterisk/stasis_channels.h"
72 #include "asterisk/paths.h"
73 #include "asterisk/astobj2.h"
74 #include "asterisk/timing.h"
75 #include "asterisk/time.h"
76 #include "asterisk/poll-compat.h"
78 #define INITIAL_NUM_FILES 8
83 <application name="MusicOnHold" language="en_US">
85 Play Music On Hold indefinitely.
88 <parameter name="class" required="true" />
89 <parameter name="duration" />
92 <para>Plays hold music specified by class. If omitted, the default music
93 source for the channel will be used. Change the default class with
94 Set(CHANNEL(musicclass)=...). If duration is given, hold music will be played
95 specified number of seconds. If duration is ommited, music plays indefinitely.
96 Returns <literal>0</literal> when done, <literal>-1</literal> on hangup.</para>
97 <para>This application does not automatically answer and should be preceeded by
98 an application such as Answer() or Progress().</para>
101 <application name="WaitMusicOnHold" language="en_US">
103 Wait, playing Music On Hold.
106 <parameter name="delay" required="true" />
109 <para> !!! DEPRECATED. Use MusicOnHold instead !!!</para>
110 <para>Plays hold music specified number of seconds. Returns <literal>0</literal> when done,
111 or <literal>-1</literal> on hangup. If no hold music is available, the delay will still occur
112 with no sound.</para>
113 <para> !!! DEPRECATED. Use MusicOnHold instead !!!</para>
116 <application name="SetMusicOnHold" language="en_US">
118 Set default Music On Hold class.
121 <parameter name="class" required="yes" />
124 <para>!!! DEPRECATED. USe Set(CHANNEL(musicclass)=...) instead !!!</para>
125 <para>Sets the default class for music on hold for a given channel.
126 When music on hold is activated, this class will be used to select which
127 music is played.</para>
128 <para>!!! DEPRECATED. USe Set(CHANNEL(musicclass)=...) instead !!!</para>
131 <application name="StartMusicOnHold" language="en_US">
136 <parameter name="class" required="true" />
139 <para>Starts playing music on hold, uses default music class for channel.
140 Starts playing music specified by class. If omitted, the default music
141 source for the channel will be used. Always returns <literal>0</literal>.</para>
144 <application name="StopMusicOnHold" language="en_US">
146 Stop playing Music On Hold.
150 <para>Stops playing music on hold.</para>
155 static const char play_moh[] = "MusicOnHold";
156 static const char wait_moh[] = "WaitMusicOnHold";
157 static const char set_moh[] = "SetMusicOnHold";
158 static const char start_moh[] = "StartMusicOnHold";
159 static const char stop_moh[] = "StopMusicOnHold";
161 static int respawn_time = 20;
163 struct moh_files_state {
164 /*! Holds a reference to the MOH class. */
165 struct mohclass *class;
166 char name[MAX_MUSICCLASS];
167 struct ast_format origwfmt;
168 struct ast_format mohwfmt;
175 char save_pos_filename[PATH_MAX];
178 #define MOH_QUIET (1 << 0)
179 #define MOH_SINGLE (1 << 1)
180 #define MOH_CUSTOM (1 << 2)
181 #define MOH_RANDOMIZE (1 << 3)
182 #define MOH_SORTALPHA (1 << 4)
184 #define MOH_CACHERTCLASSES (1 << 5) /*!< Should we use a separate instance of MOH for each user or not */
185 #define MOH_ANNOUNCEMENT (1 << 6) /*!< Do we play announcement files between songs on this channel? */
187 /* Custom astobj2 flag */
188 #define MOH_NOTDELETED (1 << 30) /*!< Find only records that aren't deleted? */
190 static struct ast_flags global_flags[1] = {{0}}; /*!< global MOH_ flags */
193 char name[MAX_MUSICCLASS];
196 char announcement[256];
199 /*! A dynamically sized array to hold the list of filenames in "files" mode */
201 /*! The current size of the filearray */
203 /*! The current number of files loaded into the filearray */
206 /*! The format from the MOH source, not applicable to "files" mode */
207 struct ast_format format;
208 /*! The pid of the external application delivering MOH */
212 /*! Source of audio */
215 struct ast_timer *timer;
216 /*! Created on the fly, from RT engine */
217 unsigned int realtime:1;
218 unsigned int delete:1;
219 AST_LIST_HEAD_NOLOCK(, mohdata) members;
220 AST_LIST_ENTRY(mohclass) list;
225 struct ast_format origwfmt;
226 struct mohclass *parent;
228 AST_LIST_ENTRY(mohdata) list;
231 static struct ao2_container *mohclasses;
233 #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
234 #define MPG_123 "/usr/bin/mpg123"
237 static int reload(void);
239 #define mohclass_ref(class,string) (ao2_t_ref((class), +1, (string)), class)
242 #define mohclass_unref(class,string) (ao2_t_ref((class), -1, (string)), (struct mohclass *) NULL)
244 #define mohclass_unref(class,string) _mohclass_unref(class, string, __FILE__,__LINE__,__PRETTY_FUNCTION__)
245 static struct mohclass *_mohclass_unref(struct mohclass *class, const char *tag, const char *file, int line, const char *funcname)
247 struct mohclass *dup;
248 if ((dup = ao2_find(mohclasses, class, OBJ_POINTER))) {
249 if (__ao2_ref_debug(dup, -1, (char *) tag, (char *) file, line, funcname) == 2) {
250 FILE *ref = fopen("/tmp/refs", "a");
252 fprintf(ref, "%p =1 %s:%d:%s (%s) BAD ATTEMPT!\n", class, file, line, funcname, tag);
255 ast_log(LOG_WARNING, "Attempt to unref mohclass %p (%s) when only 1 ref remained, and class is still in a container! (at %s:%d (%s))\n",
256 class, class->name, file, line, funcname);
261 ao2_t_ref(class, -1, (char *) tag);
267 static void moh_files_release(struct ast_channel *chan, void *data)
269 struct moh_files_state *state;
271 if (!chan || !ast_channel_music_state(chan)) {
275 state = ast_channel_music_state(chan);
277 if (ast_channel_stream(chan)) {
278 ast_closestream(ast_channel_stream(chan));
279 ast_channel_stream_set(chan, NULL);
282 ast_verb(3, "Stopped music on hold on %s\n", ast_channel_name(chan));
284 ast_format_clear(&state->mohwfmt); /* make sure to clear this format before restoring the original format. */
285 if (state->origwfmt.id && ast_set_write_format(chan, &state->origwfmt)) {
286 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%s'\n", ast_channel_name(chan), ast_getformatname(&state->origwfmt));
289 state->save_pos = state->pos;
290 state->announcement = 0;
292 state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator");
295 static int ast_moh_files_next(struct ast_channel *chan)
297 struct moh_files_state *state = ast_channel_music_state(chan);
300 /* Discontinue a stream if it is running already */
301 if (ast_channel_stream(chan)) {
302 ast_closestream(ast_channel_stream(chan));
303 ast_channel_stream_set(chan, NULL);
306 if (ast_test_flag(state->class, MOH_ANNOUNCEMENT) && state->announcement == 0) {
307 state->announcement = 1;
308 if (ast_openstream_full(chan, state->class->announcement, ast_channel_language(chan), 1)) {
309 ast_debug(1, "%s Opened announcement '%s'\n", ast_channel_name(chan), state->class->announcement);
313 state->announcement = 0;
316 if (!state->class->total_files) {
317 ast_log(LOG_WARNING, "No files available for class '%s'\n", state->class->name);
321 if (state->pos == 0 && ast_strlen_zero(state->save_pos_filename)) {
322 /* First time so lets play the file. */
323 state->save_pos = -1;
324 } else if (state->save_pos >= 0 && state->save_pos < state->class->total_files && !strcmp(state->class->filearray[state->save_pos], state->save_pos_filename)) {
325 /* If a specific file has been saved confirm it still exists and that it is still valid */
326 state->pos = state->save_pos;
327 state->save_pos = -1;
328 } else if (ast_test_flag(state->class, MOH_RANDOMIZE)) {
329 /* Get a random file and ensure we can open it */
330 for (tries = 0; tries < 20; tries++) {
331 state->pos = ast_random() % state->class->total_files;
332 if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0) {
336 state->save_pos = -1;
339 /* This is easy, just increment our position and make sure we don't exceed the total file count */
341 state->pos %= state->class->total_files;
342 state->save_pos = -1;
346 for (tries = 0; tries < state->class->total_files; ++tries) {
347 if (ast_openstream_full(chan, state->class->filearray[state->pos], ast_channel_language(chan), 1)) {
351 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
353 state->pos %= state->class->total_files;
356 if (tries == state->class->total_files) {
360 /* Record the pointer to the filename for position resuming later */
361 ast_copy_string(state->save_pos_filename, state->class->filearray[state->pos], sizeof(state->save_pos_filename));
363 ast_debug(1, "%s Opened file %d '%s'\n", ast_channel_name(chan), state->pos, state->class->filearray[state->pos]);
365 if (state->samples) {
367 /* seek *SHOULD* be good since it's from a known location */
368 ast_seekstream(ast_channel_stream(chan), state->samples, SEEK_SET);
369 /* if the seek failed then recover because if there is not a valid read,
370 * moh_files_generate will return -1 and MOH will stop */
371 loc = ast_tellstream(ast_channel_stream(chan));
372 if (state->samples > loc && loc) {
373 /* seek one sample from the end for one guaranteed valid read */
374 ast_seekstream(ast_channel_stream(chan), 1, SEEK_END);
381 static struct ast_frame *moh_files_readframe(struct ast_channel *chan)
383 struct ast_frame *f = NULL;
385 if (!(ast_channel_stream(chan) && (f = ast_readframe(ast_channel_stream(chan))))) {
386 if (!ast_moh_files_next(chan))
387 f = ast_readframe(ast_channel_stream(chan));
393 static void moh_files_write_format_change(struct ast_channel *chan, void *data)
395 struct moh_files_state *state = ast_channel_music_state(chan);
397 /* In order to prevent a recursive call to this function as a result
398 * of setting the moh write format back on the channel. Clear
399 * the moh write format before setting the write format on the channel.*/
400 if (&state->origwfmt.id) {
401 struct ast_format tmp;
403 ast_format_copy(&tmp, ast_channel_writeformat(chan));
404 if (state->mohwfmt.id) {
405 ast_format_clear(&state->origwfmt);
406 ast_set_write_format(chan, &state->mohwfmt);
408 ast_format_copy(&state->origwfmt, &tmp);
412 static int moh_files_generator(struct ast_channel *chan, void *data, int len, int samples)
414 struct moh_files_state *state = ast_channel_music_state(chan);
415 struct ast_frame *f = NULL;
418 state->sample_queue += samples;
420 while (state->sample_queue > 0) {
421 ast_channel_lock(chan);
422 if ((f = moh_files_readframe(chan))) {
423 /* We need to be sure that we unlock
424 * the channel prior to calling
425 * ast_write. Otherwise, the recursive locking
426 * that occurs can cause deadlocks when using
427 * indirect channels, like local channels
429 ast_channel_unlock(chan);
430 state->samples += f->samples;
431 state->sample_queue -= f->samples;
432 if (ast_format_cmp(&f->subclass.format, &state->mohwfmt) == AST_FORMAT_CMP_NOT_EQUAL) {
433 ast_format_copy(&state->mohwfmt, &f->subclass.format);
435 res = ast_write(chan, f);
438 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno));
442 ast_channel_unlock(chan);
449 static void *moh_files_alloc(struct ast_channel *chan, void *params)
451 struct moh_files_state *state;
452 struct mohclass *class = params;
454 if (!ast_channel_music_state(chan) && (state = ast_calloc(1, sizeof(*state)))) {
455 ast_channel_music_state_set(chan, state);
456 ast_module_ref(ast_module_info->self);
458 state = ast_channel_music_state(chan);
463 mohclass_unref(state->class, "Uh Oh. Restarting MOH with an active class");
464 ast_log(LOG_WARNING, "Uh Oh. Restarting MOH with an active class\n");
468 /* LOGIC: Comparing an unrefcounted pointer is a really bad idea, because
469 * malloc may allocate a different class to the same memory block. This
470 * might only happen when two reloads are generated in a short period of
471 * time, but it's still important to protect against.
472 * PROG: Compare the quick operation first, to save CPU. */
473 if (state->save_total != class->total_files || strcmp(state->name, class->name) != 0) {
474 memset(state, 0, sizeof(*state));
475 if (ast_test_flag(class, MOH_RANDOMIZE) && class->total_files) {
476 state->pos = ast_random() % class->total_files;
480 state->class = mohclass_ref(class, "Reffing music class for channel");
481 ast_format_copy(&state->origwfmt, ast_channel_writeformat(chan));
482 ast_format_copy(&state->mohwfmt, ast_channel_writeformat(chan));
484 /* For comparison on restart of MOH (see above) */
485 ast_copy_string(state->name, class->name, sizeof(state->name));
486 state->save_total = class->total_files;
488 ast_verb(3, "Started music on hold, class '%s', on %s\n", class->name, ast_channel_name(chan));
490 return ast_channel_music_state(chan);
493 static int moh_digit_match(void *obj, void *arg, int flags)
496 struct mohclass *class = obj;
498 return (*digit == class->digit) ? CMP_MATCH | CMP_STOP : 0;
501 /*! \note This function should be called with the mohclasses list locked */
502 static struct mohclass *get_mohbydigit(char digit)
504 return ao2_t_callback(mohclasses, 0, moh_digit_match, &digit, "digit callback");
507 static void moh_handle_digit(struct ast_channel *chan, char digit)
509 struct mohclass *class;
510 const char *classname = NULL;
512 if ((class = get_mohbydigit(digit))) {
513 classname = ast_strdupa(class->name);
514 class = mohclass_unref(class, "Unreffing ao2_find from finding by digit");
515 ast_channel_musicclass_set(chan, classname);
517 ast_moh_start(chan, classname, NULL);
521 static struct ast_generator moh_file_stream =
523 .alloc = moh_files_alloc,
524 .release = moh_files_release,
525 .generate = moh_files_generator,
526 .digit = moh_handle_digit,
527 .write_format_change = moh_files_write_format_change,
530 static int spawn_mp3(struct mohclass *class)
534 char fns[MAX_MP3S][80];
535 char *argv[MAX_MP3S + 50];
543 if (!strcasecmp(class->dir, "nodir")) {
546 dir = opendir(class->dir);
547 if (!dir && strncasecmp(class->dir, "http://", 7)) {
548 ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
553 if (!ast_test_flag(class, MOH_CUSTOM)) {
554 argv[argc++] = "mpg123";
557 argv[argc++] = "--mono";
559 argv[argc++] = "8000";
561 if (!ast_test_flag(class, MOH_SINGLE)) {
563 argv[argc++] = "2048";
568 if (ast_test_flag(class, MOH_QUIET))
569 argv[argc++] = "4096";
571 argv[argc++] = "8192";
573 /* Look for extra arguments and add them to the list */
574 ast_copy_string(xargs, class->args, sizeof(xargs));
576 while (!ast_strlen_zero(argptr)) {
577 argv[argc++] = argptr;
578 strsep(&argptr, ",");
581 /* Format arguments for argv vector */
582 ast_copy_string(xargs, class->args, sizeof(xargs));
584 while (!ast_strlen_zero(argptr)) {
585 argv[argc++] = argptr;
586 strsep(&argptr, " ");
590 if (!strncasecmp(class->dir, "http://", 7)) {
591 ast_copy_string(fns[files], class->dir, sizeof(fns[files]));
592 argv[argc++] = fns[files];
595 while ((de = readdir(dir)) && (files < MAX_MP3S)) {
596 if ((strlen(de->d_name) > 3) &&
597 ((ast_test_flag(class, MOH_CUSTOM) &&
598 (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") ||
599 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) ||
600 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
601 ast_copy_string(fns[files], de->d_name, sizeof(fns[files]));
602 argv[argc++] = fns[files];
612 ast_log(LOG_WARNING, "Pipe failed\n");
616 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
621 if (!strncasecmp(class->dir, "http://", 7) && time(NULL) - class->start < respawn_time) {
622 sleep(respawn_time - (time(NULL) - class->start));
626 class->pid = ast_safe_fork(0);
627 if (class->pid < 0) {
630 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
634 if (ast_opt_high_priority)
638 /* Stdout goes to pipe */
639 dup2(fds[1], STDOUT_FILENO);
641 /* Close everything else */
642 ast_close_fds_above_n(STDERR_FILENO);
645 if (strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir") && chdir(class->dir) < 0) {
646 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
649 setpgid(0, getpid());
650 if (ast_test_flag(class, MOH_CUSTOM)) {
651 execv(argv[0], argv);
653 /* Default install is /usr/local/bin */
654 execv(LOCAL_MPG_123, argv);
655 /* Many places have it in /usr/bin */
656 execv(MPG_123, argv);
657 /* Check PATH as a last-ditch effort */
658 execvp("mpg123", argv);
660 /* Can't use logger, since log FDs are closed */
661 fprintf(stderr, "MOH: exec failed: %s\n", strerror(errno));
671 static void *monmp3thread(void *data)
673 #define MOH_MS_INTERVAL 100
675 struct mohclass *class = data;
680 struct timeval deadline, tv_tmp;
683 deadline.tv_usec = 0;
685 pthread_testcancel();
686 /* Spawn mp3 player if it's not there */
687 if (class->srcfd < 0) {
688 if ((class->srcfd = spawn_mp3(class)) < 0) {
689 ast_log(LOG_WARNING, "Unable to spawn mp3player\n");
690 /* Try again later */
696 struct pollfd pfd = { .fd = ast_timer_fd(class->timer), .events = POLLIN | POLLPRI, };
701 /* Pause some amount of time */
702 if (ast_poll(&pfd, 1, -1) > 0) {
703 if (ast_timer_ack(class->timer, 1) < 0) {
704 ast_log(LOG_ERROR, "Failed to acknowledge timer for mp3player\n");
709 ast_log(LOG_WARNING, "poll() failed: %s\n", strerror(errno));
712 pthread_testcancel();
716 tv_tmp = ast_tvnow();
717 if (ast_tvzero(deadline))
719 delta = ast_tvdiff_ms(tv_tmp, deadline);
720 if (delta < MOH_MS_INTERVAL) { /* too early */
721 deadline = ast_tvadd(deadline, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */
722 usleep(1000 * (MOH_MS_INTERVAL - delta));
723 pthread_testcancel();
725 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
728 res = 8 * MOH_MS_INTERVAL; /* 8 samples per millisecond */
730 if ((strncasecmp(class->dir, "http://", 7) && strcasecmp(class->dir, "nodir")) && AST_LIST_EMPTY(&class->members))
733 len = ast_codec_get_len(&class->format, res);
735 if ((res2 = read(class->srcfd, sbuf, len)) != len) {
739 pthread_testcancel();
740 if (class->pid > 1) {
742 if (killpg(class->pid, SIGHUP) < 0) {
743 if (errno == ESRCH) {
746 ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno));
749 if (killpg(class->pid, SIGTERM) < 0) {
750 if (errno == ESRCH) {
753 ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno));
756 if (killpg(class->pid, SIGKILL) < 0) {
757 if (errno == ESRCH) {
760 ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno));
766 ast_debug(1, "Read %d bytes of audio while expecting %d\n", res2, len);
771 pthread_testcancel();
774 AST_LIST_TRAVERSE(&class->members, moh, list) {
776 if ((res = write(moh->pipe[1], sbuf, res2)) != res2) {
777 ast_debug(1, "Only wrote %d of %d bytes to pipe\n", res, res2);
785 static int play_moh_exec(struct ast_channel *chan, const char *data)
791 AST_DECLARE_APP_ARGS(args,
793 AST_APP_ARG(duration);
796 parse = ast_strdupa(data);
798 AST_STANDARD_APP_ARGS(args, parse);
800 if (!ast_strlen_zero(args.duration)) {
801 if (sscanf(args.duration, "%30d", &timeout) == 1) {
804 ast_log(LOG_WARNING, "Invalid MusicOnHold duration '%s'. Will wait indefinitely.\n", args.duration);
808 class = S_OR(args.class, NULL);
809 if (ast_moh_start(chan, class, NULL)) {
810 ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, ast_channel_name(chan));
815 res = ast_safe_sleep(chan, timeout);
817 while (!(res = ast_safe_sleep(chan, 10000)));
825 static int wait_moh_exec(struct ast_channel *chan, const char *data)
827 static int deprecation_warning = 0;
830 if (!deprecation_warning) {
831 deprecation_warning = 1;
832 ast_log(LOG_WARNING, "WaitMusicOnHold application is deprecated and will be removed. Use MusicOnHold with duration parameter instead\n");
835 if (!data || !atoi(data)) {
836 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
839 if (ast_moh_start(chan, NULL, NULL)) {
840 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), ast_channel_name(chan));
843 res = ast_safe_sleep(chan, atoi(data) * 1000);
848 static int set_moh_exec(struct ast_channel *chan, const char *data)
850 static int deprecation_warning = 0;
852 if (!deprecation_warning) {
853 deprecation_warning = 1;
854 ast_log(LOG_WARNING, "SetMusicOnHold application is deprecated and will be removed. Use Set(CHANNEL(musicclass)=...) instead\n");
857 if (ast_strlen_zero(data)) {
858 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
861 ast_channel_musicclass_set(chan, data);
865 static int start_moh_exec(struct ast_channel *chan, const char *data)
869 AST_DECLARE_APP_ARGS(args,
873 parse = ast_strdupa(data);
875 AST_STANDARD_APP_ARGS(args, parse);
877 class = S_OR(args.class, NULL);
878 if (ast_moh_start(chan, class, NULL))
879 ast_log(LOG_WARNING, "Unable to start music on hold class '%s' on channel %s\n", class, ast_channel_name(chan));
884 static int stop_moh_exec(struct ast_channel *chan, const char *data)
891 #define get_mohbyname(a,b,c) _get_mohbyname(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__)
893 static struct mohclass *_get_mohbyname(const char *name, int warn, int flags, const char *file, int lineno, const char *funcname)
895 struct mohclass *moh = NULL;
896 struct mohclass tmp_class = {
900 ast_copy_string(tmp_class.name, name, sizeof(tmp_class.name));
903 moh = __ao2_find_debug(mohclasses, &tmp_class, flags,
904 "get_mohbyname", file, lineno, funcname);
906 moh = __ao2_find(mohclasses, &tmp_class, flags);
910 ast_debug(1, "Music on Hold class '%s' not found in memory\n", name);
916 static struct mohdata *mohalloc(struct mohclass *cl)
921 if (!(moh = ast_calloc(1, sizeof(*moh))))
924 if (pipe(moh->pipe)) {
925 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
930 /* Make entirely non-blocking */
931 flags = fcntl(moh->pipe[0], F_GETFL);
932 fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
933 flags = fcntl(moh->pipe[1], F_GETFL);
934 fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
936 moh->f.frametype = AST_FRAME_VOICE;
937 ast_format_copy(&moh->f.subclass.format, &cl->format);
938 moh->f.offset = AST_FRIENDLY_OFFSET;
940 moh->parent = mohclass_ref(cl, "Reffing music class for mohdata parent");
943 AST_LIST_INSERT_HEAD(&cl->members, moh, list);
949 static void moh_release(struct ast_channel *chan, void *data)
951 struct mohdata *moh = data;
952 struct mohclass *class = moh->parent;
953 struct ast_format oldwfmt;
956 AST_LIST_REMOVE(&moh->parent->members, moh, list);
962 ast_format_copy(&oldwfmt, &moh->origwfmt);
964 moh->parent = class = mohclass_unref(class, "unreffing moh->parent upon deactivation of generator");
969 struct moh_files_state *state;
971 state = ast_channel_music_state(chan);
972 if (state && state->class) {
973 state->class = mohclass_unref(state->class, "Unreffing channel's music class upon deactivation of generator");
975 if (oldwfmt.id && ast_set_write_format(chan, &oldwfmt)) {
976 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n",
977 ast_channel_name(chan), ast_getformatname(&oldwfmt));
980 ast_verb(3, "Stopped music on hold on %s\n", ast_channel_name(chan));
984 static void *moh_alloc(struct ast_channel *chan, void *params)
987 struct mohclass *class = params;
988 struct moh_files_state *state;
990 /* Initiating music_state for current channel. Channel should know name of moh class */
991 if (!ast_channel_music_state(chan) && (state = ast_calloc(1, sizeof(*state)))) {
992 ast_channel_music_state_set(chan, state);
993 ast_module_ref(ast_module_info->self);
995 state = ast_channel_music_state(chan);
1000 mohclass_unref(state->class, "Uh Oh. Restarting MOH with an active class");
1001 ast_log(LOG_WARNING, "Uh Oh. Restarting MOH with an active class\n");
1003 memset(state, 0, sizeof(*state));
1006 if ((res = mohalloc(class))) {
1007 ast_format_copy(&res->origwfmt, ast_channel_writeformat(chan));
1008 if (ast_set_write_format(chan, &class->format)) {
1009 ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", ast_channel_name(chan), ast_codec2str(&class->format));
1010 moh_release(NULL, res);
1013 state->class = mohclass_ref(class, "Placing reference into state container");
1015 ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n", class->name, ast_channel_name(chan));
1020 static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
1022 struct mohdata *moh = data;
1023 short buf[1280 + AST_FRIENDLY_OFFSET / 2];
1026 len = ast_codec_get_len(&moh->parent->format, samples);
1028 if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
1029 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, ast_channel_name(chan));
1030 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
1032 res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
1036 moh->f.datalen = res;
1037 moh->f.data.ptr = buf + AST_FRIENDLY_OFFSET / 2;
1038 moh->f.samples = ast_codec_get_samples(&moh->f);
1040 if (ast_write(chan, &moh->f) < 0) {
1041 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", ast_channel_name(chan), strerror(errno));
1048 static struct ast_generator mohgen = {
1050 .release = moh_release,
1051 .generate = moh_generate,
1052 .digit = moh_handle_digit,
1055 static int moh_add_file(struct mohclass *class, const char *filepath)
1057 if (!class->allowed_files) {
1058 if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray))))
1060 class->allowed_files = INITIAL_NUM_FILES;
1061 } else if (class->total_files == class->allowed_files) {
1062 if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) {
1063 class->allowed_files = 0;
1064 class->total_files = 0;
1067 class->allowed_files *= 2;
1070 if (!(class->filearray[class->total_files] = ast_strdup(filepath)))
1073 class->total_files++;
1078 static int moh_sort_compare(const void *i1, const void *i2)
1082 s1 = ((char **)i1)[0];
1083 s2 = ((char **)i2)[0];
1085 return strcasecmp(s1, s2);
1088 static int moh_scan_files(struct mohclass *class) {
1091 struct dirent *files_dirent;
1092 char dir_path[PATH_MAX];
1093 char path[PATH_MAX];
1094 char filepath[PATH_MAX];
1096 struct stat statbuf;
1099 if (class->dir[0] != '/') {
1100 ast_copy_string(dir_path, ast_config_AST_DATA_DIR, sizeof(dir_path));
1101 strncat(dir_path, "/", sizeof(dir_path) - 1);
1102 strncat(dir_path, class->dir, sizeof(dir_path) - 1);
1104 ast_copy_string(dir_path, class->dir, sizeof(dir_path));
1106 ast_debug(4, "Scanning '%s' for files for class '%s'\n", dir_path, class->name);
1107 files_DIR = opendir(dir_path);
1109 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", dir_path);
1113 for (i = 0; i < class->total_files; i++) {
1114 ast_free(class->filearray[i]);
1116 class->total_files = 0;
1118 if (!getcwd(path, sizeof(path))) {
1119 ast_log(LOG_WARNING, "getcwd() failed: %s\n", strerror(errno));
1120 closedir(files_DIR);
1123 if (chdir(dir_path) < 0) {
1124 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
1125 closedir(files_DIR);
1128 while ((files_dirent = readdir(files_DIR))) {
1129 /* The file name must be at least long enough to have the file type extension */
1130 if ((strlen(files_dirent->d_name) < 4))
1133 /* Skip files that starts with a dot */
1134 if (files_dirent->d_name[0] == '.')
1137 /* Skip files without extensions... they are not audio */
1138 if (!strchr(files_dirent->d_name, '.'))
1141 snprintf(filepath, sizeof(filepath), "%s/%s", dir_path, files_dirent->d_name);
1143 if (stat(filepath, &statbuf))
1146 if (!S_ISREG(statbuf.st_mode))
1149 if ((ext = strrchr(filepath, '.')))
1152 /* if the file is present in multiple formats, ensure we only put it into the list once */
1153 for (i = 0; i < class->total_files; i++)
1154 if (!strcmp(filepath, class->filearray[i]))
1157 if (i == class->total_files) {
1158 if (moh_add_file(class, filepath))
1163 closedir(files_DIR);
1164 if (chdir(path) < 0) {
1165 ast_log(LOG_WARNING, "chdir() failed: %s\n", strerror(errno));
1168 if (ast_test_flag(class, MOH_SORTALPHA))
1169 qsort(&class->filearray[0], class->total_files, sizeof(char *), moh_sort_compare);
1170 return class->total_files;
1173 static int init_files_class(struct mohclass *class)
1177 res = moh_scan_files(class);
1184 ast_verb(3, "Files not found in %s for moh class:%s\n",
1185 class->dir, class->name);
1190 /* XXX This isn't correct. Args is an application for custom mode. XXX */
1191 if (strchr(class->args, 'r')) {
1192 ast_set_flag(class, MOH_RANDOMIZE);
1199 static void moh_rescan_files(void) {
1200 struct ao2_iterator i;
1203 i = ao2_iterator_init(mohclasses, 0);
1205 while ((c = ao2_iterator_next(&i))) {
1206 if (!strcasecmp(c->mode, "files")) {
1212 ao2_iterator_destroy(&i);
1215 static int moh_diff(struct mohclass *old, struct mohclass *new)
1221 if (strcmp(old->dir, new->dir)) {
1223 } else if (strcmp(old->mode, new->mode)) {
1225 } else if (strcmp(old->args, new->args)) {
1227 } else if (old->flags != new->flags) {
1234 static int init_app_class(struct mohclass *class)
1236 if (!strcasecmp(class->mode, "custom")) {
1237 ast_set_flag(class, MOH_CUSTOM);
1238 } else if (!strcasecmp(class->mode, "mp3nb")) {
1239 ast_set_flag(class, MOH_SINGLE);
1240 } else if (!strcasecmp(class->mode, "quietmp3nb")) {
1241 ast_set_flag(class, MOH_SINGLE | MOH_QUIET);
1242 } else if (!strcasecmp(class->mode, "quietmp3")) {
1243 ast_set_flag(class, MOH_QUIET);
1248 if (!(class->timer = ast_timer_open())) {
1249 ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno));
1252 if (class->timer && ast_timer_set_rate(class->timer, 25)) {
1253 ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno));
1254 ast_timer_close(class->timer);
1255 class->timer = NULL;
1258 if (ast_pthread_create_background(&class->thread, NULL, monmp3thread, class)) {
1259 ast_log(LOG_WARNING, "Unable to create moh thread...\n");
1261 ast_timer_close(class->timer);
1262 class->timer = NULL;
1271 * \note This function owns the reference it gets to moh if unref is true
1273 #define moh_register(a,b,c) _moh_register(a,b,c,__FILE__,__LINE__,__PRETTY_FUNCTION__)
1274 static int _moh_register(struct mohclass *moh, int reload, int unref, const char *file, int line, const char *funcname)
1276 struct mohclass *mohclass = NULL;
1278 mohclass = _get_mohbyname(moh->name, 0, MOH_NOTDELETED, file, line, funcname);
1280 if (mohclass && !moh_diff(mohclass, moh)) {
1281 ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
1282 mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name");
1284 moh = mohclass_unref(moh, "unreffing potential new moh class (it is a duplicate)");
1287 } else if (mohclass) {
1288 /* Found a class, but it's different from the one being registered */
1289 mohclass = mohclass_unref(mohclass, "unreffing mohclass we just found by name");
1293 moh->start -= respawn_time;
1295 if (!strcasecmp(moh->mode, "files")) {
1296 if (init_files_class(moh)) {
1298 moh = mohclass_unref(moh, "unreffing potential new moh class (init_files_class failed)");
1302 } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") ||
1303 !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") ||
1304 !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) {
1305 if (init_app_class(moh)) {
1307 moh = mohclass_unref(moh, "unreffing potential new moh class (init_app_class_failed)");
1312 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
1314 moh = mohclass_unref(moh, "unreffing potential new moh class (unknown mode)");
1319 ao2_t_link(mohclasses, moh, "Adding class to container");
1322 moh = mohclass_unref(moh, "Unreffing new moh class because we just added it to the container");
1328 static void local_ast_moh_cleanup(struct ast_channel *chan)
1330 struct moh_files_state *state = ast_channel_music_state(chan);
1334 /* This should never happen. We likely just leaked some resource. */
1336 mohclass_unref(state->class, "Uh Oh. Cleaning up MOH with an active class");
1337 ast_log(LOG_WARNING, "Uh Oh. Cleaning up MOH with an active class\n");
1339 ast_free(ast_channel_music_state(chan));
1340 ast_channel_music_state_set(chan, NULL);
1341 /* Only held a module reference if we had a music state */
1342 ast_module_unref(ast_module_info->self);
1346 static void moh_class_destructor(void *obj);
1348 #define moh_class_malloc() _moh_class_malloc(__FILE__,__LINE__,__PRETTY_FUNCTION__)
1350 static struct mohclass *_moh_class_malloc(const char *file, int line, const char *funcname)
1352 struct mohclass *class;
1356 __ao2_alloc_debug(sizeof(*class), moh_class_destructor,
1357 AO2_ALLOC_OPT_LOCK_MUTEX, "Allocating new moh class", file, line, funcname, 1)
1358 #elif defined(__AST_DEBUG_MALLOC)
1359 __ao2_alloc_debug(sizeof(*class), moh_class_destructor,
1360 AO2_ALLOC_OPT_LOCK_MUTEX, "Allocating new moh class", file, line, funcname, 0)
1362 ao2_alloc(sizeof(*class), moh_class_destructor)
1365 ast_format_set(&class->format, AST_FORMAT_SLINEAR, 0);
1372 static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
1374 struct mohclass *mohclass = NULL;
1375 struct moh_files_state *state = ast_channel_music_state(chan);
1376 struct ast_variable *var = NULL;
1377 RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
1378 RAII_VAR(struct ast_json *, json_object, NULL, ast_json_unref);
1380 int realtime_possible = ast_check_realtime("musiconhold");
1382 /* The following is the order of preference for which class to use:
1383 * 1) The channels explicitly set musicclass, which should *only* be
1384 * set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
1385 * 2) The mclass argument. If a channel is calling ast_moh_start() as the
1386 * result of receiving a HOLD control frame, this should be the
1387 * payload that came with the frame.
1388 * 3) The interpclass argument. This would be from the mohinterpret
1389 * option from channel drivers. This is the same as the old musicclass
1391 * 4) The default class.
1393 if (!ast_strlen_zero(ast_channel_musicclass(chan))) {
1394 mohclass = get_mohbyname(ast_channel_musicclass(chan), 1, 0);
1395 if (!mohclass && realtime_possible) {
1396 var = ast_load_realtime("musiconhold", "name", ast_channel_musicclass(chan), SENTINEL);
1399 if (!mohclass && !var && !ast_strlen_zero(mclass)) {
1400 mohclass = get_mohbyname(mclass, 1, 0);
1401 if (!mohclass && realtime_possible) {
1402 var = ast_load_realtime("musiconhold", "name", mclass, SENTINEL);
1405 if (!mohclass && !var && !ast_strlen_zero(interpclass)) {
1406 mohclass = get_mohbyname(interpclass, 1, 0);
1407 if (!mohclass && realtime_possible) {
1408 var = ast_load_realtime("musiconhold", "name", interpclass, SENTINEL);
1412 if (!mohclass && !var) {
1413 mohclass = get_mohbyname("default", 1, 0);
1414 if (!mohclass && realtime_possible) {
1415 var = ast_load_realtime("musiconhold", "name", "default", SENTINEL);
1419 /* If no moh class found in memory, then check RT. Note that the logic used
1420 * above guarantees that if var is non-NULL, then mohclass must be NULL.
1423 struct ast_variable *tmp = NULL;
1425 if ((mohclass = moh_class_malloc())) {
1426 mohclass->realtime = 1;
1427 for (tmp = var; tmp; tmp = tmp->next) {
1428 if (!strcasecmp(tmp->name, "name"))
1429 ast_copy_string(mohclass->name, tmp->value, sizeof(mohclass->name));
1430 else if (!strcasecmp(tmp->name, "mode"))
1431 ast_copy_string(mohclass->mode, tmp->value, sizeof(mohclass->mode));
1432 else if (!strcasecmp(tmp->name, "directory"))
1433 ast_copy_string(mohclass->dir, tmp->value, sizeof(mohclass->dir));
1434 else if (!strcasecmp(tmp->name, "application"))
1435 ast_copy_string(mohclass->args, tmp->value, sizeof(mohclass->args));
1436 else if (!strcasecmp(tmp->name, "digit") && (isdigit(*tmp->value) || strchr("*#", *tmp->value)))
1437 mohclass->digit = *tmp->value;
1438 else if (!strcasecmp(tmp->name, "random"))
1439 ast_set2_flag(mohclass, ast_true(tmp->value), MOH_RANDOMIZE);
1440 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "random"))
1441 ast_set_flag(mohclass, MOH_RANDOMIZE);
1442 else if (!strcasecmp(tmp->name, "sort") && !strcasecmp(tmp->value, "alpha"))
1443 ast_set_flag(mohclass, MOH_SORTALPHA);
1444 else if (!strcasecmp(tmp->name, "format")) {
1445 ast_getformatbyname(tmp->value, &mohclass->format);
1446 if (!mohclass->format.id) {
1447 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", tmp->value);
1448 ast_format_set(&mohclass->format, AST_FORMAT_SLINEAR, 0);
1452 ast_variables_destroy(var);
1453 if (ast_strlen_zero(mohclass->dir)) {
1454 if (!strcasecmp(mohclass->mode, "custom")) {
1455 strcpy(mohclass->dir, "nodir");
1457 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", mohclass->name);
1458 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no directory specified)");
1462 if (ast_strlen_zero(mohclass->mode)) {
1463 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", mohclass->name);
1464 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no mode specified)");
1467 if (ast_strlen_zero(mohclass->args) && !strcasecmp(mohclass->mode, "custom")) {
1468 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", mohclass->name);
1469 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (no app specified for custom mode");
1473 if (ast_test_flag(global_flags, MOH_CACHERTCLASSES)) {
1474 /* CACHERTCLASSES enabled, let's add this class to default tree */
1475 if (state && state->class) {
1476 /* Class already exist for this channel */
1477 ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name);
1478 if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) {
1479 /* we found RT class with the same name, seems like we should continue playing existing one */
1480 /* XXX This code is impossible to reach */
1481 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has a class)");
1482 mohclass = state->class;
1485 /* We don't want moh_register to unref the mohclass because we do it at the end of this function as well.
1486 * If we allowed moh_register to unref the mohclass,too, then the count would be off by one. The result would
1487 * be that the destructor would be called when the generator on the channel is deactivated. The container then
1488 * has a pointer to a freed mohclass, so any operations involving the mohclass container would result in reading
1491 if (moh_register(mohclass, 0, DONT_UNREF) == -1) {
1492 mohclass = mohclass_unref(mohclass, "unreffing mohclass failed to register");
1496 /* We don't register RT moh class, so let's init it manualy */
1498 time(&mohclass->start);
1499 mohclass->start -= respawn_time;
1501 if (!strcasecmp(mohclass->mode, "files")) {
1502 if (!moh_scan_files(mohclass)) {
1503 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)");
1506 if (strchr(mohclass->args, 'r'))
1507 ast_set_flag(mohclass, MOH_RANDOMIZE);
1508 } 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")) {
1510 if (!strcasecmp(mohclass->mode, "custom"))
1511 ast_set_flag(mohclass, MOH_CUSTOM);
1512 else if (!strcasecmp(mohclass->mode, "mp3nb"))
1513 ast_set_flag(mohclass, MOH_SINGLE);
1514 else if (!strcasecmp(mohclass->mode, "quietmp3nb"))
1515 ast_set_flag(mohclass, MOH_SINGLE | MOH_QUIET);
1516 else if (!strcasecmp(mohclass->mode, "quietmp3"))
1517 ast_set_flag(mohclass, MOH_QUIET);
1519 mohclass->srcfd = -1;
1520 if (!(mohclass->timer = ast_timer_open())) {
1521 ast_log(LOG_WARNING, "Unable to create timer: %s\n", strerror(errno));
1523 if (mohclass->timer && ast_timer_set_rate(mohclass->timer, 25)) {
1524 ast_log(LOG_WARNING, "Unable to set 40ms frame rate: %s\n", strerror(errno));
1525 ast_timer_close(mohclass->timer);
1526 mohclass->timer = NULL;
1529 /* Let's check if this channel already had a moh class before */
1530 if (state && state->class) {
1531 /* Class already exist for this channel */
1532 ast_log(LOG_NOTICE, "This channel already has a MOH class attached (%s)!\n", state->class->name);
1533 if (state->class->realtime && !ast_test_flag(global_flags, MOH_CACHERTCLASSES) && !strcasecmp(mohclass->name, state->class->name)) {
1534 /* we found RT class with the same name, seems like we should continue playing existing one */
1535 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (channel already has one)");
1536 mohclass = state->class;
1539 if (ast_pthread_create_background(&mohclass->thread, NULL, monmp3thread, mohclass)) {
1540 ast_log(LOG_WARNING, "Unable to create moh...\n");
1541 if (mohclass->timer) {
1542 ast_timer_close(mohclass->timer);
1543 mohclass->timer = NULL;
1545 mohclass = mohclass_unref(mohclass, "Unreffing potential mohclass (failed to create background thread)");
1550 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mohclass->mode);
1551 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (unknown mode)");
1556 ast_variables_destroy(var);
1565 /* If we are using a cached realtime class with files, re-scan the files */
1566 if (!var && ast_test_flag(global_flags, MOH_CACHERTCLASSES) && mohclass->realtime && !strcasecmp(mohclass->mode, "files")) {
1567 if (!moh_scan_files(mohclass)) {
1568 mohclass = mohclass_unref(mohclass, "unreffing potential mohclass (moh_scan_files failed)");
1573 ast_set_flag(ast_channel_flags(chan), AST_FLAG_MOH);
1575 if (mohclass->total_files) {
1576 res = ast_activate_generator(chan, &moh_file_stream, mohclass);
1578 res = ast_activate_generator(chan, &mohgen, mohclass);
1581 json_object = ast_json_pack("{s: s}",
1582 "class", mohclass->name);
1584 mohclass = mohclass_unref(mohclass, "unreffing local reference to mohclass in local_ast_moh_start");
1588 message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan),
1589 ast_channel_moh_start_type(),
1592 stasis_publish(ast_channel_topic(chan), message);
1595 mohclass = mohclass_unref(mohclass, "unreffing local reference to mohclass in local_ast_moh_start");
1600 static void local_ast_moh_stop(struct ast_channel *chan)
1602 RAII_VAR(struct stasis_message *, message, NULL, ao2_cleanup);
1603 ast_clear_flag(ast_channel_flags(chan), AST_FLAG_MOH);
1604 ast_deactivate_generator(chan);
1606 ast_channel_lock(chan);
1607 if (ast_channel_music_state(chan)) {
1608 if (ast_channel_stream(chan)) {
1609 ast_closestream(ast_channel_stream(chan));
1610 ast_channel_stream_set(chan, NULL);
1614 message = ast_channel_blob_create_from_cache(ast_channel_uniqueid(chan), ast_channel_moh_stop_type(), NULL);
1616 stasis_publish(ast_channel_topic(chan), message);
1618 ast_channel_unlock(chan);
1621 static void moh_class_destructor(void *obj)
1623 struct mohclass *class = obj;
1624 struct mohdata *member;
1627 ast_debug(1, "Destroying MOH class '%s'\n", class->name);
1630 while ((member = AST_LIST_REMOVE_HEAD(&class->members, list))) {
1635 /* Kill the thread first, so it cannot restart the child process while the
1636 * class is being destroyed */
1637 if (class->thread != AST_PTHREADT_NULL && class->thread != 0) {
1638 tid = class->thread;
1639 class->thread = AST_PTHREADT_NULL;
1640 pthread_cancel(tid);
1641 /* We'll collect the exit status later, after we ensure all the readers
1645 if (class->pid > 1) {
1647 int bytes, tbytes = 0, stime = 0, pid = 0;
1649 ast_debug(1, "killing %d!\n", class->pid);
1651 stime = time(NULL) + 2;
1655 /* Back when this was just mpg123, SIGKILL was fine. Now we need
1656 * to give the process a reason and time enough to kill off its
1659 if (killpg(pid, SIGHUP) < 0) {
1660 ast_log(LOG_WARNING, "Unable to send a SIGHUP to MOH process?!!: %s\n", strerror(errno));
1663 if (killpg(pid, SIGTERM) < 0) {
1664 if (errno == ESRCH) {
1667 ast_log(LOG_WARNING, "Unable to terminate MOH process?!!: %s\n", strerror(errno));
1670 if (killpg(pid, SIGKILL) < 0) {
1671 if (errno == ESRCH) {
1674 ast_log(LOG_WARNING, "Unable to kill MOH process?!!: %s\n", strerror(errno));
1678 while ((ast_wait_for_input(class->srcfd, 100) > 0) &&
1679 (bytes = read(class->srcfd, buff, 8192)) && time(NULL) < stime) {
1680 tbytes = tbytes + bytes;
1683 ast_debug(1, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
1685 close(class->srcfd);
1689 if (class->filearray) {
1691 for (i = 0; i < class->total_files; i++) {
1692 free(class->filearray[i]);
1694 free(class->filearray);
1695 class->filearray = NULL;
1699 ast_timer_close(class->timer);
1700 class->timer = NULL;
1703 /* Finally, collect the exit status of the monitor thread */
1705 pthread_join(tid, NULL);
1710 static int moh_class_mark(void *obj, void *arg, int flags)
1712 struct mohclass *class = obj;
1719 static int moh_classes_delete_marked(void *obj, void *arg, int flags)
1721 struct mohclass *class = obj;
1723 return class->delete ? CMP_MATCH : 0;
1726 static int load_moh_classes(int reload)
1728 struct ast_config *cfg;
1729 struct ast_variable *var;
1730 struct mohclass *class;
1733 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1735 cfg = ast_config_load("musiconhold.conf", config_flags);
1737 if (cfg == CONFIG_STATUS_FILEMISSING || cfg == CONFIG_STATUS_FILEINVALID) {
1738 if (ast_check_realtime("musiconhold") && reload) {
1739 ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
1740 ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, moh_classes_delete_marked, NULL, "Purge marked classes");
1744 if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
1750 ao2_t_callback(mohclasses, OBJ_NODATA, moh_class_mark, NULL, "Mark deleted classes");
1753 ast_clear_flag(global_flags, AST_FLAGS_ALL);
1755 cat = ast_category_browse(cfg, NULL);
1756 for (; cat; cat = ast_category_browse(cfg, cat)) {
1757 /* Setup common options from [general] section */
1758 if (!strcasecmp(cat, "general")) {
1759 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1760 if (!strcasecmp(var->name, "cachertclasses")) {
1761 ast_set2_flag(global_flags, ast_true(var->value), MOH_CACHERTCLASSES);
1763 ast_log(LOG_WARNING, "Unknown option '%s' in [general] section of musiconhold.conf\n", var->name);
1767 /* These names were deprecated in 1.4 and should not be used until after the next major release. */
1768 if (!strcasecmp(cat, "classes") || !strcasecmp(cat, "moh_files") ||
1769 !strcasecmp(cat, "general")) {
1773 if (!(class = moh_class_malloc())) {
1777 ast_copy_string(class->name, cat, sizeof(class->name));
1778 for (var = ast_variable_browse(cfg, cat); var; var = var->next) {
1779 if (!strcasecmp(var->name, "mode")) {
1780 ast_copy_string(class->mode, var->value, sizeof(class->mode));
1781 } else if (!strcasecmp(var->name, "directory")) {
1782 ast_copy_string(class->dir, var->value, sizeof(class->dir));
1783 } else if (!strcasecmp(var->name, "application")) {
1784 ast_copy_string(class->args, var->value, sizeof(class->args));
1785 } else if (!strcasecmp(var->name, "announcement")) {
1786 ast_copy_string(class->announcement, var->value, sizeof(class->announcement));
1787 ast_set_flag(class, MOH_ANNOUNCEMENT);
1788 } else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value))) {
1789 class->digit = *var->value;
1790 } else if (!strcasecmp(var->name, "random")) {
1791 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
1792 } else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "random")) {
1793 ast_set_flag(class, MOH_RANDOMIZE);
1794 } else if (!strcasecmp(var->name, "sort") && !strcasecmp(var->value, "alpha")) {
1795 ast_set_flag(class, MOH_SORTALPHA);
1796 } else if (!strcasecmp(var->name, "format")) {
1797 ast_getformatbyname(var->value, &class->format);
1798 if (!class->format.id) {
1799 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
1800 ast_format_set(&class->format, AST_FORMAT_SLINEAR, 0);
1805 if (ast_strlen_zero(class->dir)) {
1806 if (!strcasecmp(class->mode, "custom")) {
1807 strcpy(class->dir, "nodir");
1809 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
1810 class = mohclass_unref(class, "unreffing potential mohclass (no directory)");
1814 if (ast_strlen_zero(class->mode)) {
1815 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
1816 class = mohclass_unref(class, "unreffing potential mohclass (no mode)");
1819 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
1820 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
1821 class = mohclass_unref(class, "unreffing potential mohclass (no app for custom mode)");
1825 /* Don't leak a class when it's already registered */
1826 if (!moh_register(class, reload, HANDLE_REF)) {
1831 ast_config_destroy(cfg);
1833 ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE,
1834 moh_classes_delete_marked, NULL, "Purge marked classes");
1839 static void ast_moh_destroy(void)
1841 ast_verb(2, "Destroying musiconhold processes\n");
1843 ao2_t_callback(mohclasses, OBJ_UNLINK | OBJ_NODATA | OBJ_MULTIPLE, NULL, NULL, "Destroy callback");
1844 ao2_ref(mohclasses, -1);
1849 static char *handle_cli_moh_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1853 e->command = "moh reload";
1855 "Usage: moh reload\n"
1856 " Reloads the MusicOnHold module.\n"
1857 " Alias for 'module reload res_musiconhold.so'\n";
1863 if (a->argc != e->args)
1864 return CLI_SHOWUSAGE;
1871 static char *handle_cli_moh_show_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1873 struct mohclass *class;
1874 struct ao2_iterator i;
1878 e->command = "moh show files";
1880 "Usage: moh show files\n"
1881 " Lists all loaded file-based MusicOnHold classes and their\n"
1888 if (a->argc != e->args)
1889 return CLI_SHOWUSAGE;
1891 i = ao2_iterator_init(mohclasses, 0);
1892 for (; (class = ao2_t_iterator_next(&i, "Show files iterator")); mohclass_unref(class, "Unref iterator in moh show files")) {
1895 if (!class->total_files) {
1899 ast_cli(a->fd, "Class: %s\n", class->name);
1900 for (x = 0; x < class->total_files; x++) {
1901 ast_cli(a->fd, "\tFile: %s\n", class->filearray[x]);
1904 ao2_iterator_destroy(&i);
1909 static char *handle_cli_moh_show_classes(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1911 struct mohclass *class;
1912 struct ao2_iterator i;
1916 e->command = "moh show classes";
1918 "Usage: moh show classes\n"
1919 " Lists all MusicOnHold classes.\n";
1925 if (a->argc != e->args)
1926 return CLI_SHOWUSAGE;
1928 i = ao2_iterator_init(mohclasses, 0);
1929 for (; (class = ao2_t_iterator_next(&i, "Show classes iterator")); mohclass_unref(class, "Unref iterator in moh show classes")) {
1930 ast_cli(a->fd, "Class: %s\n", class->name);
1931 ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
1932 ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
1933 if (ast_test_flag(class, MOH_CUSTOM)) {
1934 ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
1936 if (strcasecmp(class->mode, "files")) {
1937 ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(&class->format));
1940 ao2_iterator_destroy(&i);
1945 static struct ast_cli_entry cli_moh[] = {
1946 AST_CLI_DEFINE(handle_cli_moh_reload, "Reload MusicOnHold"),
1947 AST_CLI_DEFINE(handle_cli_moh_show_classes, "List MusicOnHold classes"),
1948 AST_CLI_DEFINE(handle_cli_moh_show_files, "List MusicOnHold file-based classes")
1951 static int moh_class_hash(const void *obj, const int flags)
1953 const struct mohclass *class = obj;
1955 return ast_str_case_hash(class->name);
1958 static int moh_class_cmp(void *obj, void *arg, int flags)
1960 struct mohclass *class = obj, *class2 = arg;
1962 return strcasecmp(class->name, class2->name) ? 0 :
1963 (flags & MOH_NOTDELETED) && (class->delete || class2->delete) ? 0 :
1964 CMP_MATCH | CMP_STOP;
1968 * \brief Load the module
1970 * Module loading including tests for configuration or dependencies.
1971 * This function can return AST_MODULE_LOAD_FAILURE, AST_MODULE_LOAD_DECLINE,
1972 * or AST_MODULE_LOAD_SUCCESS. If a dependency or environment variable fails
1973 * tests return AST_MODULE_LOAD_FAILURE. If the module can not load the
1974 * configuration file or other non-critical problem return
1975 * AST_MODULE_LOAD_DECLINE. On success return AST_MODULE_LOAD_SUCCESS.
1977 static int load_module(void)
1981 if (!(mohclasses = ao2_t_container_alloc(53, moh_class_hash, moh_class_cmp, "Moh class container"))) {
1982 return AST_MODULE_LOAD_DECLINE;
1985 if (!load_moh_classes(0) && ast_check_realtime("musiconhold") == 0) { /* No music classes configured, so skip it */
1986 ast_log(LOG_WARNING, "No music on hold classes configured, "
1987 "disabling music on hold.\n");
1989 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop,
1990 local_ast_moh_cleanup);
1993 res = ast_register_application_xml(play_moh, play_moh_exec);
1994 ast_register_atexit(ast_moh_destroy);
1995 ast_cli_register_multiple(cli_moh, ARRAY_LEN(cli_moh));
1997 res = ast_register_application_xml(wait_moh, wait_moh_exec);
1999 res = ast_register_application_xml(set_moh, set_moh_exec);
2001 res = ast_register_application_xml(start_moh, start_moh_exec);
2003 res = ast_register_application_xml(stop_moh, stop_moh_exec);
2005 return AST_MODULE_LOAD_SUCCESS;
2008 static int reload(void)
2010 if (load_moh_classes(1)) {
2011 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop,
2012 local_ast_moh_cleanup);
2015 return AST_MODULE_LOAD_SUCCESS;
2018 static int moh_class_inuse(void *obj, void *arg, int flags)
2020 struct mohclass *class = obj;
2022 return AST_LIST_EMPTY(&class->members) ? 0 : CMP_MATCH | CMP_STOP;
2025 static int unload_module(void)
2028 struct mohclass *class = NULL;
2030 /* XXX This check shouldn't be required if module ref counting was being used
2032 if ((class = ao2_t_callback(mohclasses, 0, moh_class_inuse, NULL, "Module unload callback"))) {
2033 class = mohclass_unref(class, "unref of class from module unload callback");
2038 ast_log(LOG_WARNING, "Unable to unload res_musiconhold due to active MOH channels\n");
2042 ast_uninstall_music_functions();
2045 res = ast_unregister_application(play_moh);
2046 res |= ast_unregister_application(wait_moh);
2047 res |= ast_unregister_application(set_moh);
2048 res |= ast_unregister_application(start_moh);
2049 res |= ast_unregister_application(stop_moh);
2050 ast_cli_unregister_multiple(cli_moh, ARRAY_LEN(cli_moh));
2051 ast_unregister_atexit(ast_moh_destroy);
2056 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "Music On Hold Resource",
2057 .load = load_module,
2058 .unload = unload_module,
2060 .load_pri = AST_MODPRI_CHANNEL_DEPEND,