Merged revisions 83589 via svnmerge from
[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
860                 /* if the file is present in multiple formats, ensure we only put it into the list once */
861                 for (i = 0; i < class->total_files; i++)
862                         if (!strcmp(filepath, class->filearray[i]))
863                                 break;
864
865                 if (i == class->total_files) {
866                         if (moh_add_file(class, filepath))
867                                 break;
868                 }
869         }
870
871         closedir(files_DIR);
872         chdir(path);
873         return class->total_files;
874 }
875
876 static int moh_register(struct mohclass *moh, int reload)
877 {
878 #ifdef HAVE_ZAPTEL
879         int x;
880 #endif
881         struct mohclass *mohclass = NULL;
882
883         AST_RWLIST_WRLOCK(&mohclasses);
884         if ((mohclass = get_mohbyname(moh->name, 0))) {
885                 mohclass->delete = 0;
886                 if (reload) {
887                         ast_debug(1, "Music on Hold class '%s' left alone from initial load.\n", moh->name);
888                 } else {
889                         ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
890                 }
891                 ast_free(moh);  
892                 AST_RWLIST_UNLOCK(&mohclasses);
893                 return -1;
894         }
895         AST_RWLIST_UNLOCK(&mohclasses);
896
897         time(&moh->start);
898         moh->start -= respawn_time;
899         
900         if (!strcasecmp(moh->mode, "files")) {
901                 if (!moh_scan_files(moh)) {
902                         ast_moh_free_class(&moh);
903                         return -1;
904                 }
905                 if (strchr(moh->args, 'r'))
906                         ast_set_flag(moh, MOH_RANDOMIZE);
907         } 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")) {
908
909                 if (!strcasecmp(moh->mode, "custom"))
910                         ast_set_flag(moh, MOH_CUSTOM);
911                 else if (!strcasecmp(moh->mode, "mp3nb"))
912                         ast_set_flag(moh, MOH_SINGLE);
913                 else if (!strcasecmp(moh->mode, "quietmp3nb"))
914                         ast_set_flag(moh, MOH_SINGLE | MOH_QUIET);
915                 else if (!strcasecmp(moh->mode, "quietmp3"))
916                         ast_set_flag(moh, MOH_QUIET);
917                 
918                 moh->srcfd = -1;
919 #ifdef HAVE_ZAPTEL
920                 /* Open /dev/zap/pseudo for timing...  Is
921                    there a better, yet reliable way to do this? */
922                 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
923                 if (moh->pseudofd < 0) {
924                         ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
925                 } else {
926                         x = 320;
927                         ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
928                 }
929 #else
930                 moh->pseudofd = -1;
931 #endif
932                 if (ast_pthread_create_background(&moh->thread, NULL, monmp3thread, moh)) {
933                         ast_log(LOG_WARNING, "Unable to create moh...\n");
934                         if (moh->pseudofd > -1)
935                                 close(moh->pseudofd);
936                         ast_moh_free_class(&moh);
937                         return -1;
938                 }
939         } else {
940                 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
941                 ast_moh_free_class(&moh);
942                 return -1;
943         }
944
945         AST_RWLIST_WRLOCK(&mohclasses);
946         AST_RWLIST_INSERT_HEAD(&mohclasses, moh, list);
947         AST_RWLIST_UNLOCK(&mohclasses);
948         
949         return 0;
950 }
951
952 static void local_ast_moh_cleanup(struct ast_channel *chan)
953 {
954         if (chan->music_state) {
955                 ast_free(chan->music_state);
956                 chan->music_state = NULL;
957         }
958 }
959
960 static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
961 {
962         struct mohclass *mohclass = NULL;
963
964         /* The following is the order of preference for which class to use:
965          * 1) The channels explicitly set musicclass, which should *only* be
966          *    set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
967          * 2) The mclass argument. If a channel is calling ast_moh_start() as the
968          *    result of receiving a HOLD control frame, this should be the
969          *    payload that came with the frame.
970          * 3) The interpclass argument. This would be from the mohinterpret
971          *    option from channel drivers. This is the same as the old musicclass
972          *    option.
973          * 4) The default class.
974          */
975         AST_RWLIST_RDLOCK(&mohclasses);
976         if (!ast_strlen_zero(chan->musicclass))
977                 mohclass = get_mohbyname(chan->musicclass, 1);
978         if (!mohclass && !ast_strlen_zero(mclass))
979                 mohclass = get_mohbyname(mclass, 1);
980         if (!mohclass && !ast_strlen_zero(interpclass))
981                 mohclass = get_mohbyname(interpclass, 1);
982         if (!mohclass)  
983                 mohclass = get_mohbyname("default", 1);
984         if (mohclass)
985                 ast_atomic_fetchadd_int(&mohclass->inuse, +1);
986         AST_RWLIST_UNLOCK(&mohclasses);
987
988         if (!mohclass)
989                 return -1;
990
991         ast_set_flag(chan, AST_FLAG_MOH);
992         if (mohclass->total_files) {
993                 return ast_activate_generator(chan, &moh_file_stream, mohclass);
994         } else
995                 return ast_activate_generator(chan, &mohgen, mohclass);
996 }
997
998 static void local_ast_moh_stop(struct ast_channel *chan)
999 {
1000         ast_clear_flag(chan, AST_FLAG_MOH);
1001         ast_deactivate_generator(chan);
1002
1003         if (chan->music_state) {
1004                 if (chan->stream) {
1005                         ast_closestream(chan->stream);
1006                         chan->stream = NULL;
1007                 }
1008         }
1009 }
1010
1011 static struct mohclass *moh_class_malloc(void)
1012 {
1013         struct mohclass *class;
1014
1015         if ((class = ast_calloc(1, sizeof(*class))))
1016                 class->format = AST_FORMAT_SLINEAR;
1017
1018         return class;
1019 }
1020
1021 static int load_moh_classes(int reload)
1022 {
1023         struct ast_config *cfg;
1024         struct ast_variable *var;
1025         struct mohclass *class; 
1026         char *cat;
1027         int numclasses = 0;
1028         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1029
1030         cfg = ast_config_load("musiconhold.conf", config_flags);
1031
1032         if (cfg == NULL || cfg == CONFIG_STATUS_FILEUNCHANGED)
1033                 return 0;
1034
1035         if (reload) {
1036                 AST_RWLIST_WRLOCK(&mohclasses);
1037                 AST_RWLIST_TRAVERSE(&mohclasses, class, list) {
1038                         class->delete = 1;
1039                 }
1040                 AST_RWLIST_UNLOCK(&mohclasses);
1041         }
1042
1043         cat = ast_category_browse(cfg, NULL);
1044         for (; cat; cat = ast_category_browse(cfg, cat)) {
1045                 /* These names were deprecated in 1.4 and should not be used until after the next major release. */
1046                 if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) {                       
1047                         if (!(class = moh_class_malloc()))
1048                                 break;
1049
1050                         ast_copy_string(class->name, cat, sizeof(class->name)); 
1051                         var = ast_variable_browse(cfg, cat);
1052                         while (var) {
1053                                 if (!strcasecmp(var->name, "mode"))
1054                                         ast_copy_string(class->mode, var->value, sizeof(class->mode)); 
1055                                 else if (!strcasecmp(var->name, "directory"))
1056                                         ast_copy_string(class->dir, var->value, sizeof(class->dir));
1057                                 else if (!strcasecmp(var->name, "application"))
1058                                         ast_copy_string(class->args, var->value, sizeof(class->args));
1059                                 else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value)))
1060                                         class->digit = *var->value;
1061                                 else if (!strcasecmp(var->name, "random"))
1062                                         ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
1063                                 else if (!strcasecmp(var->name, "format")) {
1064                                         class->format = ast_getformatbyname(var->value);
1065                                         if (!class->format) {
1066                                                 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
1067                                                 class->format = AST_FORMAT_SLINEAR;
1068                                         }
1069                                 }
1070                                 var = var->next;
1071                         }
1072
1073                         if (ast_strlen_zero(class->dir)) {
1074                                 if (!strcasecmp(class->mode, "custom")) {
1075                                         strcpy(class->dir, "nodir");
1076                                 } else {
1077                                         ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
1078                                         ast_free(class);
1079                                         continue;
1080                                 }
1081                         }
1082                         if (ast_strlen_zero(class->mode)) {
1083                                 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
1084                                 ast_free(class);
1085                                 continue;
1086                         }
1087                         if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
1088                                 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
1089                                 ast_free(class);
1090                                 continue;
1091                         }
1092
1093                         /* Don't leak a class when it's already registered */
1094                         moh_register(class, reload);
1095
1096                         numclasses++;
1097                 }
1098         }
1099
1100         ast_config_destroy(cfg);
1101
1102         return numclasses;
1103 }
1104
1105 static int ast_moh_destroy_one(struct mohclass *moh)
1106 {
1107         char buff[8192];
1108         int bytes, tbytes = 0, stime = 0, pid = 0;
1109
1110         if (moh) {
1111                 if (moh->pid > 1) {
1112                         ast_debug(1, "killing %d!\n", moh->pid);
1113                         stime = time(NULL) + 2;
1114                         pid = moh->pid;
1115                         moh->pid = 0;
1116                         /* Back when this was just mpg123, SIGKILL was fine.  Now we need
1117                          * to give the process a reason and time enough to kill off its
1118                          * children. */
1119                         kill(pid, SIGHUP);
1120                         usleep(100000);
1121                         kill(pid, SIGTERM);
1122                         usleep(100000);
1123                         kill(pid, SIGKILL);
1124                         while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime)
1125                                 tbytes = tbytes + bytes;
1126                         ast_debug(1, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
1127                         close(moh->srcfd);
1128                 }
1129                 ast_moh_free_class(&moh);
1130         }
1131
1132         return 0;
1133 }
1134
1135 static void ast_moh_destroy(void)
1136 {
1137         struct mohclass *moh;
1138
1139         ast_verb(2, "Destroying musiconhold processes\n");
1140
1141         AST_RWLIST_WRLOCK(&mohclasses);
1142         while ((moh = AST_RWLIST_REMOVE_HEAD(&mohclasses, list))) {
1143                 ast_moh_destroy_one(moh);
1144         }
1145         AST_RWLIST_UNLOCK(&mohclasses);
1146 }
1147
1148 static char *handle_cli_moh_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1149 {
1150         switch (cmd) {
1151         case CLI_INIT:
1152                 e->command = "moh reload";
1153                 e->usage =
1154                         "Usage: moh reload\n"
1155                         "       Reloads the MusicOnHold module.\n"
1156                         "       Alias for 'module reload res_musiconhold.so'\n";
1157                 return NULL;
1158         case CLI_GENERATE:
1159                 return NULL;
1160         }
1161
1162         if (a->argc != e->args)
1163                 return CLI_SHOWUSAGE;
1164
1165         reload();
1166
1167         return CLI_SUCCESS;
1168 }
1169
1170 static char *handle_cli_moh_show_files(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1171 {
1172         int i;
1173         struct mohclass *class;
1174
1175         switch (cmd) {
1176         case CLI_INIT:
1177                 e->command = "moh show files";
1178                 e->usage =
1179                         "Usage: moh show files\n"
1180                         "       Lists all loaded file-based MusicOnHold classes and their\n"
1181                         "       files.\n";
1182                 return NULL;
1183         case CLI_GENERATE:
1184                 return NULL;
1185         }
1186
1187         if (a->argc != e->args)
1188                 return CLI_SHOWUSAGE;
1189
1190         AST_RWLIST_RDLOCK(&mohclasses);
1191         AST_RWLIST_TRAVERSE(&mohclasses, class, list) {
1192                 if (!class->total_files)
1193                         continue;
1194
1195                 ast_cli(a->fd, "Class: %s\n", class->name);
1196                 for (i = 0; i < class->total_files; i++)
1197                         ast_cli(a->fd, "\tFile: %s\n", class->filearray[i]);
1198         }
1199         AST_RWLIST_UNLOCK(&mohclasses);
1200
1201         return CLI_SUCCESS;
1202 }
1203
1204 static char *handle_cli_moh_show_classes(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
1205 {
1206         struct mohclass *class;
1207
1208         switch (cmd) {
1209         case CLI_INIT:
1210                 e->command = "moh show classes";
1211                 e->usage =
1212                         "Usage: moh show classes\n"
1213                         "       Lists all MusicOnHold classes.\n";
1214                 return NULL;
1215         case CLI_GENERATE:
1216                 return NULL;
1217         }
1218
1219         if (a->argc != e->args)
1220                 return CLI_SHOWUSAGE;
1221
1222         AST_RWLIST_RDLOCK(&mohclasses);
1223         AST_RWLIST_TRAVERSE(&mohclasses, class, list) {
1224                 ast_cli(a->fd, "Class: %s\n", class->name);
1225                 ast_cli(a->fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
1226                 ast_cli(a->fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
1227                 ast_cli(a->fd, "\tUse Count: %d\n", class->inuse);
1228                 if (class->digit)
1229                         ast_cli(a->fd, "\tDigit: %c\n", class->digit);
1230                 if (ast_test_flag(class, MOH_CUSTOM))
1231                         ast_cli(a->fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
1232                 if (strcasecmp(class->mode, "files"))
1233                         ast_cli(a->fd, "\tFormat: %s\n", ast_getformatname(class->format));
1234         }
1235         AST_RWLIST_UNLOCK(&mohclasses);
1236
1237         return CLI_SUCCESS;
1238 }
1239
1240 static struct ast_cli_entry cli_moh[] = {
1241         NEW_CLI(handle_cli_moh_reload,       "Reload MusicOnHold"),
1242         NEW_CLI(handle_cli_moh_show_classes, "List MusicOnHold classes"),
1243         NEW_CLI(handle_cli_moh_show_files,   "List MusicOnHold file-based classes")
1244 };
1245
1246 static int init_classes(int reload) 
1247 {
1248         struct mohclass *moh;
1249     
1250         if (!load_moh_classes(reload))          /* Load classes from config */
1251                 return 0;                       /* Return if nothing is found */
1252
1253         AST_RWLIST_WRLOCK(&mohclasses);
1254         AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mohclasses, moh, list) {
1255                 if (reload && moh->delete) {
1256                         AST_RWLIST_REMOVE_CURRENT(&mohclasses, list);
1257                         if (!moh->inuse)
1258                                 ast_moh_destroy_one(moh);
1259                 } else if (moh->total_files)
1260                         moh_scan_files(moh);
1261         }
1262         AST_RWLIST_TRAVERSE_SAFE_END
1263         AST_RWLIST_UNLOCK(&mohclasses);
1264
1265         return 1;
1266 }
1267
1268 static int load_module(void)
1269 {
1270         int res;
1271
1272         res = ast_register_application(play_moh, play_moh_exec, play_moh_syn, play_moh_desc);
1273         ast_register_atexit(ast_moh_destroy);
1274         ast_cli_register_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry));
1275         if (!res)
1276                 res = ast_register_application(wait_moh, wait_moh_exec, wait_moh_syn, wait_moh_desc);
1277         if (!res)
1278                 res = ast_register_application(set_moh, set_moh_exec, set_moh_syn, set_moh_desc);
1279         if (!res)
1280                 res = ast_register_application(start_moh, start_moh_exec, start_moh_syn, start_moh_desc);
1281         if (!res)
1282                 res = ast_register_application(stop_moh, stop_moh_exec, stop_moh_syn, stop_moh_desc);
1283
1284         if (!init_classes(0)) {         /* No music classes configured, so skip it */
1285                 ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold.\n");
1286         } else {
1287                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1288         }
1289
1290         return 0;
1291 }
1292
1293 static int reload(void)
1294 {
1295         if (init_classes(1))
1296                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1297
1298         return 0;
1299 }
1300
1301 static int unload_module(void)
1302 {
1303         return -1;
1304 }
1305
1306 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Music On Hold Resource",
1307                 .load = load_module,
1308                 .unload = unload_module,
1309                 .reload = reload,
1310                );