- conversions to allocation wrappers
[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  * \author Mark Spencer <markster@digium.com>
26  */
27
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <string.h>
32 #include <signal.h>
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <sys/time.h>
36 #include <sys/signal.h>
37 #include <netinet/in.h>
38 #include <sys/stat.h>
39 #include <dirent.h>
40 #ifdef ZAPATA_MOH
41 #ifdef __linux__
42 #include <linux/zaptel.h>
43 #else
44 #include <zaptel.h>
45 #endif /* __linux__ */
46 #endif
47 #include <unistd.h>
48 #include <sys/ioctl.h>
49
50 #include "asterisk.h"
51
52 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
53
54 #include "asterisk/lock.h"
55 #include "asterisk/file.h"
56 #include "asterisk/logger.h"
57 #include "asterisk/channel.h"
58 #include "asterisk/pbx.h"
59 #include "asterisk/options.h"
60 #include "asterisk/module.h"
61 #include "asterisk/translate.h"
62 #include "asterisk/say.h"
63 #include "asterisk/musiconhold.h"
64 #include "asterisk/config.h"
65 #include "asterisk/utils.h"
66 #include "asterisk/cli.h"
67
68 #define MAX_MOHFILES 512
69 #define MAX_MOHFILE_LEN 128
70
71 static char *app0 = "MusicOnHold";
72 static char *app1 = "WaitMusicOnHold";
73 static char *app2 = "SetMusicOnHold";
74 static char *app3 = "StartMusicOnHold";
75 static char *app4 = "StopMusicOnHold";
76
77 static char *synopsis0 = "Play Music On Hold indefinitely";
78 static char *synopsis1 = "Wait, playing Music On Hold";
79 static char *synopsis2 = "Set default Music On Hold class";
80 static char *synopsis3 = "Play Music On Hold";
81 static char *synopsis4 = "Stop Playing Music On Hold";
82
83 static char *descrip0 = "MusicOnHold(class): "
84 "Plays hold music specified by class.  If omitted, the default\n"
85 "music source for the channel will be used. Set the default \n"
86 "class with the SetMusicOnHold() application.\n"
87 "Returns -1 on hangup.\n"
88 "Never returns otherwise.\n";
89
90 static char *descrip1 = "WaitMusicOnHold(delay): "
91 "Plays hold music specified number of seconds.  Returns 0 when\n"
92 "done, or -1 on hangup.  If no hold music is available, the delay will\n"
93 "still occur with no sound.\n";
94
95 static char *descrip2 = "SetMusicOnHold(class): "
96 "Sets the default class for music on hold for a given channel.  When\n"
97 "music on hold is activated, this class will be used to select which\n"
98 "music is played.\n";
99
100 static char *descrip3 = "StartMusicOnHold(class): "
101 "Starts playing music on hold, uses default music class for channel.\n"
102 "Starts playing music specified by class.  If omitted, the default\n"
103 "music source for the channel will be used.  Always returns 0.\n";
104
105 static char *descrip4 = "StopMusicOnHold: "
106 "Stops playing music on hold.\n";
107
108 static int respawn_time = 20;
109
110 struct moh_files_state {
111         struct mohclass *class;
112         int origwfmt;
113         int samples;
114         int sample_queue;
115         unsigned char pos;
116         unsigned char save_pos;
117 };
118
119 #define MOH_QUIET               (1 << 0)
120 #define MOH_SINGLE              (1 << 1)
121 #define MOH_CUSTOM              (1 << 2)
122 #define MOH_RANDOMIZE           (1 << 3)
123
124 struct mohclass {
125         char name[MAX_MUSICCLASS];
126         char dir[256];
127         char args[256];
128         char mode[80];
129         char filearray[MAX_MOHFILES][MAX_MOHFILE_LEN];
130         unsigned int flags;
131         int total_files;
132         int format;
133         int pid;                /* PID of mpg123 */
134         time_t start;
135         pthread_t thread;
136         struct mohdata *members;
137         /* Source of audio */
138         int srcfd;
139         /* FD for timing source */
140         int pseudofd;
141         struct mohclass *next;
142 };
143
144 struct mohdata {
145         int pipe[2];
146         int origwfmt;
147         struct mohclass *parent;
148         struct mohdata *next;
149 };
150
151 static struct mohclass *mohclasses;
152
153 AST_MUTEX_DEFINE_STATIC(moh_lock);
154
155 #define LOCAL_MPG_123 "/usr/local/bin/mpg123"
156 #define MPG_123 "/usr/bin/mpg123"
157 #define MAX_MP3S 256
158
159
160 static void ast_moh_free_class(struct mohclass **class) 
161 {
162         struct mohdata *members, *mtmp;
163         
164         members = (*class)->members;
165         while(members) {
166                 mtmp = members;
167                 members = members->next;
168                 free(mtmp);
169         }
170         free(*class);
171         *class = NULL;
172 }
173
174
175 static void moh_files_release(struct ast_channel *chan, void *data)
176 {
177         struct moh_files_state *state = chan->music_state;
178
179         if (chan && state) {
180                 if (option_verbose > 2)
181                         ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
182
183                 if (state->origwfmt && ast_set_write_format(chan, state->origwfmt)) {
184                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, state->origwfmt);
185                 }
186                 state->save_pos = state->pos + 1;
187         }
188 }
189
190
191 static int ast_moh_files_next(struct ast_channel *chan) 
192 {
193         struct moh_files_state *state = chan->music_state;
194         int tries;
195
196         if (state->save_pos) {
197                 state->pos = state->save_pos - 1;
198                 state->save_pos = 0;
199         } else {
200                 /* Try 20 times to find something good */
201                 for (tries=0;tries < 20;tries++) {
202                         state->samples = 0;
203                         if (chan->stream) {
204                                 ast_closestream(chan->stream);
205                                 chan->stream = NULL;
206                                 state->pos++;
207                         }
208
209                         if (ast_test_flag(state->class, MOH_RANDOMIZE))
210                                 state->pos = rand();
211
212                         /* check to see if this file's format can be opened */
213                         if (ast_fileexists(state->class->filearray[state->pos], NULL, NULL) != -1)
214                                 break;
215
216                 }
217         }
218
219         state->pos = state->pos % state->class->total_files;
220         
221         if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
222                 ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
223                 return -1;
224         }
225         if (!ast_openstream_full(chan, state->class->filearray[state->pos], chan->language, 1)) {
226                 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", state->class->filearray[state->pos], strerror(errno));
227                 state->pos++;
228                 return -1;
229         }
230
231         if (option_debug)
232                 ast_log(LOG_DEBUG, "%s Opened file %d '%s'\n", chan->name, state->pos, state->class->filearray[state->pos]);
233
234         if (state->samples)
235                 ast_seekstream(chan->stream, state->samples, SEEK_SET);
236
237         return 0;
238 }
239
240
241 static struct ast_frame *moh_files_readframe(struct ast_channel *chan) 
242 {
243         struct ast_frame *f = NULL;
244         
245         if (!(chan->stream && (f = ast_readframe(chan->stream)))) {
246                 if (!ast_moh_files_next(chan))
247                         f = ast_readframe(chan->stream);
248         }
249
250         return f;
251 }
252
253 static int moh_files_generator(struct ast_channel *chan, void *data, int len, int samples)
254 {
255         struct moh_files_state *state = chan->music_state;
256         struct ast_frame *f = NULL;
257         int res = 0;
258
259         state->sample_queue += samples;
260
261         while (state->sample_queue > 0) {
262                 if ((f = moh_files_readframe(chan))) {
263                         state->samples += f->samples;
264                         res = ast_write(chan, f);
265                         state->sample_queue -= f->samples;
266                         ast_frfree(f);
267                         if (res < 0) {
268                                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
269                                 return -1;
270                         }
271                 } else
272                         return -1;      
273         }
274         return res;
275 }
276
277
278 static void *moh_files_alloc(struct ast_channel *chan, void *params)
279 {
280         struct moh_files_state *state;
281         struct mohclass *class = params;
282
283         if (!chan->music_state && (state = ast_calloc(1, sizeof(*state)))) {
284                 chan->music_state = state;
285                 state->class = class;
286         } else 
287                 state = chan->music_state;
288
289         if (state) {
290                 if (state->class != class) {
291                         /* initialize */
292                         memset(state, 0, sizeof(*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         if (!(moh = ast_calloc(1, sizeof(*moh))))
615                 return NULL;
616         if (pipe(moh->pipe)) {
617                 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
618                 free(moh);
619                 return NULL;
620         }
621         /* Make entirely non-blocking */
622         flags = fcntl(moh->pipe[0], F_GETFL);
623         fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
624         flags = fcntl(moh->pipe[1], F_GETFL);
625         fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
626         moh->parent = cl;
627         moh->next = cl->members;
628         cl->members = moh;
629         return moh;
630 }
631
632 static void moh_release(struct ast_channel *chan, void *data)
633 {
634         struct mohdata *moh = data, *prev, *cur;
635         int oldwfmt;
636         ast_mutex_lock(&moh_lock);
637         /* Unlink */
638         prev = NULL;
639         cur = moh->parent->members;
640         while (cur) {
641                 if (cur == moh) {
642                         if (prev)
643                                 prev->next = cur->next;
644                         else
645                                 moh->parent->members = cur->next;
646                         break;
647                 }
648                 prev = cur;
649                 cur = cur->next;
650         }
651         ast_mutex_unlock(&moh_lock);
652         close(moh->pipe[0]);
653         close(moh->pipe[1]);
654         oldwfmt = moh->origwfmt;
655         free(moh);
656         if (chan) {
657                 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
658                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
659                 if (option_verbose > 2)
660                         ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
661         }
662 }
663
664 static void *moh_alloc(struct ast_channel *chan, void *params)
665 {
666         struct mohdata *res;
667         struct mohclass *class = params;
668
669         if ((res = mohalloc(class))) {
670                 res->origwfmt = chan->writeformat;
671                 if (ast_set_write_format(chan, class->format)) {
672                         ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format));
673                         moh_release(NULL, res);
674                         res = NULL;
675                 }
676                 if (option_verbose > 2)
677                         ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name);
678         }
679         return res;
680 }
681
682 static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
683 {
684         struct ast_frame f;
685         struct mohdata *moh = data;
686         short buf[1280 + AST_FRIENDLY_OFFSET / 2];
687         int res;
688
689         if (!moh->parent->pid)
690                 return -1;
691
692         len = ast_codec_get_len(moh->parent->format, samples);
693
694         if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
695                 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name);
696                 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
697         }
698         res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
699 #if 0
700         if (res != len) {
701                 ast_log(LOG_WARNING, "Read only %d of %d bytes: %s\n", res, len, strerror(errno));
702         }
703 #endif
704         if (res <= 0)
705                 return 0;
706
707         memset(&f, 0, sizeof(f));
708         
709         f.frametype = AST_FRAME_VOICE;
710         f.subclass = moh->parent->format;
711         f.mallocd = 0;
712         f.datalen = res;
713         f.data = buf + AST_FRIENDLY_OFFSET / 2;
714         f.offset = AST_FRIENDLY_OFFSET;
715         f.samples = ast_codec_get_samples(&f);
716
717         if (ast_write(chan, &f) < 0) {
718                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
719                 return -1;
720         }
721
722         return 0;
723 }
724
725 static struct ast_generator mohgen = 
726 {
727         alloc: moh_alloc,
728         release: moh_release,
729         generate: moh_generate,
730 };
731
732 static int moh_scan_files(struct mohclass *class) {
733
734         DIR *files_DIR;
735         struct dirent *files_dirent;
736         char path[512];
737         char filepath[MAX_MOHFILE_LEN];
738         char *ext;
739         struct stat statbuf;
740         int dirnamelen;
741         int i;
742         
743         files_DIR = opendir(class->dir);
744         if (!files_DIR) {
745                 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist", class->dir);
746                 return -1;
747         }
748
749         class->total_files = 0;
750         dirnamelen = strlen(class->dir) + 2;
751         getcwd(path, 512);
752         chdir(class->dir);
753         memset(class->filearray, 0, MAX_MOHFILES*MAX_MOHFILE_LEN);
754         while ((files_dirent = readdir(files_DIR))) {
755                 if ((strlen(files_dirent->d_name) < 4) || ((strlen(files_dirent->d_name) + dirnamelen) >= MAX_MOHFILE_LEN))
756                         continue;
757
758                 snprintf(filepath, MAX_MOHFILE_LEN, "%s/%s", class->dir, files_dirent->d_name);
759
760                 if (stat(filepath, &statbuf))
761                         continue;
762
763                 if (!S_ISREG(statbuf.st_mode))
764                         continue;
765
766                 if ((ext = strrchr(filepath, '.'))) {
767                         *ext = '\0';
768                         ext++;
769                 }
770
771                 /* if the file is present in multiple formats, ensure we only put it into the list once */
772                 for (i = 0; i < class->total_files; i++)
773                         if (!strcmp(filepath, class->filearray[i]))
774                                 break;
775
776                 if (i == class->total_files)
777                         strcpy(class->filearray[class->total_files++], filepath);
778         }
779
780         closedir(files_DIR);
781         chdir(path);
782         return class->total_files;
783 }
784
785 static int moh_register(struct mohclass *moh, int reload)
786 {
787 #ifdef ZAPATA_MOH
788         int x;
789 #endif
790         ast_mutex_lock(&moh_lock);
791         if (get_mohbyname(moh->name)) {
792                 if (reload) {
793                         ast_log(LOG_DEBUG, "Music on Hold class '%s' left alone from initial load.\n", moh->name);
794                 } else {
795                         ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
796                 }
797                 free(moh);      
798                 ast_mutex_unlock(&moh_lock);
799                 return -1;
800         }
801         ast_mutex_unlock(&moh_lock);
802
803         time(&moh->start);
804         moh->start -= respawn_time;
805         
806         if (!strcasecmp(moh->mode, "files")) {
807                 if (!moh_scan_files(moh)) {
808                         ast_moh_free_class(&moh);
809                         return -1;
810                 }
811                 if (strchr(moh->args, 'r'))
812                         ast_set_flag(moh, MOH_RANDOMIZE);
813         } 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")) {
814
815                 if (!strcasecmp(moh->mode, "custom"))
816                         ast_set_flag(moh, MOH_CUSTOM);
817                 else if (!strcasecmp(moh->mode, "mp3nb"))
818                         ast_set_flag(moh, MOH_SINGLE);
819                 else if (!strcasecmp(moh->mode, "quietmp3nb"))
820                         ast_set_flag(moh, MOH_SINGLE | MOH_QUIET);
821                 else if (!strcasecmp(moh->mode, "quietmp3"))
822                         ast_set_flag(moh, MOH_QUIET);
823                 
824                 moh->srcfd = -1;
825 #ifdef ZAPATA_MOH
826                 /* Open /dev/zap/pseudo for timing...  Is
827                    there a better, yet reliable way to do this? */
828                 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
829                 if (moh->pseudofd < 0) {
830                         ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
831                 } else {
832                         x = 320;
833                         ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
834                 }
835 #else
836                 moh->pseudofd = -1;
837 #endif
838                 if (ast_pthread_create(&moh->thread, NULL, monmp3thread, moh)) {
839                         ast_log(LOG_WARNING, "Unable to create moh...\n");
840                         if (moh->pseudofd > -1)
841                                 close(moh->pseudofd);
842                         ast_moh_free_class(&moh);
843                         return -1;
844                 }
845         } else {
846                 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
847                 ast_moh_free_class(&moh);
848                 return -1;
849         }
850         ast_mutex_lock(&moh_lock);
851         moh->next = mohclasses;
852         mohclasses = moh;
853         ast_mutex_unlock(&moh_lock);
854         return 0;
855 }
856
857 static void local_ast_moh_cleanup(struct ast_channel *chan)
858 {
859         if (chan->music_state) {
860                 free(chan->music_state);
861                 chan->music_state = NULL;
862         }
863 }
864
865 static int local_ast_moh_start(struct ast_channel *chan, char *class)
866 {
867         struct mohclass *mohclass;
868
869         if (ast_strlen_zero(class))
870                 class = chan->musicclass;
871         if (ast_strlen_zero(class))
872                 class = "default";
873         ast_mutex_lock(&moh_lock);
874         mohclass = get_mohbyname(class);
875         ast_mutex_unlock(&moh_lock);
876
877         if (!mohclass) {
878                 ast_log(LOG_WARNING, "No class: %s\n", (char *)class);
879                 return -1;
880         }
881
882         ast_set_flag(chan, AST_FLAG_MOH);
883         if (mohclass->total_files) {
884                 return ast_activate_generator(chan, &moh_file_stream, mohclass);
885         } else
886                 return ast_activate_generator(chan, &mohgen, mohclass);
887 }
888
889 static void local_ast_moh_stop(struct ast_channel *chan)
890 {
891         ast_clear_flag(chan, AST_FLAG_MOH);
892         ast_deactivate_generator(chan);
893
894         if (chan->music_state) {
895                 if (chan->stream) {
896                         ast_closestream(chan->stream);
897                         chan->stream = NULL;
898                 }
899         }
900 }
901
902 static struct mohclass *moh_class_malloc(void)
903 {
904         struct mohclass *class;
905
906         if ((class = ast_calloc(1, sizeof(*class))))            
907                 class->format = AST_FORMAT_SLINEAR;
908
909         return class;
910 }
911
912 static int load_moh_classes(int reload)
913 {
914         struct ast_config *cfg;
915         struct ast_variable *var;
916         struct mohclass *class; 
917         char *data;
918         char *args;
919         char *cat;
920         int numclasses = 0;
921         static int dep_warning = 0;
922
923         cfg = ast_config_load("musiconhold.conf");
924
925         if (!cfg)
926                 return 0;
927
928         cat = ast_category_browse(cfg, NULL);
929         for (; cat; cat = ast_category_browse(cfg, cat)) {
930                 if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) {                       
931                         if (!(class = moh_class_malloc())) {
932                                 break;
933                         }                               
934                         ast_copy_string(class->name, cat, sizeof(class->name)); 
935                         var = ast_variable_browse(cfg, cat);
936                         while (var) {
937                                 if (!strcasecmp(var->name, "mode"))
938                                         ast_copy_string(class->mode, var->value, sizeof(class->mode)); 
939                                 else if (!strcasecmp(var->name, "directory"))
940                                         ast_copy_string(class->dir, var->value, sizeof(class->dir));
941                                 else if (!strcasecmp(var->name, "application"))
942                                         ast_copy_string(class->args, var->value, sizeof(class->args));
943                                 else if (!strcasecmp(var->name, "random"))
944                                         ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
945                                 else if (!strcasecmp(var->name, "format")) {
946                                         class->format = ast_getformatbyname(var->value);
947                                         if (!class->format) {
948                                                 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
949                                                 class->format = AST_FORMAT_SLINEAR;
950                                         }
951                                 }
952                                         var = var->next;
953                         }
954
955                         if (ast_strlen_zero(class->dir)) {
956                                 if (!strcasecmp(class->mode, "custom")) {
957                                         strcpy(class->dir, "nodir");
958                                 } else {
959                                         ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
960                                         free(class);
961                                         continue;
962                                 }
963                         }
964                         if (ast_strlen_zero(class->mode)) {
965                                 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
966                                 free(class);
967                                 continue;
968                         }
969                         if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
970                                 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
971                                 free(class);
972                                 continue;
973                         }
974
975                         /* Don't leak a class when it's already registered */
976                         moh_register(class, reload);
977
978                         numclasses++;
979                 }
980         }
981         
982
983         /* Deprecated Old-School Configuration */
984         var = ast_variable_browse(cfg, "classes");
985         while (var) {
986                 if (!dep_warning) {
987                         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");
988                         dep_warning = 1;
989                 }
990                 data = strchr(var->value, ':');
991                 if (data) {
992                         *data++ = '\0';
993                         args = strchr(data, ',');
994                         if (args)
995                                 *args++ = '\0';
996                         if (!(get_mohbyname(var->name))) {                      
997                                 if (!(class = moh_class_malloc())) {
998                                         return numclasses;
999                                 }
1000                                 
1001                                 ast_copy_string(class->name, var->name, sizeof(class->name));
1002                                 ast_copy_string(class->dir, data, sizeof(class->dir));
1003                                 ast_copy_string(class->mode, var->value, sizeof(class->mode));
1004                                 if (args)
1005                                         ast_copy_string(class->args, args, sizeof(class->args));
1006                                 
1007                                 moh_register(class, reload);
1008                                 numclasses++;
1009                         }
1010                 }
1011                 var = var->next;
1012         }
1013         var = ast_variable_browse(cfg, "moh_files");
1014         while (var) {
1015                 if (!dep_warning) {
1016                         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");
1017                         dep_warning = 1;
1018                 }
1019                 if (!(get_mohbyname(var->name))) {
1020                         args = strchr(var->value, ',');
1021                         if (args)
1022                                 *args++ = '\0';                 
1023                         if (!(class = moh_class_malloc())) {
1024                                 return numclasses;
1025                         }
1026                         
1027                         ast_copy_string(class->name, var->name, sizeof(class->name));
1028                         ast_copy_string(class->dir, var->value, sizeof(class->dir));
1029                         strcpy(class->mode, "files");
1030                         if (args)       
1031                                 ast_copy_string(class->args, args, sizeof(class->args));
1032                         
1033                         moh_register(class, reload);
1034                         numclasses++;
1035                 }
1036                 var = var->next;
1037         }
1038
1039         ast_config_destroy(cfg);
1040
1041         return numclasses;
1042 }
1043
1044 static void ast_moh_destroy(void)
1045 {
1046         struct mohclass *moh, *tmp;
1047         char buff[8192];
1048         int bytes, tbytes=0, stime = 0, pid = 0;
1049
1050         if (option_verbose > 1)
1051                 ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
1052         ast_mutex_lock(&moh_lock);
1053         moh = mohclasses;
1054
1055         while (moh) {
1056                 if (moh->pid) {
1057                         ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
1058                         stime = time(NULL) + 2;
1059                         pid = moh->pid;
1060                         moh->pid = 0;
1061                         kill(pid, SIGKILL);
1062                         while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime) {
1063                                 tbytes = tbytes + bytes;
1064                         }
1065                         ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
1066                         close(moh->srcfd);
1067                 }
1068                 tmp = moh;
1069                 moh = moh->next;
1070                 ast_moh_free_class(&tmp);
1071         }
1072         mohclasses = NULL;
1073         ast_mutex_unlock(&moh_lock);
1074 }
1075
1076 static void moh_on_off(int on)
1077 {
1078         struct ast_channel *chan = NULL;
1079
1080         while ( (chan = ast_channel_walk_locked(chan)) != NULL) {
1081                 if (ast_test_flag(chan, AST_FLAG_MOH)) {
1082                         if (on)
1083                                 local_ast_moh_start(chan, NULL);
1084                         else
1085                                 ast_deactivate_generator(chan);
1086                 }
1087                 ast_mutex_unlock(&chan->lock);
1088         }
1089 }
1090
1091 static int moh_cli(int fd, int argc, char *argv[]) 
1092 {
1093         int x;
1094
1095         moh_on_off(0);
1096         ast_moh_destroy();
1097         x = load_moh_classes(1);
1098         moh_on_off(1);
1099         ast_cli(fd, "\n%d class%s reloaded.\n", x, x == 1 ? "" : "es");
1100         return 0;
1101 }
1102
1103 static int cli_files_show(int fd, int argc, char *argv[])
1104 {
1105         int i;
1106         struct mohclass *class;
1107
1108         ast_mutex_lock(&moh_lock);
1109         for (class = mohclasses; class; class = class->next) {
1110                 if (!class->total_files)
1111                         continue;
1112
1113                 ast_cli(fd, "Class: %s\n", class->name);
1114                 for (i = 0; i < class->total_files; i++)
1115                         ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
1116         }
1117         ast_mutex_unlock(&moh_lock);
1118
1119         return 0;
1120 }
1121
1122 static int moh_classes_show(int fd, int argc, char *argv[])
1123 {
1124         struct mohclass *class;
1125
1126         ast_mutex_lock(&moh_lock);
1127         for (class = mohclasses; class; class = class->next) {
1128                 ast_cli(fd, "Class: %s\n", class->name);
1129                 ast_cli(fd, "\tMode: %s\n", ast_strlen_zero(class->mode) ? "<none>" : class->mode);
1130                 ast_cli(fd, "\tDirectory: %s\n", ast_strlen_zero(class->dir) ? "<none>" : class->dir);
1131                 if (ast_test_flag(class, MOH_CUSTOM))
1132                         ast_cli(fd, "\tApplication: %s\n", ast_strlen_zero(class->args) ? "<none>" : class->args);
1133                 ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format));
1134         }
1135         ast_mutex_unlock(&moh_lock);
1136
1137         return 0;
1138 }
1139
1140 static struct ast_cli_entry  cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL};
1141
1142 static struct ast_cli_entry  cli_moh_classes_show = { { "moh", "classes", "show"}, moh_classes_show, "List MOH classes", "Lists all MOH classes", NULL};
1143
1144 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};
1145
1146 static int init_classes(int reload) 
1147 {
1148         struct mohclass *moh;
1149     
1150         if (!load_moh_classes(reload))          /* Load classes from config */
1151                 return 0;                       /* Return if nothing is found */
1152         moh = mohclasses;
1153         while (moh) {
1154                 if (moh->total_files)
1155                         moh_scan_files(moh);
1156                 moh = moh->next;
1157         }
1158         return 1;
1159 }
1160
1161 int load_module(void)
1162 {
1163         int res;
1164
1165         res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
1166         ast_register_atexit(ast_moh_destroy);
1167         ast_cli_register(&cli_moh);
1168         ast_cli_register(&cli_moh_files_show);
1169         ast_cli_register(&cli_moh_classes_show);
1170         if (!res)
1171                 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
1172         if (!res)
1173                 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
1174         if (!res)
1175                 res = ast_register_application(app3, moh3_exec, synopsis3, descrip3);
1176         if (!res)
1177                 res = ast_register_application(app4, moh4_exec, synopsis4, descrip4);
1178
1179         if (!init_classes(0)) {         /* No music classes configured, so skip it */
1180                 ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold.");
1181         } else {
1182                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1183         }
1184
1185         return 0;
1186 }
1187
1188 int reload(void)
1189 {
1190         if (init_classes(1))
1191                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1192
1193         return 0;
1194 }
1195
1196 int unload_module(void)
1197 {
1198         return -1;
1199 }
1200
1201 char *description(void)
1202 {
1203         return "Music On Hold Resource";
1204 }
1205
1206 int usecount(void)
1207 {
1208         /* Never allow Music On Hold to be unloaded
1209            unresolve needed symbols in the dialer */
1210 #if 0
1211         int res;
1212         STANDARD_USECOUNT(res);
1213         return res;
1214 #else
1215         return 1;
1216 #endif
1217 }
1218
1219 char *key()
1220 {
1221         return ASTERISK_GPL_KEY;
1222 }