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