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