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