Reverting revision 10998 that was accidentaly committed to trunk. My apologies.
[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 = rand();
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
781         closedir(files_DIR);
782         chdir(path);
783         return class->total_files;
784 }
785
786 static int moh_register(struct mohclass *moh, int reload)
787 {
788 #ifdef ZAPATA_MOH
789         int x;
790 #endif
791         ast_mutex_lock(&moh_lock);
792         if (get_mohbyname(moh->name)) {
793                 if (reload) {
794                         ast_log(LOG_DEBUG, "Music on Hold class '%s' left alone from initial load.\n", moh->name);
795                 } else {
796                         ast_log(LOG_WARNING, "Music on Hold class '%s' already exists\n", moh->name);
797                 }
798                 free(moh);      
799                 ast_mutex_unlock(&moh_lock);
800                 return -1;
801         }
802         ast_mutex_unlock(&moh_lock);
803
804         time(&moh->start);
805         moh->start -= respawn_time;
806         
807         if (!strcasecmp(moh->mode, "files")) {
808                 if (!moh_scan_files(moh)) {
809                         ast_moh_free_class(&moh);
810                         return -1;
811                 }
812                 if (strchr(moh->args, 'r'))
813                         ast_set_flag(moh, MOH_RANDOMIZE);
814         } 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")) {
815
816                 if (!strcasecmp(moh->mode, "custom"))
817                         ast_set_flag(moh, MOH_CUSTOM);
818                 else if (!strcasecmp(moh->mode, "mp3nb"))
819                         ast_set_flag(moh, MOH_SINGLE);
820                 else if (!strcasecmp(moh->mode, "quietmp3nb"))
821                         ast_set_flag(moh, MOH_SINGLE | MOH_QUIET);
822                 else if (!strcasecmp(moh->mode, "quietmp3"))
823                         ast_set_flag(moh, MOH_QUIET);
824                 
825                 moh->srcfd = -1;
826 #ifdef ZAPATA_MOH
827                 /* Open /dev/zap/pseudo for timing...  Is
828                    there a better, yet reliable way to do this? */
829                 moh->pseudofd = open("/dev/zap/pseudo", O_RDONLY);
830                 if (moh->pseudofd < 0) {
831                         ast_log(LOG_WARNING, "Unable to open pseudo channel for timing...  Sound may be choppy.\n");
832                 } else {
833                         x = 320;
834                         ioctl(moh->pseudofd, ZT_SET_BLOCKSIZE, &x);
835                 }
836 #else
837                 moh->pseudofd = -1;
838 #endif
839                 if (ast_pthread_create(&moh->thread, NULL, monmp3thread, moh)) {
840                         ast_log(LOG_WARNING, "Unable to create moh...\n");
841                         if (moh->pseudofd > -1)
842                                 close(moh->pseudofd);
843                         ast_moh_free_class(&moh);
844                         return -1;
845                 }
846         } else {
847                 ast_log(LOG_WARNING, "Don't know how to do a mode '%s' music on hold\n", moh->mode);
848                 ast_moh_free_class(&moh);
849                 return -1;
850         }
851         ast_mutex_lock(&moh_lock);
852         moh->next = mohclasses;
853         mohclasses = moh;
854         ast_mutex_unlock(&moh_lock);
855         return 0;
856 }
857
858 static void local_ast_moh_cleanup(struct ast_channel *chan)
859 {
860         if (chan->music_state) {
861                 free(chan->music_state);
862                 chan->music_state = NULL;
863         }
864 }
865
866 static int local_ast_moh_start(struct ast_channel *chan, const char *class)
867 {
868         struct mohclass *mohclass;
869
870         if (ast_strlen_zero(class))
871                 class = chan->musicclass;
872         if (ast_strlen_zero(class))
873                 class = "default";
874         ast_mutex_lock(&moh_lock);
875         mohclass = get_mohbyname(class);
876         ast_mutex_unlock(&moh_lock);
877
878         if (!mohclass) {
879                 ast_log(LOG_WARNING, "No class: %s\n", (char *)class);
880                 return -1;
881         }
882
883         ast_set_flag(chan, AST_FLAG_MOH);
884         if (mohclass->total_files) {
885                 return ast_activate_generator(chan, &moh_file_stream, mohclass);
886         } else
887                 return ast_activate_generator(chan, &mohgen, mohclass);
888 }
889
890 static void local_ast_moh_stop(struct ast_channel *chan)
891 {
892         ast_clear_flag(chan, AST_FLAG_MOH);
893         ast_deactivate_generator(chan);
894
895         if (chan->music_state) {
896                 if (chan->stream) {
897                         ast_closestream(chan->stream);
898                         chan->stream = NULL;
899                 }
900         }
901 }
902
903 static struct mohclass *moh_class_malloc(void)
904 {
905         struct mohclass *class;
906
907         if ((class = ast_calloc(1, sizeof(*class))))            
908                 class->format = AST_FORMAT_SLINEAR;
909
910         return class;
911 }
912
913 static int load_moh_classes(int reload)
914 {
915         struct ast_config *cfg;
916         struct ast_variable *var;
917         struct mohclass *class; 
918         char *data;
919         char *args;
920         char *cat;
921         int numclasses = 0;
922         static int dep_warning = 0;
923
924         cfg = ast_config_load("musiconhold.conf");
925
926         if (!cfg)
927                 return 0;
928
929         cat = ast_category_browse(cfg, NULL);
930         for (; cat; cat = ast_category_browse(cfg, cat)) {
931                 if (strcasecmp(cat, "classes") && strcasecmp(cat, "moh_files")) {                       
932                         if (!(class = moh_class_malloc())) {
933                                 break;
934                         }                               
935                         ast_copy_string(class->name, cat, sizeof(class->name)); 
936                         var = ast_variable_browse(cfg, cat);
937                         while (var) {
938                                 if (!strcasecmp(var->name, "mode"))
939                                         ast_copy_string(class->mode, var->value, sizeof(class->mode)); 
940                                 else if (!strcasecmp(var->name, "directory"))
941                                         ast_copy_string(class->dir, var->value, sizeof(class->dir));
942                                 else if (!strcasecmp(var->name, "application"))
943                                         ast_copy_string(class->args, var->value, sizeof(class->args));
944                                 else if (!strcasecmp(var->name, "random"))
945                                         ast_set2_flag(class, ast_true(var->value), MOH_RANDOMIZE);
946                                 else if (!strcasecmp(var->name, "format")) {
947                                         class->format = ast_getformatbyname(var->value);
948                                         if (!class->format) {
949                                                 ast_log(LOG_WARNING, "Unknown format '%s' -- defaulting to SLIN\n", var->value);
950                                                 class->format = AST_FORMAT_SLINEAR;
951                                         }
952                                 }
953                                         var = var->next;
954                         }
955
956                         if (ast_strlen_zero(class->dir)) {
957                                 if (!strcasecmp(class->mode, "custom")) {
958                                         strcpy(class->dir, "nodir");
959                                 } else {
960                                         ast_log(LOG_WARNING, "A directory must be specified for class '%s'!\n", class->name);
961                                         free(class);
962                                         continue;
963                                 }
964                         }
965                         if (ast_strlen_zero(class->mode)) {
966                                 ast_log(LOG_WARNING, "A mode must be specified for class '%s'!\n", class->name);
967                                 free(class);
968                                 continue;
969                         }
970                         if (ast_strlen_zero(class->args) && !strcasecmp(class->mode, "custom")) {
971                                 ast_log(LOG_WARNING, "An application must be specified for class '%s'!\n", class->name);
972                                 free(class);
973                                 continue;
974                         }
975
976                         /* Don't leak a class when it's already registered */
977                         moh_register(class, reload);
978
979                         numclasses++;
980                 }
981         }
982         
983
984         /* Deprecated Old-School Configuration */
985         var = ast_variable_browse(cfg, "classes");
986         while (var) {
987                 if (!dep_warning) {
988                         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");
989                         dep_warning = 1;
990                 }
991                 data = strchr(var->value, ':');
992                 if (data) {
993                         *data++ = '\0';
994                         args = strchr(data, ',');
995                         if (args)
996                                 *args++ = '\0';
997                         if (!(get_mohbyname(var->name))) {                      
998                                 if (!(class = moh_class_malloc())) {
999                                         return numclasses;
1000                                 }
1001                                 
1002                                 ast_copy_string(class->name, var->name, sizeof(class->name));
1003                                 ast_copy_string(class->dir, data, sizeof(class->dir));
1004                                 ast_copy_string(class->mode, var->value, sizeof(class->mode));
1005                                 if (args)
1006                                         ast_copy_string(class->args, args, sizeof(class->args));
1007                                 
1008                                 moh_register(class, reload);
1009                                 numclasses++;
1010                         }
1011                 }
1012                 var = var->next;
1013         }
1014         var = ast_variable_browse(cfg, "moh_files");
1015         while (var) {
1016                 if (!dep_warning) {
1017                         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");
1018                         dep_warning = 1;
1019                 }
1020                 if (!(get_mohbyname(var->name))) {
1021                         args = strchr(var->value, ',');
1022                         if (args)
1023                                 *args++ = '\0';                 
1024                         if (!(class = moh_class_malloc())) {
1025                                 return numclasses;
1026                         }
1027                         
1028                         ast_copy_string(class->name, var->name, sizeof(class->name));
1029                         ast_copy_string(class->dir, var->value, sizeof(class->dir));
1030                         strcpy(class->mode, "files");
1031                         if (args)       
1032                                 ast_copy_string(class->args, args, sizeof(class->args));
1033                         
1034                         moh_register(class, reload);
1035                         numclasses++;
1036                 }
1037                 var = var->next;
1038         }
1039
1040         ast_config_destroy(cfg);
1041
1042         return numclasses;
1043 }
1044
1045 static void ast_moh_destroy(void)
1046 {
1047         struct mohclass *moh, *tmp;
1048         char buff[8192];
1049         int bytes, tbytes=0, stime = 0, pid = 0;
1050
1051         if (option_verbose > 1)
1052                 ast_verbose(VERBOSE_PREFIX_2 "Destroying musiconhold processes\n");
1053         ast_mutex_lock(&moh_lock);
1054         moh = mohclasses;
1055
1056         while (moh) {
1057                 if (moh->pid) {
1058                         ast_log(LOG_DEBUG, "killing %d!\n", moh->pid);
1059                         stime = time(NULL) + 2;
1060                         pid = moh->pid;
1061                         moh->pid = 0;
1062                         kill(pid, SIGKILL);
1063                         while ((ast_wait_for_input(moh->srcfd, 100) > 0) && (bytes = read(moh->srcfd, buff, 8192)) && time(NULL) < stime) {
1064                                 tbytes = tbytes + bytes;
1065                         }
1066                         ast_log(LOG_DEBUG, "mpg123 pid %d and child died after %d bytes read\n", pid, tbytes);
1067                         close(moh->srcfd);
1068                 }
1069                 tmp = moh;
1070                 moh = moh->next;
1071                 ast_moh_free_class(&tmp);
1072         }
1073         mohclasses = NULL;
1074         ast_mutex_unlock(&moh_lock);
1075 }
1076
1077 static void moh_on_off(int on)
1078 {
1079         struct ast_channel *chan = NULL;
1080
1081         while ( (chan = ast_channel_walk_locked(chan)) != NULL) {
1082                 if (ast_test_flag(chan, AST_FLAG_MOH)) {
1083                         if (on)
1084                                 local_ast_moh_start(chan, NULL);
1085                         else
1086                                 ast_deactivate_generator(chan);
1087                 }
1088                 ast_mutex_unlock(&chan->lock);
1089         }
1090 }
1091
1092 static int moh_cli(int fd, int argc, char *argv[]) 
1093 {
1094         int x;
1095
1096         moh_on_off(0);
1097         ast_moh_destroy();
1098         x = load_moh_classes(1);
1099         moh_on_off(1);
1100         ast_cli(fd, "\n%d class%s reloaded.\n", x, x == 1 ? "" : "es");
1101         return 0;
1102 }
1103
1104 static int cli_files_show(int fd, int argc, char *argv[])
1105 {
1106         int i;
1107         struct mohclass *class;
1108
1109         ast_mutex_lock(&moh_lock);
1110         for (class = mohclasses; class; class = class->next) {
1111                 if (!class->total_files)
1112                         continue;
1113
1114                 ast_cli(fd, "Class: %s\n", class->name);
1115                 for (i = 0; i < class->total_files; i++)
1116                         ast_cli(fd, "\tFile: %s\n", class->filearray[i]);
1117         }
1118         ast_mutex_unlock(&moh_lock);
1119
1120         return 0;
1121 }
1122
1123 static int moh_classes_show(int fd, int argc, char *argv[])
1124 {
1125         struct mohclass *class;
1126
1127         ast_mutex_lock(&moh_lock);
1128         for (class = mohclasses; class; class = class->next) {
1129                 ast_cli(fd, "Class: %s\n", class->name);
1130                 ast_cli(fd, "\tMode: %s\n", ast_strlen_zero(class->mode) ? "<none>" : class->mode);
1131                 ast_cli(fd, "\tDirectory: %s\n", ast_strlen_zero(class->dir) ? "<none>" : class->dir);
1132                 if (ast_test_flag(class, MOH_CUSTOM))
1133                         ast_cli(fd, "\tApplication: %s\n", ast_strlen_zero(class->args) ? "<none>" : class->args);
1134                 ast_cli(fd, "\tFormat: %s\n", ast_getformatname(class->format));
1135         }
1136         ast_mutex_unlock(&moh_lock);
1137
1138         return 0;
1139 }
1140
1141 static struct ast_cli_entry  cli_moh = { { "moh", "reload"}, moh_cli, "Music On Hold", "Music On Hold", NULL};
1142
1143 static struct ast_cli_entry  cli_moh_classes_show = { { "moh", "classes", "show"}, moh_classes_show, "List MOH classes", "Lists all MOH classes", NULL};
1144
1145 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};
1146
1147 static int init_classes(int reload) 
1148 {
1149         struct mohclass *moh;
1150     
1151         if (!load_moh_classes(reload))          /* Load classes from config */
1152                 return 0;                       /* Return if nothing is found */
1153         moh = mohclasses;
1154         while (moh) {
1155                 if (moh->total_files)
1156                         moh_scan_files(moh);
1157                 moh = moh->next;
1158         }
1159         return 1;
1160 }
1161
1162 int load_module(void)
1163 {
1164         int res;
1165
1166         res = ast_register_application(app0, moh0_exec, synopsis0, descrip0);
1167         ast_register_atexit(ast_moh_destroy);
1168         ast_cli_register(&cli_moh);
1169         ast_cli_register(&cli_moh_files_show);
1170         ast_cli_register(&cli_moh_classes_show);
1171         if (!res)
1172                 res = ast_register_application(app1, moh1_exec, synopsis1, descrip1);
1173         if (!res)
1174                 res = ast_register_application(app2, moh2_exec, synopsis2, descrip2);
1175         if (!res)
1176                 res = ast_register_application(app3, moh3_exec, synopsis3, descrip3);
1177         if (!res)
1178                 res = ast_register_application(app4, moh4_exec, synopsis4, descrip4);
1179
1180         if (!init_classes(0)) {         /* No music classes configured, so skip it */
1181                 ast_log(LOG_WARNING, "No music on hold classes configured, disabling music on hold.");
1182         } else {
1183                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1184         }
1185
1186         return 0;
1187 }
1188
1189 int reload(void)
1190 {
1191         if (init_classes(1))
1192                 ast_install_music_functions(local_ast_moh_start, local_ast_moh_stop, local_ast_moh_cleanup);
1193
1194         return 0;
1195 }
1196
1197 int unload_module(void)
1198 {
1199         return -1;
1200 }
1201
1202 char *description(void)
1203 {
1204         return "Music On Hold Resource";
1205 }
1206
1207 int usecount(void)
1208 {
1209         /* Never allow Music On Hold to be unloaded
1210            unresolve needed symbols in the dialer */
1211 #if 0
1212         int res;
1213         STANDARD_USECOUNT(res);
1214         return res;
1215 #else
1216         return 1;
1217 #endif
1218 }
1219
1220 char *key()
1221 {
1222         return ASTERISK_GPL_KEY;
1223 }