Apply NODIR Patch (Bug #4619)
[asterisk/asterisk.git] / res / res_musiconhold.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Routines implementing music on hold
5  * 
6  * Copyright (C) 1999 - 2005, Digium, Inc.
7  *
8  * Mark Spencer <markster@digium.com>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <stdlib.h>
15 #include <errno.h>
16 #include <unistd.h>
17 #include <string.h>
18 #include <signal.h>
19 #include <stdlib.h>
20 #include <stdio.h>
21 #include <sys/time.h>
22 #include <sys/signal.h>
23 #include <netinet/in.h>
24 #include <sys/stat.h>
25 #include <dirent.h>
26 #ifdef ZAPATA_MOH
27 #ifdef __linux__
28 #include <linux/zaptel.h>
29 #else
30 #include <zaptel.h>
31 #endif /* __linux__ */
32 #endif
33 #include <unistd.h>
34 #include <sys/ioctl.h>
35
36 #include "asterisk.h"
37
38 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
39
40 #include "asterisk/lock.h"
41 #include "asterisk/file.h"
42 #include "asterisk/logger.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/pbx.h"
45 #include "asterisk/options.h"
46 #include "asterisk/module.h"
47 #include "asterisk/translate.h"
48 #include "asterisk/say.h"
49 #include "asterisk/musiconhold.h"
50 #include "asterisk/config.h"
51 #include "asterisk/utils.h"
52 #include "asterisk/cli.h"
53
54 #define MAX_MOHFILES 512
55 #define MAX_MOHFILE_LEN 128
56
57 static char *app0 = "MusicOnHold";
58 static char *app1 = "WaitMusicOnHold";
59 static char *app2 = "SetMusicOnHold";
60 static char *app3 = "StartMusicOnHold";
61 static char *app4 = "StopMusicOnHold";
62
63 static char *synopsis0 = "Play Music On Hold indefinitely";
64 static char *synopsis1 = "Wait, playing Music On Hold";
65 static char *synopsis2 = "Set default Music On Hold class";
66 static char *synopsis3 = "Play Music On Hold";
67 static char *synopsis4 = "Stop Playing Music On Hold";
68
69 static char *descrip0 = "MusicOnHold(class): "
70 "Plays hold music specified by class.  If omitted, the default\n"
71 "music source for the channel will be used. Set the default \n"
72 "class with the SetMusicOnHold() application.\n"
73 "Returns -1 on hangup.\n"
74 "Never returns otherwise.\n";
75
76 static char *descrip1 = "WaitMusicOnHold(delay): "
77 "Plays hold music specified number of seconds.  Returns 0 when\n"
78 "done, or -1 on hangup.  If no hold music is available, the delay will\n"
79 "still occur with no sound.\n";
80
81 static char *descrip2 = "SetMusicOnHold(class): "
82 "Sets the default class for music on hold for a given channel.  When\n"
83 "music on hold is activated, this class will be used to select which\n"
84 "music is played.\n";
85
86 static char *descrip3 = "StartMusicOnHold(class): "
87 "Starts playing music on hold, uses default music class for channel.\n"
88 "Starts playing music specified by class.  If omitted, the default\n"
89 "music source for the channel will be used.  Always returns 0.\n";
90
91 static char *descrip4 = "StopMusicOnHold: "
92 "Stops playing music on hold.\n";
93
94 static int respawn_time = 20;
95
96 struct moh_files_state {
97         struct mohclass *class;
98         int origwfmt;
99         int samples;
100         int sample_queue;
101         unsigned char pos;
102         unsigned char save_pos;
103 };
104
105 #define MOH_QUIET               (1 << 0)
106 #define MOH_SINGLE              (1 << 1)
107 #define MOH_CUSTOM              (1 << 2)
108 #define MOH_RANDOMIZE           (1 << 3)
109
110 struct mohclass {
111         char class[80];
112         char dir[256];
113         char miscargs[256];
114         char filearray[MAX_MOHFILES][MAX_MOHFILE_LEN];
115         unsigned int flags;
116         int total_files;
117         int pid;                /* PID of mpg123 */
118         time_t start;
119         pthread_t thread;
120         struct mohdata *members;
121         /* Source of audio */
122         int srcfd;
123         /* FD for timing source */
124         int pseudofd;
125         struct mohclass *next;
126 };
127
128 struct mohdata {
129         int pipe[2];
130         int origwfmt;
131         struct mohclass *parent;
132         struct mohdata *next;
133 };
134
135 static struct mohclass *mohclasses;
136
137 AST_MUTEX_DEFINE_STATIC(moh_lock);
138
139 #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
140 #define MPG_123 "/usr/bin/mpg123"
141 #define MAX_MP3S 256
142
143 static void moh_files_release(struct ast_channel *chan, void *data)
144 {
145         struct moh_files_state *state = chan->music_state;
146
147         if (chan && state) {
148                 if (option_verbose > 2)
149                         ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
150
151                 if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
152                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt);
153                 }
154                 state->save_pos = state->pos + 1;
155         }
156 }
157
158
159 static int ast_moh_files_next(struct ast_channel *chan) 
160 {
161         struct moh_files_state *state = chan->music_state;
162         int tries;
163
164         if (state->save_pos) {
165                 state->pos = state->save_pos - 1;
166                 state->save_pos = 0;
167         } else {
168                 /* Try 20 times to find something good */
169                 for (tries=0;tries < 20;tries++) {
170                         state->samples = 0;
171                         if (chan->stream) {
172                                 ast_closestream(chan->stream);
173                                 chan->stream = NULL;
174                                 state->pos++;
175                         }
176
177                         if (ast_test_flag(state->class, MOH_RANDOMIZE))
178                                 state->pos = rand();
179
180                         /* check to see if this file's format can be opened */
181                         if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) != -1)
182                                 break;
183
184                 }
185         }
186
187         state->pos = state->pos % state->class->total_files;
188         
189         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
190                 ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
191                 return -1;
192         }
193         if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
194                 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
195                 state->pos++;
196                 return -1;
197         }
198
199         if (option_verbose > 2)
200                 ast_log(LOG_NOTICE, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]);
201
202         if (state->samples)
203                 ast_seekstream(chan->stream, state->samples, SEEK_SET);
204
205         return 0;
206 }
207
208
209 static struct ast_frame *moh_files_readframe(struct ast_channel *chan) 
210 {
211         struct ast_frame *f = NULL;
212         
213         if (!(chan->stream && (f = ast_readframe(chan->stream)))) {
214                 if (!ast_moh_files_next(chan))
215                         f = ast_readframe(chan->stream);
216         }
217
218         return f;
219 }
220
221 static int moh_files_generator(struct ast_channel *chan, void *data, int len, int samples)
222 {
223         struct moh_files_state *state = chan->music_state;
224         struct ast_frame *f = NULL;
225         int res = 0;
226         state->sample_queue += samples;
227
228         while (state->sample_queue > 0) {
229                 if ((f = moh_files_readframe(chan))) {
230                         state->samples += f->samples;
231                         res = ast_write(chan, f);
232                         ast_frfree(f);
233                         if (res < 0) {
234                                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
235                                 return -1;
236                         }
237                         state->sample_queue -= f->samples;
238                 } else
239                         return -1;      
240         }
241         return res;
242 }
243
244
245 static void *moh_files_alloc(struct ast_channel *chan, void *params)
246 {
247         struct moh_files_state *state;
248         struct mohclass *class = params;
249         int allocated = 0;
250
251         if (!chan->music_state && (state = malloc(sizeof(struct moh_files_state)))) {
252                 chan->music_state = state;
253                 allocated = 1;
254         } else 
255                 state = chan->music_state;
256
257         if (state) {
258                 if (allocated || state->class != class) {
259                         /* initialize */
260                         memset(state, 0, sizeof(struct moh_files_state));
261                         state->class = class;
262                 }
263
264                 state->origwfmt = chan->writeformat;
265
266                 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
267                         ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
268                         free(chan->music_state);
269                         chan->music_state = NULL;
270                 } else {
271                         if (option_verbose > 2)
272                                 ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->class, chan->name);
273                 }
274         }
275         
276         return chan->music_state;
277 }
278
279 static struct ast_generator moh_file_stream = 
280 {
281         alloc: moh_files_alloc,
282         release: moh_files_release,
283         generate: moh_files_generator,
284 };
285
286 static int spawn_mp3(struct mohclass *class)
287 {
288         int fds[2];
289         int files = 0;
290         char fns[MAX_MP3S][80];
291         char *argv[MAX_MP3S + 50];
292         char xargs[256];
293         char *argptr;
294         int argc = 0;
295         DIR *dir = NULL;
296         struct dirent *de;
297
298         
299         if (!strcasecmp(class->dir, "nodir")) {
300                 files = 1;
301         } else {
302                 dir = opendir(class->dir);
303                 if (!dir && !strstr(class->dir,"http://") && !strstr(class->dir,"HTTP://")) {
304                         ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
305                         return -1;
306                 }
307         }
308
309         if (!ast_test_flag(class, MOH_CUSTOM)) {
310                 argv[argc++] = "mpg123";
311                 argv[argc++] = "-q";
312                 argv[argc++] = "-s";
313                 argv[argc++] = "--mono";
314                 argv[argc++] = "-r";
315                 argv[argc++] = "8000";
316                 
317                 if (!ast_test_flag(class, MOH_SINGLE)) {
318                         argv[argc++] = "-b";
319                         argv[argc++] = "2048";
320                 }
321                 
322                 argv[argc++] = "-f";
323                 
324                 if (ast_test_flag(class, MOH_QUIET))
325                         argv[argc++] = "4096";
326                 else
327                         argv[argc++] = "8192";
328                 
329                 /* Look for extra arguments and add them to the list */
330                 strncpy(xargs, class->miscargs, sizeof(xargs) - 1);
331                 argptr = xargs;
332                 while (argptr && !ast_strlen_zero(argptr)) {
333                         argv[argc++] = argptr;
334                         argptr = strchr(argptr, ',');
335                         if (argptr) {
336                                 *argptr = '\0';
337                                 argptr++;
338                         }
339                 }
340         } else  {
341                 /* Format arguments for argv vector */
342                 strncpy(xargs, class->miscargs, sizeof(xargs) - 1);
343                 argptr = xargs;
344                 while (argptr && !ast_strlen_zero(argptr)) {
345                         argv[argc++] = argptr;
346                         argptr = strchr(argptr, ' ');
347                         if (argptr) {
348                                 *argptr = '\0';
349                                 argptr++;
350                         }
351                 }
352         }
353
354
355         if (strstr(class->dir,"http://") || strstr(class->dir,"HTTP://")) {
356                 strncpy(fns[files], class->dir, sizeof(fns[files]) - 1);
357                 argv[argc++] = fns[files];
358                 files++;
359         } else if (dir) {
360                 while ((de = readdir(dir)) && (files < MAX_MP3S)) {
361                         if ((strlen(de->d_name) > 3) && 
362                             ((ast_test_flag(class, MOH_CUSTOM) && 
363                               (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 
364                                !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) ||
365                              !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
366                                 strncpy(fns[files], de->d_name, sizeof(fns[files]) - 1);
367                                 argv[argc++] = fns[files];
368                                 files++;
369                         }
370                 }
371         }
372         argv[argc] = NULL;
373         if (dir) {
374                 closedir(dir);
375         }
376         if (pipe(fds)) {        
377                 ast_log(LOG_WARNING, "Pipe failed\n");
378                 return -1;
379         }
380 #if 0
381         printf("%d files total, %d args total\n", files, argc);
382         {
383                 int x;
384                 for (x=0;argv[x];x++)
385                         printf("arg%d: %s\n", x, argv[x]);
386         }
387 #endif  
388         if (!files) {
389                 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
390                 close(fds[0]);
391                 close(fds[1]);
392                 return -1;
393         }
394         if (time(NULL) - class->start < respawn_time) {
395                 sleep(respawn_time - (time(NULL) - class->start));
396         }
397         time(&class->start);
398         class->pid = fork();
399         if (class->pid < 0) {
400                 close(fds[0]);
401                 close(fds[1]);
402                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
403                 return -1;
404         }
405         if (!class->pid) {
406                 int x;
407                 close(fds[0]);
408                 /* Stdout goes to pipe */
409                 dup2(fds[1], STDOUT_FILENO);
410                 /* Close unused file descriptors */
411                 for (x=3;x<8192;x++) {
412                         if (-1 != fcntl(x, F_GETFL)) {
413                                 close(x);
414                         }
415                 }
416                 /* Child */
417                 chdir(class->dir);
418                 if (ast_test_flag(class, MOH_CUSTOM)) {
419                         execv(argv[0], argv);
420                 } else {
421                         /* Default install is /usr/local/bin */
422                         execv(LOCAL_MPG_123, argv);
423                         /* Many places have it in /usr/bin */
424                         execv(MPG_123, argv);
425                         /* Check PATH as a last-ditch effort */
426                         execvp("mpg123", argv);
427                 }
428                 ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
429                 close(fds[1]);
430                 exit(1);
431         } else {
432                 /* Parent */
433                 close(fds[1]);
434         }
435         return fds[0];
436 }
437
438 static void *monmp3thread(void *data)
439 {
440 #define MOH_MS_INTERVAL         100
441
442         struct mohclass *class = data;
443         struct mohdata *moh;
444         char buf[8192];
445         short sbuf[8192];
446         int res, res2;
447         struct timeval tv;
448         struct timeval tv_tmp;
449         long error_sec, error_usec;
450         long delay;
451
452         tv_tmp.tv_sec = 0;
453         tv_tmp.tv_usec = 0;
454         tv.tv_sec = 0;
455         tv.tv_usec = 0;
456         error_sec = 0;
457         error_usec = 0;
458         for(;/* ever */;) {
459                 /* Spawn mp3 player if it's not there */
460                 if (class->srcfd < 0) {
461                         if ((class->srcfd = spawn_mp3(class)) < 0) {
462                                 ast_log(LOG_WARNING, "unable to spawn mp3player\n");
463                                 /* Try again later */
464                                 sleep(500);
465                         }
466                 }
467                 if (class->pseudofd > -1) {
468                         /* Pause some amount of time */
469                         res = read(class->pseudofd, buf, sizeof(buf));
470                 } else {
471                         /* Reliable sleep */
472                         if (gettimeofday(&tv_tmp, NULL) < 0) {
473                                 ast_log(LOG_NOTICE, "gettimeofday() failed!\n");
474                                 return NULL;
475                         }
476                         if (((unsigned long)(tv.tv_sec) > 0)&&((unsigned long)(tv.tv_usec) > 0)) {
477                                 if ((unsigned long)(tv_tmp.tv_usec) < (unsigned long)(tv.tv_usec)) {
478                                         tv_tmp.tv_usec += 1000000;
479                                         tv_tmp.tv_sec -= 1;
480                                 }
481                                 error_sec = (unsigned long)(tv_tmp.tv_sec) - (unsigned long)(tv.tv_sec);
482                                 error_usec = (unsigned long)(tv_tmp.tv_usec) - (unsigned long)(tv.tv_usec);
483                         } else {
484                                 error_sec = 0;
485                                 error_usec = 0;
486                         }
487                         if (error_sec * 1000 + error_usec / 1000 < MOH_MS_INTERVAL) {
488                                 tv.tv_sec = tv_tmp.tv_sec + (MOH_MS_INTERVAL/1000 - error_sec);
489                                 tv.tv_usec = tv_tmp.tv_usec + ((MOH_MS_INTERVAL % 1000) * 1000 - error_usec);
490                                 delay = (MOH_MS_INTERVAL/1000 - error_sec) * 1000 +
491                                         ((MOH_MS_INTERVAL % 1000) * 1000 - error_usec) / 1000;
492                         } else {
493                                 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
494                                 tv.tv_sec = tv_tmp.tv_sec;
495                                 tv.tv_usec = tv_tmp.tv_usec;
496                                 delay = 0;
497                         }
498                         if (tv.tv_usec > 1000000) {
499                                 tv.tv_sec++;
500                                 tv.tv_usec-= 1000000;
501                         }
502                         if (delay > 0)
503                                 usleep(delay * 1000);
504                         res = 800;              /* 800 samples */
505                 }
506                 if (!class->members)
507                         continue;
508                 /* Read mp3 audio */
509                 if ((res2 = read(class->srcfd, sbuf, res * 2)) != res * 2) {
510                         if (!res2) {
511                                 close(class->srcfd);
512                                 class->srcfd = -1;
513                                 if (class->pid) {
514                                         kill(class->pid, SIGKILL);
515                                         class->pid = 0;
516                                 }
517                         } else
518                                 ast_log(LOG_DEBUG, "Read %d bytes of audio while expecting %d\n", res2, res * 2);
519                         continue;
520                 }
521                 ast_mutex_lock(&moh_lock);
522                 moh = class->members;
523                 while (moh) {
524                         /* Write data */
525                         if ((res = write(moh->pipe[1], sbuf, res2)) != res2) 
526                                 if (option_debug)
527                                         ast_log(LOG_DEBUG, "Only wrote %d of %d bytes to pipe\n", res, res2);
528                         moh = moh->next;
529                 }
530                 ast_mutex_unlock(&moh_lock);
531         }
532         return NULL;
533 }
534
535 static int moh0_exec(struct ast_channel *chan, void *data)
536 {
537         if (ast_moh_start(chan, data)) {
538                 ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
539                 return -1;
540         }
541         while (!ast_safe_sleep(chan, 10000));
542         ast_moh_stop(chan);
543         return -1;
544 }
545
546 static int moh1_exec(struct ast_channel *chan, void *data)
547 {
548         int res;
549         if (!data || !atoi(data)) {
550                 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
551                 return -1;
552         }
553         if (ast_moh_start(chan, NULL)) {
554                 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name);
555                 return -1;
556         }
557         res = ast_safe_sleep(chan, atoi(data) * 1000);
558         ast_moh_stop(chan);
559         return res;
560 }
561
562 static int moh2_exec(struct ast_channel *chan, void *data)
563 {
564         if (!data || ast_strlen_zero(data)) {
565                 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
566                 return -1;
567         }
568         strncpy(chan->musicclass, data, sizeof(chan->musicclass) - 1);
569         return 0;
570 }
571
572 static int moh3_exec(struct ast_channel *chan, void *data)
573 {
574         char *class = NULL;
575         if (data && strlen(data))
576                 class = data;
577         if (ast_moh_start(chan, class)) 
578                 ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name);
579
580         return 0;
581 }
582
583 static int moh4_exec(struct ast_channel *chan, void *data)
584 {
585         ast_moh_stop(chan);
586
587         return 0;
588 }
589
590 static struct mohclass *get_mohbyname(char *name)
591 {
592         struct mohclass *moh;
593         moh = mohclasses;
594         while (moh) {
595                 if (!strcasecmp(name, moh->class))
596                         return moh;
597                 moh = moh->next;
598         }
599         return NULL;
600 }
601
602 static struct mohdata *mohalloc(struct mohclass *cl)
603 {
604         struct mohdata *moh;
605         long flags;
606         moh = malloc(sizeof(struct mohdata));
607         if (!moh)
608                 return NULL;
609         memset(moh, 0, sizeof(struct mohdata));
610         if (pipe(moh->pipe)) {
611                 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
612                 free(moh);
613                 return NULL;
614         }
615         /* Make entirely non-blocking */
616         flags = fcntl(moh->pipe[0], F_GETFL);
617         fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
618         flags = fcntl(moh->pipe[1], F_GETFL);
619         fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
620         moh->parent = cl;
621         moh->next = cl->members;
622         cl->members = moh;
623         return moh;
624 }
625
626 static void moh_release(struct ast_channel *chan, void *data)
627 {
628         struct mohdata *moh = data, *prev, *cur;
629         int oldwfmt;
630         ast_mutex_lock(&moh_lock);
631         /* Unlink */
632         prev = NULL;
633         cur = moh->parent->members;
634         while (cur) {
635                 if (cur == moh) {
636                         if (prev)
637                                 prev->next = cur->next;
638                         else
639                                 moh->parent->members = cur->next;
640                         break;
641                 }
642                 prev = cur;
643                 cur = cur->next;
644         }
645         ast_mutex_unlock(&moh_lock);
646         close(moh->pipe[0]);
647         close(moh->pipe[1]);
648         oldwfmt = moh->origwfmt;
649         free(moh);
650         if (chan) {
651                 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
652                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
653                 if (option_verbose > 2)
654                         ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
655         }
656 }
657
658 static void *moh_alloc(struct ast_channel *chan, void *params)
659 {
660         struct mohdata *res;
661         struct mohclass *class;
662         class = params;
663
664         res = mohalloc(class);
665         if (res) {
666                 res->origwfmt = chan->writeformat;
667                 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
668                         ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format\n", chan->name);
669                         moh_release(NULL, res);
670                         res = NULL;
671                 }
672                 if (option_verbose > 2)
673                         ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->class, chan->name);
674         }
675         return res;
676 }
677
678 static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
679 {
680         struct ast_frame f;
681         struct mohdata *moh = data;
682         short buf[1280 + AST_FRIENDLY_OFFSET / 2];
683         int res;
684
685         if (!moh->parent->pid)
686                 return -1;
687
688         len = samples * 2;
689         if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
690                 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name);
691                 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
692         }
693         res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
694 #if 0
695         if (res != len) {
696                 ast_log(LOG_WARNING, "Read only %d of %d bytes: %s\n", res, len, strerror(errno));
697         }
698 #endif
699         if (res <= 0)
700                 return 0;
701
702         memset(&f, 0, sizeof(f));
703         f.frametype = AST_FRAME_VOICE;
704         f.subclass = AST_FORMAT_SLINEAR;
705         f.mallocd = 0;
706         f.datalen = res;
707         f.samples = res / 2;
708         f.data = buf + AST_FRIENDLY_OFFSET / 2;
709         f.offset = AST_FRIENDLY_OFFSET;
710         if (ast_write(chan, &f) < 0) {
711                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
712                 return -1;
713         }
714         return 0;
715 }
716
717 static struct ast_generator mohgen = 
718 {
719         alloc: moh_alloc,
720         release: moh_release,
721         generate: moh_generate,
722 };
723
724 static int moh_scan_files(struct mohclass *class) {
725
726         DIR *files_DIR;
727         struct dirent *files_dirent;
728         char path[512];
729         char filepath[MAX_MOHFILE_LEN];
730         char *ext;
731         struct stat statbuf;
732         int dirnamelen;
733         int i;
734         
735         files_DIR = opendir(class->dir);
736         if (!files_DIR) {
737                 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist", class->dir);
738                 return -1;
739         }
740
741         class->total_files = 0;
742         dirnamelen = strlen(class->dir) + 2;
743         getcwd(path, 512);
744         chdir(class->dir);
745         memset(class->filearray, 0, MAX_MOHFILES*MAX_MOHFILE_LEN);
746         while ((files_dirent = readdir(files_DIR))) {
747                 if ((strlen(files_dirent->d_name) < 4) || ((strlen(files_dirent->d_name) + dirnamelen) >= MAX_MOHFILE_LEN))
748                         continue;
749
750                 snprintf(filepath, MAX_MOHFILE_LEN, "%s/%s", class->dir, files_dirent->d_name);
751
752                 if (stat(filepath, &statbuf))
753                         continue;
754
755                 if (!S_ISREG(statbuf.st_mode))
756                         continue;
757
758                 if ((ext = strrchr(filepath, '.'))) {
759                         *ext = '\0';
760                         ext++;
761                 }
762
763                 /* if the file is present in multiple formats, ensure we only put it into the list once */
764                 for (i = 0; i < class->total_files; i++)
765                         if (!strcmp(filepath, class->filearray[i]))
766                                 break;
767
768                 if (i == class->total_files)
769                         strcpy(class->filearray[class->total_files++], filepath);
770         }
771
772         closedir(files_DIR);
773         chdir(path);
774         return class->total_files;
775 }
776
777 static int moh_register(char *classname, char *mode, char *param, char *miscargs)
778 {
779         struct mohclass *moh;
780 #ifdef ZAPATA_MOH
781         int x;
782 #endif
783         ast_mutex_lock(&moh_lock);
784         moh = get_mohbyname(classname);
785         ast_mutex_unlock(&moh_lock);
786         if (moh) {
787                 ast_log(LOG_WARNING, "Music on Hold '%s' already exists\n", classname);
788                 return -1;
789         }
790         moh = malloc(sizeof(struct mohclass));
791         if (!moh)
792                 return -1;
793         memset(moh, 0, sizeof(struct mohclass));
794         time(&moh->start);
795         moh->start -= respawn_time;
796         strncpy(moh->class, classname, sizeof(moh->class) - 1);
797         if (miscargs) {
798                 strncpy(moh->miscargs, miscargs, sizeof(moh->miscargs) - 1);
799                 if (strchr(miscargs,'r'))
800                         ast_set_flag(moh, MOH_RANDOMIZE);
801         }
802         if (!strcasecmp(mode, "files")) {
803                 if (param)
804                         strncpy(moh->dir, param, sizeof(moh->dir) - 1);
805                 if (!moh_scan_files(moh)) {
806                         free(moh);
807                         return -1;
808                 }
809         } else if (!strcasecmp(mode, "mp3") || !strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb") || !strcasecmp(mode, "httpmp3") || !strcasecmp(mode, "custom")) {
810
811                 if (param)
812                         strncpy(moh->dir, param, sizeof(moh->dir) - 1);
813
814                 if (!strcasecmp(mode, "custom"))
815                         ast_set_flag(moh, MOH_CUSTOM);
816                 else if (!strcasecmp(mode, "mp3nb") || !strcasecmp(mode, "quietmp3nb"))
817                         ast_set_flag(moh, MOH_SINGLE);
818                 else if (!strcasecmp(mode, "quietmp3") || !strcasecmp(mode, "quietmp3nb"))
819                         ast_set_flag(moh, MOH_QUIET);
820                 
821                 moh->srcfd = -1;
822 #ifdef ZAPATA_MOH
823                 /* It's an MP3 Moh -- Open /dev/zap/pseudo for timing...  Is
824                    there a better, yet reliable way to do this? */
825                 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
826                 if (moh->pseudofd < 0) {
827                         ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
828                 } else {
829                         x = 320;
830                         ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
831                 }
832 #else
833                 moh->pseudofd = -1;
834 #endif
835                 if (ast_pthread_create(&moh->thread, NULL, monmp3thread, moh)) {
836                         ast_log(LOG_WARNING, "Unable to create moh...\n");
837                         if (moh->pseudofd > -1)
838                                 close(moh->pseudofd);
839                         free(moh);
840                         return -1;
841                 }
842         } else {
843                 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", mode);
844                 free(moh);
845                 return -1;
846         }
847         ast_mutex_lock(&moh_lock);
848         moh->next = mohclasses;
849         mohclasses = moh;
850         ast_mutex_unlock(&moh_lock);
851         return 0;
852 }
853
854 static void local_ast_moh_cleanup(struct ast_channel *chan)
855 {
856         if (chan->music_state) {
857                 free(chan->music_state);
858                 chan->music_state = NULL;
859         }
860 }
861
862 static int local_ast_moh_start(struct ast_channel *chan, char *class)
863 {
864         struct mohclass *mohclass;
865
866         if (!class || ast_strlen_zero(class))
867                 class = chan->musicclass;
868         if (!class || ast_strlen_zero(class))
869                 class = "default";
870         ast_mutex_lock(&moh_lock);
871         mohclass = get_mohbyname(class);
872         ast_mutex_unlock(&moh_lock);
873
874         if (!mohclass) {
875                 ast_log(LOG_WARNING, "No class: %s\n", (char *)class);
876                 return -1;
877         }
878
879         ast_set_flag(chan, AST_FLAG_MOH);
880         if (mohclass->total_files) {
881                 return ast_activate_generator(chan, &moh_file_stream, mohclass);
882         } else
883                 return ast_activate_generator(chan, &mohgen, mohclass);
884 }
885
886 static void local_ast_moh_stop(struct ast_channel *chan)
887 {
888         ast_clear_flag(chan, AST_FLAG_MOH);
889         ast_deactivate_generator(chan);
890
891         if (chan->music_state) {
892                 if (chan->stream) {
893                         ast_closestream(chan->stream);
894                         chan->stream = NULL;
895                 }
896         }
897 }
898
899 static int load_moh_classes(void)
900 {
901         struct ast_config *cfg;
902         struct ast_variable *var;
903         char *data;
904         char *args;
905         int x = 0;
906
907         cfg = ast_config_load("musiconhold.conf");
908
909         if (!cfg)
910                 return 0;
911
912         var = ast_variable_browse(cfg, "classes");
913         while (var) {
914                 data = strchr(var->value, ':');
915                 if (data) {
916                         *data++ = '\0';
917                         args = strchr(data, ',');
918                         if (args)
919                                 *args++ = '\0';
920                         if (!(get_mohbyname(var->name))) {
921                                 moh_register(var->name, var->value, data, args);
922                                 x++;
923                         }
924                 }
925                 var = var->next;
926         }
927         var = ast_variable_browse(cfg, "moh_files");
928         while (var) {
929                 if (!(get_mohbyname(var->name))) {
930                         args = strchr(var->value, ',');
931                         if (args)
932                                 *args++ = '\0';
933                         moh_register(var->name, "files", var->value, args);
934                         x++;
935                 }
936                 var = var->next;
937         }
938
939         ast_config_destroy(cfg);
940         return x;
941 }
942
943 static void ast_moh_destroy(void)
944 {
945         struct mohclass *moh,*tmp;
946         char buff[8192];
947         int bytes, tbytes=0, stime = 0, pid = 0;
948
949         if (option_verbose > 1)
950                 ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
951         ast_mutex_lock(&moh_lock);
952         moh = mohclasses;
953
954         while (moh) {
955                 if (moh->pid) {
956                         ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
957                         stime = time(NULL) + 2;
958                         pid = moh->pid;
959                         moh->pid = 0;
960                         kill(pid, SIGKILL);
961                         while ((ast_wait_for_input(moh->srcfd, 100) > -1) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime) {
962                                 tbytes = tbytes + bytes;
963                         }
964                         ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
965                         close(moh->srcfd);
966                 }
967                 tmp = moh;
968                 moh = moh->next;
969                 free(tmp);
970         }
971         mohclasses = NULL;
972         ast_mutex_unlock(&moh_lock);
973 }
974
975 static void moh_on_off(int on)
976 {
977         struct ast_channel *chan = NULL;
978
979         while ( (chan = ast_channel_walk_locked(chan)) != NULL) {
980                 if (ast_test_flag(chan, AST_FLAG_MOH)) {
981                         if (on)
982                                 local_ast_moh_start(chan, NULL);
983                         else
984                                 ast_deactivate_generator(chan);
985                 }
986                 ast_mutex_unlock(&chan->lock);
987         }
988 }
989
990 static int moh_cli(int fd, int argc, char *argv[]) 
991 {
992         int x;
993
994         moh_on_off(0);
995         ast_moh_destroy();
996         x = load_moh_classes();
997         moh_on_off(1);
998         ast_cli(fd, "\n%d class%s reloaded.\n", x, x == 1 ? "" : "es");
999         return 0;
1000 }
1001
1002 static int cli_files_show(int fd, int argc, char *argv[])
1003 {
1004         int i;
1005         struct mohclass *class;
1006
1007         ast_mutex_lock(&moh_lock);
1008         for (class = mohclasses; class; class = class->next) {
1009                 if (!class->total_files)
1010                         continue;
1011
1012                 ast_cli(fd, "Class: %s\n", class->class);
1013                 for (i = 0; i < class->total_files; i++)
1014                         ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
1015         }
1016         ast_mutex_unlock(&moh_lock);
1017
1018         return 0;
1019 }
1020
1021 static struct ast_cli_entry  cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL};
1022
1023 static struct ast_cli_entry  cli_moh_files_show = { { "moh", "files", "show"}, cli_files_show, "List MOH file-based classes", "Lists all loaded file-based MOH classes and their files", NULL};
1024
1025 static void init_classes(void) 
1026 {
1027         struct mohclass *moh;
1028     
1029         load_moh_classes();
1030         moh = mohclasses;
1031         while (moh) {
1032                 if (moh->total_files)
1033                         moh_scan_files(moh);
1034                 moh = moh->next;
1035         }
1036 }
1037
1038 int load_module(void)
1039 {
1040         int res;
1041
1042         ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1043         res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
1044         ast_register_atexit(ast_moh_destroy);
1045         ast_cli_register(&cli_moh);
1046         ast_cli_register(&cli_moh_files_show);
1047         if (!res)
1048                 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
1049         if (!res)
1050                 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
1051         if (!res)
1052                 res = ast_register_application(app3, moh3_exec, synopsis3, descrip3);
1053         if (!res)
1054                 res = ast_register_application(app4, moh4_exec, synopsis4, descrip4);
1055
1056         init_classes();
1057
1058         return 0;
1059 }
1060
1061 int reload(void)
1062 {
1063         init_classes();
1064
1065         return 0;
1066 }
1067
1068 int unload_module(void)
1069 {
1070         return -1;
1071 }
1072
1073 char *description(void)
1074 {
1075         return "Music On Hold Resource";
1076 }
1077
1078 int usecount(void)
1079 {
1080         /* Never allow Music On Hold to be unloaded
1081            unresolve needed symbols in the dialer */
1082 #if 0
1083         int res;
1084         STANDARD_USECOUNT(res);
1085         return res;
1086 #else
1087         return 1;
1088 #endif
1089 }
1090
1091 char *key()
1092 {
1093         return ASTERISK_GPL_KEY;
1094 }