Merged revisions 74323 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)
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)
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         AST_LIST_INSERT_HEAD(&cl->members, moh, list);
699         
700         return moh;
701 }
702
703 static void moh_release(struct ast_channel *chan, void *data)
704 {
705         struct mohdata *moh = data;
706         int oldwfmt;
707
708         AST_RWLIST_WRLOCK(&mohclasses);
709         AST_RWLIST_REMOVE(&moh->parent->members, moh, list);    
710         AST_RWLIST_UNLOCK(&mohclasses);
711         
712         close(moh->pipe[0]);
713         close(moh->pipe[1]);
714         oldwfmt = moh->origwfmt;
715         ast_free(moh);
716         if (chan) {
717                 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
718                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
719                 if (option_verbose > 2)
720                         ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
721         }
722 }
723
724 static void *moh_alloc(struct ast_channel *chan, void *params)
725 {
726         struct mohdata *res;
727         struct mohclass *class = params;
728
729         if ((res = mohalloc(class))) {
730                 res->origwfmt = chan->writeformat;
731                 if (ast_set_write_format(chan, class->format)) {
732                         ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format));
733                         moh_release(NULL, res);
734                         res = NULL;
735                 }
736                 if (option_verbose > 2)
737                         ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name);
738         }
739         return res;
740 }
741
742 static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
743 {
744         struct mohdata *moh = data;
745         short buf[1280 + AST_FRIENDLY_OFFSET / 2];
746         int res;
747
748         if (!moh->parent->pid)
749                 return -1;
750
751         len = ast_codec_get_len(moh->parent->format, samples);
752
753         if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
754                 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name);
755                 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
756         }
757         res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
758         if (res <= 0)
759                 return 0;
760
761         moh->f.datalen = res;
762         moh->f.data = buf + AST_FRIENDLY_OFFSET / 2;
763         moh->f.samples = ast_codec_get_samples(&moh->f);
764
765         if (ast_write(chan, &moh->f) < 0) {
766                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
767                 return -1;
768         }
769
770         return 0;
771 }
772
773 static struct ast_generator mohgen = 
774 {
775         alloc: moh_alloc,
776         release: moh_release,
777         generate: moh_generate,
778         digit: moh_handle_digit
779 };
780
781 static int moh_add_file(struct mohclass *class, const char *filepath)
782 {
783         if (!class->allowed_files) {
784                 if (!(class->filearray = ast_calloc(1, INITIAL_NUM_FILES * sizeof(*class->filearray))))
785                         return -1;
786                 class->allowed_files = INITIAL_NUM_FILES;
787         } else if (class->total_files == class->allowed_files) {
788                 if (!(class->filearray = ast_realloc(class->filearray, class->allowed_files * sizeof(*class->filearray) * 2))) {
789                         class->allowed_files = 0;
790                         class->total_files = 0;
791                         return -1;
792                 }
793                 class->allowed_files *= 2;
794         }
795
796         if (!(class->filearray[class->total_files] = ast_strdup(filepath)))
797                 return -1;
798
799         class->total_files++;
800
801         return 0;
802 }
803
804 static int moh_scan_files(struct mohclass *class) {
805
806         DIR *files_DIR;
807         struct dirent *files_dirent;
808         char path[PATH_MAX];
809         char filepath[PATH_MAX];
810         char *ext;
811         struct stat statbuf;
812         int dirnamelen;
813         int i;
814         
815         files_DIR = opendir(class->dir);
816         if (!files_DIR) {
817                 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist\n", class->dir);
818                 return -1;
819         }
820
821         for (i = 0; i < class->total_files; i++)
822                 ast_free(class->filearray[i]);
823
824         class->total_files = 0;
825         dirnamelen = strlen(class->dir) + 2;
826         getcwd(path, sizeof(path));
827         chdir(class->dir);
828         while ((files_dirent = readdir(files_DIR))) {
829                 /* The file name must be at least long enough to have the file type extension */
830                 if ((strlen(files_dirent->d_name) < 4))
831                         continue;
832
833                 /* Skip files that starts with a dot */
834                 if (files_dirent->d_name[0] == '.')
835                         continue;
836
837                 /* Skip files without extensions... they are not audio */
838                 if (!strchr(files_dirent->d_name, '.'))
839                         continue;
840
841                 snprintf(filepath, sizeof(filepath), "%s/%s", class->dir, files_dirent->d_name);
842
843                 if (stat(filepath, &statbuf))
844                         continue;
845
846                 if (!S_ISREG(statbuf.st_mode))
847                         continue;
848
849                 if ((ext = strrchr(filepath, '.'))) {
850                         *ext = '\0';
851                         ext++;
852                 }
853
854                 /* if the file is present in multiple formats, ensure we only put it into the list once */
855                 for (i = 0; i < class->total_files; i++)
856                         if (!strcmp(filepath, class->filearray[i]))
857                                 break;
858
859                 if (i == class->total_files) {
860                         if (moh_add_file(class, filepath))
861                                 break;
862                 }
863         }
864
865         closedir(files_DIR);
866         chdir(path);
867         return class->total_files;
868 }
869
870 static int moh_register(struct mohclass *moh, int reload)
871 {
872 #ifdef HAVE_ZAPTEL
873         int x;
874 #endif
875         AST_RWLIST_WRLOCK(&mohclasses);
876         if (get_mohbyname(moh->name)) {
877                 if (reload) {
878                         ast_debug(1, "Music on Hold class '%s' left alone from initial load.\n", moh->name);
879                 } else {
880                         ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
881                 }
882                 ast_free(moh);  
883                 AST_RWLIST_UNLOCK(&mohclasses);
884                 return -1;
885         }
886         AST_RWLIST_UNLOCK(&mohclasses);
887
888         time(&moh->start);
889         moh->start -= respawn_time;
890         
891         if (!strcasecmp(moh->mode, "files")) {
892                 if (!moh_scan_files(moh)) {
893                         ast_moh_free_class(&moh);
894                         return -1;
895                 }
896                 if (strchr(moh->args, 'r'))
897                         ast_set_flag(moh, MOH_RANDOMIZE);
898         } 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")) {
899
900                 if (!strcasecmp(moh->mode, "custom"))
901                         ast_set_flag(moh, MOH_CUSTOM);
902                 else if (!strcasecmp(moh->mode, "mp3nb"))
903                         ast_set_flag(moh, MOH_SINGLE);
904                 else if (!strcasecmp(moh->mode, "quietmp3nb"))
905                         ast_set_flag(moh, MOH_SINGLE | MOH_QUIET);
906                 else if (!strcasecmp(moh->mode, "quietmp3"))
907                         ast_set_flag(moh, MOH_QUIET);
908                 
909                 moh->srcfd = -1;
910 #ifdef HAVE_ZAPTEL
911                 /* Open /dev/zap/pseudo for timing...  Is
912                    there a better, yet reliable way to do this? */
913                 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
914                 if (moh->pseudofd < 0) {
915                         ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
916                 } else {
917                         x = 320;
918                         ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
919                 }
920 #else
921                 moh->pseudofd = -1;
922 #endif
923                 if (ast_pthread_create_background(&moh->thread, NULL, monmp3thread, moh)) {
924                         ast_log(LOG_WARNING, "Unable to create moh...\n");
925                         if (moh->pseudofd > -1)
926                                 close(moh->pseudofd);
927                         ast_moh_free_class(&moh);
928                         return -1;
929                 }
930         } else {
931                 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
932                 ast_moh_free_class(&moh);
933                 return -1;
934         }
935
936         AST_RWLIST_WRLOCK(&mohclasses);
937         AST_RWLIST_INSERT_HEAD(&mohclasses, moh, list);
938         AST_RWLIST_UNLOCK(&mohclasses);
939         
940         return 0;
941 }
942
943 static void local_ast_moh_cleanup(struct ast_channel *chan)
944 {
945         if (chan->music_state) {
946                 ast_free(chan->music_state);
947                 chan->music_state = NULL;
948         }
949 }
950
951 static int local_ast_moh_start(struct ast_channel *chan, const char *mclass, const char *interpclass)
952 {
953         struct mohclass *mohclass = NULL;
954
955         /* The following is the order of preference for which class to use:
956          * 1) The channels explicitly set musicclass, which should *only* be
957          *    set by a call to Set(CHANNEL(musicclass)=whatever) in the dialplan.
958          * 2) The mclass argument. If a channel is calling ast_moh_start() as the
959          *    result of receiving a HOLD control frame, this should be the
960          *    payload that came with the frame.
961          * 3) The interpclass argument. This would be from the mohinterpret
962          *    option from channel drivers. This is the same as the old musicclass
963          *    option.
964          * 4) The default class.
965          */
966         AST_RWLIST_RDLOCK(&mohclasses);
967         if (!ast_strlen_zero(chan->musicclass))
968                 mohclass = get_mohbyname(chan->musicclass);
969         if (!mohclass && !ast_strlen_zero(mclass))
970                 mohclass = get_mohbyname(mclass);
971         if (!mohclass && !ast_strlen_zero(interpclass))
972                 mohclass = get_mohbyname(interpclass);
973         if (!mohclass)  
974                 mohclass = get_mohbyname("default");
975         AST_RWLIST_UNLOCK(&mohclasses);
976
977         if (!mohclass)
978                 return -1;
979
980         ast_set_flag(chan, AST_FLAG_MOH);
981         if (mohclass->total_files) {
982                 return ast_activate_generator(chan, &moh_file_stream, mohclass);
983         } else
984                 return ast_activate_generator(chan, &mohgen, mohclass);
985 }
986
987 static void local_ast_moh_stop(struct ast_channel *chan)
988 {
989         ast_clear_flag(chan, AST_FLAG_MOH);
990         ast_deactivate_generator(chan);
991
992         if (chan->music_state) {
993                 if (chan->stream) {
994                         ast_closestream(chan->stream);
995                         chan->stream = NULL;
996                 }
997         }
998 }
999
1000 static struct mohclass *moh_class_malloc(void)
1001 {
1002         struct mohclass *class;
1003
1004         if ((class = ast_calloc(1, sizeof(*class))))            
1005                 class->format = AST_FORMAT_SLINEAR;
1006
1007         return class;
1008 }
1009
1010 static int load_moh_classes(int reload)
1011 {
1012         struct ast_config *cfg;
1013         struct ast_variable *var;
1014         struct mohclass *class; 
1015         char *cat;
1016         int numclasses = 0;
1017
1018         cfg = ast_config_load("musiconhold.conf");
1019
1020         if (!cfg)
1021                 return 0;
1022
1023         cat = ast_category_browse(cfg, NULL);
1024         for (; cat; cat = ast_category_browse(cfg, cat)) {
1025                 /* These names were deprecated in 1.4 and should not be used until after the next major release. */
1026                 if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) {                       
1027                         if (!(class = moh_class_malloc()))
1028                                 break;
1029
1030                         ast_copy_string(class->name, cat, sizeof(class->name)); 
1031                         var = ast_variable_browse(cfg, cat);
1032                         while (var) {
1033                                 if (!strcasecmp(var->name, "mode"))
1034                                         ast_copy_string(class->mode, var->value, sizeof(class->mode)); 
1035                                 else if (!strcasecmp(var->name, "directory"))
1036                                         ast_copy_string(class->dir, var->value, sizeof(class->dir));
1037                                 else if (!strcasecmp(var->name, "application"))
1038                                         ast_copy_string(class->args, var->value, sizeof(class->args));
1039                                 else if (!strcasecmp(var->name, "digit") && (isdigit(*var->value) || strchr("*#", *var->value)))
1040                                         class->digit = *var->value;
1041                                 else if (!strcasecmp(var->name, "random"))
1042                                         ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
1043                                 else if (!strcasecmp(var->name, "format")) {
1044                                         class->format = ast_getformatbyname(var->value);
1045                                         if (!class->format) {
1046                                                 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
1047                                                 class->format = AST_FORMAT_SLINEAR;
1048                                         }
1049                                 }
1050                                 var = var->next;
1051                         }
1052
1053                         if (ast_strlen_zero(class->dir)) {
1054                                 if (!strcasecmp(class->mode, "custom")) {
1055                                         strcpy(class->dir, "nodir");
1056                                 } else {
1057                                         ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
1058                                         ast_free(class);
1059                                         continue;
1060                                 }
1061                         }
1062                         if (ast_strlen_zero(class->mode)) {
1063                                 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
1064                                 ast_free(class);
1065                                 continue;
1066                         }
1067                         if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
1068                                 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
1069                                 ast_free(class);
1070                                 continue;
1071                         }
1072
1073                         /* Don't leak a class when it's already registered */
1074                         moh_register(class, reload);
1075
1076                         numclasses++;
1077                 }
1078         }
1079         
1080         ast_config_destroy(cfg);
1081
1082         return numclasses;
1083 }
1084
1085 static void ast_moh_destroy(void)
1086 {
1087         struct mohclass *moh;
1088         char buff[8192];
1089         int bytes, tbytes = 0, stime = 0, pid = 0;
1090
1091         if (option_verbose > 1)
1092                 ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
1093
1094         AST_RWLIST_WRLOCK(&mohclasses);
1095         while ((moh = AST_RWLIST_REMOVE_HEAD(&mohclasses, list))) {
1096                 if (moh->pid > 1) {
1097                         ast_debug(1, "killing %d!\n", moh->pid);
1098                         stime = time(NULL) + 2;
1099                         pid = moh->pid;
1100                         moh->pid = 0;
1101                         /* Back when this was just mpg123, SIGKILL was fine.  Now we need
1102                          * to give the process a reason and time enough to kill off its
1103                          * children. */
1104                         kill(pid, SIGHUP);
1105                         usleep(100000);
1106                         kill(pid, SIGTERM);
1107                         usleep(100000);
1108                         kill(pid, SIGKILL);
1109                         while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime)
1110                                 tbytes = tbytes + bytes;
1111                         ast_debug(1, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
1112                         close(moh->srcfd);
1113                 }
1114                 ast_moh_free_class(&moh);
1115         }
1116         AST_RWLIST_UNLOCK(&mohclasses);
1117 }
1118
1119 static void moh_on_off(int on)
1120 {
1121         struct ast_channel *chan = NULL;
1122
1123         while ( (chan = ast_channel_walk_locked(chan)) != NULL) {
1124                 if (ast_test_flag(chan, AST_FLAG_MOH)) {
1125                         if (on)
1126                                 local_ast_moh_start(chan, NULL, NULL);
1127                         else
1128                                 ast_deactivate_generator(chan);
1129                 }
1130                 ast_channel_unlock(chan);
1131         }
1132 }
1133
1134 static int moh_cli(int fd, int argc, char *argv[]) 
1135 {
1136         int x;
1137
1138         moh_on_off(0);
1139         ast_moh_destroy();
1140         x = load_moh_classes(1);
1141         moh_on_off(1);
1142         ast_cli(fd, "\n%d class%s reloaded.\n", x, x == 1 ? "" : "es");
1143         return 0;
1144 }
1145
1146 static int cli_files_show(int fd, int argc, char *argv[])
1147 {
1148         int i;
1149         struct mohclass *class;
1150
1151         AST_RWLIST_RDLOCK(&mohclasses);
1152         AST_RWLIST_TRAVERSE(&mohclasses, class, list) {
1153                 if (!class->total_files)
1154                         continue;
1155
1156                 ast_cli(fd, "Class: %s\n", class->name);
1157                 for (i = 0; i < class->total_files; i++)
1158                         ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
1159         }
1160         AST_RWLIST_UNLOCK(&mohclasses);
1161
1162         return 0;
1163 }
1164
1165 static int moh_classes_show(int fd, int argc, char *argv[])
1166 {
1167         struct mohclass *class;
1168
1169         AST_RWLIST_RDLOCK(&mohclasses);
1170         AST_RWLIST_TRAVERSE(&mohclasses, class, list) {
1171                 ast_cli(fd, "Class: %s\n", class->name);
1172                 ast_cli(fd, "\tMode: %s\n", S_OR(class->mode, "<none>"));
1173                 ast_cli(fd, "\tDirectory: %s\n", S_OR(class->dir, "<none>"));
1174                 if (class->digit)
1175                         ast_cli(fd, "\tDigit: %c\n", class->digit);
1176                 if (ast_test_flag(class, MOH_CUSTOM))
1177                         ast_cli(fd, "\tApplication: %s\n", S_OR(class->args, "<none>"));
1178                 if (strcasecmp(class->mode, "files"))
1179                         ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format));
1180         }
1181         AST_RWLIST_UNLOCK(&mohclasses);
1182
1183         return 0;
1184 }
1185
1186 static struct ast_cli_entry cli_moh[] = {
1187         { { "moh", "reload"},
1188         moh_cli, "Music On Hold",
1189         "Music On Hold" },
1190
1191         { { "moh", "show", "classes"},
1192         moh_classes_show, "List MOH classes",
1193         "Lists all MOH classes" },
1194
1195         { { "moh", "show", "files"},
1196         cli_files_show, "List MOH file-based classes",
1197         "Lists all loaded file-based MOH classes and their files" },
1198 };
1199
1200 static int init_classes(int reload) 
1201 {
1202         struct mohclass *moh;
1203     
1204         if (!load_moh_classes(reload))          /* Load classes from config */
1205                 return 0;                       /* Return if nothing is found */
1206
1207         AST_RWLIST_WRLOCK(&mohclasses);
1208         AST_RWLIST_TRAVERSE(&mohclasses, moh, list) {
1209                 if (moh->total_files)
1210                         moh_scan_files(moh);
1211         }
1212         AST_RWLIST_UNLOCK(&mohclasses);
1213
1214         return 1;
1215 }
1216
1217 static int load_module(void)
1218 {
1219         int res;
1220
1221         res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
1222         ast_register_atexit(ast_moh_destroy);
1223         ast_cli_register_multiple(cli_moh, sizeof(cli_moh) / sizeof(struct ast_cli_entry));
1224         if (!res)
1225                 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
1226         if (!res)
1227                 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
1228         if (!res)
1229                 res = ast_register_application(app3, moh3_exec, synopsis3, descrip3);
1230         if (!res)
1231                 res = ast_register_application(app4, moh4_exec, synopsis4, descrip4);
1232
1233         if (!init_classes(0)) {         /* No music classes configured, so skip it */
1234                 ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold.\n");
1235         } else {
1236                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1237         }
1238
1239         return 0;
1240 }
1241
1242 static int reload(void)
1243 {
1244         if (init_classes(1))
1245                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1246
1247         return 0;
1248 }
1249
1250 static int unload_module(void)
1251 {
1252         return -1;
1253 }
1254
1255 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Music On Hold Resource",
1256                 .load = load_module,
1257                 .unload = unload_module,
1258                 .reload = reload,
1259                );