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