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