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