(closes issue #10684)
[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         } else 
314                 state = chan->music_state;
315
316         if (state) {
317                 if (state->class != class) {
318                         /* initialize */
319                         memset(state, 0, sizeof(*state));
320                         state->class = class;
321                         if (ast_test_flag(state->class, MOH_RANDOMIZE))
322                                 state->pos = ast_random() % class->total_files;
323                 }
324
325                 state->origwfmt = chan->writeformat;
326
327                 ast_verb(3, "Started music on hold, class '%s', on %s\n", class->name, chan->name);
328         }
329         
330         return chan->music_state;
331 }
332
333 /*! \note This function should be called with the mohclasses list locked */
334 static struct mohclass *get_mohbydigit(char digit)
335 {
336         struct mohclass *moh = NULL;
337
338         AST_RWLIST_TRAVERSE(&mohclasses, moh, list) {
339                 if (digit == moh->digit)
340                         break;
341         }
342
343         return moh;
344 }
345
346 static void moh_handle_digit(struct ast_channel *chan, char digit)
347 {
348         struct mohclass *moh;
349         const char *classname = NULL;
350
351         AST_RWLIST_RDLOCK(&mohclasses);
352         if ((moh = get_mohbydigit(digit)))
353                 classname = ast_strdupa(moh->name);
354         AST_RWLIST_UNLOCK(&mohclasses);
355
356         if (!moh)
357                 return;
358
359         ast_moh_stop(chan);
360         ast_moh_start(chan, classname, NULL);
361 }
362
363 static struct ast_generator moh_file_stream = 
364 {
365         alloc: moh_files_alloc,
366         release: moh_files_release,
367         generate: moh_files_generator,
368         digit: moh_handle_digit,
369 };
370
371 static int spawn_mp3(struct mohclass *class)
372 {
373         int fds[2];
374         int files = 0;
375         char fns[MAX_MP3S][80];
376         char *argv[MAX_MP3S + 50];
377         char xargs[256];
378         char *argptr;
379         int argc = 0;
380         DIR *dir = NULL;
381         struct dirent *de;
382         sigset_t signal_set, old_set;
383
384         
385         if (!strcasecmp(class->dir, "nodir")) {
386                 files = 1;
387         } else {
388                 dir = opendir(class->dir);
389                 if (!dir && !strstr(class->dir,"http://") && !strstr(class->dir,"HTTP://")) {
390                         ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
391                         return -1;
392                 }
393         }
394
395         if (!ast_test_flag(class, MOH_CUSTOM)) {
396                 argv[argc++] = "mpg123";
397                 argv[argc++] = "-q";
398                 argv[argc++] = "-s";
399                 argv[argc++] = "--mono";
400                 argv[argc++] = "-r";
401                 argv[argc++] = "8000";
402                 
403                 if (!ast_test_flag(class, MOH_SINGLE)) {
404                         argv[argc++] = "-b";
405                         argv[argc++] = "2048";
406                 }
407                 
408                 argv[argc++] = "-f";
409                 
410                 if (ast_test_flag(class, MOH_QUIET))
411                         argv[argc++] = "4096";
412                 else
413                         argv[argc++] = "8192";
414                 
415                 /* Look for extra arguments and add them to the list */
416                 ast_copy_string(xargs, class->args, sizeof(xargs));
417                 argptr = xargs;
418                 while (!ast_strlen_zero(argptr)) {
419                         argv[argc++] = argptr;
420                         strsep(&argptr, ",");
421                 }
422         } else  {
423                 /* Format arguments for argv vector */
424                 ast_copy_string(xargs, class->args, sizeof(xargs));
425                 argptr = xargs;
426                 while (!ast_strlen_zero(argptr)) {
427                         argv[argc++] = argptr;
428                         strsep(&argptr, " ");
429                 }
430         }
431
432
433         if (strstr(class->dir,"http://") || strstr(class->dir,"HTTP://")) {
434                 ast_copy_string(fns[files], class->dir, sizeof(fns[files]));
435                 argv[argc++] = fns[files];
436                 files++;
437         } else if (dir) {
438                 while ((de = readdir(dir)) && (files < MAX_MP3S)) {
439                         if ((strlen(de->d_name) > 3) && 
440                             ((ast_test_flag(class, MOH_CUSTOM) && 
441                               (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 
442                                !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) ||
443                              !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
444                                 ast_copy_string(fns[files], de->d_name, sizeof(fns[files]));
445                                 argv[argc++] = fns[files];
446                                 files++;
447                         }
448                 }
449         }
450         argv[argc] = NULL;
451         if (dir) {
452                 closedir(dir);
453         }
454         if (pipe(fds)) {        
455                 ast_log(LOG_WARNING, "Pipe failed\n");
456                 return -1;
457         }
458         if (!files) {
459                 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
460                 close(fds[0]);
461                 close(fds[1]);
462                 return -1;
463         }
464         if (time(NULL) - class->start < respawn_time) {
465                 sleep(respawn_time - (time(NULL) - class->start));
466         }
467
468         /* Block signals during the fork() */
469         sigfillset(&signal_set);
470         pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
471
472         time(&class->start);
473         class->pid = fork();
474         if (class->pid < 0) {
475                 close(fds[0]);
476                 close(fds[1]);
477                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
478                 return -1;
479         }
480         if (!class->pid) {
481                 int x;
482
483                 if (ast_opt_high_priority)
484                         ast_set_priority(0);
485
486                 /* Reset ignored signals back to default */
487                 signal(SIGPIPE, SIG_DFL);
488                 pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
489
490                 close(fds[0]);
491                 /* Stdout goes to pipe */
492                 dup2(fds[1], STDOUT_FILENO);
493                 /* Close unused file descriptors */
494                 for (x=3;x<8192;x++) {
495                         if (-1 != fcntl(x, F_GETFL)) {
496                                 close(x);
497                         }
498                 }
499                 /* Child */
500                 chdir(class->dir);
501                 if (ast_test_flag(class, MOH_CUSTOM)) {
502                         execv(argv[0], argv);
503                 } else {
504                         /* Default install is /usr/local/bin */
505                         execv(LOCAL_MPG_123, argv);
506                         /* Many places have it in /usr/bin */
507                         execv(MPG_123, argv);
508                         /* Check PATH as a last-ditch effort */
509                         execvp("mpg123", argv);
510                 }
511                 ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
512                 close(fds[1]);
513                 _exit(1);
514         } else {
515                 /* Parent */
516                 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
517                 close(fds[1]);
518         }
519         return fds[0];
520 }
521
522 static void *monmp3thread(void *data)
523 {
524 #define MOH_MS_INTERVAL         100
525
526         struct mohclass *class = data;
527         struct mohdata *moh;
528         char buf[8192];
529         short sbuf[8192];
530         int res, res2;
531         int len;
532         struct timeval tv, tv_tmp;
533
534         tv.tv_sec = 0;
535         tv.tv_usec = 0;
536         for(;/* ever */;) {
537                 pthread_testcancel();
538                 /* Spawn mp3 player if it's not there */
539                 if (class->srcfd < 0) {
540                         if ((class->srcfd = spawn_mp3(class)) < 0) {
541                                 ast_log(LOG_WARNING, "Unable to spawn mp3player\n");
542                                 /* Try again later */
543                                 sleep(500);
544                                 pthread_testcancel();
545                         }
546                 }
547                 if (class->pseudofd > -1) {
548 #ifdef SOLARIS
549                         thr_yield();
550 #endif
551                         /* Pause some amount of time */
552                         res = read(class->pseudofd, buf, sizeof(buf));
553                         pthread_testcancel();
554                 } else {
555                         long delta;
556                         /* Reliable sleep */
557                         tv_tmp = ast_tvnow();
558                         if (ast_tvzero(tv))
559                                 tv = tv_tmp;
560                         delta = ast_tvdiff_ms(tv_tmp, tv);
561                         if (delta < MOH_MS_INTERVAL) {  /* too early */
562                                 tv = ast_tvadd(tv, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */
563                                 usleep(1000 * (MOH_MS_INTERVAL - delta));
564                                 pthread_testcancel();
565                         } else {
566                                 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
567                                 tv = tv_tmp;
568                         }
569                         res = 8 * MOH_MS_INTERVAL;      /* 8 samples per millisecond */
570                 }
571                 if (AST_LIST_EMPTY(&class->members))
572                         continue;
573                 /* Read mp3 audio */
574                 len = ast_codec_get_len(class->format, res);
575                 
576                 if ((res2 = read(class->srcfd, sbuf, len)) != len) {
577                         if (!res2) {
578                                 close(class->srcfd);
579                                 class->srcfd = -1;
580                                 pthread_testcancel();
581                                 if (class->pid > 1) {
582                                         kill(class->pid, SIGHUP);
583                                         usleep(100000);
584                                         kill(class->pid, SIGTERM);
585                                         usleep(100000);
586                                         kill(class->pid, SIGKILL);
587                                         class->pid = 0;
588                                 }
589                         } else {
590                                 ast_debug(1, "Read %d bytes of audio while expecting %d\n", res2, len);
591                         }
592                         continue;
593                 }
594                 pthread_testcancel();
595                 AST_RWLIST_RDLOCK(&mohclasses);
596                 AST_RWLIST_TRAVERSE(&class->members, moh, list) {
597                         /* Write data */
598                         if ((res = write(moh->pipe[1], sbuf, res2)) != res2) {
599                                 ast_debug(1, "Only wrote %d of %d bytes to pipe\n", res, res2);
600                         }
601                 }
602                 AST_RWLIST_UNLOCK(&mohclasses);
603         }
604         return NULL;
605 }
606
607 static int play_moh_exec(struct ast_channel *chan, void *data)
608 {
609         if (ast_moh_start(chan, data, NULL)) {
610                 ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
611                 return 0;
612         }
613         while (!ast_safe_sleep(chan, 10000));
614         ast_moh_stop(chan);
615         return -1;
616 }
617
618 static int wait_moh_exec(struct ast_channel *chan, void *data)
619 {
620         int res;
621         if (!data || !atoi(data)) {
622                 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
623                 return -1;
624         }
625         if (ast_moh_start(chan, NULL, NULL)) {
626                 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name);
627                 return 0;
628         }
629         res = ast_safe_sleep(chan, atoi(data) * 1000);
630         ast_moh_stop(chan);
631         return res;
632 }
633
634 static int set_moh_exec(struct ast_channel *chan, void *data)
635 {
636         if (ast_strlen_zero(data)) {
637                 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
638                 return -1;
639         }
640         ast_string_field_set(chan, musicclass, data);
641         return 0;
642 }
643
644 static int start_moh_exec(struct ast_channel *chan, void *data)
645 {
646         char *class = NULL;
647         if (data && strlen(data))
648                 class = data;
649         if (ast_moh_start(chan, class, NULL)) 
650                 ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name);
651
652         return 0;
653 }
654
655 static int stop_moh_exec(struct ast_channel *chan, void *data)
656 {
657         ast_moh_stop(chan);
658
659         return 0;
660 }
661
662 /*! \note This function should be called with the mohclasses list locked */
663 static struct mohclass *get_mohbyname(const char *name, int warn)
664 {
665         struct mohclass *moh = NULL;
666
667         AST_RWLIST_TRAVERSE(&mohclasses, moh, list) {
668                 if (!strcasecmp(name, moh->name))
669                         break;
670         }
671
672         if (!moh && warn)
673                 ast_log(LOG_WARNING, "Music on Hold class '%s' not found\n", name);
674
675         return moh;
676 }
677
678 static struct mohdata *mohalloc(struct mohclass *cl)
679 {
680         struct mohdata *moh;
681         long flags;     
682         
683         if (!(moh = ast_calloc(1, sizeof(*moh))))
684                 return NULL;
685         
686         if (pipe(moh->pipe)) {
687                 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
688                 ast_free(moh);
689                 return NULL;
690         }
691
692         /* Make entirely non-blocking */
693         flags = fcntl(moh->pipe[0], F_GETFL);
694         fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
695         flags = fcntl(moh->pipe[1], F_GETFL);
696         fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
697
698         moh->f.frametype = AST_FRAME_VOICE;
699         moh->f.subclass = cl->format;
700         moh->f.offset = AST_FRIENDLY_OFFSET;
701
702         moh->parent = cl;
703
704         AST_RWLIST_WRLOCK(&mohclasses);
705         AST_LIST_INSERT_HEAD(&cl->members, moh, list);
706         AST_RWLIST_UNLOCK(&mohclasses);
707         
708         return moh;
709 }
710
711 static void moh_release(struct ast_channel *chan, void *data)
712 {
713         struct mohdata *moh = data;
714         int oldwfmt;
715
716         AST_RWLIST_WRLOCK(&mohclasses);
717         AST_RWLIST_REMOVE(&moh->parent->members, moh, list);    
718         AST_RWLIST_UNLOCK(&mohclasses);
719         
720         close(moh->pipe[0]);
721         close(moh->pipe[1]);
722         oldwfmt = moh->origwfmt;
723         if (moh->parent->delete && ast_atomic_dec_and_test(&moh->parent->inuse))
724                 ast_moh_destroy_one(moh->parent);
725         ast_free(moh);
726         if (chan) {
727                 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
728                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
729                 ast_verb(3, "Stopped music on hold on %s\n", chan->name);
730         }
731 }
732
733 static void *moh_alloc(struct ast_channel *chan, void *params)
734 {
735         struct mohdata *res;
736         struct mohclass *class = params;
737
738         if ((res = mohalloc(class))) {
739                 res->origwfmt = chan->writeformat;
740                 if (ast_set_write_format(chan, class->format)) {
741                         ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format));
742                         moh_release(NULL, res);
743                         res = NULL;
744                 }
745                 ast_verb(3, "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name);
746         }
747         return res;
748 }
749
750 static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
751 {
752         struct mohdata *moh = data;
753         short buf[1280 + AST_FRIENDLY_OFFSET / 2];
754         int res;
755
756         if (!moh->parent->pid)
757                 return -1;
758
759         len = ast_codec_get_len(moh->parent->format, samples);
760
761         if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
762                 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name);
763                 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
764         }
765         res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
766         if (res <= 0)
767                 return 0;
768
769         moh->f.datalen = res;
770         moh->f.data = buf + AST_FRIENDLY_OFFSET / 2;
771         moh->f.samples = ast_codec_get_samples(&moh->f);
772
773         if (ast_write(chan, &moh->f) < 0) {
774                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
775                 return -1;
776         }
777
778         return 0;
779 }
780
781 static struct ast_generator mohgen = 
782 {
783         alloc: moh_alloc,
784         release: moh_release,
785         generate: moh_generate,
786         digit: moh_handle_digit
787 };
788
789 static int moh_add_file(struct mohclass *class, const char *filepath)
790 {
791         if (!class->allowed_files) {
792                 if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray))))
793                         return -1;
794                 class->allowed_files = INITIAL_NUM_FILES;
795         } else if (class->total_files == class->allowed_files) {
796                 if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) {
797                         class->allowed_files = 0;
798                         class->total_files = 0;
799                         return -1;
800                 }
801                 class->allowed_files *= 2;
802         }
803
804         if (!(class->filearray[class->total_files] = ast_strdup(filepath)))
805                 return -1;
806
807         class->total_files++;
808
809         return 0;
810 }
811
812 static int moh_scan_files(struct mohclass *class) {
813
814         DIR *files_DIR;
815         struct dirent *files_dirent;
816         char path[PATH_MAX];
817         char filepath[PATH_MAX];
818         char *ext;
819         struct stat statbuf;
820         int dirnamelen;
821         int i;
822         
823         files_DIR = opendir(class->dir);
824         if (!files_DIR) {
825                 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", class->dir);
826                 return -1;
827         }
828
829         for (i = 0; i < class->total_files; i++)
830                 ast_free(class->filearray[i]);
831
832         class->total_files = 0;
833         dirnamelen = strlen(class->dir) + 2;
834         getcwd(path, sizeof(path));
835         chdir(class->dir);
836         while ((files_dirent = readdir(files_DIR))) {
837                 /* The file name must be at least long enough to have the file type extension */
838                 if ((strlen(files_dirent->d_name) < 4))
839                         continue;
840
841                 /* Skip files that starts with a dot */
842                 if (files_dirent->d_name[0] == '.')
843                         continue;
844
845                 /* Skip files without extensions... they are not audio */
846                 if (!strchr(files_dirent->d_name, '.'))
847                         continue;
848
849                 snprintf(filepath, sizeof(filepath), "%s/%s", class->dir, files_dirent->d_name);
850
851                 if (stat(filepath, &statbuf))
852                         continue;
853
854                 if (!S_ISREG(statbuf.st_mode))
855                         continue;
856
857                 if ((ext = strrchr(filepath, '.'))) {
858                         *ext = '\0';
859                         ext++;
860                 }
861
862                 /* if the file is present in multiple formats, ensure we only put it into the list once */
863                 for (i = 0; i < class->total_files; i++)
864                         if (!strcmp(filepath, class->filearray[i]))
865                                 break;
866
867                 if (i == class->total_files) {
868                         if (moh_add_file(class, filepath))
869                                 break;
870                 }
871         }
872
873         closedir(files_DIR);
874         chdir(path);
875         return class->total_files;
876 }
877
878 static int moh_register(struct mohclass *moh, int reload)
879 {
880 #ifdef HAVE_ZAPTEL
881         int x;
882 #endif
883         struct mohclass *mohclass = NULL;
884
885         AST_RWLIST_WRLOCK(&mohclasses);
886         if ((mohclass = get_mohbyname(moh->name, 0))) {
887                 mohclass->delete = 0;
888                 if (reload) {
889                         ast_debug(1, "Music on Hold class '%s' left alone from initial load.\n", moh->name);
890                 } else {
891                         ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
892                 }
893                 ast_free(moh);  
894                 AST_RWLIST_UNLOCK(&mohclasses);
895                 return -1;
896         }
897         AST_RWLIST_UNLOCK(&mohclasses);
898
899         time(&moh->start);
900         moh->start -= respawn_time;
901         
902         if (!strcasecmp(moh->mode, "files")) {
903                 if (!moh_scan_files(moh)) {
904                         ast_moh_free_class(&moh);
905                         return -1;
906                 }
907                 if (strchr(moh->args, 'r'))
908                         ast_set_flag(moh, MOH_RANDOMIZE);
909         } 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")) {
910
911                 if (!strcasecmp(moh->mode, "custom"))
912                         ast_set_flag(moh, MOH_CUSTOM);
913                 else if (!strcasecmp(moh->mode, "mp3nb"))
914                         ast_set_flag(moh, MOH_SINGLE);
915                 else if (!strcasecmp(moh->mode, "quietmp3nb"))
916                         ast_set_flag(moh, MOH_SINGLE | MOH_QUIET);
917                 else if (!strcasecmp(moh->mode, "quietmp3"))
918                         ast_set_flag(moh, MOH_QUIET);
919                 
920                 moh->srcfd = -1;
921 #ifdef HAVE_ZAPTEL
922                 /* Open /dev/zap/pseudo for timing...  Is
923                    there a better, yet reliable way to do this? */
924                 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
925                 if (moh->pseudofd < 0) {
926                         ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
927                 } else {
928                         x = 320;
929                         ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
930                 }
931 #else
932                 moh->pseudofd = -1;
933 #endif
934                 if (ast_pthread_create_background(&moh->thread, NULL, monmp3thread, moh)) {
935                         ast_log(LOG_WARNING, "Unable to create moh...\n");
936                         if (moh->pseudofd > -1)
937                                 close(moh->pseudofd);
938                         ast_moh_free_class(&moh);
939                         return -1;
940                 }
941         } else {
942                 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
943                 ast_moh_free_class(&moh);
944                 return -1;
945         }
946
947         AST_RWLIST_WRLOCK(&mohclasses);
948         AST_RWLIST_INSERT_HEAD(&mohclasses, moh, list);
949         AST_RWLIST_UNLOCK(&mohclasses);
950         
951         return 0;
952 }
953
954 static void local_ast_moh_cleanup(struct ast_channel *chan)
955 {
956         if (chan->music_state) {
957                 ast_free(chan->music_state);
958                 chan->music_state = NULL;
959         }
960 }
961
962 static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
963 {
964         struct mohclass *mohclass = NULL;
965
966         /* The following is the order of preference for which class to use:
967          * 1) The channels explicitly set musicclass, which should *only* be
968          *    set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
969          * 2) The mclass argument. If a channel is calling ast_moh_start() as the
970          *    result of receiving a HOLD control frame, this should be the
971          *    payload that came with the frame.
972          * 3) The interpclass argument. This would be from the mohinterpret
973          *    option from channel drivers. This is the same as the old musicclass
974          *    option.
975          * 4) The default class.
976          */
977         AST_RWLIST_RDLOCK(&mohclasses);
978         if (!ast_strlen_zero(chan->musicclass))
979                 mohclass = get_mohbyname(chan->musicclass, 1);
980         if (!mohclass && !ast_strlen_zero(mclass))
981                 mohclass = get_mohbyname(mclass, 1);
982         if (!mohclass && !ast_strlen_zero(interpclass))
983                 mohclass = get_mohbyname(interpclass, 1);
984         if (!mohclass)  
985                 mohclass = get_mohbyname("default", 1);
986         if (mohclass)
987                 ast_atomic_fetchadd_int(&mohclass->inuse, +1);
988         AST_RWLIST_UNLOCK(&mohclasses);
989
990         if (!mohclass)
991                 return -1;
992
993         ast_set_flag(chan, AST_FLAG_MOH);
994         if (mohclass->total_files) {
995                 return ast_activate_generator(chan, &moh_file_stream, mohclass);
996         } else
997                 return ast_activate_generator(chan, &mohgen, mohclass);
998 }
999
1000 static void local_ast_moh_stop(struct ast_channel *chan)
1001 {
1002         ast_clear_flag(chan, AST_FLAG_MOH);
1003         ast_deactivate_generator(chan);
1004
1005         if (chan->music_state) {
1006                 if (chan->stream) {
1007                         ast_closestream(chan->stream);
1008                         chan->stream = NULL;
1009                 }
1010         }
1011 }
1012
1013 static struct mohclass *moh_class_malloc(void)
1014 {
1015         struct mohclass *class;
1016
1017         if ((class = ast_calloc(1, sizeof(*class))))
1018                 class->format = AST_FORMAT_SLINEAR;
1019
1020         return class;
1021 }
1022
1023 static int load_moh_classes(int reload)
1024 {
1025         struct ast_config *cfg;
1026         struct ast_variable *var;
1027         struct mohclass *class; 
1028         char *cat;
1029         int numclasses = 0;
1030         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1031
1032         cfg = ast_config_load("musiconhold.conf", config_flags);
1033
1034         if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED)
1035                 return 0;
1036
1037         if (reload) {
1038                 AST_RWLIST_WRLOCK(&mohclasses);
1039                 AST_RWLIST_TRAVERSE(&mohclasses, class, list) {
1040                         class->delete = 1;
1041                 }
1042                 AST_RWLIST_UNLOCK(&mohclasses);
1043         }
1044
1045         cat = ast_category_browse(cfg, NULL);
1046         for (; cat; cat = ast_category_browse(cfg, cat)) {
1047                 /* These names were deprecated in 1.4 and should not be used until after the next major release. */
1048                 if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) {                       
1049                         if (!(class = moh_class_malloc()))
1050                                 break;
1051
1052                         ast_copy_string(class->name, cat, sizeof(class->name)); 
1053                         var = ast_variable_browse(cfg, cat);
1054                         while (var) {
1055                                 if (!strcasecmp(var->name, "mode"))
1056                                         ast_copy_string(class->mode, var->value, sizeof(class->mode)); 
1057                                 else if (!strcasecmp(var->name, "directory"))
1058                                         ast_copy_string(class->dir, var->value, sizeof(class->dir));
1059                                 else if (!strcasecmp(var->name, "application"))
1060                                         ast_copy_string(class->args, var->value, sizeof(class->args));
1061                                 else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value)))
1062                                         class->digit = *var->value;
1063                                 else if (!strcasecmp(var->name, "random"))
1064                                         ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
1065                                 else if (!strcasecmp(var->name, "format")) {
1066                                         class->format = ast_getformatbyname(var->value);
1067                                         if (!class->format) {
1068                                                 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
1069                                                 class->format = AST_FORMAT_SLINEAR;
1070                                         }
1071                                 }
1072                                 var = var->next;
1073                         }
1074
1075                         if (ast_strlen_zero(class->dir)) {
1076                                 if (!strcasecmp(class->mode, "custom")) {
1077                                         strcpy(class->dir, "nodir");
1078                                 } else {
1079                                         ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
1080                                         ast_free(class);
1081                                         continue;
1082                                 }
1083                         }
1084                         if (ast_strlen_zero(class->mode)) {
1085                                 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
1086                                 ast_free(class);
1087                                 continue;
1088                         }
1089                         if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
1090                                 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
1091                                 ast_free(class);
1092                                 continue;
1093                         }
1094
1095                         /* Don't leak a class when it's already registered */
1096                         moh_register(class, reload);
1097
1098                         numclasses++;
1099                 }
1100         }
1101
1102         ast_config_destroy(cfg);
1103
1104         return numclasses;
1105 }
1106
1107 static int ast_moh_destroy_one(struct mohclass *moh)
1108 {
1109         char buff[8192];
1110         int bytes, tbytes = 0, stime = 0, pid = 0;
1111
1112         if (moh) {
1113                 if (moh->pid > 1) {
1114                         ast_debug(1, "killing %d!\n", moh->pid);
1115                         stime = time(NULL) + 2;
1116                         pid = moh->pid;
1117                         moh->pid = 0;
1118                         /* Back when this was just mpg123, SIGKILL was fine.  Now we need
1119                          * to give the process a reason and time enough to kill off its
1120                          * children. */
1121                         kill(pid, SIGHUP);
1122                         usleep(100000);
1123                         kill(pid, SIGTERM);
1124                         usleep(100000);
1125                         kill(pid, SIGKILL);
1126                         while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime)
1127                                 tbytes = tbytes + bytes;
1128                         ast_debug(1, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
1129                         close(moh->srcfd);
1130                 }
1131                 ast_moh_free_class(&moh);
1132         }
1133
1134         return 0;
1135 }
1136
1137 static void ast_moh_destroy(void)
1138 {
1139         struct mohclass *moh;
1140
1141         ast_verb(2, "Destroying musiconhold processes\n");
1142
1143         AST_RWLIST_WRLOCK(&mohclasses);
1144         while ((moh = AST_RWLIST_REMOVE_HEAD(&mohclasses, list))) {
1145                 ast_moh_destroy_one(moh);
1146         }
1147         AST_RWLIST_UNLOCK(&mohclasses);
1148 }
1149
1150 static int moh_cli(int fd, int argc, char *argv[]) 
1151 {
1152         reload();
1153
1154         return 0;
1155 }
1156
1157 static int cli_files_show(int fd, int argc, char *argv[])
1158 {
1159         int i;
1160         struct mohclass *class;
1161
1162         AST_RWLIST_RDLOCK(&mohclasses);
1163         AST_RWLIST_TRAVERSE(&mohclasses, class, list) {
1164                 if (!class->total_files)
1165                         continue;
1166
1167                 ast_cli(fd, "Class: %s\n", class->name);
1168                 for (i = 0; i < class->total_files; i++)
1169                         ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
1170         }
1171         AST_RWLIST_UNLOCK(&mohclasses);
1172
1173         return 0;
1174 }
1175
1176 static int moh_classes_show(int fd, int argc, char *argv[])
1177 {
1178         struct mohclass *class;
1179
1180         AST_RWLIST_RDLOCK(&mohclasses);
1181         AST_RWLIST_TRAVERSE(&mohclasses, class, list) {
1182                 ast_cli(fd, "Class: %s\n", class->name);
1183                 ast_cli(fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
1184                 ast_cli(fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
1185                 ast_cli(fd, "\tUse Count: %d\n", class->inuse);
1186                 if (class->digit)
1187                         ast_cli(fd, "\tDigit: %c\n", class->digit);
1188                 if (ast_test_flag(class, MOH_CUSTOM))
1189                         ast_cli(fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
1190                 if (strcasecmp(class->mode, "files"))
1191                         ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format));
1192         }
1193         AST_RWLIST_UNLOCK(&mohclasses);
1194
1195         return 0;
1196 }
1197
1198 static struct ast_cli_entry cli_moh[] = {
1199         { { "moh", "reload"},
1200         moh_cli, "Music On Hold",
1201         "Music On Hold" },
1202
1203         { { "moh", "show", "classes"},
1204         moh_classes_show, "List MOH classes",
1205         "Lists all MOH classes" },
1206
1207         { { "moh", "show", "files"},
1208         cli_files_show, "List MOH file-based classes",
1209         "Lists all loaded file-based MOH classes and their files" },
1210 };
1211
1212 static int init_classes(int reload) 
1213 {
1214         struct mohclass *moh;
1215     
1216         if (!load_moh_classes(reload))          /* Load classes from config */
1217                 return 0;                       /* Return if nothing is found */
1218
1219         AST_RWLIST_WRLOCK(&mohclasses);
1220         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mohclasses, moh, list) {
1221                 if (reload && moh->delete) {
1222                         AST_RWLIST_REMOVE_CURRENT(&mohclasses, list);
1223                         if (!moh->inuse)
1224                                 ast_moh_destroy_one(moh);
1225                 } else if (moh->total_files)
1226                         moh_scan_files(moh);
1227         }
1228         AST_RWLIST_TRAVERSE_SAFE_END
1229         AST_RWLIST_UNLOCK(&mohclasses);
1230
1231         return 1;
1232 }
1233
1234 static int load_module(void)
1235 {
1236         int res;
1237
1238         res = ast_register_application(play_moh, play_moh_exec, play_moh_syn, play_moh_desc);
1239         ast_register_atexit(ast_moh_destroy);
1240         ast_cli_register_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry));
1241         if (!res)
1242                 res = ast_register_application(wait_moh, wait_moh_exec, wait_moh_syn, wait_moh_desc);
1243         if (!res)
1244                 res = ast_register_application(set_moh, set_moh_exec, set_moh_syn, set_moh_desc);
1245         if (!res)
1246                 res = ast_register_application(start_moh, start_moh_exec, start_moh_syn, start_moh_desc);
1247         if (!res)
1248                 res = ast_register_application(stop_moh, stop_moh_exec, stop_moh_syn, stop_moh_desc);
1249
1250         if (!init_classes(0)) {         /* No music classes configured, so skip it */
1251                 ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold.\n");
1252         } else {
1253                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1254         }
1255
1256         return 0;
1257 }
1258
1259 static int reload(void)
1260 {
1261         if (init_classes(1))
1262                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1263
1264         return 0;
1265 }
1266
1267 static int unload_module(void)
1268 {
1269         return -1;
1270 }
1271
1272 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Music On Hold Resource",
1273                 .load = load_module,
1274                 .unload = unload_module,
1275                 .reload = reload,
1276                );