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