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