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