2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2006, 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 * \arg See also \ref Config_moh
25 * \author Mark Spencer <markster@digium.com>
29 <conflict>win32</conflict>
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
45 #include <sys/signal.h>
46 #include <netinet/in.h>
50 #include <sys/ioctl.h>
53 #include <zaptel/zaptel.h>
56 #include "asterisk/lock.h"
57 #include "asterisk/file.h"
58 #include "asterisk/logger.h"
59 #include "asterisk/channel.h"
60 #include "asterisk/pbx.h"
61 #include "asterisk/options.h"
62 #include "asterisk/module.h"
63 #include "asterisk/translate.h"
64 #include "asterisk/say.h"
65 #include "asterisk/musiconhold.h"
66 #include "asterisk/config.h"
67 #include "asterisk/utils.h"
68 #include "asterisk/cli.h"
69 #include "asterisk/stringfields.h"
70 #include "asterisk/linkedlists.h"
72 #define INITIAL_NUM_FILES 8
74 static char *app0 = "MusicOnHold";
75 static char *app1 = "WaitMusicOnHold";
76 static char *app2 = "SetMusicOnHold";
77 static char *app3 = "StartMusicOnHold";
78 static char *app4 = "StopMusicOnHold";
80 static char *synopsis0 = "Play Music On Hold indefinitely";
81 static char *synopsis1 = "Wait, playing Music On Hold";
82 static char *synopsis2 = "Set default Music On Hold class";
83 static char *synopsis3 = "Play Music On Hold";
84 static char *synopsis4 = "Stop Playing Music On Hold";
86 static char *descrip0 = "MusicOnHold(class): "
87 "Plays hold music specified by class. If omitted, the default\n"
88 "music source for the channel will be used. Set the default \n"
89 "class with the SetMusicOnHold() application.\n"
90 "Returns -1 on hangup.\n"
91 "Never returns otherwise.\n";
93 static char *descrip1 = "WaitMusicOnHold(delay): "
94 "Plays hold music specified number of seconds. Returns 0 when\n"
95 "done, or -1 on hangup. If no hold music is available, the delay will\n"
96 "still occur with no sound.\n";
98 static char *descrip2 = "SetMusicOnHold(class): "
99 "Sets the default class for music on hold for a given channel. When\n"
100 "music on hold is activated, this class will be used to select which\n"
101 "music is played.\n";
103 static char *descrip3 = "StartMusicOnHold(class): "
104 "Starts playing music on hold, uses default music class for channel.\n"
105 "Starts playing music specified by class. If omitted, the default\n"
106 "music source for the channel will be used. Always returns 0.\n";
108 static char *descrip4 = "StopMusicOnHold: "
109 "Stops playing music on hold.\n";
111 static int respawn_time = 20;
113 struct moh_files_state {
114 struct mohclass *class;
119 unsigned char save_pos;
122 #define MOH_QUIET (1 << 0)
123 #define MOH_SINGLE (1 << 1)
124 #define MOH_CUSTOM (1 << 2)
125 #define MOH_RANDOMIZE (1 << 3)
128 char name[MAX_MUSICCLASS];
132 /*! A dynamically sized array to hold the list of filenames in "files" mode */
134 /*! The current size of the filearray */
136 /*! The current number of files loaded into the filearray */
139 /*! The format from the MOH source, not applicable to "files" mode */
141 /*! The pid of the external application delivering MOH */
145 /*! Source of audio */
147 /*! FD for timing source */
149 AST_LIST_HEAD_NOLOCK(, mohdata) members;
150 AST_LIST_ENTRY(mohclass) list;
156 struct mohclass *parent;
158 AST_LIST_ENTRY(mohdata) list;
161 AST_LIST_HEAD_STATIC(mohclasses, mohclass);
163 #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
164 #define MPG_123 "/usr/bin/mpg123"
168 static void ast_moh_free_class(struct mohclass **mohclass)
170 struct mohdata *member;
171 struct mohclass *class = *mohclass;
174 while ((member = AST_LIST_REMOVE_HEAD(&class->members, list)))
178 pthread_cancel(class->thread);
182 if (class->filearray) {
183 for (i = 0; i < class->total_files; i++)
184 free(class->filearray[i]);
185 free(class->filearray);
193 static void moh_files_release(struct ast_channel *chan, void *data)
195 struct moh_files_state *state = chan->music_state;
199 ast_closestream(chan->stream);
202 if (option_verbose > 2)
203 ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
205 if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
206 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt);
208 state->save_pos = state->pos;
213 static int ast_moh_files_next(struct ast_channel *chan)
215 struct moh_files_state *state = chan->music_state;
218 if (state->save_pos) {
219 state->pos = state->save_pos;
225 ast_closestream(chan->stream);
228 state->pos %= state->class->total_files;
231 if (ast_test_flag(state->class, MOH_RANDOMIZE)) {
232 /* Try 20 times to find something good */
233 for (tries = 0; tries < 20; tries++) {
234 state->pos = rand() % state->class->total_files;
236 /* check to see if this file's format can be opened */
237 if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) > 0)
242 if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
243 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
245 state->pos %= state->class->total_files;
250 ast_log(LOG_DEBUG, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]);
253 ast_seekstream(chan->stream, state->samples, SEEK_SET);
259 static struct ast_frame *moh_files_readframe(struct ast_channel *chan)
261 struct ast_frame *f = NULL;
263 if (!(chan->stream && (f = ast_readframe(chan->stream)))) {
264 if (!ast_moh_files_next(chan))
265 f = ast_readframe(chan->stream);
271 static int moh_files_generator(struct ast_channel *chan, void *data, int len, int samples)
273 struct moh_files_state *state = chan->music_state;
274 struct ast_frame *f = NULL;
277 state->sample_queue += samples;
279 while (state->sample_queue > 0) {
280 if ((f = moh_files_readframe(chan))) {
281 state->samples += f->samples;
282 res = ast_write(chan, f);
283 state->sample_queue -= f->samples;
286 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
296 static void *moh_files_alloc(struct ast_channel *chan, void *params)
298 struct moh_files_state *state;
299 struct mohclass *class = params;
301 if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) {
302 chan->music_state = state;
303 state->class = class;
305 state = chan->music_state;
308 if (state->class != class) {
310 memset(state, 0, sizeof(*state));
311 state->class = class;
312 if (ast_test_flag(state->class, MOH_RANDOMIZE))
313 state->pos = ast_random() % class->total_files;
316 state->origwfmt = chan->writeformat;
318 if (option_verbose > 2)
319 ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->name, chan->name);
322 return chan->music_state;
325 static struct ast_generator moh_file_stream =
327 alloc: moh_files_alloc,
328 release: moh_files_release,
329 generate: moh_files_generator,
332 static int spawn_mp3(struct mohclass *class)
336 char fns[MAX_MP3S][80];
337 char *argv[MAX_MP3S + 50];
343 sigset_t signal_set, old_set;
346 if (!strcasecmp(class->dir, "nodir")) {
349 dir = opendir(class->dir);
350 if (!dir && !strstr(class->dir,"http://") && !strstr(class->dir,"HTTP://")) {
351 ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
356 if (!ast_test_flag(class, MOH_CUSTOM)) {
357 argv[argc++] = "mpg123";
360 argv[argc++] = "--mono";
362 argv[argc++] = "8000";
364 if (!ast_test_flag(class, MOH_SINGLE)) {
366 argv[argc++] = "2048";
371 if (ast_test_flag(class, MOH_QUIET))
372 argv[argc++] = "4096";
374 argv[argc++] = "8192";
376 /* Look for extra arguments and add them to the list */
377 ast_copy_string(xargs, class->args, sizeof(xargs));
379 while (!ast_strlen_zero(argptr)) {
380 argv[argc++] = argptr;
381 strsep(&argptr, ",");
384 /* Format arguments for argv vector */
385 ast_copy_string(xargs, class->args, sizeof(xargs));
387 while (!ast_strlen_zero(argptr)) {
388 argv[argc++] = argptr;
389 strsep(&argptr, " ");
394 if (strstr(class->dir,"http://") || strstr(class->dir,"HTTP://")) {
395 ast_copy_string(fns[files], class->dir, sizeof(fns[files]));
396 argv[argc++] = fns[files];
399 while ((de = readdir(dir)) && (files < MAX_MP3S)) {
400 if ((strlen(de->d_name) > 3) &&
401 ((ast_test_flag(class, MOH_CUSTOM) &&
402 (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") ||
403 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) ||
404 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
405 ast_copy_string(fns[files], de->d_name, sizeof(fns[files]));
406 argv[argc++] = fns[files];
416 ast_log(LOG_WARNING, "Pipe failed\n");
420 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
425 if (time(NULL) - class->start < respawn_time) {
426 sleep(respawn_time - (time(NULL) - class->start));
429 /* Block signals during the fork() */
430 sigfillset(&signal_set);
431 pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
435 if (class->pid < 0) {
438 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
444 if (ast_opt_high_priority)
447 /* Reset ignored signals back to default */
448 signal(SIGPIPE, SIG_DFL);
449 pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
452 /* Stdout goes to pipe */
453 dup2(fds[1], STDOUT_FILENO);
454 /* Close unused file descriptors */
455 for (x=3;x<8192;x++) {
456 if (-1 != fcntl(x, F_GETFL)) {
462 if (ast_test_flag(class, MOH_CUSTOM)) {
463 execv(argv[0], argv);
465 /* Default install is /usr/local/bin */
466 execv(LOCAL_MPG_123, argv);
467 /* Many places have it in /usr/bin */
468 execv(MPG_123, argv);
469 /* Check PATH as a last-ditch effort */
470 execvp("mpg123", argv);
472 ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
477 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
483 static void *monmp3thread(void *data)
485 #define MOH_MS_INTERVAL 100
487 struct mohclass *class = data;
493 struct timeval tv, tv_tmp;
498 pthread_testcancel();
499 /* Spawn mp3 player if it's not there */
500 if (class->srcfd < 0) {
501 if ((class->srcfd = spawn_mp3(class)) < 0) {
502 ast_log(LOG_WARNING, "Unable to spawn mp3player\n");
503 /* Try again later */
505 pthread_testcancel();
508 if (class->pseudofd > -1) {
509 /* Pause some amount of time */
510 res = read(class->pseudofd, buf, sizeof(buf));
511 pthread_testcancel();
515 tv_tmp = ast_tvnow();
518 delta = ast_tvdiff_ms(tv_tmp, tv);
519 if (delta < MOH_MS_INTERVAL) { /* too early */
520 tv = ast_tvadd(tv, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */
521 usleep(1000 * (MOH_MS_INTERVAL - delta));
522 pthread_testcancel();
524 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
527 res = 8 * MOH_MS_INTERVAL; /* 8 samples per millisecond */
529 if (AST_LIST_EMPTY(&class->members))
532 len = ast_codec_get_len(class->format, res);
534 if ((res2 = read(class->srcfd, sbuf, len)) != len) {
538 pthread_testcancel();
539 if (class->pid > 1) {
540 kill(class->pid, SIGHUP);
542 kill(class->pid, SIGTERM);
544 kill(class->pid, SIGKILL);
549 ast_log(LOG_DEBUG, "Read %d bytes of audio while expecting %d\n", res2, len);
553 pthread_testcancel();
554 AST_LIST_LOCK(&mohclasses);
555 AST_LIST_TRAVERSE(&class->members, moh, list) {
557 if ((res = write(moh->pipe[1], sbuf, res2)) != res2) {
559 ast_log(LOG_DEBUG, "Only wrote %d of %d bytes to pipe\n", res, res2);
562 AST_LIST_UNLOCK(&mohclasses);
567 static int moh0_exec(struct ast_channel *chan, void *data)
569 if (ast_moh_start(chan, data, NULL)) {
570 ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
573 while (!ast_safe_sleep(chan, 10000));
578 static int moh1_exec(struct ast_channel *chan, void *data)
581 if (!data || !atoi(data)) {
582 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
585 if (ast_moh_start(chan, NULL, NULL)) {
586 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name);
589 res = ast_safe_sleep(chan, atoi(data) * 1000);
594 static int moh2_exec(struct ast_channel *chan, void *data)
596 if (ast_strlen_zero(data)) {
597 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
600 ast_string_field_set(chan, musicclass, data);
604 static int moh3_exec(struct ast_channel *chan, void *data)
607 if (data && strlen(data))
609 if (ast_moh_start(chan, class, NULL))
610 ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name);
615 static int moh4_exec(struct ast_channel *chan, void *data)
622 /*! \note This function should be called with the mohclasses list locked */
623 static struct mohclass *get_mohbyname(const char *name)
625 struct mohclass *moh = NULL;
627 AST_LIST_TRAVERSE(&mohclasses, moh, list) {
628 if (!strcasecmp(name, moh->name))
635 static struct mohdata *mohalloc(struct mohclass *cl)
640 if (!(moh = ast_calloc(1, sizeof(*moh))))
643 if (pipe(moh->pipe)) {
644 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
649 /* Make entirely non-blocking */
650 flags = fcntl(moh->pipe[0], F_GETFL);
651 fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
652 flags = fcntl(moh->pipe[1], F_GETFL);
653 fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
655 moh->f.frametype = AST_FRAME_VOICE;
656 moh->f.subclass = cl->format;
657 moh->f.offset = AST_FRIENDLY_OFFSET;
660 AST_LIST_INSERT_HEAD(&cl->members, moh, list);
665 static void moh_release(struct ast_channel *chan, void *data)
667 struct mohdata *moh = data;
670 AST_LIST_LOCK(&mohclasses);
671 AST_LIST_REMOVE(&moh->parent->members, moh, list);
672 AST_LIST_UNLOCK(&mohclasses);
676 oldwfmt = moh->origwfmt;
679 if (oldwfmt && ast_set_write_format(chan, oldwfmt))
680 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
681 if (option_verbose > 2)
682 ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
686 static void *moh_alloc(struct ast_channel *chan, void *params)
689 struct mohclass *class = params;
691 if ((res = mohalloc(class))) {
692 res->origwfmt = chan->writeformat;
693 if (ast_set_write_format(chan, class->format)) {
694 ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format));
695 moh_release(NULL, res);
698 if (option_verbose > 2)
699 ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name);
704 static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
706 struct mohdata *moh = data;
707 short buf[1280 + AST_FRIENDLY_OFFSET / 2];
710 if (!moh->parent->pid)
713 len = ast_codec_get_len(moh->parent->format, samples);
715 if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
716 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name);
717 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
719 res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
723 moh->f.datalen = res;
724 moh->f.data = buf + AST_FRIENDLY_OFFSET / 2;
725 moh->f.samples = ast_codec_get_samples(&moh->f);
727 if (ast_write(chan, &moh->f) < 0) {
728 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
735 static struct ast_generator mohgen =
738 release: moh_release,
739 generate: moh_generate,
742 static int moh_add_file(struct mohclass *class, const char *filepath)
744 if (!class->allowed_files) {
745 if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray))))
747 class->allowed_files = INITIAL_NUM_FILES;
748 } else if (class->total_files == class->allowed_files) {
749 if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) {
750 class->allowed_files = 0;
751 class->total_files = 0;
754 class->allowed_files *= 2;
757 if (!(class->filearray[class->total_files] = ast_strdup(filepath)))
760 class->total_files++;
765 static int moh_scan_files(struct mohclass *class) {
768 struct dirent *files_dirent;
770 char filepath[PATH_MAX];
776 files_DIR = opendir(class->dir);
778 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", class->dir);
782 for (i = 0; i < class->total_files; i++)
783 free(class->filearray[i]);
785 class->total_files = 0;
786 dirnamelen = strlen(class->dir) + 2;
787 getcwd(path, sizeof(path));
789 while ((files_dirent = readdir(files_DIR))) {
790 /* The file name must be at least long enough to have the file type extension */
791 if ((strlen(files_dirent->d_name) < 4))
794 /* Skip files that starts with a dot */
795 if (files_dirent->d_name[0] == '.')
798 /* Skip files without extensions... they are not audio */
799 if (!strchr(files_dirent->d_name, '.'))
802 snprintf(filepath, sizeof(filepath), "%s/%s", class->dir, files_dirent->d_name);
804 if (stat(filepath, &statbuf))
807 if (!S_ISREG(statbuf.st_mode))
810 if ((ext = strrchr(filepath, '.'))) {
815 /* if the file is present in multiple formats, ensure we only put it into the list once */
816 for (i = 0; i < class->total_files; i++)
817 if (!strcmp(filepath, class->filearray[i]))
820 if (i == class->total_files) {
821 if (moh_add_file(class, filepath))
828 return class->total_files;
831 static int moh_register(struct mohclass *moh, int reload)
836 AST_LIST_LOCK(&mohclasses);
837 if (get_mohbyname(moh->name)) {
840 ast_log(LOG_DEBUG, "Music on Hold class '%s' left alone from initial load.\n", moh->name);
842 ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
845 AST_LIST_UNLOCK(&mohclasses);
848 AST_LIST_UNLOCK(&mohclasses);
851 moh->start -= respawn_time;
853 if (!strcasecmp(moh->mode, "files")) {
854 if (!moh_scan_files(moh)) {
855 ast_moh_free_class(&moh);
858 if (strchr(moh->args, 'r'))
859 ast_set_flag(moh, MOH_RANDOMIZE);
860 } else if (!strcasecmp(moh->mode, "mp3") || !strcasecmp(moh->mode, "mp3nb") || !strcasecmp(moh->mode, "quietmp3") || !strcasecmp(moh->mode, "quietmp3nb") || !strcasecmp(moh->mode, "httpmp3") || !strcasecmp(moh->mode, "custom")) {
862 if (!strcasecmp(moh->mode, "custom"))
863 ast_set_flag(moh, MOH_CUSTOM);
864 else if (!strcasecmp(moh->mode, "mp3nb"))
865 ast_set_flag(moh, MOH_SINGLE);
866 else if (!strcasecmp(moh->mode, "quietmp3nb"))
867 ast_set_flag(moh, MOH_SINGLE | MOH_QUIET);
868 else if (!strcasecmp(moh->mode, "quietmp3"))
869 ast_set_flag(moh, MOH_QUIET);
873 /* Open /dev/zap/pseudo for timing... Is
874 there a better, yet reliable way to do this? */
875 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
876 if (moh->pseudofd < 0) {
877 ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n");
880 ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
885 if (ast_pthread_create_background(&moh->thread, NULL, monmp3thread, moh)) {
886 ast_log(LOG_WARNING, "Unable to create moh...\n");
887 if (moh->pseudofd > -1)
888 close(moh->pseudofd);
889 ast_moh_free_class(&moh);
893 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
894 ast_moh_free_class(&moh);
898 AST_LIST_LOCK(&mohclasses);
899 AST_LIST_INSERT_HEAD(&mohclasses, moh, list);
900 AST_LIST_UNLOCK(&mohclasses);
905 static void local_ast_moh_cleanup(struct ast_channel *chan)
907 if (chan->music_state) {
908 free(chan->music_state);
909 chan->music_state = NULL;
913 static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
915 struct mohclass *mohclass;
918 /* The following is the order of preference for which class to use:
919 * 1) The channels explicitly set musicclass, which should *only* be
920 * set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
921 * 2) The mclass argument. If a channel is calling ast_moh_start() as the
922 * result of receiving a HOLD control frame, this should be the
923 * payload that came with the frame.
924 * 3) The interpclass argument. This would be from the mohinterpret
925 * option from channel drivers. This is the same as the old musicclass
927 * 4) The default class.
929 if (!ast_strlen_zero(chan->musicclass))
930 class = chan->musicclass;
931 else if (!ast_strlen_zero(mclass))
933 else if (!ast_strlen_zero(interpclass))
938 AST_LIST_LOCK(&mohclasses);
939 mohclass = get_mohbyname(class);
940 AST_LIST_UNLOCK(&mohclasses);
943 ast_log(LOG_WARNING, "No class: %s\n", class);
947 ast_set_flag(chan, AST_FLAG_MOH);
948 if (mohclass->total_files) {
949 return ast_activate_generator(chan, &moh_file_stream, mohclass);
951 return ast_activate_generator(chan, &mohgen, mohclass);
954 static void local_ast_moh_stop(struct ast_channel *chan)
956 ast_clear_flag(chan, AST_FLAG_MOH);
957 ast_deactivate_generator(chan);
959 if (chan->music_state) {
961 ast_closestream(chan->stream);
967 static struct mohclass *moh_class_malloc(void)
969 struct mohclass *class;
971 if ((class = ast_calloc(1, sizeof(*class))))
972 class->format = AST_FORMAT_SLINEAR;
977 static int load_moh_classes(int reload)
979 struct ast_config *cfg;
980 struct ast_variable *var;
981 struct mohclass *class;
985 cfg = ast_config_load("musiconhold.conf");
990 cat = ast_category_browse(cfg, NULL);
991 for (; cat; cat = ast_category_browse(cfg, cat)) {
992 /* These names were deprecated in 1.4 and should not be used until after the next major release. */
993 if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) {
994 if (!(class = moh_class_malloc())) {
997 ast_copy_string(class->name, cat, sizeof(class->name));
998 var = ast_variable_browse(cfg, cat);
1000 if (!strcasecmp(var->name, "mode"))
1001 ast_copy_string(class->mode, var->value, sizeof(class->mode));
1002 else if (!strcasecmp(var->name, "directory"))
1003 ast_copy_string(class->dir, var->value, sizeof(class->dir));
1004 else if (!strcasecmp(var->name, "application"))
1005 ast_copy_string(class->args, var->value, sizeof(class->args));
1006 else if (!strcasecmp(var->name, "random"))
1007 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
1008 else if (!strcasecmp(var->name, "format")) {
1009 class->format = ast_getformatbyname(var->value);
1010 if (!class->format) {
1011 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
1012 class->format = AST_FORMAT_SLINEAR;
1018 if (ast_strlen_zero(class->dir)) {
1019 if (!strcasecmp(class->mode, "custom")) {
1020 strcpy(class->dir, "nodir");
1022 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
1027 if (ast_strlen_zero(class->mode)) {
1028 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
1032 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
1033 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
1038 /* Don't leak a class when it's already registered */
1039 moh_register(class, reload);
1045 ast_config_destroy(cfg);
1050 static void ast_moh_destroy(void)
1052 struct mohclass *moh;
1054 int bytes, tbytes = 0, stime = 0, pid = 0;
1056 if (option_verbose > 1)
1057 ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
1059 AST_LIST_LOCK(&mohclasses);
1060 while ((moh = AST_LIST_REMOVE_HEAD(&mohclasses, list))) {
1063 ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
1064 stime = time(NULL) + 2;
1067 /* Back when this was just mpg123, SIGKILL was fine. Now we need
1068 * to give the process a reason and time enough to kill off its
1075 while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime)
1076 tbytes = tbytes + bytes;
1078 ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
1081 ast_moh_free_class(&moh);
1083 AST_LIST_UNLOCK(&mohclasses);
1086 static void moh_on_off(int on)
1088 struct ast_channel *chan = NULL;
1090 while ( (chan = ast_channel_walk_locked(chan)) != NULL) {
1091 if (ast_test_flag(chan, AST_FLAG_MOH)) {
1093 local_ast_moh_start(chan, NULL, NULL);
1095 ast_deactivate_generator(chan);
1097 ast_channel_unlock(chan);
1101 static int moh_cli(int fd, int argc, char *argv[])
1107 x = load_moh_classes(1);
1109 ast_cli(fd, "\n%d class%s reloaded.\n", x, x == 1 ? "" : "es");
1113 static int cli_files_show(int fd, int argc, char *argv[])
1116 struct mohclass *class;
1118 AST_LIST_LOCK(&mohclasses);
1119 AST_LIST_TRAVERSE(&mohclasses, class, list) {
1120 if (!class->total_files)
1123 ast_cli(fd, "Class: %s\n", class->name);
1124 for (i = 0; i < class->total_files; i++)
1125 ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
1127 AST_LIST_UNLOCK(&mohclasses);
1132 static int moh_classes_show(int fd, int argc, char *argv[])
1134 struct mohclass *class;
1136 AST_LIST_LOCK(&mohclasses);
1137 AST_LIST_TRAVERSE(&mohclasses, class, list) {
1138 ast_cli(fd, "Class: %s\n", class->name);
1139 ast_cli(fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
1140 ast_cli(fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
1141 if (ast_test_flag(class, MOH_CUSTOM))
1142 ast_cli(fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
1143 if (strcasecmp(class->mode, "files"))
1144 ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format));
1146 AST_LIST_UNLOCK(&mohclasses);
1151 static struct ast_cli_entry cli_moh[] = {
1152 { { "moh", "reload"},
1153 moh_cli, "Music On Hold",
1156 { { "moh", "show", "classes"},
1157 moh_classes_show, "List MOH classes",
1158 "Lists all MOH classes" },
1160 { { "moh", "show", "files"},
1161 cli_files_show, "List MOH file-based classes",
1162 "Lists all loaded file-based MOH classes and their files" },
1165 static int init_classes(int reload)
1167 struct mohclass *moh;
1169 if (!load_moh_classes(reload)) /* Load classes from config */
1170 return 0; /* Return if nothing is found */
1172 AST_LIST_LOCK(&mohclasses);
1173 AST_LIST_TRAVERSE(&mohclasses, moh, list) {
1174 if (moh->total_files)
1175 moh_scan_files(moh);
1177 AST_LIST_UNLOCK(&mohclasses);
1182 static int load_module(void)
1186 res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
1187 ast_register_atexit(ast_moh_destroy);
1188 ast_cli_register_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry));
1190 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
1192 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
1194 res = ast_register_application(app3, moh3_exec, synopsis3, descrip3);
1196 res = ast_register_application(app4, moh4_exec, synopsis4, descrip4);
1198 if (!init_classes(0)) { /* No music classes configured, so skip it */
1199 ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold.\n");
1201 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1207 static int reload(void)
1209 if (init_classes(1))
1210 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1215 static int unload_module(void)
1220 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Music On Hold Resource",
1221 .load = load_module,
1222 .unload = unload_module,