merge Russell's 'hold_handling' branch, finally implementing music-on-hold handling...
[asterisk/asterisk.git] / res / res_musiconhold.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
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.
13  *
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.
17  */
18
19 /*! \file
20  *
21  * \brief Routines implementing music on hold
22  *
23  * \arg See also \ref Config_moh
24  * 
25  * \author Mark Spencer <markster@digium.com>
26  */
27
28 /*** MODULEINFO
29         <conflict>win32</conflict>
30         <use>zaptel</use>
31  ***/
32
33 #include "asterisk.h"
34
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
36
37 #include <stdlib.h>
38 #include <errno.h>
39 #include <unistd.h>
40 #include <string.h>
41 #include <signal.h>
42 #include <stdlib.h>
43 #include <stdio.h>
44 #include <sys/time.h>
45 #include <sys/signal.h>
46 #include <netinet/in.h>
47 #include <sys/stat.h>
48 #include <dirent.h>
49 #include <unistd.h>
50 #include <sys/ioctl.h>
51
52 #ifdef HAVE_ZAPTEL
53 #include <zaptel/zaptel.h>
54 #endif
55
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"
71
72 #define INITIAL_NUM_FILES   8
73
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";
79
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";
85
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";
92
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";
97
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";
102
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";
107
108 static char *descrip4 = "StopMusicOnHold: "
109 "Stops playing music on hold.\n";
110
111 static int respawn_time = 20;
112
113 struct moh_files_state {
114         struct mohclass *class;
115         int origwfmt;
116         int samples;
117         int sample_queue;
118         unsigned char pos;
119         unsigned char save_pos;
120 };
121
122 #define MOH_QUIET               (1 << 0)
123 #define MOH_SINGLE              (1 << 1)
124 #define MOH_CUSTOM              (1 << 2)
125 #define MOH_RANDOMIZE           (1 << 3)
126
127 struct mohclass {
128         char name[MAX_MUSICCLASS];
129         char dir[256];
130         char args[256];
131         char mode[80];
132         /*! A dynamically sized array to hold the list of filenames in "files" mode */
133         char **filearray;
134         /*! The current size of the filearray */
135         int allowed_files;
136         /*! The current number of files loaded into the filearray */
137         int total_files;
138         unsigned int flags;
139         /*! The format from the MOH source, not applicable to "files" mode */
140         int format;
141         /*! The pid of the external application delivering MOH */
142         int pid;
143         time_t start;
144         pthread_t thread;
145         /*! Source of audio */
146         int srcfd;
147         /*! FD for timing source */
148         int pseudofd;
149         AST_LIST_HEAD_NOLOCK(, mohdata) members;
150         AST_LIST_ENTRY(mohclass) list;
151 };
152
153 struct mohdata {
154         int pipe[2];
155         int origwfmt;
156         struct mohclass *parent;
157         struct ast_frame f;
158         AST_LIST_ENTRY(mohdata) list;
159 };
160
161 AST_LIST_HEAD_STATIC(mohclasses, mohclass);
162
163 #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
164 #define MPG_123 "/usr/bin/mpg123"
165 #define MAX_MP3S 256
166
167
168 static void ast_moh_free_class(struct mohclass **mohclass) 
169 {
170         struct mohdata *member;
171         struct mohclass *class = *mohclass;
172         int i;
173         
174         while ((member = AST_LIST_REMOVE_HEAD(&class->members, list)))
175                 free(member);
176         
177         if (class->thread) {
178                 pthread_cancel(class->thread);
179                 class->thread = 0;
180         }
181
182         if (class->filearray) {
183                 for (i = 0; i < class->total_files; i++)
184                         free(class->filearray[i]);
185                 free(class->filearray);
186         }
187
188         free(class);
189         *mohclass = NULL;
190 }
191
192
193 static void moh_files_release(struct ast_channel *chan, void *data)
194 {
195         struct moh_files_state *state = chan->music_state;
196
197         if (chan && state) {
198                 if (option_verbose > 2)
199                         ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
200
201                 if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
202                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt);
203                 }
204                 state->save_pos = state->pos + 1;
205         }
206 }
207
208
209 static int ast_moh_files_next(struct ast_channel *chan) 
210 {
211         struct moh_files_state *state = chan->music_state;
212         int tries;
213
214         if (state->save_pos) {
215                 state->pos = state->save_pos - 1;
216                 state->save_pos = 0;
217         } else {
218                 /* Try 20 times to find something good */
219                 for (tries=0;tries < 20;tries++) {
220                         state->samples = 0;
221                         if (chan->stream) {
222                                 ast_closestream(chan->stream);
223                                 chan->stream = NULL;
224                                 state->pos++;
225                         }
226
227                         if (ast_test_flag(state->class, MOH_RANDOMIZE))
228                                 state->pos = ast_random();
229
230                         state->pos %= state->class->total_files;
231
232                         /* check to see if this file's format can be opened */
233                         if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) != -1)
234                                 break;
235
236                 }
237         }
238
239         state->pos = state->pos % state->class->total_files;
240         
241         if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
242                 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
243                 state->pos++;
244                 return -1;
245         }
246
247         if (option_debug)
248                 ast_log(LOG_DEBUG, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]);
249
250         if (state->samples)
251                 ast_seekstream(chan->stream, state->samples, SEEK_SET);
252
253         return 0;
254 }
255
256
257 static struct ast_frame *moh_files_readframe(struct ast_channel *chan) 
258 {
259         struct ast_frame *f = NULL;
260         
261         if (!(chan->stream && (f = ast_readframe(chan->stream)))) {
262                 if (!ast_moh_files_next(chan))
263                         f = ast_readframe(chan->stream);
264         }
265
266         return f;
267 }
268
269 static int moh_files_generator(struct ast_channel *chan, void *data, int len, int samples)
270 {
271         struct moh_files_state *state = chan->music_state;
272         struct ast_frame *f = NULL;
273         int res = 0;
274
275         state->sample_queue += samples;
276
277         while (state->sample_queue > 0) {
278                 if ((f = moh_files_readframe(chan))) {
279                         state->samples += f->samples;
280                         res = ast_write(chan, f);
281                         state->sample_queue -= f->samples;
282                         ast_frfree(f);
283                         if (res < 0) {
284                                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
285                                 return -1;
286                         }
287                 } else
288                         return -1;      
289         }
290         return res;
291 }
292
293
294 static void *moh_files_alloc(struct ast_channel *chan, void *params)
295 {
296         struct moh_files_state *state;
297         struct mohclass *class = params;
298
299         if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) {
300                 chan->music_state = state;
301                 state->class = class;
302         } else 
303                 state = chan->music_state;
304
305         if (state) {
306                 if (state->class != class) {
307                         /* initialize */
308                         memset(state, 0, sizeof(*state));
309                         state->class = class;
310                 }
311
312                 state->origwfmt = chan->writeformat;
313
314                 if (option_verbose > 2)
315                         ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->name, chan->name);
316         }
317         
318         return chan->music_state;
319 }
320
321 static struct ast_generator moh_file_stream = 
322 {
323         alloc: moh_files_alloc,
324         release: moh_files_release,
325         generate: moh_files_generator,
326 };
327
328 static int spawn_mp3(struct mohclass *class)
329 {
330         int fds[2];
331         int files = 0;
332         char fns[MAX_MP3S][80];
333         char *argv[MAX_MP3S + 50];
334         char xargs[256];
335         char *argptr;
336         int argc = 0;
337         DIR *dir = NULL;
338         struct dirent *de;
339
340         
341         if (!strcasecmp(class->dir, "nodir")) {
342                 files = 1;
343         } else {
344                 dir = opendir(class->dir);
345                 if (!dir && !strstr(class->dir,"http://") && !strstr(class->dir,"HTTP://")) {
346                         ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
347                         return -1;
348                 }
349         }
350
351         if (!ast_test_flag(class, MOH_CUSTOM)) {
352                 argv[argc++] = "mpg123";
353                 argv[argc++] = "-q";
354                 argv[argc++] = "-s";
355                 argv[argc++] = "--mono";
356                 argv[argc++] = "-r";
357                 argv[argc++] = "8000";
358                 
359                 if (!ast_test_flag(class, MOH_SINGLE)) {
360                         argv[argc++] = "-b";
361                         argv[argc++] = "2048";
362                 }
363                 
364                 argv[argc++] = "-f";
365                 
366                 if (ast_test_flag(class, MOH_QUIET))
367                         argv[argc++] = "4096";
368                 else
369                         argv[argc++] = "8192";
370                 
371                 /* Look for extra arguments and add them to the list */
372                 ast_copy_string(xargs, class->args, sizeof(xargs));
373                 argptr = xargs;
374                 while (!ast_strlen_zero(argptr)) {
375                         argv[argc++] = argptr;
376                         strsep(&argptr, ",");
377                 }
378         } else  {
379                 /* Format arguments for argv vector */
380                 ast_copy_string(xargs, class->args, sizeof(xargs));
381                 argptr = xargs;
382                 while (!ast_strlen_zero(argptr)) {
383                         argv[argc++] = argptr;
384                         strsep(&argptr, " ");
385                 }
386         }
387
388
389         if (strstr(class->dir,"http://") || strstr(class->dir,"HTTP://")) {
390                 ast_copy_string(fns[files], class->dir, sizeof(fns[files]));
391                 argv[argc++] = fns[files];
392                 files++;
393         } else if (dir) {
394                 while ((de = readdir(dir)) && (files < MAX_MP3S)) {
395                         if ((strlen(de->d_name) > 3) && 
396                             ((ast_test_flag(class, MOH_CUSTOM) && 
397                               (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 
398                                !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) ||
399                              !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
400                                 ast_copy_string(fns[files], de->d_name, sizeof(fns[files]));
401                                 argv[argc++] = fns[files];
402                                 files++;
403                         }
404                 }
405         }
406         argv[argc] = NULL;
407         if (dir) {
408                 closedir(dir);
409         }
410         if (pipe(fds)) {        
411                 ast_log(LOG_WARNING, "Pipe failed\n");
412                 return -1;
413         }
414         if (!files) {
415                 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
416                 close(fds[0]);
417                 close(fds[1]);
418                 return -1;
419         }
420         if (time(NULL) - class->start < respawn_time) {
421                 sleep(respawn_time - (time(NULL) - class->start));
422         }
423         time(&class->start);
424         class->pid = fork();
425         if (class->pid < 0) {
426                 close(fds[0]);
427                 close(fds[1]);
428                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
429                 return -1;
430         }
431         if (!class->pid) {
432                 int x;
433
434                 if (ast_opt_high_priority)
435                         ast_set_priority(0);
436
437                 close(fds[0]);
438                 /* Stdout goes to pipe */
439                 dup2(fds[1], STDOUT_FILENO);
440                 /* Close unused file descriptors */
441                 for (x=3;x<8192;x++) {
442                         if (-1 != fcntl(x, F_GETFL)) {
443                                 close(x);
444                         }
445                 }
446                 /* Child */
447                 chdir(class->dir);
448                 if (ast_test_flag(class, MOH_CUSTOM)) {
449                         execv(argv[0], argv);
450                 } else {
451                         /* Default install is /usr/local/bin */
452                         execv(LOCAL_MPG_123, argv);
453                         /* Many places have it in /usr/bin */
454                         execv(MPG_123, argv);
455                         /* Check PATH as a last-ditch effort */
456                         execvp("mpg123", argv);
457                 }
458                 ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
459                 close(fds[1]);
460                 exit(1);
461         } else {
462                 /* Parent */
463                 close(fds[1]);
464         }
465         return fds[0];
466 }
467
468 static void *monmp3thread(void *data)
469 {
470 #define MOH_MS_INTERVAL         100
471
472         struct mohclass *class = data;
473         struct mohdata *moh;
474         char buf[8192];
475         short sbuf[8192];
476         int res, res2;
477         int len;
478         struct timeval tv, tv_tmp;
479
480         tv.tv_sec = 0;
481         tv.tv_usec = 0;
482         for(;/* ever */;) {
483                 pthread_testcancel();
484                 /* Spawn mp3 player if it's not there */
485                 if (class->srcfd < 0) {
486                         if ((class->srcfd = spawn_mp3(class)) < 0) {
487                                 ast_log(LOG_WARNING, "Unable to spawn mp3player\n");
488                                 /* Try again later */
489                                 sleep(500);
490                                 pthread_testcancel();
491                         }
492                 }
493                 if (class->pseudofd > -1) {
494                         /* Pause some amount of time */
495                         res = read(class->pseudofd, buf, sizeof(buf));
496                         pthread_testcancel();
497                 } else {
498                         long delta;
499                         /* Reliable sleep */
500                         tv_tmp = ast_tvnow();
501                         if (ast_tvzero(tv))
502                                 tv = tv_tmp;
503                         delta = ast_tvdiff_ms(tv_tmp, tv);
504                         if (delta < MOH_MS_INTERVAL) {  /* too early */
505                                 tv = ast_tvadd(tv, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */
506                                 usleep(1000 * (MOH_MS_INTERVAL - delta));
507                                 pthread_testcancel();
508                         } else {
509                                 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
510                                 tv = tv_tmp;
511                         }
512                         res = 8 * MOH_MS_INTERVAL;      /* 8 samples per millisecond */
513                 }
514                 if (AST_LIST_EMPTY(&class->members))
515                         continue;
516                 /* Read mp3 audio */
517                 len = ast_codec_get_len(class->format, res);
518                 
519                 if ((res2 = read(class->srcfd, sbuf, len)) != len) {
520                         if (!res2) {
521                                 close(class->srcfd);
522                                 class->srcfd = -1;
523                                 pthread_testcancel();
524                                 if (class->pid) {
525                                         kill(class->pid, SIGHUP);
526                                         usleep(100000);
527                                         kill(class->pid, SIGTERM);
528                                         usleep(100000);
529                                         kill(class->pid, SIGKILL);
530                                         class->pid = 0;
531                                 }
532                         } else
533                                 ast_log(LOG_DEBUG, "Read %d bytes of audio while expecting %d\n", res2, len);
534                         continue;
535                 }
536                 pthread_testcancel();
537                 AST_LIST_LOCK(&mohclasses);
538                 AST_LIST_TRAVERSE(&class->members, moh, list) {
539                         /* Write data */
540                         if ((res = write(moh->pipe[1], sbuf, res2)) != res2) {
541                                 if (option_debug)
542                                         ast_log(LOG_DEBUG, "Only wrote %d of %d bytes to pipe\n", res, res2);
543                         }
544                 }
545                 AST_LIST_UNLOCK(&mohclasses);
546         }
547         return NULL;
548 }
549
550 static int moh0_exec(struct ast_channel *chan, void *data)
551 {
552         if (ast_moh_start(chan, data, NULL)) {
553                 ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
554                 return -1;
555         }
556         while (!ast_safe_sleep(chan, 10000));
557         ast_moh_stop(chan);
558         return -1;
559 }
560
561 static int moh1_exec(struct ast_channel *chan, void *data)
562 {
563         int res;
564         if (!data || !atoi(data)) {
565                 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
566                 return -1;
567         }
568         if (ast_moh_start(chan, NULL, NULL)) {
569                 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name);
570                 return -1;
571         }
572         res = ast_safe_sleep(chan, atoi(data) * 1000);
573         ast_moh_stop(chan);
574         return res;
575 }
576
577 static int moh2_exec(struct ast_channel *chan, void *data)
578 {
579         if (ast_strlen_zero(data)) {
580                 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
581                 return -1;
582         }
583         ast_string_field_set(chan, musicclass, data);
584         return 0;
585 }
586
587 static int moh3_exec(struct ast_channel *chan, void *data)
588 {
589         char *class = NULL;
590         if (data && strlen(data))
591                 class = data;
592         if (ast_moh_start(chan, class, NULL)) 
593                 ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name);
594
595         return 0;
596 }
597
598 static int moh4_exec(struct ast_channel *chan, void *data)
599 {
600         ast_moh_stop(chan);
601
602         return 0;
603 }
604
605 /*! \note This function should be called with the mohclasses list locked */
606 static struct mohclass *get_mohbyname(const char *name)
607 {
608         struct mohclass *moh = NULL;
609
610         AST_LIST_TRAVERSE(&mohclasses, moh, list) {
611                 if (!strcasecmp(name, moh->name))
612                         break;
613         }
614
615         return moh;
616 }
617
618 static struct mohdata *mohalloc(struct mohclass *cl)
619 {
620         struct mohdata *moh;
621         long flags;     
622         
623         if (!(moh = ast_calloc(1, sizeof(*moh))))
624                 return NULL;
625         
626         if (pipe(moh->pipe)) {
627                 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
628                 free(moh);
629                 return NULL;
630         }
631
632         /* Make entirely non-blocking */
633         flags = fcntl(moh->pipe[0], F_GETFL);
634         fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
635         flags = fcntl(moh->pipe[1], F_GETFL);
636         fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
637
638         moh->f.frametype = AST_FRAME_VOICE;
639         moh->f.subclass = cl->format;
640         moh->f.offset = AST_FRIENDLY_OFFSET;
641
642         moh->parent = cl;
643         AST_LIST_INSERT_HEAD(&cl->members, moh, list);
644         
645         return moh;
646 }
647
648 static void moh_release(struct ast_channel *chan, void *data)
649 {
650         struct mohdata *moh = data;
651         int oldwfmt;
652
653         AST_LIST_LOCK(&mohclasses);
654         AST_LIST_REMOVE(&moh->parent->members, moh, list);      
655         AST_LIST_UNLOCK(&mohclasses);
656         
657         close(moh->pipe[0]);
658         close(moh->pipe[1]);
659         oldwfmt = moh->origwfmt;
660         free(moh);
661         if (chan) {
662                 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
663                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
664                 if (option_verbose > 2)
665                         ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
666         }
667 }
668
669 static void *moh_alloc(struct ast_channel *chan, void *params)
670 {
671         struct mohdata *res;
672         struct mohclass *class = params;
673
674         if ((res = mohalloc(class))) {
675                 res->origwfmt = chan->writeformat;
676                 if (ast_set_write_format(chan, class->format)) {
677                         ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format));
678                         moh_release(NULL, res);
679                         res = NULL;
680                 }
681                 if (option_verbose > 2)
682                         ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name);
683         }
684         return res;
685 }
686
687 static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
688 {
689         struct mohdata *moh = data;
690         short buf[1280 + AST_FRIENDLY_OFFSET / 2];
691         int res;
692
693         if (!moh->parent->pid)
694                 return -1;
695
696         len = ast_codec_get_len(moh->parent->format, samples);
697
698         if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
699                 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name);
700                 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
701         }
702         res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
703         if (res <= 0)
704                 return 0;
705
706         moh->f.datalen = res;
707         moh->f.data = buf + AST_FRIENDLY_OFFSET / 2;
708         moh->f.samples = ast_codec_get_samples(&moh->f);
709
710         if (ast_write(chan, &moh->f) < 0) {
711                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
712                 return -1;
713         }
714
715         return 0;
716 }
717
718 static struct ast_generator mohgen = 
719 {
720         alloc: moh_alloc,
721         release: moh_release,
722         generate: moh_generate,
723 };
724
725 static int moh_add_file(struct mohclass *class, const char *filepath)
726 {
727         if (!class->allowed_files) {
728                 if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray))))
729                         return -1;
730                 class->allowed_files = INITIAL_NUM_FILES;
731         } else if (class->total_files == class->allowed_files) {
732                 if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) {
733                         class->allowed_files = 0;
734                         class->total_files = 0;
735                         return -1;
736                 }
737                 class->allowed_files *= 2;
738         }
739
740         if (!(class->filearray[class->total_files] = ast_strdup(filepath)))
741                 return -1;
742
743         class->total_files++;
744
745         return 0;
746 }
747
748 static int moh_scan_files(struct mohclass *class) {
749
750         DIR *files_DIR;
751         struct dirent *files_dirent;
752         char path[PATH_MAX];
753         char filepath[PATH_MAX];
754         char *ext;
755         struct stat statbuf;
756         int dirnamelen;
757         int i;
758         
759         files_DIR = opendir(class->dir);
760         if (!files_DIR) {
761                 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist", class->dir);
762                 return -1;
763         }
764
765         for (i = 0; i < class->total_files; i++)
766                 free(class->filearray[i]);
767
768         class->total_files = 0;
769         dirnamelen = strlen(class->dir) + 2;
770         getcwd(path, sizeof(path));
771         chdir(class->dir);
772         while ((files_dirent = readdir(files_DIR))) {
773                 /* The file name must be at least long enough to have the file type extension */
774                 if ((strlen(files_dirent->d_name) < 4))
775                         continue;
776
777                 snprintf(filepath, sizeof(filepath), "%s/%s", class->dir, files_dirent->d_name);
778
779                 if (stat(filepath, &statbuf))
780                         continue;
781
782                 if (!S_ISREG(statbuf.st_mode))
783                         continue;
784
785                 if ((ext = strrchr(filepath, '.'))) {
786                         *ext = '\0';
787                         ext++;
788                 }
789
790                 /* if the file is present in multiple formats, ensure we only put it into the list once */
791                 for (i = 0; i < class->total_files; i++)
792                         if (!strcmp(filepath, class->filearray[i]))
793                                 break;
794
795                 if (i == class->total_files) {
796                         if (moh_add_file(class, filepath))
797                                 break;
798                 }
799         }
800
801         closedir(files_DIR);
802         chdir(path);
803         return class->total_files;
804 }
805
806 static int moh_register(struct mohclass *moh, int reload)
807 {
808 #ifdef HAVE_ZAPTEL
809         int x;
810 #endif
811         AST_LIST_LOCK(&mohclasses);
812         if (get_mohbyname(moh->name)) {
813                 if (reload) {
814                         ast_log(LOG_DEBUG, "Music on Hold class '%s' left alone from initial load.\n", moh->name);
815                 } else {
816                         ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
817                 }
818                 free(moh);      
819                 AST_LIST_UNLOCK(&mohclasses);
820                 return -1;
821         }
822         AST_LIST_UNLOCK(&mohclasses);
823
824         time(&moh->start);
825         moh->start -= respawn_time;
826         
827         if (!strcasecmp(moh->mode, "files")) {
828                 if (!moh_scan_files(moh)) {
829                         ast_moh_free_class(&moh);
830                         return -1;
831                 }
832                 if (strchr(moh->args, 'r'))
833                         ast_set_flag(moh, MOH_RANDOMIZE);
834         } 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")) {
835
836                 if (!strcasecmp(moh->mode, "custom"))
837                         ast_set_flag(moh, MOH_CUSTOM);
838                 else if (!strcasecmp(moh->mode, "mp3nb"))
839                         ast_set_flag(moh, MOH_SINGLE);
840                 else if (!strcasecmp(moh->mode, "quietmp3nb"))
841                         ast_set_flag(moh, MOH_SINGLE | MOH_QUIET);
842                 else if (!strcasecmp(moh->mode, "quietmp3"))
843                         ast_set_flag(moh, MOH_QUIET);
844                 
845                 moh->srcfd = -1;
846 #ifdef HAVE_ZAPTEL
847                 /* Open /dev/zap/pseudo for timing...  Is
848                    there a better, yet reliable way to do this? */
849                 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
850                 if (moh->pseudofd < 0) {
851                         ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
852                 } else {
853                         x = 320;
854                         ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
855                 }
856 #else
857                 moh->pseudofd = -1;
858 #endif
859                 if (ast_pthread_create(&moh->thread, NULL, monmp3thread, moh)) {
860                         ast_log(LOG_WARNING, "Unable to create moh...\n");
861                         if (moh->pseudofd > -1)
862                                 close(moh->pseudofd);
863                         ast_moh_free_class(&moh);
864                         return -1;
865                 }
866         } else {
867                 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
868                 ast_moh_free_class(&moh);
869                 return -1;
870         }
871
872         AST_LIST_LOCK(&mohclasses);
873         AST_LIST_INSERT_HEAD(&mohclasses, moh, list);
874         AST_LIST_UNLOCK(&mohclasses);
875         
876         return 0;
877 }
878
879 static void local_ast_moh_cleanup(struct ast_channel *chan)
880 {
881         if (chan->music_state) {
882                 free(chan->music_state);
883                 chan->music_state = NULL;
884         }
885 }
886
887 static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
888 {
889         struct mohclass *mohclass;
890         const char *class;
891
892         /* The following is the order of preference for which class to use:
893          * 1) The channels explicitly set musicclass, which should *only* be
894          *    set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
895          * 2) The mclass argument. If a channel is calling ast_moh_start() as the
896          *    result of receiving a HOLD control frame, this should be the
897          *    payload that came with the frame.
898          * 3) The interpclass argument. This would be from the mohinterpret
899          *    option from channel drivers. This is the same as the old musicclass
900          *    option.
901          * 4) The default class.
902          */
903         if (!ast_strlen_zero(chan->musicclass))
904                 class = chan->musicclass;
905         else if (!ast_strlen_zero(mclass))
906                 class = mclass;
907         else if (!ast_strlen_zero(interpclass))
908                 class = interpclass;
909         else
910                 class = "default";
911
912         AST_LIST_LOCK(&mohclasses);
913         mohclass = get_mohbyname(class);
914         AST_LIST_UNLOCK(&mohclasses);
915
916         if (!mohclass) {
917                 ast_log(LOG_WARNING, "No class: %s\n", class);
918                 return -1;
919         }
920
921         ast_set_flag(chan, AST_FLAG_MOH);
922         if (mohclass->total_files) {
923                 return ast_activate_generator(chan, &moh_file_stream, mohclass);
924         } else
925                 return ast_activate_generator(chan, &mohgen, mohclass);
926 }
927
928 static void local_ast_moh_stop(struct ast_channel *chan)
929 {
930         ast_clear_flag(chan, AST_FLAG_MOH);
931         ast_deactivate_generator(chan);
932
933         if (chan->music_state) {
934                 if (chan->stream) {
935                         ast_closestream(chan->stream);
936                         chan->stream = NULL;
937                 }
938         }
939 }
940
941 static struct mohclass *moh_class_malloc(void)
942 {
943         struct mohclass *class;
944
945         if ((class = ast_calloc(1, sizeof(*class))))            
946                 class->format = AST_FORMAT_SLINEAR;
947
948         return class;
949 }
950
951 static int load_moh_classes(int reload)
952 {
953         struct ast_config *cfg;
954         struct ast_variable *var;
955         struct mohclass *class; 
956         char *data;
957         char *args;
958         char *cat;
959         int numclasses = 0;
960         static int dep_warning = 0;
961
962         cfg = ast_config_load("musiconhold.conf");
963
964         if (!cfg)
965                 return 0;
966
967         cat = ast_category_browse(cfg, NULL);
968         for (; cat; cat = ast_category_browse(cfg, cat)) {
969                 if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) {                       
970                         if (!(class = moh_class_malloc())) {
971                                 break;
972                         }                               
973                         ast_copy_string(class->name, cat, sizeof(class->name)); 
974                         var = ast_variable_browse(cfg, cat);
975                         while (var) {
976                                 if (!strcasecmp(var->name, "mode"))
977                                         ast_copy_string(class->mode, var->value, sizeof(class->mode)); 
978                                 else if (!strcasecmp(var->name, "directory"))
979                                         ast_copy_string(class->dir, var->value, sizeof(class->dir));
980                                 else if (!strcasecmp(var->name, "application"))
981                                         ast_copy_string(class->args, var->value, sizeof(class->args));
982                                 else if (!strcasecmp(var->name, "random"))
983                                         ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
984                                 else if (!strcasecmp(var->name, "format")) {
985                                         class->format = ast_getformatbyname(var->value);
986                                         if (!class->format) {
987                                                 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
988                                                 class->format = AST_FORMAT_SLINEAR;
989                                         }
990                                 }
991                                 var = var->next;
992                         }
993
994                         if (ast_strlen_zero(class->dir)) {
995                                 if (!strcasecmp(class->mode, "custom")) {
996                                         strcpy(class->dir, "nodir");
997                                 } else {
998                                         ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
999                                         free(class);
1000                                         continue;
1001                                 }
1002                         }
1003                         if (ast_strlen_zero(class->mode)) {
1004                                 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
1005                                 free(class);
1006                                 continue;
1007                         }
1008                         if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
1009                                 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
1010                                 free(class);
1011                                 continue;
1012                         }
1013
1014                         /* Don't leak a class when it's already registered */
1015                         moh_register(class, reload);
1016
1017                         numclasses++;
1018                 }
1019         }
1020         
1021
1022         /* Deprecated Old-School Configuration */
1023         var = ast_variable_browse(cfg, "classes");
1024         while (var) {
1025                 if (!dep_warning) {
1026                         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");
1027                         dep_warning = 1;
1028                 }
1029                 data = strchr(var->value, ':');
1030                 if (data) {
1031                         *data++ = '\0';
1032                         args = strchr(data, ',');
1033                         if (args)
1034                                 *args++ = '\0';
1035                         if (!(get_mohbyname(var->name))) {                      
1036                                 if (!(class = moh_class_malloc())) {
1037                                         return numclasses;
1038                                 }
1039                                 
1040                                 ast_copy_string(class->name, var->name, sizeof(class->name));
1041                                 ast_copy_string(class->dir, data, sizeof(class->dir));
1042                                 ast_copy_string(class->mode, var->value, sizeof(class->mode));
1043                                 if (args)
1044                                         ast_copy_string(class->args, args, sizeof(class->args));
1045                                 
1046                                 moh_register(class, reload);
1047                                 numclasses++;
1048                         }
1049                 }
1050                 var = var->next;
1051         }
1052         var = ast_variable_browse(cfg, "moh_files");
1053         while (var) {
1054                 if (!dep_warning) {
1055                         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");
1056                         dep_warning = 1;
1057                 }
1058                 if (!(get_mohbyname(var->name))) {
1059                         args = strchr(var->value, ',');
1060                         if (args)
1061                                 *args++ = '\0';                 
1062                         if (!(class = moh_class_malloc())) {
1063                                 return numclasses;
1064                         }
1065                         
1066                         ast_copy_string(class->name, var->name, sizeof(class->name));
1067                         ast_copy_string(class->dir, var->value, sizeof(class->dir));
1068                         strcpy(class->mode, "files");
1069                         if (args)       
1070                                 ast_copy_string(class->args, args, sizeof(class->args));
1071                         
1072                         moh_register(class, reload);
1073                         numclasses++;
1074                 }
1075                 var = var->next;
1076         }
1077
1078         ast_config_destroy(cfg);
1079
1080         return numclasses;
1081 }
1082
1083 static void ast_moh_destroy(void)
1084 {
1085         struct mohclass *moh;
1086         char buff[8192];
1087         int bytes, tbytes = 0, stime = 0, pid = 0;
1088
1089         if (option_verbose > 1)
1090                 ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
1091
1092         AST_LIST_LOCK(&mohclasses);
1093         while ((moh = AST_LIST_REMOVE_HEAD(&mohclasses, list))) {
1094                 if (moh->pid) {
1095                         ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
1096                         stime = time(NULL) + 2;
1097                         pid = moh->pid;
1098                         moh->pid = 0;
1099                         /* Back when this was just mpg123, SIGKILL was fine.  Now we need
1100                          * to give the process a reason and time enough to kill off its
1101                          * children. */
1102                         kill(pid, SIGHUP);
1103                         usleep(100000);
1104                         kill(pid, SIGTERM);
1105                         usleep(100000);
1106                         kill(pid, SIGKILL);
1107                         while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime)
1108                                 tbytes = tbytes + bytes;
1109                         ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
1110                         close(moh->srcfd);
1111                 }
1112                 ast_moh_free_class(&moh);
1113         }
1114         AST_LIST_UNLOCK(&mohclasses);
1115 }
1116
1117 static void moh_on_off(int on)
1118 {
1119         struct ast_channel *chan = NULL;
1120
1121         while ( (chan = ast_channel_walk_locked(chan)) != NULL) {
1122                 if (ast_test_flag(chan, AST_FLAG_MOH)) {
1123                         if (on)
1124                                 local_ast_moh_start(chan, NULL, NULL);
1125                         else
1126                                 ast_deactivate_generator(chan);
1127                 }
1128                 ast_channel_unlock(chan);
1129         }
1130 }
1131
1132 static int moh_cli(int fd, int argc, char *argv[]) 
1133 {
1134         int x;
1135
1136         moh_on_off(0);
1137         ast_moh_destroy();
1138         x = load_moh_classes(1);
1139         moh_on_off(1);
1140         ast_cli(fd, "\n%d class%s reloaded.\n", x, x == 1 ? "" : "es");
1141         return 0;
1142 }
1143
1144 static int cli_files_show(int fd, int argc, char *argv[])
1145 {
1146         int i;
1147         struct mohclass *class;
1148
1149         AST_LIST_LOCK(&mohclasses);
1150         AST_LIST_TRAVERSE(&mohclasses, class, list) {
1151                 if (!class->total_files)
1152                         continue;
1153
1154                 ast_cli(fd, "Class: %s\n", class->name);
1155                 for (i = 0; i < class->total_files; i++)
1156                         ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
1157         }
1158         AST_LIST_UNLOCK(&mohclasses);
1159
1160         return 0;
1161 }
1162
1163 static int moh_classes_show(int fd, int argc, char *argv[])
1164 {
1165         struct mohclass *class;
1166
1167         AST_LIST_LOCK(&mohclasses);
1168         AST_LIST_TRAVERSE(&mohclasses, class, list) {
1169                 ast_cli(fd, "Class: %s\n", class->name);
1170                 ast_cli(fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
1171                 ast_cli(fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
1172                 if (ast_test_flag(class, MOH_CUSTOM))
1173                         ast_cli(fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
1174                 if (strcasecmp(class->mode, "files"))
1175                         ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format));
1176         }
1177         AST_LIST_UNLOCK(&mohclasses);
1178
1179         return 0;
1180 }
1181
1182 static struct ast_cli_entry  cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL};
1183
1184 static struct ast_cli_entry  cli_moh_classes_show = { { "moh", "classes", "show"}, moh_classes_show, "List MOH classes", "Lists all MOH classes", NULL};
1185
1186 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};
1187
1188 static int init_classes(int reload) 
1189 {
1190         struct mohclass *moh;
1191     
1192         if (!load_moh_classes(reload))          /* Load classes from config */
1193                 return 0;                       /* Return if nothing is found */
1194
1195         AST_LIST_LOCK(&mohclasses);
1196         AST_LIST_TRAVERSE(&mohclasses, moh, list) {
1197                 if (moh->total_files)
1198                         moh_scan_files(moh);
1199         }
1200         AST_LIST_UNLOCK(&mohclasses);
1201
1202         return 1;
1203 }
1204
1205 static int load_module(void *mod)
1206 {
1207         int res;
1208
1209         res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
1210         ast_register_atexit(ast_moh_destroy);
1211         ast_cli_register(&cli_moh);
1212         ast_cli_register(&cli_moh_files_show);
1213         ast_cli_register(&cli_moh_classes_show);
1214         if (!res)
1215                 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
1216         if (!res)
1217                 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
1218         if (!res)
1219                 res = ast_register_application(app3, moh3_exec, synopsis3, descrip3);
1220         if (!res)
1221                 res = ast_register_application(app4, moh4_exec, synopsis4, descrip4);
1222
1223         if (!init_classes(0)) {         /* No music classes configured, so skip it */
1224                 ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold.");
1225         } else {
1226                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1227         }
1228
1229         return 0;
1230 }
1231
1232 static int reload(void *mod)
1233 {
1234         if (init_classes(1))
1235                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1236
1237         return 0;
1238 }
1239
1240 static int unload_module(void *mod)
1241 {
1242         return -1;
1243 }
1244
1245 static const char *description(void)
1246 {
1247         return "Music On Hold Resource";
1248 }
1249
1250 static const char *key(void)
1251 {
1252         return ASTERISK_GPL_KEY;
1253 }
1254
1255 STD_MOD(MOD_0 | NO_USECOUNT | NO_UNLOAD, reload, NULL, NULL);
1256