2 * Asterisk -- A telephony toolkit for Linux.
4 * Routines implementing music on hold
6 * Copyright (C) 1999 - 2005, Digium, Inc.
8 * Mark Spencer <markster@digium.com>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
22 #include <sys/signal.h>
23 #include <netinet/in.h>
28 #include <linux/zaptel.h>
31 #endif /* __linux__ */
34 #include <sys/ioctl.h>
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
40 #include "asterisk/lock.h"
41 #include "asterisk/file.h"
42 #include "asterisk/logger.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/pbx.h"
45 #include "asterisk/options.h"
46 #include "asterisk/module.h"
47 #include "asterisk/translate.h"
48 #include "asterisk/say.h"
49 #include "asterisk/musiconhold.h"
50 #include "asterisk/config.h"
51 #include "asterisk/utils.h"
52 #include "asterisk/cli.h"
54 #define MAX_MOHFILES 512
55 #define MAX_MOHFILE_LEN 128
57 static char *app0 = "MusicOnHold";
58 static char *app1 = "WaitMusicOnHold";
59 static char *app2 = "SetMusicOnHold";
60 static char *app3 = "StartMusicOnHold";
61 static char *app4 = "StopMusicOnHold";
63 static char *synopsis0 = "Play Music On Hold indefinitely";
64 static char *synopsis1 = "Wait, playing Music On Hold";
65 static char *synopsis2 = "Set default Music On Hold class";
66 static char *synopsis3 = "Play Music On Hold";
67 static char *synopsis4 = "Stop Playing Music On Hold";
69 static char *descrip0 = "MusicOnHold(class): "
70 "Plays hold music specified by class. If omitted, the default\n"
71 "music source for the channel will be used. Set the default \n"
72 "class with the SetMusicOnHold() application.\n"
73 "Returns -1 on hangup.\n"
74 "Never returns otherwise.\n";
76 static char *descrip1 = "WaitMusicOnHold(delay): "
77 "Plays hold music specified number of seconds. Returns 0 when\n"
78 "done, or -1 on hangup. If no hold music is available, the delay will\n"
79 "still occur with no sound.\n";
81 static char *descrip2 = "SetMusicOnHold(class): "
82 "Sets the default class for music on hold for a given channel. When\n"
83 "music on hold is activated, this class will be used to select which\n"
86 static char *descrip3 = "StartMusicOnHold(class): "
87 "Starts playing music on hold, uses default music class for channel.\n"
88 "Starts playing music specified by class. If omitted, the default\n"
89 "music source for the channel will be used. Always returns 0.\n";
91 static char *descrip4 = "StopMusicOnHold: "
92 "Stops playing music on hold.\n";
94 static int respawn_time = 20;
96 struct moh_files_state {
97 struct mohclass *class;
102 unsigned char save_pos;
105 #define MOH_QUIET (1 << 0)
106 #define MOH_SINGLE (1 << 1)
107 #define MOH_CUSTOM (1 << 2)
108 #define MOH_RANDOMIZE (1 << 3)
111 char name[MAX_MUSICCLASS];
115 char filearray[MAX_MOHFILES][MAX_MOHFILE_LEN];
119 int pid; /* PID of mpg123 */
122 struct mohdata *members;
123 /* Source of audio */
125 /* FD for timing source */
127 struct mohclass *next;
133 struct mohclass *parent;
134 struct mohdata *next;
137 static struct mohclass *mohclasses;
139 AST_MUTEX_DEFINE_STATIC(moh_lock);
141 #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
142 #define MPG_123 "/usr/bin/mpg123"
146 static void ast_moh_free_class(struct mohclass **class)
148 struct mohdata *members, *mtmp;
150 members = (*class)->members;
153 members = members->next;
161 static void moh_files_release(struct ast_channel *chan, void *data)
163 struct moh_files_state *state = chan->music_state;
166 if (option_verbose > 2)
167 ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
169 if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
170 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt);
172 state->save_pos = state->pos + 1;
177 static int ast_moh_files_next(struct ast_channel *chan)
179 struct moh_files_state *state = chan->music_state;
182 if (state->save_pos) {
183 state->pos = state->save_pos - 1;
186 /* Try 20 times to find something good */
187 for (tries=0;tries < 20;tries++) {
190 ast_closestream(chan->stream);
195 if (ast_test_flag(state->class, MOH_RANDOMIZE))
198 /* check to see if this file's format can be opened */
199 if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) != -1)
205 state->pos = state->pos % state->class->total_files;
207 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
208 ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
211 if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
212 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
218 ast_log(LOG_DEBUG, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]);
221 ast_seekstream(chan->stream, state->samples, SEEK_SET);
227 static struct ast_frame *moh_files_readframe(struct ast_channel *chan)
229 struct ast_frame *f = NULL;
231 if (!(chan->stream && (f = ast_readframe(chan->stream)))) {
232 if (!ast_moh_files_next(chan))
233 f = ast_readframe(chan->stream);
239 static int moh_files_generator(struct ast_channel *chan, void *data, int len, int samples)
241 struct moh_files_state *state = chan->music_state;
242 struct ast_frame *f = NULL;
244 state->sample_queue += samples;
246 while (state->sample_queue > 0) {
247 if ((f = moh_files_readframe(chan))) {
248 state->samples += f->samples;
249 res = ast_write(chan, f);
252 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
255 state->sample_queue -= f->samples;
263 static void *moh_files_alloc(struct ast_channel *chan, void *params)
265 struct moh_files_state *state;
266 struct mohclass *class = params;
269 if (!chan->music_state && (state = malloc(sizeof(struct moh_files_state)))) {
270 chan->music_state = state;
273 state = chan->music_state;
276 if (allocated || state->class != class) {
278 memset(state, 0, sizeof(struct moh_files_state));
279 state->class = class;
282 state->origwfmt = chan->writeformat;
284 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
285 ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
286 free(chan->music_state);
287 chan->music_state = NULL;
289 if (option_verbose > 2)
290 ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->name, chan->name);
294 return chan->music_state;
297 static struct ast_generator moh_file_stream =
299 alloc: moh_files_alloc,
300 release: moh_files_release,
301 generate: moh_files_generator,
304 static int spawn_mp3(struct mohclass *class)
308 char fns[MAX_MP3S][80];
309 char *argv[MAX_MP3S + 50];
317 if (!strcasecmp(class->dir, "nodir")) {
320 dir = opendir(class->dir);
321 if (!dir && !strstr(class->dir,"http://") && !strstr(class->dir,"HTTP://")) {
322 ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
327 if (!ast_test_flag(class, MOH_CUSTOM)) {
328 argv[argc++] = "mpg123";
331 argv[argc++] = "--mono";
333 argv[argc++] = "8000";
335 if (!ast_test_flag(class, MOH_SINGLE)) {
337 argv[argc++] = "2048";
342 if (ast_test_flag(class, MOH_QUIET))
343 argv[argc++] = "4096";
345 argv[argc++] = "8192";
347 /* Look for extra arguments and add them to the list */
348 strncpy(xargs, class->args, sizeof(xargs) - 1);
350 while (argptr && !ast_strlen_zero(argptr)) {
351 argv[argc++] = argptr;
352 argptr = strchr(argptr, ',');
359 /* Format arguments for argv vector */
360 strncpy(xargs, class->args, sizeof(xargs) - 1);
362 while (argptr && !ast_strlen_zero(argptr)) {
363 argv[argc++] = argptr;
364 argptr = strchr(argptr, ' ');
373 if (strstr(class->dir,"http://") || strstr(class->dir,"HTTP://")) {
374 strncpy(fns[files], class->dir, sizeof(fns[files]) - 1);
375 argv[argc++] = fns[files];
378 while ((de = readdir(dir)) && (files < MAX_MP3S)) {
379 if ((strlen(de->d_name) > 3) &&
380 ((ast_test_flag(class, MOH_CUSTOM) &&
381 (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") ||
382 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) ||
383 !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
384 strncpy(fns[files], de->d_name, sizeof(fns[files]) - 1);
385 argv[argc++] = fns[files];
395 ast_log(LOG_WARNING, "Pipe failed\n");
399 printf("%d files total, %d args total\n", files, argc);
402 for (x=0;argv[x];x++)
403 printf("arg%d: %s\n", x, argv[x]);
407 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
412 if (time(NULL) - class->start < respawn_time) {
413 sleep(respawn_time - (time(NULL) - class->start));
417 if (class->pid < 0) {
420 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
426 /* Stdout goes to pipe */
427 dup2(fds[1], STDOUT_FILENO);
428 /* Close unused file descriptors */
429 for (x=3;x<8192;x++) {
430 if (-1 != fcntl(x, F_GETFL)) {
436 if (ast_test_flag(class, MOH_CUSTOM)) {
437 execv(argv[0], argv);
439 /* Default install is /usr/local/bin */
440 execv(LOCAL_MPG_123, argv);
441 /* Many places have it in /usr/bin */
442 execv(MPG_123, argv);
443 /* Check PATH as a last-ditch effort */
444 execvp("mpg123", argv);
446 ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
456 static void *monmp3thread(void *data)
458 #define MOH_MS_INTERVAL 100
460 struct mohclass *class = data;
466 struct timeval tv, tv_tmp;
471 /* Spawn mp3 player if it's not there */
472 if (class->srcfd < 0) {
473 if ((class->srcfd = spawn_mp3(class)) < 0) {
474 ast_log(LOG_WARNING, "Unable to spawn mp3player\n");
475 /* Try again later */
479 if (class->pseudofd > -1) {
480 /* Pause some amount of time */
481 res = read(class->pseudofd, buf, sizeof(buf));
485 tv_tmp = ast_tvnow();
488 delta = ast_tvdiff_ms(tv_tmp, tv);
489 if (delta < MOH_MS_INTERVAL) { /* too early */
490 tv = ast_tvadd(tv, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */
491 usleep(1000 * (MOH_MS_INTERVAL - delta));
493 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
496 res = 8 * MOH_MS_INTERVAL; /* 8 samples per millisecond */
501 len = ast_codec_get_len(class->format, res);
503 if ((res2 = read(class->srcfd, sbuf, len)) != len) {
508 kill(class->pid, SIGKILL);
512 ast_log(LOG_DEBUG, "Read %d bytes of audio while expecting %d\n", res2, len);
515 ast_mutex_lock(&moh_lock);
516 moh = class->members;
519 if ((res = write(moh->pipe[1], sbuf, res2)) != res2)
521 ast_log(LOG_DEBUG, "Only wrote %d of %d bytes to pipe\n", res, res2);
524 ast_mutex_unlock(&moh_lock);
529 static int moh0_exec(struct ast_channel *chan, void *data)
531 if (ast_moh_start(chan, data)) {
532 ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
535 while (!ast_safe_sleep(chan, 10000));
540 static int moh1_exec(struct ast_channel *chan, void *data)
543 if (!data || !atoi(data)) {
544 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
547 if (ast_moh_start(chan, NULL)) {
548 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name);
551 res = ast_safe_sleep(chan, atoi(data) * 1000);
556 static int moh2_exec(struct ast_channel *chan, void *data)
558 if (!data || ast_strlen_zero(data)) {
559 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
562 strncpy(chan->musicclass, data, sizeof(chan->musicclass) - 1);
566 static int moh3_exec(struct ast_channel *chan, void *data)
569 if (data && strlen(data))
571 if (ast_moh_start(chan, class))
572 ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name);
577 static int moh4_exec(struct ast_channel *chan, void *data)
584 static struct mohclass *get_mohbyname(char *name)
586 struct mohclass *moh;
589 if (!strcasecmp(name, moh->name))
596 static struct mohdata *mohalloc(struct mohclass *cl)
600 moh = malloc(sizeof(struct mohdata));
603 memset(moh, 0, sizeof(struct mohdata));
604 if (pipe(moh->pipe)) {
605 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
609 /* Make entirely non-blocking */
610 flags = fcntl(moh->pipe[0], F_GETFL);
611 fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
612 flags = fcntl(moh->pipe[1], F_GETFL);
613 fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
615 moh->next = cl->members;
620 static void moh_release(struct ast_channel *chan, void *data)
622 struct mohdata *moh = data, *prev, *cur;
624 ast_mutex_lock(&moh_lock);
627 cur = moh->parent->members;
631 prev->next = cur->next;
633 moh->parent->members = cur->next;
639 ast_mutex_unlock(&moh_lock);
642 oldwfmt = moh->origwfmt;
645 if (oldwfmt && ast_set_write_format(chan, oldwfmt))
646 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
647 if (option_verbose > 2)
648 ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
652 static void *moh_alloc(struct ast_channel *chan, void *params)
655 struct mohclass *class = params;
657 res = mohalloc(class);
659 res->origwfmt = chan->writeformat;
660 if (ast_set_write_format(chan, class->format)) {
661 ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format));
662 moh_release(NULL, res);
665 if (option_verbose > 2)
666 ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name);
671 static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
674 struct mohdata *moh = data;
675 short buf[1280 + AST_FRIENDLY_OFFSET / 2];
678 if (!moh->parent->pid)
681 len = ast_codec_get_len(moh->parent->format, samples);
683 if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
684 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name);
685 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
687 res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
690 ast_log(LOG_WARNING, "Read only %d of %d bytes: %s\n", res, len, strerror(errno));
696 memset(&f, 0, sizeof(f));
698 f.frametype = AST_FRAME_VOICE;
699 f.subclass = moh->parent->format;
702 f.data = buf + AST_FRIENDLY_OFFSET / 2;
703 f.offset = AST_FRIENDLY_OFFSET;
704 f.samples = ast_codec_get_samples(&f);
706 if (ast_write(chan, &f) < 0) {
707 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
714 static struct ast_generator mohgen =
717 release: moh_release,
718 generate: moh_generate,
721 static int moh_scan_files(struct mohclass *class) {
724 struct dirent *files_dirent;
726 char filepath[MAX_MOHFILE_LEN];
732 files_DIR = opendir(class->dir);
734 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist", class->dir);
738 class->total_files = 0;
739 dirnamelen = strlen(class->dir) + 2;
742 memset(class->filearray, 0, MAX_MOHFILES*MAX_MOHFILE_LEN);
743 while ((files_dirent = readdir(files_DIR))) {
744 if ((strlen(files_dirent->d_name) < 4) || ((strlen(files_dirent->d_name) + dirnamelen) >= MAX_MOHFILE_LEN))
747 snprintf(filepath, MAX_MOHFILE_LEN, "%s/%s", class->dir, files_dirent->d_name);
749 if (stat(filepath, &statbuf))
752 if (!S_ISREG(statbuf.st_mode))
755 if ((ext = strrchr(filepath, '.'))) {
760 /* if the file is present in multiple formats, ensure we only put it into the list once */
761 for (i = 0; i < class->total_files; i++)
762 if (!strcmp(filepath, class->filearray[i]))
765 if (i == class->total_files)
766 strcpy(class->filearray[class->total_files++], filepath);
771 return class->total_files;
774 static int moh_register(struct mohclass *moh)
779 ast_mutex_lock(&moh_lock);
780 if (get_mohbyname(moh->name)) {
781 ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
783 ast_mutex_unlock(&moh_lock);
786 ast_mutex_unlock(&moh_lock);
789 moh->start -= respawn_time;
791 if (!strcasecmp(moh->mode, "files")) {
792 if (!moh_scan_files(moh)) {
793 ast_moh_free_class(&moh);
796 if (strchr(moh->args, 'r'))
797 ast_set_flag(moh, MOH_RANDOMIZE);
798 } 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")) {
800 if (!strcasecmp(moh->mode, "custom"))
801 ast_set_flag(moh, MOH_CUSTOM);
802 else if (!strcasecmp(moh->mode, "mp3nb"))
803 ast_set_flag(moh, MOH_SINGLE);
804 else if (!strcasecmp(moh->mode, "quietmp3nb"))
805 ast_set_flag(moh, MOH_SINGLE | MOH_QUIET);
806 else if (!strcasecmp(moh->mode, "quietmp3"))
807 ast_set_flag(moh, MOH_QUIET);
811 /* Open /dev/zap/pseudo for timing... Is
812 there a better, yet reliable way to do this? */
813 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
814 if (moh->pseudofd < 0) {
815 ast_log(LOG_WARNING, "Unable to open pseudo channel for timing... Sound may be choppy.\n");
818 ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
823 if (ast_pthread_create(&moh->thread, NULL, monmp3thread, moh)) {
824 ast_log(LOG_WARNING, "Unable to create moh...\n");
825 if (moh->pseudofd > -1)
826 close(moh->pseudofd);
827 ast_moh_free_class(&moh);
831 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
832 ast_moh_free_class(&moh);
835 ast_mutex_lock(&moh_lock);
836 moh->next = mohclasses;
838 ast_mutex_unlock(&moh_lock);
842 static void local_ast_moh_cleanup(struct ast_channel *chan)
844 if (chan->music_state) {
845 free(chan->music_state);
846 chan->music_state = NULL;
850 static int local_ast_moh_start(struct ast_channel *chan, char *class)
852 struct mohclass *mohclass;
854 if (!class || ast_strlen_zero(class))
855 class = chan->musicclass;
856 if (!class || ast_strlen_zero(class))
858 ast_mutex_lock(&moh_lock);
859 mohclass = get_mohbyname(class);
860 ast_mutex_unlock(&moh_lock);
863 ast_log(LOG_WARNING, "No class: %s\n", (char *)class);
867 ast_set_flag(chan, AST_FLAG_MOH);
868 if (mohclass->total_files) {
869 return ast_activate_generator(chan, &moh_file_stream, mohclass);
871 return ast_activate_generator(chan, &mohgen, mohclass);
874 static void local_ast_moh_stop(struct ast_channel *chan)
876 ast_clear_flag(chan, AST_FLAG_MOH);
877 ast_deactivate_generator(chan);
879 if (chan->music_state) {
881 ast_closestream(chan->stream);
887 static struct mohclass *moh_class_malloc(void)
889 struct mohclass *class;
891 class = malloc(sizeof(struct mohclass));
896 memset(class, 0, sizeof(struct mohclass));
898 class->format = AST_FORMAT_SLINEAR;
903 static int load_moh_classes(void)
905 struct ast_config *cfg;
906 struct ast_variable *var;
907 struct mohclass *class;
912 static int dep_warning = 0;
914 cfg = ast_config_load("musiconhold.conf");
919 cat = ast_category_browse(cfg, NULL);
920 for (; cat; cat = ast_category_browse(cfg, cat)) {
921 if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) {
922 class = moh_class_malloc();
924 ast_log(LOG_WARNING, "Out of memory!\n");
927 ast_copy_string(class->name, cat, sizeof(class->name));
928 var = ast_variable_browse(cfg, cat);
930 if (!strcasecmp(var->name, "mode"))
931 ast_copy_string(class->mode, var->value, sizeof(class->name));
932 else if (!strcasecmp(var->name, "directory"))
933 ast_copy_string(class->dir, var->value, sizeof(class->dir));
934 else if (!strcasecmp(var->name, "application"))
935 ast_copy_string(class->args, var->value, sizeof(class->args));
936 else if (!strcasecmp(var->name, "random"))
937 ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
938 else if (!strcasecmp(var->name, "format")) {
939 class->format = ast_getformatbyname(var->value);
940 if (!class->format) {
941 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
942 class->format = AST_FORMAT_SLINEAR;
948 if (ast_strlen_zero(class->dir)) {
949 if (!strcasecmp(class->mode, "custom")) {
950 strcpy(class->dir, "nodir");
952 ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
957 if (ast_strlen_zero(class->mode)) {
958 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
962 if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
963 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
974 /* Deprecated Old-School Configuration */
975 var = ast_variable_browse(cfg, "classes");
978 ast_log(LOG_WARNING, "The old musiconhold.conf syntax has been deprecated! Please refer to the sample configuration for information on the new syntax.\n");
981 data = strchr(var->value, ':');
984 args = strchr(data, ',');
987 if (!(get_mohbyname(var->name))) {
988 class = moh_class_malloc();
990 ast_log(LOG_WARNING, "Out of memory!\n");
994 ast_copy_string(class->name, var->name, sizeof(class->name));
995 ast_copy_string(class->dir, data, sizeof(class->dir));
996 ast_copy_string(class->mode, var->value, sizeof(class->mode));
998 ast_copy_string(class->args, args, sizeof(class->args));
1000 moh_register(class);
1006 var = ast_variable_browse(cfg, "moh_files");
1009 ast_log(LOG_WARNING, "The old musiconhold.conf syntax has been deprecated! Please refer to the sample configuration for information on the new syntax.\n");
1012 if (!(get_mohbyname(var->name))) {
1013 args = strchr(var->value, ',');
1016 class = moh_class_malloc();
1018 ast_log(LOG_WARNING, "Out of memory!\n");
1022 ast_copy_string(class->name, var->name, sizeof(class->name));
1023 ast_copy_string(class->dir, var->value, sizeof(class->dir));
1024 strcpy(class->mode, "files");
1026 ast_copy_string(class->args, args, sizeof(class->args));
1028 moh_register(class);
1034 ast_config_destroy(cfg);
1039 static void ast_moh_destroy(void)
1041 struct mohclass *moh, *tmp;
1043 int bytes, tbytes=0, stime = 0, pid = 0;
1045 if (option_verbose > 1)
1046 ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
1047 ast_mutex_lock(&moh_lock);
1052 ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
1053 stime = time(NULL) + 2;
1057 while ((ast_wait_for_input(moh->srcfd, 100) > -1) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime) {
1058 tbytes = tbytes + bytes;
1060 ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
1065 ast_moh_free_class(&tmp);
1068 ast_mutex_unlock(&moh_lock);
1071 static void moh_on_off(int on)
1073 struct ast_channel *chan = NULL;
1075 while ( (chan = ast_channel_walk_locked(chan)) != NULL) {
1076 if (ast_test_flag(chan, AST_FLAG_MOH)) {
1078 local_ast_moh_start(chan, NULL);
1080 ast_deactivate_generator(chan);
1082 ast_mutex_unlock(&chan->lock);
1086 static int moh_cli(int fd, int argc, char *argv[])
1092 x = load_moh_classes();
1094 ast_cli(fd, "\n%d class%s reloaded.\n", x, x == 1 ? "" : "es");
1098 static int cli_files_show(int fd, int argc, char *argv[])
1101 struct mohclass *class;
1103 ast_mutex_lock(&moh_lock);
1104 for (class = mohclasses; class; class = class->next) {
1105 if (!class->total_files)
1108 ast_cli(fd, "Class: %s\n", class->name);
1109 for (i = 0; i < class->total_files; i++)
1110 ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
1112 ast_mutex_unlock(&moh_lock);
1117 static int moh_classes_show(int fd, int argc, char *argv[])
1119 struct mohclass *class;
1121 ast_mutex_lock(&moh_lock);
1122 for (class = mohclasses; class; class = class->next) {
1123 ast_cli(fd, "Class: %s\n", class->name);
1124 ast_cli(fd, "\tMode: %s\n", ast_strlen_zero(class->mode) ? "<none>" : class->mode);
1125 ast_cli(fd, "\tDirectory: %s\n", ast_strlen_zero(class->dir) ? "<none>" : class->dir);
1126 if (ast_test_flag(class, MOH_CUSTOM))
1127 ast_cli(fd, "\tApplication: %s\n", ast_strlen_zero(class->args) ? "<none>" : class->args);
1128 ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format));
1130 ast_mutex_unlock(&moh_lock);
1135 static struct ast_cli_entry cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL};
1137 static struct ast_cli_entry cli_moh_classes_show = { { "moh", "classes", "show"}, moh_classes_show, "List MOH classes", "Lists all MOH classes", NULL};
1139 static struct ast_cli_entry cli_moh_files_show = { { "moh", "files", "show"}, cli_files_show, "List MOH file-based classes", "Lists all loaded file-based MOH classes and their files", NULL};
1141 static int init_classes(void)
1143 struct mohclass *moh;
1145 if (!load_moh_classes()) /* Load classes from config */
1146 return 0; /* Return if nothing is found */
1149 if (moh->total_files)
1150 moh_scan_files(moh);
1156 int load_module(void)
1160 res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
1161 ast_register_atexit(ast_moh_destroy);
1162 ast_cli_register(&cli_moh);
1163 ast_cli_register(&cli_moh_files_show);
1164 ast_cli_register(&cli_moh_classes_show);
1166 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
1168 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
1170 res = ast_register_application(app3, moh3_exec, synopsis3, descrip3);
1172 res = ast_register_application(app4, moh4_exec, synopsis4, descrip4);
1174 if (!init_classes()) { /* No music classes configured, so skip it */
1175 ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold.");
1177 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1186 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1191 int unload_module(void)
1196 char *description(void)
1198 return "Music On Hold Resource";
1203 /* Never allow Music On Hold to be unloaded
1204 unresolve needed symbols in the dialer */
1207 STANDARD_USECOUNT(res);
1216 return ASTERISK_GPL_KEY;