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