ffbd41713a6b3bbc59d31da542047c8e796dc2a9
[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         int allocated = 0;
283
284         if (!chan->music_state && (state = malloc(sizeof(struct moh_files_state)))) {
285                 chan->music_state = state;
286                 allocated = 1;
287         } else 
288                 state = chan->music_state;
289
290         if (state) {
291                 if (allocated || state->class != class) {
292                         /* initialize */
293                         memset(state, 0, sizeof(struct moh_files_state));
294                         state->class = class;
295                 }
296
297                 state->origwfmt = chan->writeformat;
298
299                 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
300                         ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
301                         free(chan->music_state);
302                         chan->music_state = NULL;
303                 } else {
304                         if (option_verbose > 2)
305                                 ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on %s\n", class->name, chan->name);
306                 }
307         }
308         
309         return chan->music_state;
310 }
311
312 static struct ast_generator moh_file_stream = 
313 {
314         alloc: moh_files_alloc,
315         release: moh_files_release,
316         generate: moh_files_generator,
317 };
318
319 static int spawn_mp3(struct mohclass *class)
320 {
321         int fds[2];
322         int files = 0;
323         char fns[MAX_MP3S][80];
324         char *argv[MAX_MP3S + 50];
325         char xargs[256];
326         char *argptr;
327         int argc = 0;
328         DIR *dir = NULL;
329         struct dirent *de;
330
331         
332         if (!strcasecmp(class->dir, "nodir")) {
333                 files = 1;
334         } else {
335                 dir = opendir(class->dir);
336                 if (!dir && !strstr(class->dir,"http://") && !strstr(class->dir,"HTTP://")) {
337                         ast_log(LOG_WARNING, "%s is not a valid directory\n", class->dir);
338                         return -1;
339                 }
340         }
341
342         if (!ast_test_flag(class, MOH_CUSTOM)) {
343                 argv[argc++] = "mpg123";
344                 argv[argc++] = "-q";
345                 argv[argc++] = "-s";
346                 argv[argc++] = "--mono";
347                 argv[argc++] = "-r";
348                 argv[argc++] = "8000";
349                 
350                 if (!ast_test_flag(class, MOH_SINGLE)) {
351                         argv[argc++] = "-b";
352                         argv[argc++] = "2048";
353                 }
354                 
355                 argv[argc++] = "-f";
356                 
357                 if (ast_test_flag(class, MOH_QUIET))
358                         argv[argc++] = "4096";
359                 else
360                         argv[argc++] = "8192";
361                 
362                 /* Look for extra arguments and add them to the list */
363                 strncpy(xargs, class->args, sizeof(xargs) - 1);
364                 argptr = xargs;
365                 while (!ast_strlen_zero(argptr)) {
366                         argv[argc++] = argptr;
367                         argptr = strchr(argptr, ',');
368                         if (argptr) {
369                                 *argptr = '\0';
370                                 argptr++;
371                         }
372                 }
373         } else  {
374                 /* Format arguments for argv vector */
375                 strncpy(xargs, class->args, sizeof(xargs) - 1);
376                 argptr = xargs;
377                 while (!ast_strlen_zero(argptr)) {
378                         argv[argc++] = argptr;
379                         argptr = strchr(argptr, ' ');
380                         if (argptr) {
381                                 *argptr = '\0';
382                                 argptr++;
383                         }
384                 }
385         }
386
387
388         if (strstr(class->dir,"http://") || strstr(class->dir,"HTTP://")) {
389                 strncpy(fns[files], class->dir, sizeof(fns[files]) - 1);
390                 argv[argc++] = fns[files];
391                 files++;
392         } else if (dir) {
393                 while ((de = readdir(dir)) && (files < MAX_MP3S)) {
394                         if ((strlen(de->d_name) > 3) && 
395                             ((ast_test_flag(class, MOH_CUSTOM) && 
396                               (!strcasecmp(de->d_name + strlen(de->d_name) - 4, ".raw") || 
397                                !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".sln"))) ||
398                              !strcasecmp(de->d_name + strlen(de->d_name) - 4, ".mp3"))) {
399                                 strncpy(fns[files], de->d_name, sizeof(fns[files]) - 1);
400                                 argv[argc++] = fns[files];
401                                 files++;
402                         }
403                 }
404         }
405         argv[argc] = NULL;
406         if (dir) {
407                 closedir(dir);
408         }
409         if (pipe(fds)) {        
410                 ast_log(LOG_WARNING, "Pipe failed\n");
411                 return -1;
412         }
413 #if 0
414         printf("%d files total, %d args total\n", files, argc);
415         {
416                 int x;
417                 for (x=0;argv[x];x++)
418                         printf("arg%d: %s\n", x, argv[x]);
419         }
420 #endif  
421         if (!files) {
422                 ast_log(LOG_WARNING, "Found no files in '%s'\n", class->dir);
423                 close(fds[0]);
424                 close(fds[1]);
425                 return -1;
426         }
427         if (time(NULL) - class->start < respawn_time) {
428                 sleep(respawn_time - (time(NULL) - class->start));
429         }
430         time(&class->start);
431         class->pid = fork();
432         if (class->pid < 0) {
433                 close(fds[0]);
434                 close(fds[1]);
435                 ast_log(LOG_WARNING, "Fork failed: %s\n", strerror(errno));
436                 return -1;
437         }
438         if (!class->pid) {
439                 int x;
440                 close(fds[0]);
441                 /* Stdout goes to pipe */
442                 dup2(fds[1], STDOUT_FILENO);
443                 /* Close unused file descriptors */
444                 for (x=3;x<8192;x++) {
445                         if (-1 != fcntl(x, F_GETFL)) {
446                                 close(x);
447                         }
448                 }
449                 /* Child */
450                 chdir(class->dir);
451                 if (ast_test_flag(class, MOH_CUSTOM)) {
452                         execv(argv[0], argv);
453                 } else {
454                         /* Default install is /usr/local/bin */
455                         execv(LOCAL_MPG_123, argv);
456                         /* Many places have it in /usr/bin */
457                         execv(MPG_123, argv);
458                         /* Check PATH as a last-ditch effort */
459                         execvp("mpg123", argv);
460                 }
461                 ast_log(LOG_WARNING, "Exec failed: %s\n", strerror(errno));
462                 close(fds[1]);
463                 exit(1);
464         } else {
465                 /* Parent */
466                 close(fds[1]);
467         }
468         return fds[0];
469 }
470
471 static void *monmp3thread(void *data)
472 {
473 #define MOH_MS_INTERVAL         100
474
475         struct mohclass *class = data;
476         struct mohdata *moh;
477         char buf[8192];
478         short sbuf[8192];
479         int res, res2;
480         int len;
481         struct timeval tv, tv_tmp;
482
483         tv.tv_sec = 0;
484         tv.tv_usec = 0;
485         for(;/* ever */;) {
486                 /* Spawn mp3 player if it's not there */
487                 if (class->srcfd < 0) {
488                         if ((class->srcfd = spawn_mp3(class)) < 0) {
489                                 ast_log(LOG_WARNING, "Unable to spawn mp3player\n");
490                                 /* Try again later */
491                                 sleep(500);
492                         }
493                 }
494                 if (class->pseudofd > -1) {
495                         /* Pause some amount of time */
496                         res = read(class->pseudofd, buf, sizeof(buf));
497                 } else {
498                         long delta;
499                         /* Reliable sleep */
500                         tv_tmp = ast_tvnow();
501                         if (ast_tvzero(tv))
502                                 tv = tv_tmp;
503                         delta = ast_tvdiff_ms(tv_tmp, tv);
504                         if (delta < MOH_MS_INTERVAL) {  /* too early */
505                                 tv = ast_tvadd(tv, ast_samp2tv(MOH_MS_INTERVAL, 1000)); /* next deadline */
506                                 usleep(1000 * (MOH_MS_INTERVAL - delta));
507                         } else {
508                                 ast_log(LOG_NOTICE, "Request to schedule in the past?!?!\n");
509                                 tv = tv_tmp;
510                         }
511                         res = 8 * MOH_MS_INTERVAL;      /* 8 samples per millisecond */
512                 }
513                 if (!class->members)
514                         continue;
515                 /* Read mp3 audio */
516                 len = ast_codec_get_len(class->format, res);
517                 
518                 if ((res2 = read(class->srcfd, sbuf, len)) != len) {
519                         if (!res2) {
520                                 close(class->srcfd);
521                                 class->srcfd = -1;
522                                 if (class->pid) {
523                                         kill(class->pid, SIGKILL);
524                                         class->pid = 0;
525                                 }
526                         } else
527                                 ast_log(LOG_DEBUG, "Read %d bytes of audio while expecting %d\n", res2, len);
528                         continue;
529                 }
530                 ast_mutex_lock(&moh_lock);
531                 moh = class->members;
532                 while (moh) {
533                         /* Write data */
534                         if ((res = write(moh->pipe[1], sbuf, res2)) != res2) 
535                                 if (option_debug)
536                                         ast_log(LOG_DEBUG, "Only wrote %d of %d bytes to pipe\n", res, res2);
537                         moh = moh->next;
538                 }
539                 ast_mutex_unlock(&moh_lock);
540         }
541         return NULL;
542 }
543
544 static int moh0_exec(struct ast_channel *chan, void *data)
545 {
546         if (ast_moh_start(chan, data)) {
547                 ast_log(LOG_WARNING, "Unable to start music on hold (class '%s') on channel %s\n", (char *)data, chan->name);
548                 return -1;
549         }
550         while (!ast_safe_sleep(chan, 10000));
551         ast_moh_stop(chan);
552         return -1;
553 }
554
555 static int moh1_exec(struct ast_channel *chan, void *data)
556 {
557         int res;
558         if (!data || !atoi(data)) {
559                 ast_log(LOG_WARNING, "WaitMusicOnHold requires an argument (number of seconds to wait)\n");
560                 return -1;
561         }
562         if (ast_moh_start(chan, NULL)) {
563                 ast_log(LOG_WARNING, "Unable to start music on hold for %d seconds on channel %s\n", atoi(data), chan->name);
564                 return -1;
565         }
566         res = ast_safe_sleep(chan, atoi(data) * 1000);
567         ast_moh_stop(chan);
568         return res;
569 }
570
571 static int moh2_exec(struct ast_channel *chan, void *data)
572 {
573         if (ast_strlen_zero(data)) {
574                 ast_log(LOG_WARNING, "SetMusicOnHold requires an argument (class)\n");
575                 return -1;
576         }
577         strncpy(chan->musicclass, data, sizeof(chan->musicclass) - 1);
578         return 0;
579 }
580
581 static int moh3_exec(struct ast_channel *chan, void *data)
582 {
583         char *class = NULL;
584         if (data && strlen(data))
585                 class = data;
586         if (ast_moh_start(chan, class)) 
587                 ast_log(LOG_NOTICE, "Unable to start music on hold class '%s' on channel %s\n", class ? class : "default", chan->name);
588
589         return 0;
590 }
591
592 static int moh4_exec(struct ast_channel *chan, void *data)
593 {
594         ast_moh_stop(chan);
595
596         return 0;
597 }
598
599 static struct mohclass *get_mohbyname(char *name)
600 {
601         struct mohclass *moh;
602         moh = mohclasses;
603         while (moh) {
604                 if (!strcasecmp(name, moh->name))
605                         return moh;
606                 moh = moh->next;
607         }
608         return NULL;
609 }
610
611 static struct mohdata *mohalloc(struct mohclass *cl)
612 {
613         struct mohdata *moh;
614         long flags;
615         moh = malloc(sizeof(struct mohdata));
616         if (!moh)
617                 return NULL;
618         memset(moh, 0, sizeof(struct mohdata));
619         if (pipe(moh->pipe)) {
620                 ast_log(LOG_WARNING, "Failed to create pipe: %s\n", strerror(errno));
621                 free(moh);
622                 return NULL;
623         }
624         /* Make entirely non-blocking */
625         flags = fcntl(moh->pipe[0], F_GETFL);
626         fcntl(moh->pipe[0], F_SETFL, flags | O_NONBLOCK);
627         flags = fcntl(moh->pipe[1], F_GETFL);
628         fcntl(moh->pipe[1], F_SETFL, flags | O_NONBLOCK);
629         moh->parent = cl;
630         moh->next = cl->members;
631         cl->members = moh;
632         return moh;
633 }
634
635 static void moh_release(struct ast_channel *chan, void *data)
636 {
637         struct mohdata *moh = data, *prev, *cur;
638         int oldwfmt;
639         ast_mutex_lock(&moh_lock);
640         /* Unlink */
641         prev = NULL;
642         cur = moh->parent->members;
643         while (cur) {
644                 if (cur == moh) {
645                         if (prev)
646                                 prev->next = cur->next;
647                         else
648                                 moh->parent->members = cur->next;
649                         break;
650                 }
651                 prev = cur;
652                 cur = cur->next;
653         }
654         ast_mutex_unlock(&moh_lock);
655         close(moh->pipe[0]);
656         close(moh->pipe[1]);
657         oldwfmt = moh->origwfmt;
658         free(moh);
659         if (chan) {
660                 if (oldwfmt && ast_set_write_format(chan, oldwfmt)) 
661                         ast_log(LOG_WARNING, "Unable to restore channel '%s' to format %s\n", chan->name, ast_getformatname(oldwfmt));
662                 if (option_verbose > 2)
663                         ast_verbose(VERBOSE_PREFIX_3 "Stopped music on hold on %s\n", chan->name);
664         }
665 }
666
667 static void *moh_alloc(struct ast_channel *chan, void *params)
668 {
669         struct mohdata *res;
670         struct mohclass *class = params;
671
672         res = mohalloc(class);
673         if (res) {
674                 res->origwfmt = chan->writeformat;
675                 if (ast_set_write_format(chan, class->format)) {
676                         ast_log(LOG_WARNING, "Unable to set channel '%s' to format '%s'\n", chan->name, ast_codec2str(class->format));
677                         moh_release(NULL, res);
678                         res = NULL;
679                 }
680                 if (option_verbose > 2)
681                         ast_verbose(VERBOSE_PREFIX_3 "Started music on hold, class '%s', on channel '%s'\n", class->name, chan->name);
682         }
683         return res;
684 }
685
686 static int moh_generate(struct ast_channel *chan, void *data, int len, int samples)
687 {
688         struct ast_frame f;
689         struct mohdata *moh = data;
690         short buf[1280 + AST_FRIENDLY_OFFSET / 2];
691         int res;
692
693         if (!moh->parent->pid)
694                 return -1;
695
696         len = ast_codec_get_len(moh->parent->format, samples);
697
698         if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
699                 ast_log(LOG_WARNING, "Only doing %d of %d requested bytes on %s\n", (int)sizeof(buf), len, chan->name);
700                 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
701         }
702         res = read(moh->pipe[0], buf + AST_FRIENDLY_OFFSET/2, len);
703 #if 0
704         if (res != len) {
705                 ast_log(LOG_WARNING, "Read only %d of %d bytes: %s\n", res, len, strerror(errno));
706         }
707 #endif
708         if (res <= 0)
709                 return 0;
710
711         memset(&f, 0, sizeof(f));
712         
713         f.frametype = AST_FRAME_VOICE;
714         f.subclass = moh->parent->format;
715         f.mallocd = 0;
716         f.datalen = res;
717         f.data = buf + AST_FRIENDLY_OFFSET / 2;
718         f.offset = AST_FRIENDLY_OFFSET;
719         f.samples = ast_codec_get_samples(&f);
720
721         if (ast_write(chan, &f) < 0) {
722                 ast_log(LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror(errno));
723                 return -1;
724         }
725
726         return 0;
727 }
728
729 static struct ast_generator mohgen = 
730 {
731         alloc: moh_alloc,
732         release: moh_release,
733         generate: moh_generate,
734 };
735
736 static int moh_scan_files(struct mohclass *class) {
737
738         DIR *files_DIR;
739         struct dirent *files_dirent;
740         char path[512];
741         char filepath[MAX_MOHFILE_LEN];
742         char *ext;
743         struct stat statbuf;
744         int dirnamelen;
745         int i;
746         
747         files_DIR = opendir(class->dir);
748         if (!files_DIR) {
749                 ast_log(LOG_WARNING, "Cannot open dir %s or dir does not exist", class->dir);
750                 return -1;
751         }
752
753         class->total_files = 0;
754         dirnamelen = strlen(class->dir) + 2;
755         getcwd(path, 512);
756         chdir(class->dir);
757         memset(class->filearray, 0, MAX_MOHFILES*MAX_MOHFILE_LEN);
758         while ((files_dirent = readdir(files_DIR))) {
759                 if ((strlen(files_dirent->d_name) < 4) || ((strlen(files_dirent->d_name) + dirnamelen) >= MAX_MOHFILE_LEN))
760                         continue;
761
762                 snprintf(filepath, MAX_MOHFILE_LEN, "%s/%s", class->dir, files_dirent->d_name);
763
764                 if (stat(filepath, &statbuf))
765                         continue;
766
767                 if (!S_ISREG(statbuf.st_mode))
768                         continue;
769
770                 if ((ext = strrchr(filepath, '.'))) {
771                         *ext = '\0';
772                         ext++;
773                 }
774
775                 /* if the file is present in multiple formats, ensure we only put it into the list once */
776                 for (i = 0; i < class->total_files; i++)
777                         if (!strcmp(filepath, class->filearray[i]))
778                                 break;
779
780                 if (i == class->total_files)
781                         strcpy(class->filearray[class->total_files++], filepath);
782         }
783
784         closedir(files_DIR);
785         chdir(path);
786         return class->total_files;
787 }
788
789 static int moh_register(struct mohclass *moh, int reload)
790 {
791 #ifdef ZAPATA_MOH
792         int x;
793 #endif
794         ast_mutex_lock(&moh_lock);
795         if (get_mohbyname(moh->name)) {
796                 if (reload) {
797                         ast_log(LOG_DEBUG, "Music on Hold class '%s' left alone from initial load.\n", moh->name);
798                 } else {
799                         ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
800                 }
801                 free(moh);      
802                 ast_mutex_unlock(&moh_lock);
803                 return -1;
804         }
805         ast_mutex_unlock(&moh_lock);
806
807         time(&moh->start);
808         moh->start -= respawn_time;
809         
810         if (!strcasecmp(moh->mode, "files")) {
811                 if (!moh_scan_files(moh)) {
812                         ast_moh_free_class(&moh);
813                         return -1;
814                 }
815                 if (strchr(moh->args, 'r'))
816                         ast_set_flag(moh, MOH_RANDOMIZE);
817         } 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")) {
818
819                 if (!strcasecmp(moh->mode, "custom"))
820                         ast_set_flag(moh, MOH_CUSTOM);
821                 else if (!strcasecmp(moh->mode, "mp3nb"))
822                         ast_set_flag(moh, MOH_SINGLE);
823                 else if (!strcasecmp(moh->mode, "quietmp3nb"))
824                         ast_set_flag(moh, MOH_SINGLE | MOH_QUIET);
825                 else if (!strcasecmp(moh->mode, "quietmp3"))
826                         ast_set_flag(moh, MOH_QUIET);
827                 
828                 moh->srcfd = -1;
829 #ifdef ZAPATA_MOH
830                 /* Open /dev/zap/pseudo for timing...  Is
831                    there a better, yet reliable way to do this? */
832                 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
833                 if (moh->pseudofd < 0) {
834                         ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
835                 } else {
836                         x = 320;
837                         ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
838                 }
839 #else
840                 moh->pseudofd = -1;
841 #endif
842                 if (ast_pthread_create(&moh->thread, NULL, monmp3thread, moh)) {
843                         ast_log(LOG_WARNING, "Unable to create moh...\n");
844                         if (moh->pseudofd > -1)
845                                 close(moh->pseudofd);
846                         ast_moh_free_class(&moh);
847                         return -1;
848                 }
849         } else {
850                 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
851                 ast_moh_free_class(&moh);
852                 return -1;
853         }
854         ast_mutex_lock(&moh_lock);
855         moh->next = mohclasses;
856         mohclasses = moh;
857         ast_mutex_unlock(&moh_lock);
858         return 0;
859 }
860
861 static void local_ast_moh_cleanup(struct ast_channel *chan)
862 {
863         if (chan->music_state) {
864                 free(chan->music_state);
865                 chan->music_state = NULL;
866         }
867 }
868
869 static int local_ast_moh_start(struct ast_channel *chan, char *class)
870 {
871         struct mohclass *mohclass;
872
873         if (ast_strlen_zero(class))
874                 class = chan->musicclass;
875         if (ast_strlen_zero(class))
876                 class = "default";
877         ast_mutex_lock(&moh_lock);
878         mohclass = get_mohbyname(class);
879         ast_mutex_unlock(&moh_lock);
880
881         if (!mohclass) {
882                 ast_log(LOG_WARNING, "No class: %s\n", (char *)class);
883                 return -1;
884         }
885
886         ast_set_flag(chan, AST_FLAG_MOH);
887         if (mohclass->total_files) {
888                 return ast_activate_generator(chan, &moh_file_stream, mohclass);
889         } else
890                 return ast_activate_generator(chan, &mohgen, mohclass);
891 }
892
893 static void local_ast_moh_stop(struct ast_channel *chan)
894 {
895         ast_clear_flag(chan, AST_FLAG_MOH);
896         ast_deactivate_generator(chan);
897
898         if (chan->music_state) {
899                 if (chan->stream) {
900                         ast_closestream(chan->stream);
901                         chan->stream = NULL;
902                 }
903         }
904 }
905
906 static struct mohclass *moh_class_malloc(void)
907 {
908         struct mohclass *class;
909
910         class = malloc(sizeof(struct mohclass));
911
912         if (!class)
913                 return NULL;
914
915         memset(class, 0, sizeof(struct mohclass));
916
917         class->format = AST_FORMAT_SLINEAR;
918
919         return class;
920 }
921
922 static int load_moh_classes(int reload)
923 {
924         struct ast_config *cfg;
925         struct ast_variable *var;
926         struct mohclass *class; 
927         char *data;
928         char *args;
929         char *cat;
930         int numclasses = 0;
931         static int dep_warning = 0;
932
933         cfg = ast_config_load("musiconhold.conf");
934
935         if (!cfg)
936                 return 0;
937
938         cat = ast_category_browse(cfg, NULL);
939         for (; cat; cat = ast_category_browse(cfg, cat)) {
940                 if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) {
941                         class = moh_class_malloc();
942                         if (!class) {
943                                 ast_log(LOG_WARNING, "Out of memory!\n");
944                                 break;
945                         }                               
946                         ast_copy_string(class->name, cat, sizeof(class->name)); 
947                         var = ast_variable_browse(cfg, cat);
948                         while (var) {
949                                 if (!strcasecmp(var->name, "mode"))
950                                         ast_copy_string(class->mode, var->value, sizeof(class->mode)); 
951                                 else if (!strcasecmp(var->name, "directory"))
952                                         ast_copy_string(class->dir, var->value, sizeof(class->dir));
953                                 else if (!strcasecmp(var->name, "application"))
954                                         ast_copy_string(class->args, var->value, sizeof(class->args));
955                                 else if (!strcasecmp(var->name, "random"))
956                                         ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
957                                 else if (!strcasecmp(var->name, "format")) {
958                                         class->format = ast_getformatbyname(var->value);
959                                         if (!class->format) {
960                                                 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
961                                                 class->format = AST_FORMAT_SLINEAR;
962                                         }
963                                 }
964                                         var = var->next;
965                         }
966
967                         if (ast_strlen_zero(class->dir)) {
968                                 if (!strcasecmp(class->mode, "custom")) {
969                                         strcpy(class->dir, "nodir");
970                                 } else {
971                                         ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
972                                         free(class);
973                                         continue;
974                                 }
975                         }
976                         if (ast_strlen_zero(class->mode)) {
977                                 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
978                                 free(class);
979                                 continue;
980                         }
981                         if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
982                                 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
983                                 free(class);
984                                 continue;
985                         }
986
987                         /* Don't leak a class when it's already registered */
988                         moh_register(class, reload);
989
990                         numclasses++;
991                 }
992         }
993         
994
995         /* Deprecated Old-School Configuration */
996         var = ast_variable_browse(cfg, "classes");
997         while (var) {
998                 if (!dep_warning) {
999                         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");
1000                         dep_warning = 1;
1001                 }
1002                 data = strchr(var->value, ':');
1003                 if (data) {
1004                         *data++ = '\0';
1005                         args = strchr(data, ',');
1006                         if (args)
1007                                 *args++ = '\0';
1008                         if (!(get_mohbyname(var->name))) {
1009                                 class = moh_class_malloc();
1010                                 if (!class) {
1011                                         ast_log(LOG_WARNING, "Out of memory!\n");
1012                                         return numclasses;
1013                                 }
1014                                 
1015                                 ast_copy_string(class->name, var->name, sizeof(class->name));
1016                                 ast_copy_string(class->dir, data, sizeof(class->dir));
1017                                 ast_copy_string(class->mode, var->value, sizeof(class->mode));
1018                                 if (args)
1019                                         ast_copy_string(class->args, args, sizeof(class->args));
1020                                 
1021                                 moh_register(class, reload);
1022                                 numclasses++;
1023                         }
1024                 }
1025                 var = var->next;
1026         }
1027         var = ast_variable_browse(cfg, "moh_files");
1028         while (var) {
1029                 if (!dep_warning) {
1030                         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");
1031                         dep_warning = 1;
1032                 }
1033                 if (!(get_mohbyname(var->name))) {
1034                         args = strchr(var->value, ',');
1035                         if (args)
1036                                 *args++ = '\0';
1037                         class = moh_class_malloc();
1038                         if (!class) {
1039                                 ast_log(LOG_WARNING, "Out of memory!\n");
1040                                 return numclasses;
1041                         }
1042                         
1043                         ast_copy_string(class->name, var->name, sizeof(class->name));
1044                         ast_copy_string(class->dir, var->value, sizeof(class->dir));
1045                         strcpy(class->mode, "files");
1046                         if (args)       
1047                                 ast_copy_string(class->args, args, sizeof(class->args));
1048                         
1049                         moh_register(class, reload);
1050                         numclasses++;
1051                 }
1052                 var = var->next;
1053         }
1054
1055         ast_config_destroy(cfg);
1056
1057         return numclasses;
1058 }
1059
1060 static void ast_moh_destroy(void)
1061 {
1062         struct mohclass *moh, *tmp;
1063         char buff[8192];
1064         int bytes, tbytes=0, stime = 0, pid = 0;
1065
1066         if (option_verbose > 1)
1067                 ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
1068         ast_mutex_lock(&moh_lock);
1069         moh = mohclasses;
1070
1071         while (moh) {
1072                 if (moh->pid) {
1073                         ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
1074                         stime = time(NULL) + 2;
1075                         pid = moh->pid;
1076                         moh->pid = 0;
1077                         kill(pid, SIGKILL);
1078                         while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime) {
1079                                 tbytes = tbytes + bytes;
1080                         }
1081                         ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
1082                         close(moh->srcfd);
1083                 }
1084                 tmp = moh;
1085                 moh = moh->next;
1086                 ast_moh_free_class(&tmp);
1087         }
1088         mohclasses = NULL;
1089         ast_mutex_unlock(&moh_lock);
1090 }
1091
1092 static void moh_on_off(int on)
1093 {
1094         struct ast_channel *chan = NULL;
1095
1096         while ( (chan = ast_channel_walk_locked(chan)) != NULL) {
1097                 if (ast_test_flag(chan, AST_FLAG_MOH)) {
1098                         if (on)
1099                                 local_ast_moh_start(chan, NULL);
1100                         else
1101                                 ast_deactivate_generator(chan);
1102                 }
1103                 ast_mutex_unlock(&chan->lock);
1104         }
1105 }
1106
1107 static int moh_cli(int fd, int argc, char *argv[]) 
1108 {
1109         int x;
1110
1111         moh_on_off(0);
1112         ast_moh_destroy();
1113         x = load_moh_classes(1);
1114         moh_on_off(1);
1115         ast_cli(fd, "\n%d class%s reloaded.\n", x, x == 1 ? "" : "es");
1116         return 0;
1117 }
1118
1119 static int cli_files_show(int fd, int argc, char *argv[])
1120 {
1121         int i;
1122         struct mohclass *class;
1123
1124         ast_mutex_lock(&moh_lock);
1125         for (class = mohclasses; class; class = class->next) {
1126                 if (!class->total_files)
1127                         continue;
1128
1129                 ast_cli(fd, "Class: %s\n", class->name);
1130                 for (i = 0; i < class->total_files; i++)
1131                         ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
1132         }
1133         ast_mutex_unlock(&moh_lock);
1134
1135         return 0;
1136 }
1137
1138 static int moh_classes_show(int fd, int argc, char *argv[])
1139 {
1140         struct mohclass *class;
1141
1142         ast_mutex_lock(&moh_lock);
1143         for (class = mohclasses; class; class = class->next) {
1144                 ast_cli(fd, "Class: %s\n", class->name);
1145                 ast_cli(fd, "\tMode: %s\n", ast_strlen_zero(class->mode) ? "<none>" : class->mode);
1146                 ast_cli(fd, "\tDirectory: %s\n", ast_strlen_zero(class->dir) ? "<none>" : class->dir);
1147                 if (ast_test_flag(class, MOH_CUSTOM))
1148                         ast_cli(fd, "\tApplication: %s\n", ast_strlen_zero(class->args) ? "<none>" : class->args);
1149                 ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format));
1150         }
1151         ast_mutex_unlock(&moh_lock);
1152
1153         return 0;
1154 }
1155
1156 static struct ast_cli_entry  cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL};
1157
1158 static struct ast_cli_entry  cli_moh_classes_show = { { "moh", "classes", "show"}, moh_classes_show, "List MOH classes", "Lists all MOH classes", NULL};
1159
1160 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};
1161
1162 static int init_classes(int reload) 
1163 {
1164         struct mohclass *moh;
1165     
1166         if (!load_moh_classes(reload))          /* Load classes from config */
1167                 return 0;                       /* Return if nothing is found */
1168         moh = mohclasses;
1169         while (moh) {
1170                 if (moh->total_files)
1171                         moh_scan_files(moh);
1172                 moh = moh->next;
1173         }
1174         return 1;
1175 }
1176
1177 int load_module(void)
1178 {
1179         int res;
1180
1181         res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
1182         ast_register_atexit(ast_moh_destroy);
1183         ast_cli_register(&cli_moh);
1184         ast_cli_register(&cli_moh_files_show);
1185         ast_cli_register(&cli_moh_classes_show);
1186         if (!res)
1187                 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
1188         if (!res)
1189                 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
1190         if (!res)
1191                 res = ast_register_application(app3, moh3_exec, synopsis3, descrip3);
1192         if (!res)
1193                 res = ast_register_application(app4, moh4_exec, synopsis4, descrip4);
1194
1195         if (!init_classes(0)) {         /* No music classes configured, so skip it */
1196                 ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold.");
1197         } else {
1198                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1199         }
1200
1201         return 0;
1202 }
1203
1204 int reload(void)
1205 {
1206         if (init_classes(1))
1207                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1208
1209         return 0;
1210 }
1211
1212 int unload_module(void)
1213 {
1214         return -1;
1215 }
1216
1217 char *description(void)
1218 {
1219         return "Music On Hold Resource";
1220 }
1221
1222 int usecount(void)
1223 {
1224         /* Never allow Music On Hold to be unloaded
1225            unresolve needed symbols in the dialer */
1226 #if 0
1227         int res;
1228         STANDARD_USECOUNT(res);
1229         return res;
1230 #else
1231         return 1;
1232 #endif
1233 }
1234
1235 char *key()
1236 {
1237         return ASTERISK_GPL_KEY;
1238 }