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