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